感知器
感知器是一个二元线性分类器,其目标是找到一个超平面将训练样本进行分隔(分类),其表示为
一般使用的激活函数不是阶跃函数,常用的有sigmoid函数(其导数:
σ′=σ(1−σ)
)
在1个样本的训练集上代价函数(最小均方误差)通常为
C=12|a−y|2
训练过程中步长(学习速率)为 α 的 w 和
w′ib′=wi−α∇wiC=b−α∇bC
分别求其梯度,由于在神经元中,上一步的输出是下一步的输入,也就是下一步中的自变量,根据链式法则可以得到
∂C∂wi∂C∂b=∂C∂z∂z∂wi=∂C∂z∂z∂b
其中
∂C∂z∂z∂wi∂z∂b=∂C∂a∂a∂z=12∂∂a|a−y|2∂a∂z=(a−y)σ(1−σ)=∂∂wi(∑i=0n−1wixi+b)=xi=∂∂wi(∑i=0n−1wixi+b)=1
最终可得
∂C∂wi∂C∂b=∂C∂z∂z∂wi=∂C∂a∂a∂z∂z∂wi=(a−y)σ(z)(1−σ(z))xi=∂C∂z∂z∂b=∂C∂a∂a∂z∂z∂b=(a−y)σ(z)(1−σ(z))
最终对有k个训练样本的感知机的迭代函数为
w′ib′=wi−α1k∑k=0k−1(ak−yk)σ(z)(1−σ(z))xi=b−α1k∑k=0k−1(ak−yk)σ(z)(1−σ(z))
多层神经网络
感知器可以看成一个最简单的二层神经网络,作为一个线性分类器它使用的局限性太大,而多层神经网络可以弥补它的缺点,并且训练原理与其类似
上图的三层神经网络多了一个隐含层,其中隐含层和输出层均为左下角的神经元,这个神经网络在训练过程时需要训练两层的神经网络,并且隐层的误差无法直接获取,而输出层的误差则和感知器相同:
同样在1个样本的训练集上代价函数(均方误差)通常为
C=12∑i=0n−1|aji−yji|2
也就是输出层每个神经元的输出和对应的目标值误差的平方和。
训练输出层
因为只有输出层的误差可以获取,所以训练从输出层开始,对第三层的第一个来说
∂C∂w31i∂C∂b31=∂C∂a31∂a31∂z31∂z31∂w31i=∂C∂a31∂a31∂z31x31i=∂C∂a31∂a31∂z31a21i=∂C∂a31∂a31∂z31∂z31∂b31=∂C∂a31∂a31∂z31
反向传播,训练隐含层
隐含层的训练也就是BP神经网络的重点,即误差的反向传播过程,因为隐含层的误差无法直接获取,所以才从输出层开始调整参数,然后误差向出入层开始传播,一层一层的进行训练
以训练隐含层的第一个神经元为例
∂C∂w21i=∂C∂z21∂z21∂w1i2=∂C∂a21∂a21∂z21∂z21∂w1i2=∂C∂z31∂z31∂a21∂a21∂z21∂z21∂w21i+∂C∂z32∂z32∂a21∂a21∂z21∂z21∂w21i=∂C∂a31∂a31∂z31∂z31∂a21∂a21∂z21∂z21∂w21i+∂C∂a32∂a32∂z32∂z32∂a21∂a21∂z21∂z21∂w21i
式子中红色部分即为输出层两个神经元计算过的,蓝色部分
z31=∑w31a2i+b
∂z31∂a21=w31∂z32∂a21=w32
weight这些值都是确定的,最后黄色部分也很容易求得。
∂C∂w21i∂C∂b21=∂C∂a31∂a31∂z31∂z31∂a21∂a21∂z21a11i+∂C∂a32∂a32∂z32∂z32∂a21∂a21∂z21a11i=∂C∂a31∂a31∂z31∂z31∂a21∂a21∂z21+∂C∂a32∂a32∂z32∂z32∂a21∂a21∂z21
如果有更多层,则都是在后一层计算完成的基础上进行更新。
K个训练样本
同感知器的K个同理,使用k个样本的平均误差进行更新
批随机梯度下降
因为样本的巨大,所以一次不会使用所有的样本进行训练,而是将训练样本分为比较小的部分进行分批训练。
实现
使用三层神经网络识别手写数字。
语言:C++
数据:Mnist
具体实现在我的图像处理库:zMatrix中的zml中。仅做参考