本章的链接:http://neuralnetworksanddeeplearning.com/chap2.html
1. 梯度下降的理解
在神经网络的输出层(output layer)可以定义一个loss function,例如C,我们使用梯度下降法的目的就是使得C的值降低到最小。
梯度的定义如下,
而C是关于权重矩阵W以及偏置b的函数,因此可以求出其梯度,在梯度的负方向上C的值下降最快,又因为梯度其实就是偏导数组成的向量,所以根据求出的偏导数来更新权重W和偏置b(也即在梯度的方向更新向量W和b)可以达到使C降低速度最快的目的。而当方向定了之后,一次更新多少?这个问题就要由学习率α来决定,所以在求梯度下降算法的更新公式里通常会带有学习率α。
2. 权重矩阵的元素下标为什么是后一层的在前,而前一层的在后?
简单地理解,当这样表示权重矩阵的元素时,权重矩阵第i行的所有元素便代表着第l-1层的所有节点到第l层的第i个节点的权重值,这样便可以简化向量形式的公式写法,
而如果反过来,l层的下标在后,l-1层的下标在前(也就是按照层的顺序排列),那么上述公式就需要对w进行一次转置,让表达式变得有些annoying了。
3. 神经网络每一层的输入输出
以上面这个图为例,假设layer1的输入是向量X,且layer1到layer2的权重矩阵为W12,那么有
这个z2叫做weighted input,代表着layer1对layer2的输入,也就是对layer1的输出做了一定处理,变成了layer2的输入,
然后到了layer2之后,会在layer2中对z2做一次处理,记做
a代表activation,也就是layer2的激活值,也代表着layer2的输出值,然后再经过上述同样的步骤传递到layer3,以此类推。
4. demon的故事
当这个demon对其中的施以一个微小的变化时,最终的output的cost会改变一个相应的值,即
从这个故事中得到了一些启发,即微小的改变对最终的cost会有影响,那么现在细化到每一层来看,定义layerl的误差
个人理解这里的定义只是为了方便求解,先求出,然后再求对w或者b的偏导,即可求得C对w或b的偏导数。
这里也强调了此处的误差并不是我们通常意义上的离正确值的偏差,而是一个为了方便计算的定义
5. 一些推导与说明
而由于最终的cost并不是完全取决于某一特定的神经元j,所以这里的值会较小,这也正是我们所期望的;同时,也反映了sigma(激活函数)相应于的变化速度。且上式中的每一项都非常好进行计算。
最后,上式可写作
其中,
也可写作
而上述公式又可以写成如下形式
这个公式看起来就像是l+1层的误差反向传播到了第l层上,因此我们通过联合下下面两个公式,就可以求出一个神经网络中的所有层的误差了
1)BP3:
最初,我们有前向传播公式
,其中是l-1层的激活值(也就是输出值),和分别是权重矩阵和偏置向量
那么向量化求导可得
,其中代表元素相乘积。
同理可推导BP4,
2) BP4:
最初有
由于w是个矩阵,所以先对元素求偏导,计算每个元素的值,有:
然后再写成向量化的形式,
,因为w的行代表l+1层的神经元,列代表l层的神经元,故写为(j*k)
6. 总结
当一个权重所连接的两端神经元中,输入神经元的激活值较低或者输出神经元的值已接近饱和,那么这个权重学习的速度就会降低,这也是由这些偏导公式决定的。
bp算法的公式总结,也是反向传播的计算公式:
7. 写代码时遇到的一些困惑点
首先,神经网络的输出层的z和a是相同的(就目前学习到的神经网络来看)(z和a分别代表一个神经元的输入和输出,一般有),而在输出层会定义一个loss function,这个loss function是a的函数,也就是z的函数,例如平方误差或者softmax等。
那么loss function会对a有一个偏导数,此偏导代表了a的变化对loss func的影响,记做,而a对z也会有一个偏导,又因为a通常和z在输出层是相等的,即a=z,故,所以在BP算法的公式BP1中有,即输出层的误差,然后就可以通过这个误差进行权重矩阵的求解和反向传播了。
示例代码的loss func是softmax函数,即
那么可求得
即代码中4/5/6行所代表的意思,这里的实际上就是,即输出层的输出值。
# 先求出输出层softmax型的loss func对输出层的偏导数,作为反向传播的起点,此处与SVM相同
# softmax公式为L=-s[yi]+ln(∑e^s[j]),可以求得L对s[yi]的偏导数为-1+e^s[yi]/∑e^s[j],也就是下面代码中的-1+prob
# 由于输出层的z和a是相同的值(即a==z),所以此处delta(L)/delta(a) == delta(L)/delta(z)
output = np.zeros_like(scores)
output[range(N), y] = -1
output += prob
# 先根据反向传播的上层梯度乘以本地变量求出W2的梯度
grads['W2'] = (a2.T).dot(output) # 公式BP4
grads['W2'] = grads['W2'] / N + reg * W2
# 求取b2的梯度,方法同上
grads['b2'] = np.ones(N).dot(output) / N
# 将最后一层节点的误差反向传播至隐藏层
hidden = output.dot(W2.T)
# 考虑到ReLU函数的作用,可以知道只有在z2矩阵中大于零的部分才会被传递至后面的层中,这里求的就是ReLU函数的偏导矩阵
mask = np.zeros_like(z2)
mask[z2 > 0] = 1
hidden = hidden * mask # N*H,这里相当于求解出了how bp algorithm works那一章中的公式BP2
# 再从隐藏层反向传播至W1
grads['W1'] = (X.T).dot(hidden) # 公式BP4
grads['W1'] = grads['W1'] / N + reg * W1
# W1同理
grads['b1'] = np.ones(N).dot(hidden) / N
pass