多层感知机

多层感知机,第1张

        前面介绍的线性回归与Softmax回归,都属于单层神经网络,而在深度学习领域,主要关注多层模型,这节主要熟悉多层感知机(MultiLayer Perceptron,MLP),因为神经网络是由感知机启发而来的,尤其是深度学习模型,都是很多层的。

        从图中我们可以看到,相比单层神经网络,多了一层隐藏层(Hidden Layer大于等于1),如果展开之后,我们发现其实本质上还是等价于一个单层神经网络,但是这个隐藏层的加入,可以解决很多非线性的问题,处理办法就是在每个隐藏层的每个神经单元加一个激活函数(逐元素 *** 作),对于常见的激活函数的求导过程,有兴趣的可以查阅:sigmoid和tanh激活函数与其导数的绘图详解https://blog.csdn.net/weixin_41896770/article/details/124425011

 多层感知机的构建

import d2lzh as d2l
from mxnet import nd
from mxnet.gluon import loss as gloss

batch_size=200
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)
num_inputs,num_outputs,num_hiddens=784,10,256 #图片形状是28x28,输出为10个类别,隐藏层单元个数256
W1=nd.random.normal(scale=0.01,shape=(num_inputs,num_hiddens))
b1=nd.zeros(num_hiddens)
W2=nd.random.normal(scale=0.01,shape=(num_hiddens,num_outputs))
b2=nd.zeros(num_outputs)
params=[W1,b1,W2,b2]
for param in params:
    param.attach_grad()

#ReLU激活函数
def relu(X):
    return nd.maximum(X,0)

#多层感知机模型
def net(X):
    X=X.reshape((-1,num_inputs))
    H=relu(nd.dot(X,W1)+b1)
    return nd.dot(H,W2)+b2

loss=gloss.SoftmaxCrossEntropyLoss()
num_epochs,lr=5,0.5
d2l.train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,params,lr)#训练跟softmax一样,使用同样方法

epoch 1, loss 0.8012, train acc 0.703, test acc 0.819
epoch 2, loss 0.4749, train acc 0.823, test acc 0.839
epoch 3, loss 0.4096, train acc 0.850, test acc 0.855
epoch 4, loss 0.3833, train acc 0.858, test acc 0.873
epoch 5, loss 0.3702, train acc 0.864, test acc 0.871

        当我将隐藏层的单元个数增大到1000,测试结果看到损失率降低的快很多,准确率好像变化不大;将单元个数减少到50个,测试结果的准确率相对降低一点,这个参数属于超参数,有时候需要自己试着去调节,因为影响因素很多,有样本数量,初始化值等影响
新增一个隐藏层【两个隐藏层】,且epochs增加为10:

batch_size=200
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)
num_inputs,num_outputs,num_hiddens=784,10,256 #图片形状是28x28,输出为10个类别,隐藏层单元个数256
W1=nd.random.normal(scale=0.01,shape=(num_inputs,num_hiddens))
b1=nd.zeros(num_hiddens)
W2=nd.random.normal(scale=0.01,shape=(num_hiddens,num_hiddens))
b2=nd.zeros(num_hiddens)
W3=nd.random.normal(scale=0.01,shape=(num_hiddens,num_outputs))
b3=nd.zeros(num_outputs)

params=[W1,b1,W2,b2,W3,b3]
for param in params:
    param.attach_grad()

#ReLU激活函数
def relu(X):
    return nd.maximum(X,0)

#多层感知机模型
def net(X):
    X=X.reshape((-1,num_inputs))
    H1=relu(nd.dot(X,W1)+b1)
    H2=relu(nd.dot(H1,W2)+b2)
    return nd.dot(H2,W2)+b2

loss=gloss.SoftmaxCrossEntropyLoss()
num_epochs,lr=10,0.5
d2l.train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,params,lr)#训练跟softmax一样,使用同样方法

epoch 1, loss 1.9877, train acc 0.424, test acc 0.683
epoch 2, loss 0.6836, train acc 0.721, test acc 0.805
epoch 3, loss 0.5642, train acc 0.790, test acc 0.826
epoch 4, loss 0.4941, train acc 0.820, test acc 0.810
epoch 5, loss 0.4614, train acc 0.832, test acc 0.838
epoch 6, loss 0.4328, train acc 0.842, test acc 0.837
epoch 7, loss 0.4079, train acc 0.850, test acc 0.861
epoch 8, loss 0.4003, train acc 0.853, test acc 0.858
epoch 9, loss 0.3858, train acc 0.857, test acc 0.846
epoch 10, loss 0.3765, train acc 0.861, test acc 0.860

 另外需要注意的就是relu激活函数中的maximum函数与max函数的区别

x1=nd.array([1,9,2])
x2=nd.array([2,3,33])
nd.maximum(x1,x2)
[ 2.  9. 33.]#逐个元素比较,返回大的

而max是在指定的维度里面返回大的
x3=nd.array([[11,4,2],[3,8,13]])
nd.max(x3)#[13.]
nd.max(x3,0,keepdims=True)#[[11.  8. 13.]]
nd.max(x3,axis=1)#[11. 13.]
nd.max(x3,axis=1,keepdims=True)#[[11.],[13.]]

Gluon的简洁实现

import d2lzh as d2l
from mxnet import gluon,init
from mxnet.gluon import loss as gloss,nn

net=nn.Sequential()
net.add(nn.Dense(256,activation='tanh'),nn.Dense(10))#添加一个激活函数为tanh的隐藏层,单元个数为256个
net.initialize(init.Normal(sigma=0.01))

batch_size=200
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)
loss=gloss.SoftmaxCrossEntropyLoss()
trainer=gluon.Trainer(net.collect_params(),'sgd',{'learning_rate':0.5})
num_epochs=5
d2l.train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,None,None,trainer)

epoch 1, loss 0.7378, train acc 0.729, test acc 0.802
epoch 2, loss 0.5022, train acc 0.817, test acc 0.814
epoch 3, loss 0.4516, train acc 0.834, test acc 0.821
epoch 4, loss 0.4144, train acc 0.848, test acc 0.848
epoch 5, loss 0.3968, train acc 0.854, test acc 0.843

 修改为三个隐藏层:

net.add(nn.Dense(256,activation='relu'))
net.add(nn.Dense(128,activation='relu'))
net.add(nn.Dense(64,activation='relu'))
net.add(nn.Dense(10))
net.initialize(init.Normal(sigma=0.01))
print(net.collect_params())

sequential11_ (
  Parameter dense26_weight (shape=(256, 0), dtype=float32)
  Parameter dense26_bias (shape=(256,), dtype=float32)
  Parameter dense27_weight (shape=(128, 0), dtype=float32)
  Parameter dense27_bias (shape=(128,), dtype=float32)
  Parameter dense28_weight (shape=(64, 0), dtype=float32)
  Parameter dense28_bias (shape=(64,), dtype=float32)
  Parameter dense29_weight (shape=(10, 0), dtype=float32)
  Parameter dense29_bias (shape=(10,), dtype=float32)
)
epoch 1, loss 2.1370, train acc 0.150, test acc 0.262
epoch 2, loss 1.0931, train acc 0.553, test acc 0.765
epoch 3, loss 0.6632, train acc 0.748, test acc 0.788
epoch 4, loss 0.5276, train acc 0.806, test acc 0.805
epoch 5, loss 0.4569, train acc 0.832, test acc 0.846

        最后讲解下net.initialize(init.Normal(sigma=0.01))这个0.01标准差的正态分布,一般来说,模型的权重参数都是采用正态分布的随机初始化,而不是自己去指定同样的值,为什么呢?因为大家想想,如果参数值都一样,是不是在正向传播和反向传播当中的参数值都没有变化,梯度值也没有在迭代中优化,那么多层的神经网络跟单个隐藏层就没有区别了,所以我们都会对权重参数做随机初始化。
随机初始化除了正态分布,还有He和xavier,其中xavier的特点是不会受到输入层和输出层的个数的影响,Xavier公式为:    [其中a为输入个数,b为输出个数]
一般怎么选择,看激活函数,如果激活函数是ReLU就选择He,激活函数是sigmoid就选择Xavier.

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/791722.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存