0
点赞
收藏
分享

微信扫一扫

多层感知机(MLP)的构建与实现

文风起武 2022-04-29 阅读 53

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

        从图中我们可以看到,相比单层神经网络,多了一层隐藏层(Hidden Layer大于等于1),如果展开之后,我们发现其实本质上还是等价于一个单层神经网络,但是这个隐藏层的加入,可以解决很多非线性的问题,处理办法就是在每个隐藏层的每个神经单元加一个激活函数(逐元素操作),对于常见的激活函数的求导过程,有兴趣的可以查阅:sigmoid和tanh激活函数与其导数的绘图详解icon-default.png?t=M3K6https://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一样,使用同样方法

        当我将隐藏层的单元个数增大到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一样,使用同样方法

 另外需要注意的就是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)

 修改为三个隐藏层:

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())

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

举报

相关推荐

0 条评论