Skip to content


概念

在神经网络中,我们通常使用反向传播来求梯度,这需要求解微分。

使用计算机求解微分的方法有很多,如符号微分,首先将目标函数转换为closed-form表达式,再利用求导法则,对表达式自动计算,求解梯度。该方案计算结果精确,但是要求表达式为closed-form(限制了使用场景),且表达式较为复杂时,可能会产生表达式膨胀(Expression swell)的问题。

另一种典型的求微分方法如数值微分,通过差分逼近。该方法适用于各种情况,但是需要权衡截断误差(truncation error)和舍入误差(Rounding error),对高维度函数计算速度较慢。

自动微分不要求函数的表达式为closed-form,算法和符号微分相同精度,直接获得梯度结果而不得到导数表达式。

自动微分利用表达式追踪机制,记录每一次计算过程中的中间变量,再利用链式求导法则组合各部分中间变量,生成梯度结果。

自动微分有两个主要版本,Forward mode and Reverse mode

以下列的函数为例

f(x1,x2)=ln(x1)+x1x2sin(x2)

接下来我们要求函数对x1的偏导数,因此先定义中间变量的偏导数

v˙i=vix1

Forward Primal Trace如下

v1=x1=2v0=x2=5v1=lnv1=ln2v2=v1×v0=2×5v3=sinv0=sin5v4=v4+v2=0.693+10v5=v4v3=10.652+0.959y=v5=11.652

对于上述函数,自动微分方法分成 Forward mode 和 Reverse mode

Forward mode

Forward Tangent (Derivative) Trace如下

v˙1=x˙1=1v˙0=x˙2=0v˙1=v˙1/v1=1/2v˙2=v˙1×v0+v˙0×v1=1×5+0×2v˙3=v˙0×cosv0=0×cos5v˙4=v˙1+v˙2=0.5+5v˙5=v˙4v˙3=5.50y˙=v˙5=5.5

Reverse mode

定义与算法

这里我们首先定义

v¯i=yjvi

然后我们需要考虑Forward Primal Trace的树形图,利用如下性质,建立中间变量之间的依赖关系(有向图)

v¯i=j=child of imv¯jvjvi

具体到本例中,有向图如下

函数有向图

我们得到如下计算式子,需要指出的是,以下是从下往上计算,也就是先有v¯=y¯=1,最后再得到x¯1,x¯2.

x¯1=v¯1=5.5x¯2=v¯0=1.716v¯1=v¯1+v¯1v1v1=v¯1+v¯1/v1=5.5v¯0=v¯0+v¯2v2v0=v¯0+v¯2×v1=1.716v¯1=v¯2v2v1=v¯2×v0=5v¯0=v¯3v3v0=v¯3×cosv0=0.284v¯2=v¯4v4v2=v¯4×1=1v¯1=v¯4v4v1=v¯4×1=1v¯3=v¯5v5v3=v¯5×(1)=1v¯4=v¯5v¯v5v4=v¯5×1=1v¯5=y¯=1

详细流程

详细来说反向计算导数值时,顺序如下:

  1. 计算yv5的导数值,因为y=v5,所以 yv5=v¯5=1 .

  2. 计算yv4的导数值,因为v4在图上只有一个后续节点v5,并且v5=v4v3,所以依据链式法则得到下式,并将结果写在v4指向v5的边上

yv4=yv5×v5v4=v¯5v5v4=v¯5(v4v3)v4=v¯5×1=1
  1. 计算yv3的导数值,因为v3在图上只有一个后续节点v5,并且v5=v4v3。所以依据链式法则得到下式,并将结果写在v3指向v5的边上
yv3=yv5×v5v3=v¯5v5v3=v¯5(v4v3)v3=v¯5×(1)=1
  1. 计算yv2的导数值,因为v2在图上只有一个后续节点v4,并且v4=v1+v2,所以依据链式法则得到下式,并将结果写在v2指向v4的边上
yv2=yv4×v4v2=v¯4v4v2=v¯4(v1+v2)v2=v¯4×1=1
  1. 计算yv1的导数值,因为v1在图上只有一个后续节点v4,并且v4=v1+v2,所以依据链式法则得到下式,并将结果写在v1指向v4的边上
yv1=yv4×v4v1=v¯4v4v1=v¯4(v1+v2)v1=v¯4×1=1
  1. 接下来要计算yv0v1的导数值,因为v0v1都是有两个后续节点,所以我们只能分开计算。

  2. 计算下式,并将结果写在v0指向v3的边上

v3v0=sinv0v0=cosv0=0.284
  1. 计算下式,并将结果写在v0指向v2的边上
v2v0=(v1v0)v0=v1=2
  1. 计算下式,并将结果写在v1指向v2的边上
v2v1=(v1v0)v1=v0=5,
  1. 计算下式,并将结果写在v1指向v1的边上
v1v1=(lnv1)v1=1v1=0.5

到日前为止,我们已经计算出来了所有步骤的偏导数的数值。现在需要计算yx1yx2

计算yx1就是从y开始从后向前走,走回到x1,因为有多条路径,所以对于每一条路径,需要将这个路径上的数值连乘起来得到一个乘积数值,然后将这多条路径的乘积数值相加起来,就得到了yx1的数值。yx2的计算方法与此相同

yx1的路径有两条,分别是:

· v5v4v1v1:其数值乘积是110.5=0.5

· v5v4v2v1:其数值乘积是115=5

因此,yx1=0.5+5=5.5

yx2的路径有两条,分别是:

· v5v4v2v0:其数值乘积是112=2.0

· v5v3v0:其数值乘积是10.284=0.284

因此,yx2=2.00.284=1.716

Auto Diff 与 Jacobian

如果f的输出也是多维的,比如

f: Rn Rm

其Jacobian矩阵如下

Jf=[yx1yxn]=[y1x1y1xnymx1ymxn]

具体而言,我们有:

δy=Jfδx

则每次Forward mode得到的将是Jacobian矩阵Jf的一列。

每次Reverse mode得到的将是Jacobian矩阵Jf的一行。

在实际的神经网络中,损失函数的输出为标量,但是参数矩阵很多。即如下形式

f: Rn R

因此神经网络中通常选择Reverse mode.

相应的,如果输入维度小于输出维度,即Jacobian矩阵的行数大于列数,比如n>m=1,则选择Forward mode。