反向传播算法基于多元函数链式法则,以下记录多元函数链式法则的证明与反向传播算法的实例推演。
多元复合函数的求导法则(多元链式法则)
定义
如果函数$u=varphi(t)$及$v=psi(t)$都在点$t$可导,函数$z = f(u,v)$在对应点$(u,v)$具有连续偏导数(重点),那么复合函数$z = f[varphi(t),psi(t)]$在点$t$可导,且有:
$displaystyle frac{mathrm{d}z}{mathrm{d}t} = frac{partial z}{partial u}frac{mathrm{d}u}{mathrm{d}t}+ frac{partial z}{partial v}frac{mathrm{d}v}{mathrm{d}t} $
证明
设$t$获得增量$Delta t$,此时$u = varphi(t),v = psi(t)$的对应增量为$Delta u,Delta v$,由此,$z=f(u,v)$获得增量$Delta z$。因为函数$z = f(u,v)$在点$(u,v)$有连续偏导数,于是全增量$Delta z$可表示为(全微分的充分条件):
$displaystyleDelta z = frac{partial z}{partial u}Delta u+ frac{partial z}{partial v}Delta v+varepsilon_1Delta u+varepsilon_2Delta v$
这里有,当$Delta u o 0,Delta v o 0$时,有$varepsilon_1 o0,varepsilon_2 o 0$。
上式两边各除以$Delta t$,得:
$displaystylefrac{Delta z}{Delta t} = frac{partial z}{partial u}frac{Delta u}{Delta t}+ frac{partial z}{partial v}frac{Delta v}{Delta t}+varepsilon_1frac{Delta u}{Delta t}+varepsilon_2frac{Delta v}{Delta t}$
于是,取极限$Delta t o0$,就有:
$displaystyle frac{mathrm{d}z}{mathrm{d}t} = frac{partial z}{partial u}frac{mathrm{d}u}{mathrm{d}t}+ frac{partial z}{partial v}frac{mathrm{d}v}{mathrm{d}t} $
得证。(主要功劳在于它有连续偏导数,于是有全微分,才能用来加)
而神经网络中的多元函数大多是仿射函数(激活函数不是,但是也符合可微条件),符合上述全微分的充分条件,所以可以使用反向传播来计算所有参数的梯度。
反向传播算法的实例推演
反向传播的过程与公式推导(点击链接)不难,主要就是运用上述的多元函数链式法则。
但是看完原理后,代码如何实现呢?有个疑问就是,第n层的一个参数$w$,要使用第n+1层所有相关导数的累加,假设需要累加$n$次;而第n+1层的相关导数,又要第n+2层的所有相关导数的相关导数的累加,假设累加$m$次。也就是说,对于第n层的这个参数的导数,仅通过两层就要计算$n imes m$次。如此嵌套下去,要进行的加和运算似乎是指数级上升,这样是肯定不行的。可以想到,某些中间结果需要暂存,以防上述重复计算。以下直接举一个具体的例子来说明。
实例推演
定义一个全连接网络,规模与各层激活函数如下图所示:
如图所示,神经网络使用MSE来作为损失函数。网络使用随机梯度下降,即每次传入一个样本。实际上,使用MSE时,批量梯度下降每次更新的梯度是批次中各个样本点梯度的简单相加,与随机梯度下降相比并没有其他复杂操作,所以这里只举随机梯度下降的为例。
每一层的操作都已在图中标出。其中$xin R^4,yin R^3$分别是样本的特征向量和标记向量;$hin R^5,gin R^6,fin R^3$分别是输入层、隐层、输出层的输出向量;$w^k,b^k$分别是第$k$层用于仿射变换的矩阵和偏置向量,$i^k$是仿射变换的结果;$delta(x)$是ReLu激活函数(对向量元素进行的运算),$sigma(x)$是Softmax激活函数(对整个向量进行的运算)。
为了便于理解各个步骤之间的联系,以下将一些步骤的结果命名为大写字母。
首先算损失$L$对$f$的梯度,存入$A$中:
$ displaystyle A =frac{partial L}{partial f} = left[ egin{matrix} frac{partial L}{partial f_1}\ frac{partial L}{partial f_2}\ frac{partial L}{partial f_3}\ end{matrix} ight] = left[ egin{matrix} f_1 - y_1\ f_2 - y_2\ f_3 - y_3\ end{matrix} ight] = f-y $
再算$f$对$i^3$的导数,由于激活函数使用的是Softmax,每个$i_k$都参与了每个$f_j$的计算,所以是一个雅可比矩阵:
$displaystyle egin{aligned} B &= frac{partial f}{partial i^3}= left[ egin{matrix} frac{partial f_1}{partial i^3_1}&frac{partial f_1}{partial i^3_2}&frac{partial f_1}{partial i^3_3}\ frac{partial f_2}{partial i^3_1}&frac{partial f_2}{partial i^3_2}&frac{partial f_2}{partial i^3_3}\ frac{partial f_3}{partial i^3_1}&frac{partial f_3}{partial i^3_2}&frac{partial f_3}{partial i^3_3}\ end{matrix} ight]= left[ egin{matrix} frac{partial sigma_1(i^3)}{partial i^3_1}&frac{partial sigma_1(i^3)}{partial i^3_2}&frac{partial sigma_1(i^3)}{partial i^3_3}\ frac{partial sigma_2(i^3)}{partial i^3_1}&frac{partial sigma_2(i^3)}{partial i^3_2}&frac{partial sigma_2(i^3)}{partial i^3_3}\ frac{partial sigma_3(i^3)}{partial i^3_1}&frac{partial sigma_3(i^3)}{partial i^3_2}&frac{partial sigma_3(i^3)}{partial i^3_3}\ end{matrix} ight]\& =left[ egin{matrix} f_1-f_1f_1&-f_1f_2&-f_1f_3\ -f_1f_2&f_2-f_2f_2&-f_2f_3\ -f_1f_3&-f_2f_3&f_3-f_3f_3\ end{matrix} ight] = ext{diag}(f)-ff^T end{aligned} $
于是$L$对$i^3$求梯度就是($cdot$表示矩阵乘法):
$egin{gather} C =frac{partial L}{partial i^3} = left[ egin{matrix} frac{partial L}{partial i^3_1}\ frac{partial L}{partial i^3_2}\ frac{partial L}{partial i^3_3}\ end{matrix} ight] =left[ egin{matrix} sum_{j=1}^3frac{partial L}{partial f_j}frac{partial f_j}{partial i^3_1}\ sum_{j=1}^3frac{partial L}{partial f_j}frac{partial f_j}{partial i^3_2}\ sum_{j=1}^3frac{partial L}{partial f_j}frac{partial f_j}{partial i^3_3}\ end{matrix} ight] =B^Tcdot A label{}end{gather}$
接下来就是求$L$对参数$w^3$的梯度,但是它们中间有个$i^3$隔着,所以要先求$i^3$对$w$的导数。$i^3$是向量,$w^3$是矩阵,如果一一对应求导就变成了一个三维的张量(不知道有没有雅可比张量的说法)。但是可以发现,每个$w^3_{jk}$($j$行$k$列)只参与$i^3_j$的计算,所以每个$w^3_{jk}$只需求其对应的$i^3_j$的导数即可,求出的是一个矩阵(这一步在代码中并不需要计算,只是为了容易理解):
$egin{gather}displaystyle frac{partial i^3}{partial w^3} =left[ egin{matrix} frac{partial i_1^3}{partial w_{11}^3}&cdots&frac{partial i_1^3}{partial w_{16}^3}\ frac{partial i_2^3}{partial w_{21}^3}&cdots&frac{partial i_2^3}{partial w_{26}^3}\ frac{partial i_3^3}{partial w_{31}^3}&cdots&frac{partial i_3^3}{partial w_{36}^3}\ end{matrix} ight] =left[ egin{matrix} g_1&cdots &g_6\ g_1&cdots &g_6\ g_1&cdots &g_6\ end{matrix} ight] =left[ egin{matrix} g^T\ g^T\ g^T\ end{matrix} ight] label{}end{gather}$
于是$L$对$w^3$的梯度就是($ imes$表示按元素进行的乘法):
$egin{gather}displaystyle frac{partial L}{partial w^3} =left[ egin{matrix} frac{partial L}{partial i_1^3}frac{partial i_1^3}{partial w_{11}^3}&cdots&frac{partial L}{partial i_1^3}frac{partial i_1^3}{partial w_{16}^3}\ frac{partial L}{partial i_2^3}frac{partial i_2^3}{partial w_{21}^3}&cdots&frac{partial L}{partial i_2^3}frac{partial i_2^3}{partial w_{26}^3}\ frac{partial L}{partial i_3^3}frac{partial i_3^3}{partial w_{31}^3}&cdots&frac{partial L}{partial i_3^3}frac{partial i_3^3}{partial w_{36}^3}\ end{matrix} ight] =left[ CCCCCC ight] imes left[ egin{matrix} g^T\ g^T\ g^T\ end{matrix} ight] =Ccdot g^T label{}end{gather}$
接下来求$L$关于$b^3$的导数,因为$b^3_k$的只参与$i^3_k$的计算,且导数为1,所以很简单:
$egin{gather} displaystyle frac{partial L}{partial b^3} =left[ egin{matrix} frac{partial L}{partial i^3_1}frac{partial i^3_1}{partial b^3_1}\ frac{partial L}{partial i^3_2}frac{partial i^3_2}{partial b^3_2}\ frac{partial L}{partial i^3_3}frac{partial i^3_3}{partial b^3_3}\ end{matrix} ight] =frac{partial L}{partial i^3}=C label{}end{gather}$
然后就要向前传播到隐层了,要算出$L$对$g$的梯度,首先要算出$i^3$对$g$的导数(这一步在代码中并不需要计算,只是为了容易理解):
$egin{gather} displaystyle frac{partial i^3}{partial g} =left[ egin{matrix} frac{partial i_1^3}{partial g_1}&cdots&frac{partial i_1^3}{partial g_6}\ frac{partial i_2^3}{partial g_1}&cdots&frac{partial i_2^3}{partial g_6}\ frac{partial i_3^3}{partial g_1}&cdots&frac{partial i_3^3}{partial g_6}\ end{matrix} ight] =w^3 label{}end{gather}$
分析可以发现,每个$g_j$都参与了所有$i^3_k$的计算,所以$L$对$g_j$的导数由多元函数链式法则可得:
$displaystyle D =frac{partial L}{partial g} =left[ egin{matrix} frac{partial L}{partial g_1}\ vdots\ frac{partial L}{partial g_6}\ end{matrix} ight] =left[ egin{matrix} frac{partial L}{partial i_1^3}frac{partial i_1^3}{partial g_1} +frac{partial L}{partial i_2^3}frac{partial i_2^3}{partial g_1} +frac{partial L}{partial i_3^3}frac{partial i_3^3}{partial g_1}\ vdots\ frac{partial L}{partial i_1^3}frac{partial i_1^3}{partial g_6} +frac{partial L}{partial i_2^3}frac{partial i_2^3}{partial g_6} +frac{partial L}{partial i_3^3}frac{partial i_3^3}{partial g_6}\ end{matrix} ight] ={w^3}^Tcdot C $
求出$L$对$g$的梯度后,就开始隐层各个参数的计算了。还是要一步一步算,首先算$g$关于$i^2$的梯度。因为隐层的激活函数是ReLu,是按元素进行的运算,所以每个$g_k$只对它对应的那个$i^2_k$求导。导数也很简单,判断大小即可:
$displaystyle E =frac{partial g}{partial i^2} =left[ egin{matrix} frac{partial g_1}{partial i_1^2}\ vdots\ frac{partial g_6}{partial i_6^2}\ end{matrix} ight] =left[ egin{matrix} delta'(i_1^2)\ vdots\ delta'(i_6^2)\ end{matrix} ight] ,;;; delta'(x) = left{ egin{matrix} 1,xge0\ 0,x<0 end{matrix} ight. $
再求$L$关于$i^2$的梯度,它和$L$关于$i^3$的梯度$(1)$式不同,因为激活函数的计算方式不同:
$displaystyle F =frac{partial L}{partial i^2} =left[ egin{matrix} frac{partial L}{partial i_1^2}\ vdots\ frac{partial L}{partial i_6^2}\ end{matrix} ight] =left[ egin{matrix} frac{partial L}{partial g_1}frac{partial g_1}{partial i_1^2}\ vdots\ frac{partial L}{partial g_6}frac{partial g_6}{partial i_6^2}\ end{matrix} ight] = E imes D $
为了容易理解,在求$L$对$w^2$的梯度之前,先求$i^2$对$w^2$的导数,与$(2)$式类似,求出的是6行5列的矩阵:
$displaystyle frac{partial i^2}{partial w^2} =left[ egin{matrix} frac{partial i_1^2}{partial w_{11}^2}&cdots&frac{partial i_1^2}{partial w_{15}^2}\ vdots&vdots&vdots\ frac{partial i_6^2}{partial w_{61}^2}&cdots&frac{partial i_6^2}{partial w_{65}^2}\ end{matrix} ight] =left[ egin{matrix} h_1&cdots&h_5\ &vdots&\ h_1&cdots&h_5\ end{matrix} ight] =left.left[ egin{matrix} h^T\ vdots\ h^T\ end{matrix} ight] ight} 6 ;r $
与$(3)$式类似,$L$对$w^2$的梯度就是:
$displaystyle frac{partial L}{partial w^2} =left[ egin{matrix} frac{partial L}{partial i_1^2}frac{partial i_1^2}{partial w_{11}^2}&cdots&frac{partial L}{partial i_1^2}frac{partial i_1^2}{partial w_{15}^2}\ vdots&vdots&vdots\ frac{partial L}{partial i_6^2}frac{partial i_6^2}{partial w_{61}^2}&cdots&frac{partial L}{partial i_6^2}frac{partial i_6^2}{partial w_{65}^2}\ end{matrix} ight] = left[FFFFF ight] imes left.left[ egin{matrix} h^T\ vdots\ h^T\ end{matrix} ight] ight}6 ;r =Fcdot h^T $
与$(4)$式类似,$L$对$b^2$的梯度为:
$displaystyle frac{partial L}{partial b^2}= frac{partial L}{partial i^2}=F $
现在,输出层与隐层的参数梯度已经计算完毕了。还剩输入层,它与隐层的唯一区别就在于层中元素数量不同,而传播与求梯度的方法和隐层是一样的,只需对输入层进行$(5)$式及以后的相应操作即可。
总结
通过以上的推演,可以发现,在全连接神经网络中,梯度$frac{partial L}{partial i^k}$是关键。它涉及到参数$w^k$与$b^k$梯度的直接计算,是反向传播的载体。上面使用大写字母标记的变量中,实际上只有$frac{partial L}{partial i^k}$多次参与计算。因此,在以上推演的反向传播中,真正要在迭代中暂存的只有$C$和$F$,其他步骤都合并在一个式子中完成即可。以下是迭代的示意图: