自行构造一个多层感知机,完成对某种类型的样本数据的分类(如图像、文本等),也可以对人工自行构造的二维平面超过3类数据点(或者其它标准数据集)进行分类。
能给出与线性分类器(自行实现)作对比,并分析原因。
用不同数据量,不同超参数,比较实验效果。
不许用现成的平台,例如Pytorch,Tensorflow的自动微分工具。
实现实验结果的可视化。
如图1所示,在这个模型中,神经元接收到来自 n n n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接(connection)进行传递,神经元接收到的总输入值将与神经元的阈值(偏置)进行比较,然后通过“激活函数”(activation function) 处理以产生神经元的输出。
理想中的激活函数是阶跃函数 s g n ( ? ) sgn( \bullet ) sgn(?),它将输入值映射为输出值“0”或“1”,显然“1”对应于神经元兴奋,“0”对应于神经元抑制。然而,阶跃函数具有不连续、不光滑等不太好的性质,实际常用Sigmoid、ReLU等函数作为激活函数
把许多个这样的神经元按一定的层次结构连接起来,就得到了神经网络。
多层感知机(Multilayer Perceptron, MLP)是一种前向结构的人工神经网络,映射一组输入向量到一组输出向量,MLP可以被看作是一个有向图,由多个的节点层所组成,每一层都全连接到下一层,除了输入节点,每个节点都是一个带有非线性激活函数的神经元。MLP网络结构包含输入层、输出层及多个隐藏层,其中输入层神经元接收外界输入,隐藏层与输出层神经元对信号进行加工,最终结果由输出层神经元输出。3层感知机的神经网络图如下所示:
一个MLP可以视为包含了许多参数的数学模型,这个模型是若干个函数 y j = f ( ∑ i w i b i ? θ i ) y_{j} = f(\sum_{i}{w_{i}b_{i} - \theta_{i}}) yj?=f(∑i?wi?bi??θi?) 相互(嵌套)代入得到的。而对于给定由 d d d个属性描述,输出为 l l l维实值向量的训练集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x m , y m ) ) , x ∈ R d , y ∈ R l D = \left\{ {(x}_{1},y_{1} \right),{(x}_{2},y_{2}),\ldots,{(x}_{m},y_{m})),x \in \mathbb{R}^{d},y \in \mathbb{R}^{l} D={(x1?,y1?),(x2?,y2?),…,(xm?,ym?)),x∈Rd,y∈Rl,则隐藏层第 h h h个神经元接收到的输入为 α h = ∑ i = 1 d v i h x i \alpha_{h} = \sum_{i = 1}^{d}{v_{ih}x_{i}} αh?=∑i=1d?vih?xi?,输出层第 j j j个神经元接收到的输入为 α h = ∑ h = 1 q w h j b h \alpha_{h} = \sum_{h = 1}^{q}{w_{hj}b_{h}} αh?=∑h=1q?whj?bh?。假设神经元激活函数为 σ ( ? ) \sigma( \bullet ) σ(?)。
模型训练主要包括前馈传播和反向传播两个步骤,前馈传播负责计算模型的预测值,而反向传播负责计算梯度并更新模型的参数,降低损失函数,以便在训练中不断改进模型的性能。
具体而言,前馈传播是神经网络中的正向计算过程,它从输入层开始,沿着网络的层级顺序将数据传递到输出层,从而计算模型的预测值,但此过程并不涉及权重和偏差的更新,即计算
y k = g { ∑ j = 1 m w k j ( s ) ? [ a ( ∑ i = 1 n w j i ( 1 ) x i + b j ( 1 ) ) ] ? + b k ( s ) } , k = 1 , 2 , ? ? , l y_{k} = g\left\{ \sum_{j = 1}^{m}w_{kj}^{(s)}\cdots\left\lbrack a\left( \sum_{i = 1}^{n}{w_{ji}^{(1)}x_{i}} + b_{j}^{(1)} \right) \right\rbrack\cdots + b_{k}^{(s)} \right\},k = 1,2,\cdots\text{?},l yk?=g{j=1∑m?wkj(s)??[a(i=1∑n?wji(1)?xi?+bj(1)?)]?+bk(s)?},k=1,2,??,l
反向传播则是使用前馈传播计算模型的输出,并将其与实际目标进行比较,计算损失(误差)。
ALGORITHM 1 Backpropagation(反向传播算法)
基于梯度下降GD或随机梯度下降SGD的学习算法的核心是针对给定样本,计算损失函数对神经网络所有参数的梯度 ? L ? θ \frac{\partial L}{\partial\theta} ?θ?L?,并以此更新所有参数 θ \theta θ。考虑一个 s s s层神经网络,其中第 t t t层的神经元定义为:
h j ( t ) = a ( z j ( t ) ) , z j ( t ) = ∑ i = 1 n w j i ( t ) h i ( t ? 1 ) + b j ( t ) , j = 1 , 2 , ? ? , m h_{j}^{(t)} = a\left( z_{j}^{(t)} \right),z_{j}^{(t)} = \sum_{i = 1}^{n}{w_{ji}^{(t)}h_{i}^{(t - 1)}} + b_{j}^{(t)},j = 1,2,\cdots\text{?},m hj(t)?=a(zj(t)?),zj(t)?=i=1∑n?wji(t)?hi(t?1)?+bj(t)?,j=1,2,??,m
损失函数对第 t t t层的权重和偏置的梯度分别为 ? L ? w j i ( t ) \frac{\partial L}{\partial w_{ji}^{(t)}} ?wji(t)??L?和 ? L ? b j ( t ) \frac{\partial L}{\partial b_{j}^{(t)}} ?bj(t)??L?。根据链式求导规则,可以展开为:
? L ? w j i ( t ) = ? L ? z j ( t ) ? z j ( t ) ? w j i ( t ) , ?? ? L ? b j ( t ) = ? L ? z j ( t ) ? z j ( t ) ? b j ( t ) \frac{\partial L}{\partial w_{ji}^{(t)}} = \frac{\partial L}{\partial z_{j}^{(t)}}\frac{\partial z_{j}^{(t)}}{\partial w_{ji}^{(t)}},\ \ \frac{\partial L}{\partial b_{j}^{(t)}} = \frac{\partial L}{\partial z_{j}^{(t)}}\frac{\partial z_{j}^{(t)}}{\partial b_{j}^{(t)}} ?wji(t)??L?=?zj(t)??L??wji(t)??zj(t)??,???bj(t)??L?=?zj(t)??L??bj(t)??zj(t)??
考虑损失函数对第 t t t层的净输入的梯度 δ j ( t ) = ? L ? z j ( t ) , j = 1 , 2 , ? ? , m \delta_{j}^{(t)} = \frac{\partial L}{\partial z_{j}^{(t)}},j = 1,2,\cdots\text{?},m δj(t)?=?zj(t)??L?,j=1,2,??,m,则上式可写成:
? L ? w j i ( t ) = δ j ( t ) h i ( t ? 1 ) , ?? ? L ? b j ( t ) = δ j ( t ) \frac{\partial L}{\partial w_{ji}^{(t)}} = \delta_{j}^{(t)}h_{i}^{(t - 1)},\ \ \frac{\partial L}{\partial b_{j}^{(t)}} = \delta_{j}^{(t)} ?wji(t)??L?=δj(t)?hi(t?1)?,???bj(t)??L?=δj(t)?
而对于第 t t t层的 δ j ( t ) \delta_{j}^{(t)} δj(t)?,可展开为
δ j ( t ) = ? L ? z j ( t ) = ∑ k = 1 l ? L ? z k ( t + 1 ) ? z k ( t + 1 ) ? z j ( t ) , j = 1 , 2 , ? ? , m \delta_{j}^{(t)} = \frac{\partial L}{\partial z_{j}^{(t)}} = \sum_{k = 1}^{l}{\frac{\partial L}{\partial z_{k}^{(t + 1)}}\frac{\partial z_{k}^{(t + 1)}}{\partial z_{j}^{(t)}}},j = 1,2,\cdots\text{?},m δj(t)?=?zj(t)??L?=k=1∑l??zk(t+1)??L??zj(t)??zk(t+1)??,j=1,2,??,m
求解得到 δ j ( t ) = d a d z j ( t ) ∑ k = 1 l w k j ( t + 1 ) δ k ( t + 1 ) \delta_{j}^{(t)} = \frac{da}{dz_{j}^{(t)}}\sum_{k = 1}^{l}{w_{kj}^{(t + 1)}\delta_{k}^{(t + 1)}} δj(t)?=dzj(t)?da?∑k=1l?wkj(t+1)?δk(t+1)?。其中, d a d z j ( t ) \frac{da}{dz_{j}^{(t)}} dzj(t)?da?为第 t t t层激活函数关于 z j ( t ) z_{j}^{(t)} zj(t)?的导数。也就是说可以根据 t + 1 t + 1 t+1层的 δ k ( t + 1 ) \delta_{k}^{(t + 1)} δk(t+1)?计算 δ j ( t ) \delta_{j}^{(t)} δj(t)?。
多分类问题中,输出层由 l l l个输出表示 l l l个类别的概率。损失函数是交叉熵损失 ? ∑ k = 1 l y k log ? h k ( s ) - \sum_{k = 1}^{l}{y_{k}\log h_{k}^{(s)}} ?∑k=1l?yk?loghk(s)?,激活函数是Softmax函数 g ( z ) = e z ∑ z ′ e z ′ g(z) = \frac{e^{z}}{\sum_{z^{'}}^{}e^{z^{'}}} g(z)=∑z′?ez′ez?,此时误差是
δ k ( s ) = h k ( s ) ? y k , ? k = 1 , 2 , ? ? , l \delta_{k}^{(s)} = h_{k}^{(s)} - y_{k},\ k = 1,2,\cdots\text{?},l δk(s)?=hk(s)??yk?,?k=1,2,??,l
而后从输出层开始基于链式法则计算损失对每个权重和偏差的梯度,使用Adam、SGD等优化算法来更新网络中的权重和偏差,以减小损失函数的值。
通过反复迭代前馈传播和反向传播过程,多层感知机可以逐渐调整其权重和偏差,从而提高对输入数据的表示能力和泛化能力。
4.2.1 数据处理
读入数据,标签采用独热编码( 1 ? o f ? K 1\ of\ K 1?of?K)。
使用np.random.randn
方法随机初始化神经元之间的连接矩阵
w
w
w和偏置
b
b
b,同时初始化各层神经元为
h
(
i
)
h^{(i)}
h(i)以保存中间结果(包含输入输出层)
将输入
w
w
w赋值给
h
(
0
)
h^{(0)}
h(0),随后逐层计算
a
(
W
(
t
)
h
(
t
?
1
)
+
b
(
t
)
)
a\left( W^{(t)}h^{(t - 1)} + b^{(t)} \right)
a(W(t)h(t?1)+b(t)),使用函数类保存中间结果,同时返回最终输出层
h
(
s
)
h^{(s)}
h(s)。实验激活函数采用sigmoid
和softmax
函数。
4.2. 反向传播
给定最终标签计算当前预测值的损失和梯度 δ ( s ) = h ( s ) ? y ′ \delta^{(s)} = h^{(s)} - y^{'} δ(s)=h(s)?y′。随后按 W n e w ( t ) ← W ( t ) ? η ? W ( t ) L , b n e w ( t ) ← b ( t ) ? η ? b ( t ) L , δ ( t ? 1 ) = ? a ? z j ( t ? 1 ) ? ( W ( t ) T ? δ ( t ) ) W_{new}^{(t)} \leftarrow W^{(t)} - \eta\nabla_{W^{(t)}L},b_{new}^{(t)} \leftarrow b^{(t)} - \eta\nabla_{b^{(t)}L},\delta^{(t - 1)} = \frac{\partial a}{\partial z_{j}^{(t - 1)}}\bigodot\left( {W^{(t)}}^{T} \bullet \delta^{(t)} \right) Wnew(t)?←W(t)?η?W(t)L?,bnew(t)?←b(t)?η?b(t)L?,δ(t?1)=?zj(t?1)??a??(W(t)T?δ(t))依层记录梯度和参数并返回。
使用random.shuffle
方法打乱数据,每次取数据中的前batch_size
组使用前向传播和反向传播计算更新梯度和偏置,随后取算数平均对参数进行更新。
随后设置迭代次数,重复上述步骤,即可训练得到可以分类的神经网络。
使用和逻辑回归相似的Softmax回归构造线性分类器,和逻辑回归唯一不同的地方在于,由于此问题中对应的是多分类问题,因此Softmax回归最后改用Softmax()
替代Sigmoid()
进行概率的选择。其余交叉熵损失函数及梯度下降求导的式子完全一致。
在本次实验中,使用神经元数目分别为 784 , 100 , 10 784,100,10 784,100,10的三层感知机,采用Sigmoid函数作为激活函数和Softmax函数对MNIST数据集进行分类。
使用交叉熵损失函数和SGD优化器,将模型输入通道根据数据集设为1,并设置训练超参数epoch
为100,batch size
为256(相当于只用了25600组训练数据),学习率learning rate
为0.1。训练过程中损失函数loss
的值和在测试集上的准确率变化如下图所示。
实验发现,随训练过程的进行,损失函数不断降低,在测试集上准确率逐渐升高,最终测试正确率最高能够达到约92%。损失函数和测试准确率在训练最后阶段呈现波动态,可能原因是在局部最优点附近振荡。
多层感知机模型是矩阵与向量的乘积的非线性变换的多次重复,其核心在与引入了非线性因素,能够学习和捕捉复杂的非线性关系,其基本结构较为简单,其具有较强的表达能力,可适应图像分类、识别等多种人工智能任务。
Softmax回归相当于2层(只有输入输出层)的多层感知机,没有引入非线性因素,在一定程度上对数据更为敏感,且对非线性问题表达能力较弱。
选择合适的学习率能够减少模型训练的时间,但梯度下降法较难收敛,提高训练轮次可能会提供模型的能力。同时,合适的权重初始化也能减少模型的训练时间和提高模型的训练效果。
但是,单纯加深模型深度没有特别大的意义,除了训练时间会增加,还可能会出现梯度消失或者梯度爆炸等问题,可以考虑引入残差等结构。
[1] 李航. 统计学习方法[M]. 清华大学出版社, 2012.
[2] 周志华. 机器学习[M]. 清华大学出版社, 2016.