一、代价函数的形式
二次代价函数如下:
其中$x$为输入数据对应的正确输出,$a^L(x)$为输出节点对应的输出。将其简化为对单个$x$输出的误差公式如下:
可以看出$C$就是对众多$C_x$求平均。接下来对$C_x$做单独分析。
二、根据输出误差对b,w求导
数学符号定义
$a^L$:输出向量(第三节定义会改)
$w^L$:输出层的权重
$b^L$:输出层偏置
2.1 定义神经元
首先确定神经元形状,这里确定为s型神经元,公式如下:
对其求导得:(后面用得上)
2.2 误差函数说明
输出节点的误差为:
其中$a^L(x)$为:(对于$w,a,b$均是向量)
对$a^L(x)$求w偏导为:(后面2.3用的上)
对$a^L$求b偏导为:(后面2.3用的上)
2.3 使用输出误差函数对w,b偏导
$C_x^L$对w求偏导得:
$C_x^L$对b求偏导得:
这里仅仅求出了输出层的w,b偏导,那如何求出其他层的w,b偏导呢?使用反向传播公式推导。
三、反向传播公式推导
数学符定义
$a^L$:第L层的输出向量
$z^L$:第L层的输入向量
$w^L$:输出层的权重
$b^L$:输出层偏置
$C_x^L$:第L层误差向量,一般只有输出层用的上
$y$:正确的输出向量
3.1 正常的推导方法
假设当前L层误差定义为:
$C_x^L$对w求偏导得:
$C_x^L$对b求偏导得:
这样一层一层传递,就可以计算出每一个w,b的偏导数。但是公式会越来越长,计算量越来越大,接下来提出一种简化计算的方法。
3.2 优化的推导方法
3.2.1 当L前层对b,w求导
令$\delta ^ L$为第L层的误差,公式为:(这里还没有和w,b关联起来)
则此时根据2.3节可以得出如下结果:
由此可以,当前L层的b偏导向量等于当前层的误差向量,w偏导向量等于误差向量乘L-1层的输出向量,后面我们只需到得到每一层的误差向量就好。这里可能会有问题,这个$\delta ^ L$看不懂啊?可以理解为没有意义,为了简化计算。(实际上有其物理意义)
由于上式只适用于s型神经元,和二元误差,修改为更加通用的:
其中$\nabla_a C$对应于$(a^{L}-y)$,$\sigma’(z^L)$对应于$(a^L(1-a^L))$
3.2.2 L-1前层对b,w求导
接下来推导下一节点的误差$\delta ^ {L-1}$,仔细观察$\frac{\partial C_x^L}{\partial b^{L-1}}$,根据上面的结论它其实等于L-1层的误差值,表达式如下:
则此时
可以验证,和提出$\delta ^L$误差向量之前的证明结果一样,优点是计算量固定,由前一层的误差推倒后一层的误差,每次的计算量相差不大。
3.2.3 四大公式汇总
其中:$\nabla_a C$为输出层的求导,然后经过第二个公式层层推导,推导出每一层的$\delta ^ L$,最后两个公式根据每一层的误差对w,b求导。
四、python算法实现
直接上程序,注:是不能直接运行的,为了更好理解:
符号说明:
delta对应于符号$\delta$
nabla对应于符号$\nabla$
1 | def backprop(self,x,y): |
1 | # 定义S型函数 |