人工神经网络——【BP】反向传播算法证明
第一步:前向传播
【注】此BP算法的证明仅限sigmoid**函数情况。本博文讲道理是没错的,毕竟最后还利用代码还核对了一次理论证明结果。
关于更为严谨的BP证明,即严格通过上下标证明BP的博客请戳这里
简单的三层网络结构如下
参数定义:
可见层定义为X,共有n个单元,下标用 i表示
隐藏层定义为B,共有p个单元,下标用 j 表示
输出层定义为Y,共有q个单元,下标用 k表示
可见层到隐藏层权重矩阵为W,大小为 p*n
隐藏层到输出层权重矩阵为V,大小为q*p
① 计算隐藏层各神经元**值
代表所有可见层单元乘以连接到第j个隐单元的权重,再减去偏置或者阈值
②计算隐含层单元的输出值
采用sigmoid函数即S型函数
③计算输出层各神经元**值
④计算输出层单元的输出值
第二步:逆向传播
校正是从后往前进行的,所以称为误差逆传播,计算是从输出层到隐藏层,再从隐藏层到输入层。更新的是权重和偏置,称为模型参数
两层的权重和偏置的更新是类似的,下面以输出层到隐藏层的权重和偏置更新为例。
采用平方和误差衡量期望输出与实际输出的差别:
输出层→隐藏层的更新
先对权重求梯度:
【注】上式中最后一个等号左边第二项求导利用对sigmoid函数求导
接下来对偏置求梯度
隐藏层→输入层的更新
【注】建议这一层的更新,读者认真推导,这样会对BP的更新有更深刻的印象
第四步:模型参数校正
这一步就非常简单啦,直接用原始的模型参数,减去现在的模型参数就行啦,其中会加入一个学习率η,控制梯度下降速度
第五步:一般性推导
【注】以下纯为个人理解,与网络上那些复杂点的公式可能有出入,实际情况有待考证..............
上面只是三层BP神经网络的推导,看着已经很复杂了,这时候会产生一个想法:如果是很多层的BP神经网络该如何去推导?难道是每一层都得从最后一层挨个朝前推导一次?这时候就得考察我们的归纳能力。这里有一个题外话,何为归纳?何为演绎?简单点,归纳就是从特殊性到一般性,而演绎则是从一般到特殊。当然内中道理还有很多,就不说了。
如何去归纳,这里就得说到BP中经常遇到的一个词语:链式求导。如果不知道具体定义也没事,朝下看:
①从最后一个权重开始看:这个权重连接了中间隐层和最后的输出层,求导过程是对输出层的sigmoid**函数求导,然后进一步得到的结果是:输出误差*输出值*(1-输出值)*(隐层值),换个方法说:权重右边的输出误差*权重右边的输出*(1-权重右边的输出)*(权重左边的输出);——分割线——权重连接的右边层的偏置更新就是去掉权重更新中乘以的权重左端值的那一参数(即权重连接的左层单元的值)。
②然后看倒数第二个权重:这个权重连接了原始输出层和中间隐层,求导过程还是对输出层的sigmoid**函数求导,只不过求导对象是第二个权重,而不是①中的权重。接下来发现不好求导,需要按照求导法则变换,变成了最后的输出层对隐层的输出求导乘以隐层输出对第二个权重的求导,可以发现这两个都好求,因为他们都直接存在与被求导的**函数(也就是分母的表达式)中。然后发现输出层关于第二层权重的导数变成了:权重右边某种值*权重右边的输出*(1-权重右边的输出)*(权重左边的输出)。发现与①很相似,只不过第一项有差别,然后观察何为“权重右边某式”,发现就是此层权重的后一层权重连接的层的偏置更新乘以连接到后一层的权重。
这样总结出一个规律:
建立的一个BP网络如***意,最后的伪层只是第n层的副本,实际的BP是没有这一层的,此处只是为了方便理解罢了,原因继续看下去:
如图所示,W左边连接层A,右边连接层B,B层的下一层是C,B和C的连接权重为V,C的偏置更新为△c,B的偏置更新为△b,则按照归纳的结论可以得到下式:
其实这里的V是被转置了的,因为V是从B到C的权重,那么从C的维度到B的维度,就必须通过转置相乘。具体涉及到矩阵求导法则,后面有博客更新这一内容。
【注】有时候面试会经常问:权重可以初始化为零?为什么?直接看这两个公式就能很清晰发现是不能的,因为这两个公式的更新都与权重有关,如果初始权重为0的时候,这两个梯度就都是0了。
但是突然想到当A是第n-1层的时候,并没有对应的"C"层去计算第n-1层到第n层的连接权重,也就是最后一层的权重, 那么怎么办?
方法一:
我们建立了第n层数据的副本,称为伪层,那么此时C就是伪层了,对应的伪层偏置设置为:
对应的第n层到伪层的连接权重为主对角线为1,其它值都为0的矩阵.
这样一来,我们可以轻松发现,BP的更新步骤可以用一个递归来解决:
步骤1:建立一个伪层副本,伪层偏置设置为△c,伪层与输出层(第n层)的连接权重为V
步骤2:从伪层往前推,建立一个层数为3的滑动窗口,从左到右依次称为上面介绍过的A、B、C层
步骤3:套用上面ABC更新△W和△b的方法去计算权重与偏置梯度
步骤4:返回步骤2(即往前移动一层)
步骤5:每一层的更新后参数就是
方法二:
忽视方法一种的伪层, 因为我们发现除了最后一层的所有的偏置都能用相同的公式解决,那么我们怎么得到最后一层的偏置?简单,直接轱辘上一节看《输出层→隐藏层的更新》这一节, 记住最后一层,也就是输出层的偏置更新, 然后再去套那个三层的通用公式就OK了
【注】最近看了一个关于残差项的博文:https://zhuanlan.zhihu.com/p/27664917,感觉文章的残差项其实就是这里的偏置变化量,然后在这个博客的基础上继续推导(每层输出相对于**函数的导数)就能得到我们的式子咯。所以本博客的结论(ABC三层递归求解)是无问题的
关于从sigmoid**的三层BP到任意**函数的三层BP到任意**函数任意层的BP的证明请移步这里
验证
说了这么多公式,还是一句话说得好: no can no bb, show me your code →__→
那么,就扒一扒matlab的deep learning toolbox里面的BP代码,以sigmoid为例,对照第五步的那个三层递推公式看:
伪层的建立其实就是链式求导的开端,伪层的△c就是那个减法公式:
nn.e = y - nn.a{n};
然后推导出最后一层的△c:
-
switch nn.output
-
case 'sigm'
-
d{n} = - nn.e .* (nn.a{n} .* (1 - nn.a{n}));
-
case {'softmax','linear'}
-
d{n} = - nn.e;
-
end
然后从倒数第二层开始
for i = (n - 1) : -1 : 2
计算我们的ABC三层推导中的B(1-B):
-
switch nn.activation_function
-
case 'sigm'
-
d_act = nn.a{i} .* (1 - nn.a{i});
-
case 'tanh_opt'
-
d_act = 1.7159 * 2/3 * (1 - 1/(1.7159)^2 * nn.a{i}.^2);
-
end
随后计算△c*V*B(1-B),也就是当前层的偏置更新量△b:
-
if i+1==n % in this case in d{n} there is not the bias term to be removed
-
d{i} = (d{i + 1} * nn.W{i} + sparsityError) .* d_act; % Bishop (5.56)
-
else % in this case in d{i} the bias term has to be removed
-
d{i} = (d{i + 1}(:,2:end) * nn.W{i} + sparsityError) .* d_act;
-
end
至此上一层循环结束,计算得到了当前层的偏置更新量。
对于权重,可以发现是△c*V*B(1-B)*A,其实就是△b乘以当前层的上一层输出就行了,直接在最后单独开启新的循环乘一下就行了:
-
for i = 1 : (n - 1)
-
if i+1==n
-
nn.dW{i} = (d{i + 1}' * nn.a{i}) / size(d{i + 1}, 1);
-
else
-
nn.dW{i} = (d{i + 1}(:,2:end)' * nn.a{i}) / size(d{i + 1}, 1);
-
end
-
end
附录:参数调整方法
以下摘自【模式识别与智能计算——MATLAB技术实现】
梯度下降法
有动量的梯度下降法
有自适应lr的梯度下降法
有动量加自适应lr的梯度下降法
弹性梯度下降法
Fletcher-Reeves共轭梯度法
Polak-Ribiere共轭梯度法
Powell-Beale共轭梯度法
量化共轭梯度法
三层BP神经网络学习的过程:
①输入模式顺传播(输入模型由输入层经隐藏层向输出层传播)
②输出误差逆传播(输出的误差由输出层经隐含层传向输入层)
③循环记忆训练(模式顺传播与误差逆传播的计算过程反复交替循环进行)
④学习结果判定(判定全局误差是否趋向极小值)
UFLDL中的证明:UFLDL
上一篇: 深度学习(3)--反向传播算法
下一篇: python字典,集合,函数