多层感知机含有一个隐藏层,
以下是一种含单隐藏层的多层感知机的设计,其输出O∈Rn×q\boldsymbol{O} \in \mathbb{R}^{n \times q}O∈Rn×q的公式为:
H=XWh+bh,O=HWo+bo, \begin{aligned} \boldsymbol{H} &= \boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h,\\ \boldsymbol{O} &= \boldsymbol{H} \boldsymbol{W}_o + \boldsymbol{b}_o, \end{aligned} HO=XWh+bh,=HWo+bo,
将以上两个式子联立起来,可以得到
O=(XWh+bh)Wo+bo=XWhWo+bhWo+bo. \boldsymbol{O} = (\boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h)\boldsymbol{W}_o + \boldsymbol{b}_o = \boldsymbol{X} \boldsymbol{W}_h\boldsymbol{W}_o + \boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_o. O=(XWh+bh)Wo+bo=XWhWo+bhWo+bo.
虽然神经网络引入了隐藏层,却依然等价于一个单层神经网络:其中输出层权重参数为WhWo\boldsymbol{W}_h\boldsymbol{W}_oWhWo,偏差参数为bhWo+bo\boldsymbol{b}_h \boldsymbol{W}_o + \boldsymbol{b}_obhWo+bo。不难发现,即便再添加更多的隐藏层,以上设计依然只能与仅含输出层的单层神经网络等价。
解决办法是引入非线性变换,也叫激活函数。
激活函数 ReLU函数ReLU(rectified linear unit)函数提供了一个很简单的非线性变换。给定元素xxx,该函数定义为
ReLU(x)=max(x,0). \text{ReLU}(x) = \max(x, 0). ReLU(x)=max(x,0).
可以看出,ReLU函数只保留正数元素,并将负数元素清零。
Sigmoid函数sigmoid函数可以将元素的值变换到0和1之间:
sigmoid(x)=11+exp(−x). \text{sigmoid}(x) = \frac{1}{1 + \exp(-x)}. sigmoid(x)=1+exp(−x)1.
tanh函数tanh(双曲正切)函数可以将元素的值变换到-1和1之间:
tanh(x)=1−exp(−2x)1+exp(−2x). \text{tanh}(x) = \frac{1 - \exp(-2x)}{1 + \exp(-2x)}. tanh(x)=1+exp(−2x)1−exp(−2x).
关于激活函数的选择ReLu函数是一个通用的激活函数,目前在大多数情况下使用。但是,ReLU函数只能在隐藏层中使用。
用于分类器时,sigmoid函数及其组合通常效果更好。由于梯度消失问题,有时要避免使用sigmoid和tanh函数。
在神经网络层数较多的时候,最好使用ReLu函数,ReLu函数比较简单计算量少,而sigmoid和tanh函数计算量大很多。
在选择激活函数的时候可以先选用ReLu函数如果效果不理想可以尝试其他激活函数。
加上激活函数之后,我们的多层感知机公式为
H=ϕ(XWh+bh),O=HWo+bo,
\begin{aligned} \boldsymbol{H} &= \phi(\boldsymbol{X} \boldsymbol{W}_h + \boldsymbol{b}_h),\\ \boldsymbol{O} &= \boldsymbol{H} \boldsymbol{W}_o + \boldsymbol{b}_o, \end{aligned}
HO=ϕ(XWh+bh),=HWo+bo,
其中ϕ\phiϕ表示激活函数。
多层感知机pytorch实现import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
num_inputs, num_outputs, num_hiddens = 784, 10, 256
# 网络结构
net = nn.Sequential(
d2l.FlattenLayer(), # 图片数据转为一维
nn.Linear(num_inputs, num_hiddens), # 线性模型
nn.ReLU(), # 激活函数
nn.Linear(num_hiddens, num_outputs), # 线性模型
)
for params in net.parameters():
init.normal_(params, mean=0, std=0.01) # 初始化参数
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')
loss = torch.nn.CrossEntropyLoss() # 损失函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.5) # 梯度下降
num_epochs = 5
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, None, None, optimizer)