深度学习入门之反向传播算法

引言

在神经网络中,为了更有效的计算梯度,需要用到反向传播算法。我们先从链式求导法则开始。

链式求导法

先介绍下链式求导法则,在后面的反向传播算法中会用到。

y=g(x),z=h(y)y = g(x),z=h(y)

那么dzdx=dzdydydx\frac{dz}{dx} = \frac{dz}{dy}\frac{dy}{dx};

x=g(s),y=h(s),z=k(x,y)x=g(s) ,y = h(s), z = k(x,y)

深度学习入门之反向传播算法

改变了s会改变x和y,从而改变了z。

dzds=zxdxds+zydyds\frac{dz}{ds} = \frac{\partial{z}}{\partial{x}}\frac{dx}{ds} + \frac{\partial{z}}{\partial{y}}\frac{dy}{ds}

注意,如果改变s会改变多个变量,它们的关系也是成立的。

损失函数

深度学习入门之反向传播算法

假设给定一组参数θ\theta,把一个训练数据xnx^n代入NN(神经网络)中,会得到输出yny^n

CnC^n是输出yny^n和实际y^n\hat{y}^n距离函数,值越大代表越距离远,也就是效果越不好。

那在神经网络训练算法中,损失函数定义为:

L(θ)=n=1NCn(θ) L(\theta) = \sum^{N}_{n=1}C^n(\theta)

如果把损失函数对参数ww做微分的话,得到

L(θ)w=n=1NCn(θ)w \frac{\partial L(\theta)}{\partial w} = \sum^{N}_{n=1}\frac{\partial C^n(\theta)}{\partial w}

只要计算出某一笔数据对ww的微分,就可以得到L(θ)L(\theta)ww的微分。

深度学习入门之反向传播算法

假设我们先考虑这个神经元。

深度学习入门之反向传播算法

假设只有两个输入x1,x2x_1,x_2,计算z=x1w1+x2w2+bz = x_1w_1 + x_2w_2 + b得到zz后再代入**函数,经过多次运算会得到最终的输出y1,y2y_1,y_2

深度学习入门之反向传播算法

现在问题是如何计算损失(距离函数)CCww的偏微分Cw\frac{\partial C}{\partial w}

利用链式求导法

Cw=Czzw \frac{\partial C}{\partial w} = \frac{\partial C}{\partial z} \frac{\partial z}{\partial w}

计算zw\frac{\partial z}{\partial w}的过程叫做正向过程(Forward pass);计算Cz\frac{\partial C}{\partial z}的过程叫做反向过程(Backward pass)

正向过程

z=x1w1+x2w2+bz = x_1w_1 + x_2w_2 + b

zw1=x1zw2=x2 \frac{\partial z}{\partial w_1} = x_1 \\ \frac{\partial z}{\partial w_2} = x_2 \\
深度学习入门之反向传播算法

如上图所示,假设输入是1,11,-1,上面蓝色神经元的参数:w1=1,w2=2,b=1w_1=1,w_2=-2,b=1,**函数是Sigmoid函数;
下面蓝色神经元的参数:w1=1,w2=1,b=0w_1=-1,w_2=1,b=0

对下面的神经元来说,计算w2w_2的偏微分,可以很快得出zw=1\frac{\partial z}{\partial w} = -1,也就是输入x2(1)x_2(-1),随着从前往后计算每个神经元的输出,整个过程就可以很快结束,因此叫正向过程。

反向过程

深度学习入门之反向传播算法

困难的是如何计算Cz\frac{\partial C}{\partial z}

a=11+eza = \frac{1}{1+e^{-z}}

假设**函数是Sigmoid函数a=σ(z)a=\sigma(z),然后得到的函数值aa会乘上某个权重(比如w3w_3)再加上其他值得到zz^\prime(注意这里只是一个符号,不是zz的导数);aa也会乘上权重(比如w4w_4)再加上其他东西得到zz^{\prime\prime}(注意这里只是一个符号,不是zz的二阶导数);

深度学习入门之反向传播算法

Cz=Caaz \frac{\partial C}{\partial z} = \frac{\partial C}{\partial a} \frac{\partial a}{\partial z}

可以这样理解,zz通过影响aa来影响CC

az=σ(z)z=σ(z) \frac{\partial a}{\partial z} = \frac{\partial \sigma(z)}{\partial z} = \sigma^\prime(z)

那就剩下

Ca=Czza+Czza \frac{\partial C}{\partial a} = \frac{\partial C}{\partial z^\prime}\frac{\partial z^\prime}{\partial a} + \frac{\partial C}{\partial z^{\prime\prime}}\frac{\partial z^{\prime\prime}}{\partial a}

改变了aa会改变zz^{\prime}zz^{\prime\prime},从而改变了CC

我们先计算简单的

z=aw3+z^{\prime} = aw_3 + \cdots


za=w3\frac{\partial z^{\prime}}{\partial a} = w_3

同理

za=w4\frac{\partial z^{\prime\prime}}{\partial a} = w_4

现在难点就是Cz\frac{\partial C}{\partial z^\prime}Cz\frac{\partial C}{\partial z^{\prime\prime}}

我们这里先假装我们知道这两项的值。然后整理下原来的式子:

Cz=σ(z)[w3Cz+w4Cz] \frac{\partial C}{\partial z} = \sigma^\prime(z)[w_3\frac{\partial C}{\partial z^\prime} + w_4\frac{\partial C}{\partial z^{\prime\prime}}]

深度学习入门之反向传播算法

假设有另外一个特殊的神经元,它是上图的样子,输入就是Cz\frac{\partial C}{\partial z^\prime}Cz\frac{\partial C}{\partial z^{\prime\prime}},它们分别乘以w3w_3w4w_4,然后求和得到的结果再乘上σ(z)\sigma^\prime(z)
就得到了Cz\frac{\partial C}{\partial z}

zz在正向传播的过程中已经知道了,因此这里的σ(z)\sigma^\prime(z)是一个常数。

说了这么多,还是没说怎么计算Cz\frac{\partial C}{\partial z^\prime}Cz\frac{\partial C}{\partial z^{\prime\prime}}啊。别急,下面就开始计算。

这里要分两种情况考虑:

深度学习入门之反向传播算法

情形一: 红色的两个神经元就是输出层,它们能直接得到输出。

根据链式法则有:

Cz=y1zCy1 \frac{\partial C}{\partial z^\prime} = \frac{\partial y_1}{\partial z^\prime}\frac{\partial C}{\partial y_1}

只要知道**函数是啥就能计算出y1z\frac{\partial y_1}{\partial z^\prime}

Cy1\frac{\partial C}{\partial y_1}也可以根据我们选取的损失函数简单的计算出来。

同理Cz\frac{\partial C}{\partial z^{\prime\prime}}的计算也一样

情形二:红色的不是输出层

深度学习入门之反向传播算法

红色的是中间层,它们的**函数的值会当成下一层的输入继续参数计算。

深度学习入门之反向传播算法

如果我们知道Cza\frac{\partial C}{\partial z_a}Czb\frac{\partial C}{\partial z_b}

同理(回顾一下上面那个特殊的神经元)我们就可以计算Cz\frac{\partial C}{\partial z^{\prime}}

深度学习入门之反向传播算法

问题就会这样反复循环下去,我们不停的看下一层,直到遇到了输出层。然后就可以由输出层往前计算出整个NN的所有的参数。

那我们为何不换个角度考虑问题,我们直接先算输出层的偏微分,然后依次往前计算。

深度学习入门之反向传播算法

这就是反向传播算法的思想。