这是我阅读在线书籍《Neural Networks and Deep Learning》第二章的笔记。
手残不小心把整个笔记的文件夹误删了,原来这种事是真的会发生的啊,还好对第一章笔记做了备份= =、
章节链接: http://neuralnetworksanddeeplearning.com/chap2.html
尽力恢复车祸现场。。
先给出一堆变量定义(图来自知乎https://zhuanlan.zhihu.com/p/26765585):
在”The four fundamental equations behind backpropagation”之前,主要介绍了一个化简前馈表示的方法:al=σ(wlal−1+bl)。
还有两个一个函数允许作为损失函数的两个条件:1. 必须是以网络输出作为参数;2. 损失函数必须写成多个独立样本的损失的和的形式。
以及介绍了哈达玛积(Hadamard product):(s⊙t)j=sjtj,就是对应项相乘,例:
$$
\left[\begin{array}{c} 1 \ 2 \end{array}\right]
\odot \left[\begin{array}{c} 3 \ 4\end{array} \right]
= \left[ \begin{array}{c} 1 3 \ 2 4 \end{array} \right]
= \left[ 3 8
$$
The four fundamental equations behind backpropagation
反向传播会计算出δlj,表示为第l层的第j个神经元的误差。
定义:δlj=∂C∂zlj,zlj为第l层的第j个神经元的加权输入结果。反向传播的目标就是计算每一层的δl,称之为measure of error。反向传播总的来说是4个方程。
words
- intermediate:中间的
- messes with:由于……而迷糊
- perturb:扰乱
首先看看最后一层的损失如何计算:
δLj=∂C∂aLjσ′(zLj)
∂C/∂aLj用于描述作为第j个激活函数的输出变化有多快,如果C不依赖于这个神经元,那么δLj会比较小(接近收敛)。后面的σ的导数表示激活函数在这个点的变化有多快。
这个式子的计算瓶颈在于这个偏导数,于是转换成了下面的形式:
δL=(aL−y)⊙σ′(zL)
aL−y是C的变化率,就是个Δ,拆开后就写成上面哈达玛积的形式了。
再次重申,δL表示的是第L层(也就是最后一层)的传播误差。for the error in the output layer。
接着看看隐层的传播如何计算:
δl=((wl+1)Tδl+1)⊙σ′(zl)
式子中很明显,l层的误差就是由下一层(l+1层)反传回去的。
关于对wl+1参数矩阵求转置:我是这么理解的,因为输出的时候l层用的是n×m的矩阵,想要传回去的话,下层的size就不能是n×m了,而是m×n。转置和下一层的误差相乘,可以把误差传回对应的神经元。
网络中偏差(bias)的损失的计算:
∂C∂blj=δlj
模型直接可以用该层的损失来更新某个神经元的bias,于是可以简写:∂C/∂b=δ。
网络中权重的损失的计算:
∂C∂wljk=al−1kδlj
某层某个神经元的输入乘以该神经元的偏差可以认为是这个神经元对于最终损失的影响值。简写为:∂C∂w=ainδout。
总结四个BP的关键等式:
下面对每一个等式进行证明,加深理解。
证明主要分两个部分:
第一部分是推导出反向传播损失函数和输出之间的关系(BP1 BP2)
第二部分是推导出损失函数与权重weight和偏差bias的关系(BP3 BP4)
BP1:
δL=∇aC⊙σ′(zL)
证:对于第j个激活函数,有定义:
δLj=∂C∂zLj
展开:
δLj=∂C∂aLjσ′(zLj)=\partC\partaLj\partaLj\partzLj
由于aLj=σ(zLj),那么σ′(zLj)=∂aLj∂zLj,即:δLj=∂C∂aLjσ′(zLj)
推广至L层,公式可简写为:
δL=∂C∂aLσ′(zL)
BP2:
δl=((wl+1)Tδl+1)⊙σ′(zl)
证:由定义展开δl:
δl=∂C∂zl
利用导数的链式法则,对拆成对zl+1求导的形式:
δl=∂C∂zl+1\partzl+1\partzl=∂zl+1∂zlδl+1
由于zl+1=∑jwl+1jδl(zl+1j)+bl+1,带入上式即证。
BP3:
∂C∂blj=δlj
证:
∂C∂blj=\partC\partzl+1j\partzl+1j\partblj=δlj\part(wljzl+blj)\partblj=δlj
BP4:
和上面一样,把b换成w就行。
The backpropagation algorithm
利用上面证明过的4个结论,就可以推导出反向传播算法,算法可以递归形式地定义成这样:
- 输入x
- 前馈:zl=wlal−1+bl,夏日难al=σ(zl)
- 输出误差:δL=∇aC⊙σ′(zL)
- 反向传播误差:对于每一层l,l=L−1,L−2…,2,于是δl=((wl+1)Tδl+1)⊙σ′(zl)
- 输出:w,b的损失函数定义为∂C∂wljk=al−1kδlj和∂C∂blj=δlj。
- ∂C∂blj=δlj。
The code for backpropagation
这章实现了用SGD训练的的BP:每次叠小批量的训练集,再计算损失后反传。
介绍了一个可以同时计算多个mini-batch的trick:把多个mini-batch放到一个矩阵里,利用矩阵计算库对矩阵计算的优化来加速训练。
In what sense is backpropagation a fast algorithm?
想在求偏导这一步加速梯度下降的计算,考虑利用∂C∂wj≈C(w+ϵej)−C(w)ϵ这样近的似来代替计算偏导,当ϵ很小的时候,起码GD方向是不会变的(ϵ很小的话,多叠几次就可以近似等价于梯度方向走步长步)。但是实际上这样做的计算开销仍然会非常大。
而反向传播可以DP地把损失传回去。
Backpropagation: the big picture
对于每层输出产生的误差Δalj,可以用下式做近似:
Δalj≈∂alj∂wljkΔwljk
那么对于这层而言其中一条由输出反传回来的结果则是:
ΔC≈∂C∂aLm∂aLm∂aL−1n∂aL−1n∂aL−2p…∂al+1q∂alj∂alj∂wljkΔwljk
于是考虑所有连通的情况:
ΔC≈∑mnp…q∂C∂aLm∂aLm∂aL−1n∂aL−1n∂aL−2p…∂al+1q∂alj∂alj∂wljkΔwljk
这就是反向传播对于某一条边更新时需要的计算:
∂C∂wljk=∑mnp…q∂C∂aLm∂aLm∂aL−1n∂aL−1n∂aL−2p…∂al+1q∂alj∂alj∂wljk
v1.5.2