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

0 序言

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

1 激活函数的位置

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

层)在Feedforward过程仍使用了激活函数

,得到

,再对

做softmax得到

.

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

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

.

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

如果采用其他的激活函数,甚至有可能导致网络无法输出全部范围的值(如Relu),或是激活函数的导数在-1和1附近变得非常小,发生“梯度消失”.[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. 读者也可以结合矩阵相乘的定义,用元素乘累加的方式定量表述两式,对比一下很容易理解,作为小练习吧:).图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点性质:正定性、齐次性、三角不等式. 由此可以进一步将距离的定义推广至赋范空间. 如

范数:

图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损失函数.

一些结果:网络4层:隐藏层神经元个数:25, 25. 3分类,BGD Optimizer, iterations = 25000.图3 BGD, Sigmoid激活图4 BGD, Relu激活图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.图6 MBGD, Sigmoid激活

对比图3、图6,采用小批量梯度下降后,sigmoid激活函数也可以较好地拟合(99.16%),但训练时间随着计算次数增加而增加.图7 MBGD, Relu激活图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小波神经网络)