python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现...

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第1张图片

0 序言

上一篇文章中,结合全连接神经网络对反向传播算法(BP)进行了分析.

本文将对模型细节进行讨论补充,定性分析激活函数的使用,阐述网络中数据维度情况;记录自己在BP算法学习过程中的一些思考(纯属发散,可跳过. 如有不正确之处欢迎讨论);给出深度神经网络BP算法代码实现(文末)及结果.

1 激活函数的位置

上文最后小节(3.3)介绍了结合Softmax和Cross Entropy Loss Function的神经网络反向传播输出层梯度计算. 在该网络中,输出层(第

层)在Feedforward过程仍使用了激活函数
,得到
,再对
做softmax得到
.

代表Sigmoid函数,常见激活函数还包括Relu(族)、Softplus、Tanh等,下表给出了几种经典激活函数及对应求导结果.

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第2张图片
表1 典型激活函数及对应导数

可见,实际上对于输出层,我们进行了2种操作:

.
的作用是将网络输出映射至(0, 1),便于划分阈值,处理
二分类问题;对于 多分类问题,则可以通过Softmax将输出归一化至(0, 1),得到类似概率分布的结果进行判断. 因此实际上这两种操作(activation, softmax)并不需要对输出层同时使用.

如果采用其他的激活函数,甚至有可能导致网络无法输出全部范围的值(如Relu),或是激活函数的导数在-1和1附近变得非常小,发生“梯度消失”.

"一般来说,为了保险起见,不要在最后一层使用激活函数. 有时候聪明反被聪明误. " ['In general your best bet is often to play it safe and use no activation function at all on the final layer rather than trying to do something clever that may backfire.']

[Stanford CS231]示例中输出层未接激活函数,直接做Softmax.

2 Further discussion on Softmax + Cross Entropy

在一些文章中,将Softmax也称为激活函数,对输出层进行softmax激活. 在不接其他激活函数的情况下,上篇文章3.3节中递推起始层对权重矩阵和偏置向量梯度计算没有了对

的导数
,因此下面两式(上篇文章中(3.16),(3.17))中没有了
部分.

即:

可以看出,使用Softmax和交叉熵,可以减少输出层的

,从而略微减轻"梯度消失".

另一方面,由于真实标签

采用one-hot编码,仅有1个分量为1,因此在一些文章和代码demo中梯度计算项会出现
的记法,其实是式(2.2)中真实类别对应的元素项,从向量角度的计算为(
是真实类别
):

3 还是数据数量的问题:向量→矩阵→平均梯度

把输出层做Softmax激活的网络的BP算法递推重写如下:

观察第2组式子,

是一个
维矩阵,即
维向量. 这个向量是由1个输入数据
经过各层正向传播得到的向量
,再逐层反向递推得到,从而计算出每一层的
.

注意,上述过程中,输入1个数据

,对应产生1组梯度
,这正是随机梯度下降(SGD)算法的数据情况. 那么在使用Batch GD或Mini-batch GD进行优化的情况下,
输入
个数据组成的
维矩阵,
输出
个对应
组成的
维矩阵. 下面我们分析权重矩阵
和偏置向量
的计算. 首先看
,以第
层为例,输入1个数据时:

输入

个数据时,输出变为
,因此应计算
个梯度(这里特指
的梯度)
,形成以每列为一个数据对应梯度组成的矩阵:

最终我们需要的梯度

是向量,但得到了
个梯度,因此需要将所有向量求平均,作为该次iteration的梯度. 示意代码如下:
# y_label即使没有做one-hot来与y对齐行数,np中的Broadcast机制也能保证正确计算
Delta = y - y_label  
delta = np.sum(Delta, axis = 1, keepdims=True) / M

再看

:

个数据输入的情况下,对于输出层的梯度,式(3.3)应写为:

式(3.3)中向量相乘维度为:

;

式(3.4)中矩阵相乘维度为:
.

两者结果维数完全相同,但(3.4)式的结果其实对应着

个(3.3)结果中矩阵之和,定性理解见图1. 读者也可以结合矩阵相乘的定义,用元素乘累加的方式定量表述两式,对比一下很容易理解,作为小练习吧:).

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第3张图片
图1 梯度矩阵与输出层矩阵相乘示意

从图1可看出,在网络一次输入

个数据时,误差对权重的梯度矩阵变成了每次输入1个数据计算得到的
个梯度矩阵之和。因此也需将计算结果求平均,示意代码如下:
dW_L = np.dot(Delta, ys[-2].T) / M  # ys是存放各层激活值的list
对于隐藏层
的梯度在
个数据输入时的情况,只是
的计算式从
变为
,均为
的向量,因此从向量到矩阵,再到梯度平均的过程和输出层分析完全相同.

4 一些思考和自言自语(可直接跳过)

4.1 DNN

从线性到非线性的飞跃:激活函数.

4.2 正向传播

这里需注意:也许是人们的成长经历养成的视觉和思维习惯,使得我们在第一眼看见神经网络的结构图时,潜意识里会更加关注圆圈,认为圆圈(神经元)比线条(权重)更加重要(我的第一感觉就是这样). 但是这在神经网络这个scenario,其实最重要的是

,请牢记!我们所做的所有思维体操,都围绕着这两个家伙展开. 而代表着神经元的圆圈,其实只是
的byproduct. 3blue1brown中打了个很巧妙的比喻:神经元neurons就是装
结果的容器.

4.3 Loss Function

  • 衡量真实值与网络输出值之间的差异. 包含了特征提取、模式识别、信号稀疏表示、空间投影等多个信息技术领域的原理与思想:样本的数据空间由一组广义基(区别于该空间的向量空间基)张成,这组广义基并不一定相互正交,也可以是low coherence的. 于是,广义基的基数(Cardinality)可以大于该数据空间的向量空间的基的数量.
  • 对于特征提取、模式识别,广义基可以理解为目标空间所包含的所有特征组成的集合,如:各种形状、局部器官、纹理、层次、颜色等,具有很好的直观意义,便于理解和解释.
  • 对于信号稀疏表示(sparse reprensentation),广义基可以理解为该空间所对应的超完备字典/正交级联字典中的所有原子,或者DFT, DWT, DCT, wavelet, Harr小波基, Doubechies的D4, D8小波基, chirplet/curvelet/bandlet/Contourlet基, Gabor基等等对应的各种基向量.
  • 有了广义基,输入数据(信号)即可在广义基张成的空间上进行投影,保留最重要的分量,使得逼近信号和原信号的误差最小,得到数据的稀疏表示. 如果将傅里叶分析作为鼻祖,信号表示中的各种基的寻找已有至少两个世纪的研究和积累. 这种方式得到的广义基具有更明确的自然和物理意义,有很强的可解释性.
  • 对于经训练得到的冗余字典,已经具有了一定的“自适应”特点,这和深度神经网络的训练的本质非常相似,都是通过数据(信号)驱动,去得到尽可能匹配数据空间的模型或者框架,这也是“智能”开始的标志. 前文所述的技术——深度神经网络更往前走了一步:几乎不通过任何结构化/先验的框架(神经元模型当然是必须有的),完全“自组织”地生成网络结构,最终数据(信号)通过这个网络可得到连续/离散的输出. 其实也相当于数据(信号)在一个高维空间上对其所有广义基的投影,而由于空间结构的约束,投影结果维度就是网络输出层维数. 最为精妙的地方在于:这种“自组织”的广义基没有了训练基、框架、线性等因素的限制,能够更好地匹配训练数据对应的空间.
  • 另一方面,没有了诸多约束条件,使得得到的网络结构/广义基难以描述和解释,这是目前深度学习理论的短板,也是很多学者在不断探索的领域. 笔者认为结合信号表述、空间投影理论,也许能够一定程度上解决深度学习理论的可解释性问题.
  • 明白了上面小节,可以继续来思考误差的定义:真实值/原始信号与预测值/经过广义基线性组合的逼近信号 之间的差异. 怎么衡量差异?最直观的想法就是两点之间距离,进而演进到向量的距离的定义,或者从“熵增”的角度来度量等等. 这些度量方式抽象出来,都包含3点性质:正定性、齐次性、三角不等式. 由此可以进一步将距离的定义推广至赋范空间. 如
    范数:

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第4张图片
图2 lp范数示意
  • 图2给出了常见的几种
    范数在三维空间下的图像.
    时,将
    范数形式作为正则化项可以增加稀疏性. 2范数也就是常用的欧式距离. 实际中,
    一般取0,1,2,因为这几种范数的计算比
    简单. 但应注意,不同的
    对应不同几何意义,有兴趣的同学可查阅相关资料.
  • 降低误差直至达到可接受的值. 最好的结果:找到最小值;其次是找到局部最小值;再其次是小于一个设定的误差阈值. 无论要达到哪个目标,总归是要降低误差,而误差又是的函数. 这个函数的输入是
    . 函数
    的系数是待训练的数据
    .

4.4 梯度下降法

  • 要使误差逐渐降低,可以有无数种方式,但要“最效率”地达到这个目标,最直观的想法就是“怎么不走弯路就怎么走”. 用生活中最直观的例子:下山. An intuitive idea is:迈步子之前先看看,然后朝着垂直下降最快的方向走. 从理论上可以证明(李宏毅教授DL课程),这种直观而又朴素的想法是非常正确的. 这里隐隐地包含了“奥卡姆剃刀原理”,在生活中我们常常可以用这种方法论来帮助自己.
  • 回到正题,刚才说到方向,但请别忘了步子大小,这也是个非常重要的因素!还是下山的例子(文章标题上方配图),如果发现这里有个悬崖,嗯,下降的方向完美:垂直于地面,但是咱们绝不能一步就从悬崖跳到地面!这个方向确实是最好的,可还是只能一点一点往下走,比方说利用工具固定在悬崖边上,一步一步挪。当然,在实际中我们也绝对不会这么干:遇上这种情况,我们会找一条次优的、可行的路径平安下山;而在数学上,“从悬崖直接往下跳”这种操作表明该点不可导,已经不符合梯度下降要处处可导的前提了. 退一步想想,即使可导,也不能在一个点上飞快地下降一大段,因为也许在你前进的这一段路径中,又出现了下降更快(梯度更大)的方向.

4.5 关于

的初始值
  • 不能为零矩阵
    可以为零向量
    ,否则网络更新参数计算梯度时,梯度为零,无法更新.
  • 不能在初始化时每层矩阵都用全部相同数值,否则可能导致各隐藏层的输入输出都相同,神经网络“退化”成了一根导线/一个低秩(
    )矩阵/一个线性函数
    ,失去了我们所希望的非线性特质.

5 代码与结果

实现了Fully Connected Neural Network的BP算法及训练过程. 模型层数、神经元个数、隐藏层激活函数类型可设置(3种经典激活:sigmoid, relu, tanh),方便调参对比结果. 输出层使用softmax激活,Cross Entropy损失函数.

Github传送门

一些结果:

网络4层:隐藏层神经元个数:25, 25. 3分类,BGD Optimizer, iterations = 25000.

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第5张图片
图3 BGD, Sigmoid激活

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第6张图片
图4 BGD, Relu激活

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第7张图片
图5 BGD, Tanh激活

对比图3-图5,Sigmoid激活函数训练时间居中,但是达到训练次数时仍欠拟合,性能54.0%;Relu激活函数时间最短,性能较好99.33%;Tanh函数训练时间最长,效果与Relu接近98.83%.

网络4层:隐藏层神经元个数:25, 25. 3分类,MBGD Optimizer, mini-batch-size =20, epochs = 10000.

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第8张图片
图6 MBGD, Sigmoid激活

对比图3、图6,采用小批量梯度下降后,sigmoid激活函数也可以较好地拟合(99.16%),但训练时间随着计算次数增加而增加.

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第9张图片
图7 MBGD, Relu激活

python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第10张图片
图8 MBGD, Tanh激活

观察图7,图8,Relu和Tanh激活函数收敛速度明显快于Sigmoid(图6),两者性能相当(99.67%). Tanh函数训练时间最长,且在该实验参数条件下,已经开始出现过拟合.

6 总结

本系列是笔者学习DL的一些思考和记录. 可以说,所有想学深度学习的同学都有矩阵、概率和一定的泛函、随机过程基础. 对于很多经典算法理论,如LR、NN、SVM、kNN、决策树PCA、Manifold等都有掌握. 为了迅速上手,也许一上来就开始看CNN、RNN,LSTM, resNet,甚至Attention、HAN、Transformer、BERT、GPT2.0这些近几年出现的最新模型和方法.

相信我,如果不是科班ML出身,又决心把DL扎扎实实学好的话,还是会一步一步反向回溯每个知识点,最终来到知识的源头——DNN和BP的. 那么,就正向地从BP开始吧。毕竟DNN的第一步也是正向传播嘛,哈哈.

同时,从理论到代码还有很长的路要走,每次操作的对象是什么?输入、输出是什么?数据在每层是怎么流动的?矩阵还是向量还是标量?它们的的维度又是多少?写代码的时候如果把这些问题都想明白了,才算真的吃透了深度神经网络,迈出了DL的第一步.

参考了前辈、大神们的代码,自己也写了一个,并做了尽量详尽的注释,欢迎交流指正.

“万丈高楼平地起”——此为自勉.

声明:本文为原创文章,欢迎转载。转载时请注明出处:

观海云远:深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现​zhuanlan.zhihu.com
python bp神经网络_深度学习之反向传播算法(3)——全连接神经网络BP算法思考及Python实现..._第11张图片

你可能感兴趣的:(python,bp神经网络,深度回声状态网络python)