神经网络与反向传播算法

相信对于神经网络大家都已经不陌生了,这篇文章主要介绍一下神经网络参数优化的时候反向传播算法的原理。

我们使用的神经网络

为了简单起见,我们使用只有三层的神经网络(包括输入层)如下图所示
神经网络与反向传播算法

神经网络中的参数表示

我们用wijl{w_{ij}}^{l}来表示第l1l-1层的中第jj个结点到第ll层中第ii个结点的偏置
bil{b_{i}}^{l}表示第ll层中第ii个结点的偏置
ail{a_{i}}^{l}表示第ll层中第ii个结点通过**函数之后的输出值
zil{z_{i}}^{l}表示第ll层中第ii个结点没有经过**函数时的输出
基于上面的约定,我们可以给出上述神经网络的数学表示
从输入层到隐藏层可以表示为
神经网络与反向传播算法
从隐藏层到输出层可以表示为
神经网络与反向传播算法
当然,这样表示可能有点乱,我们可以将上述两个式子写成喜闻乐见的矩阵形式
神经网络与反向传播算法
zi3{z_{i}}^{3}同理这里就不写了。

损失函数

我们使用均方误差C作为损失函数,其数学表达式为
c=12((t1a13)2+(t2a23)2)c = \frac{1}{2}*(({t_{1}}-{a_{1}}^{3})^{2}+({t_{2}}-{a_{2}}^{3})^{2})
其中t1{t_{1}}为输出层中第一个结点的标记值;t2{t_{2}}为输出层中第二个结点的标记值
我们的优化目标就是求出让损失函数的值最小的各个参数的值
神经网络中的参数非常多(包括wijl{w_{ij}}^{l}bil{b_{i}}^{l}),如果我们使用求导的方式来求最小值的话就很不现实。为了解决这个问题,我们可以使用反向传播算法,这个算法的神奇之处在于可以把优化参数时的求导操作变成求数列的地推式。
容易发现,我们很容易求得误差cc对于a13{a_{1}}^{3}a23{a_{2}}^{3}的导数,这样一来我们便可以根据a13{a_{1}}^{3}a23{a_{2}}^{3}的导数来求ai2{a_{i}}^{2}的导数,如此传递下去便能完成一轮优化的过程,是不是很神奇呢。下面我们来具体介绍一下反向传播算法的过程。

神经单元误差δ\delta

这一块就是我们的重头戏了。不过在介绍反向传播算法前,我们需要先介绍神经单元误差δil{\delta_{i}}^{l}的概念。
我们定义神经单元误差δil=czil{\delta_{i}}^{l}=\frac{\partial c}{\partial {z_{i}}^{l}}
有了这个误差,我们可以化简之前用链式求导法则得出的结果,比如我们要求 wij3{w_{ij}}^{3}的变化值Δwij3\Delta {w_{ij}}^{3},其中Δwij3=ηcwij3\Delta {w_{ij}}^{3}=-\eta*\frac{\partial c}{\partial {w_{ij}}^{3}}。其求导路径如下图所示
神经网络与反向传播算法
我们根据链式求导法则得到
cwij3=ca23a23z23z23w233\frac{\partial c}{\partial {w_{ij}}^{3}}=\frac{\partial c}{\partial {a_{2}}^{3}}\frac{\partial {a_{2}}^{3}}{\partial {z_{2}}^{3}}\frac{\partial {z_{2}}^{3}}{\partial {w_{23}}^{3}}
其中ca23\frac{\partial c}{\partial {a_{2}}^{3}}可以根据损失函数
c=12((t1a13)2+(t2a23)2)c = \frac{1}{2}*(({t_{1}}-{a_{1}}^{3})^{2}+({t_{2}}-{a_{2}}^{3})^{2})求出来ca23=(a23t2)\frac{\partial c}{\partial {a_{2}}^{3}}=({a_{2}}^{3}-{t_{2}})
其中a23z23\frac{\partial {a_{2}}^{3}}{\partial {z_{2}}^{3}}可以根据**函数来求导,比如我们用sigmoid函数来举例,sigmoid函数的函数图像如下所示
神经网络与反向传播算法
其函数表达式为σ(x)=11+ex\sigma (x)=\frac{1}{1+e^{-x}},对这个函数求导得到其导数为σ(x)(1σ(x))\sigma (x)(1-\sigma (x))
那么就有a23z23=σ(z23)(1σ(z23))\frac{\partial {a_{2}}^{3}}{\partial {z_{2}}^{3}}=\sigma ({z_{2}}^{3})(1-\sigma ({z_{2}}^{3}))
最后,为了求得z23w233\frac{\partial {z_{2}}^{3}}{\partial {w_{23}}^{3}},我们先来写一下z23{z_{2}}^{3}的表达式
z23=w213a12+w223a22+w233a32+b23{z_{2}}^{3}={w_{21}}^{3}{a_{1}}^{2}+{w_{22}}^{3}{a_{2}}^{2}+{w_{23}}^{3}{a_{3}}^{2}+{b_{2}}^{3}
这是一个线性函数,很容易可以得到z23w233=a32\frac{\partial {z_{2}}^{3}}{\partial {w_{23}}^{3}}={a_{3}}^{2}
如果我们令cwij3=cz23z23w233\frac{\partial c}{\partial {w_{ij}}^{3}}=\frac{\partial c}{\partial {z_{2}}^{3}}\frac{\partial {z_{2}}^{3}}{\partial {w_{23}}^{3}}
那么就有cwij3=δ23a32\frac{\partial c}{\partial {w_{ij}}^{3}}={\delta _{2}}^{3}{a_{3}}^{2}
同理可得cb23=cz23z23b23=δ23\frac{\partial c}{\partial {b_{2}}^{3}}=\frac{\partial c}{\partial {z_{2}}^{3}}\frac{\partial {z_{2}}^{3}}{\partial {b_{2}}^{3}}={\delta _{2}}^{3}
有了上面的理论基础,我们就可以继续介绍反向传播算法了。

反向传播算法

下面我们在来讨论一下神经单元误差δ\delta的性质,也就是传递性。
我们可以将上一节的求导结果抽象化为任意一个参数的形式
cwijl=δilajl1\frac{\partial c}{\partial {w_{ij}}^{l}}={\delta _{i}}^{l}{a_{j}}^{l-1}
cbil=δil\frac{\partial c}{\partial {b_{i}}^{l}}={\delta _{i}}^{l} 其中l=(2,3)l=(2, 3)
根据上面的式子,我们可以得到隐藏层中神经元的单元误差
δi2=(δ13w1i3+δ23w2i3)a(zi2)(i=1,2,3){\delta _{i}}^{2}=({\delta _{1}}^{3}{w_{1i}}^{3}+{\delta _{2}}^{3}{w_{2i}}^{3}){a}'({z_{i}}^{2})(i=1,2,3),这样子我们便得到了第二层与第三层神经元δ\delta之间的关系
其中δi3=czi3=cai3ai3zi3{\delta_{i}}^{3}=\frac{\partial c}{\partial {z_{i}}^{3}}=\frac{\partial c}{\partial {a_{i}}^{3}}\frac{\partial {a_{i}}^{3}}{\partial {z_{i}}^{3}},这里面cai3\frac{\partial c}{\partial {a_{i}}^{3}}通过损失函数就可以算出来,因为损失函数为c(a13,a23)c({a_{1}}^{3},{a_{2}}^{3})
并且ai3zi3\frac{\partial {a_{i}}^{3}}{\partial {z_{i}}^{3}}通过**函数可以算出来,以sigmoid函数举例
ai3zi3=σ(zi3)(1σ(zi3))\frac{\partial {a_{i}}^{3}}{\partial {z_{i}}^{3}}=\sigma ({z_{i}}^{3})(1-\sigma ({z_{i}}^{3})),这样一来,我们就可以算出δ13{\delta_{1}}^{3}δ23{\delta_{2}}^{3}了。
有了这两个值,我们根据递推式δi2=(δ13w1i3+δ23w2i3)a(zi2)(i=1,2,3){\delta _{i}}^{2}=({\delta _{1}}^{3}{w_{1i}}^{3}+{\delta _{2}}^{3}{w_{2i}}^{3}){a}'({z_{i}}^{2})(i=1,2,3)就可以算出δi2(i=1,2,3){\delta_{i}}^{2}(i=1,2,3)
同理,有了δi2(i=1,2,3){\delta_{i}}^{2}(i=1,2,3),我们就可以继续算出δi1(i=1,2,3,4){\delta_{i}}^{1}(i=1,2,3,4),再将δil{\delta_{i}}^{l}带入到cwijl\frac{\partial c}{\partial {w_{ij}}^{l}}cbil\frac{\partial c}{\partial {b_{i}}^{l}}的式子中就可以计算出各个参数的导数值,有了这个导数值,我们乘上学习率η-\eta就能得到各个参数在这一轮训练中的变化率Δwijl\Delta{w_{ij}}^{l}Δbil\Delta{b_{i}}^{l}
于是,在这一轮训练中我们可以更新我们的参数为wijl=wijl+Δwijl{w_{ij}}^{l}={w_{ij}}^{l}+\Delta{w_{ij}}^{l}bil=bil+Δbil{b_{i}}^{l}={b_{i}}^{l}+\Delta{b_{i}}^{l}
在理想状态下,经过很多很多次优化后,我们的模型中的参数最终收敛了,我们便得到了一个可用的神经网络,是不是很简单呢,哈哈哈。

总结

数学真神奇。