若是能二秒内在脑壳里解出下面的问题,本文便结束了。php
已知:,其中
。编程
求:,
,
。网络
到这里,请耐心看完下面的公式推导,无需长久内心建设。数据结构
首先,反向传播的数学原理是“求导的链式法则” :函数
设和
为
的可导函数,则
。优化
接下来介绍3d
这一节展现如何使用链式法则、转置、组合等技巧来快速完成对矩阵、向量的求导orm
一个原则维数相容,实质是多元微分基本知识,没有在课本中找到下列内容,维数相容原则是我我的总结:教程
维数相容原则:经过先后换序、转置 使求导结果知足矩阵乘法且结果维数知足下式:ci
若是,
,那么
。
利用维数相容原则解上例:
step1:把全部参数当作实数来求导,,
依据链式法则有,
,
能够看出除了,
和
的求导结果在维数上连矩阵乘法都不能知足。
step2:根据step1的求导结果,依据维数相容原则作调整:先后换序、转置
依据维数相容原则,但
中
、
,天然得调整为
;
同理:,但
中
、
,那么经过换序、转置咱们能够获得维数相容的结果
。
对于矩阵、向量求导:
神经网络的反向传播求得“各层”参数和
的导数,使用梯度降低(一阶GD、SGD,二阶LBFGS、共轭梯度等)优化目标函数。
接下来,展现不使用下标的记法(,
or
)直接对
和
求导,反向传播是链式法则和维数相容原则的完美体现,对每一层参数的求导利用上一层的中间结果完成。
这里的标号,参考UFLDL教程 - Ufldl
前向传播:
(公式2)
为第
层的中间结果,
为第
层的激活值,其中第
层包含元素:输入
,参数
、
,激活函数
,中间结果
,输出
。
设神经网络的损失函数为(这里不给出具体公式,能够是交叉熵、MSE等),根据链式法则有:
这里记 ,其中
、
可由 公式1 得出,
加转置符号
是根据维数相容原则做出的调整。
如何求 ? 可以使用以下递推(需根据维数相容原则做出调整):
其中、
。
那么咱们能够从最顶层逐层往下,即可以递推求得每一层的
注意:是逐维求导,在公式中是点乘的形式。
反向传播整个流程以下:
1) 进行前向传播计算,利用前向传播公式,获得隐藏层和输出层 的激活值。
2) 对输出层(第层),计算残差:
(不一样损失函数,结果不一样,这里不给出具体形式)
3) 对于的隐藏层,计算:
4) 计算各层参数、
偏导数:
大部分开源library(如:caffe,Kaldi/src/{nnet1,nnet2})的实现一般把、
做为一个layer,激活函数
做为一个layer(如:sigmoid、relu、softplus、softmax)。
反向传播时分清楚该层的输入、输出即能正确编程实现,如:
(公式1)
(公式2)
(1)式AffineTransform/FullConnected层,如下是伪代码:
注: out_diff = 是上一层(Softmax 或 Sigmoid/ReLU的 in_diff)已经求得:
(公式 1-1)
(公式 1-2)
(公式 1-3)
(2)式激活函数层(以Sigmoid为例)
注:out_diff = 是上一层AffineTransform的in_diff,已经求得,
在实际编程实现时,in、out多是矩阵(一般以一行存储一个输入向量,矩阵的行数就是batch_size),那么上面的C++代码就要作出变化(改变先后顺序、转置,把函数参数的Vector换成Matrix,此时Matrix out_diff 每一行就要存储对应一个Vector的diff,在update的时候要作这个batch的加和,这个加和能够经过矩阵相乘out_diff*input(适当的转置)获得。
若是熟悉SVD分解的过程,经过SVD逆过程就能够轻松理解这种经过乘积来作加和的技巧。
丢掉那些下标记法吧!
卷积怎么求导呢?实际上卷积能够经过矩阵乘法来实现(是否旋转无所谓的,对称处理,caffe里面是否是有image2col),固然也可使用FFT在频率域作加法。
那么既然经过矩阵乘法,维数相容原则仍然能够运用,CNN求导比DNN复杂一些,要作些累加的操做。具体怎么作还要看编程时选择怎样的策略、数据结构。
快速矩阵、向量求导之维数相容大法已成。