矩阵求导
关于矩阵求导,其实严格意义上来说仅仅只是一种求导的矩阵表示形式,其本质还是和普通多元函数求导过程是一致的。将矩阵的各个元素拆分开来,将矩阵运算写成各个元素之间的运算,矩阵变换可以变成多元函数,这样矩阵求导过程就可以与多元函数求导过程联系起来了。要理解矩阵求导运算,最主要的其实是理解矩阵导数的表示,将矩阵导数的拆分形式与多元函数求导联系起来。
本文主要参考《Matrix cookbook》和wiki上面的内容,下面简单介绍一下矩阵求导的相关内容,为后面介绍前馈神经网络FNN的反向传播过程做铺垫。
矩阵求导的表示形式之一:值函数对向量/矩阵变量的导数
下面表达式中,yy表示一个实值函数,xx表示一个向量变量,那么他们的矩阵求导含义为:
∂y∂x=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y∂x1∂y∂x2⋯∂y∂xn⎤⎦⎥⎥⎥⎥⎥⎥⎥∂y∂x=[∂y∂x1∂y∂x2⋯∂y∂xn]
yy
表示一个实值函数,
XX
表示一个矩阵变量:
∂y∂X=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y∂x11∂y∂x21⋯∂y∂xp1∂y∂x12∂y∂x22⋯∂y∂xp2⋯⋯⋯⋯∂y∂x1q∂y∂x2q⋯∂y∂xpq⎤⎦⎥⎥⎥⎥⎥⎥⎥∂y∂X=[∂y∂x11∂y∂x12⋯∂y∂x1q∂y∂x21∂y∂x22⋯∂y∂x2q⋯⋯⋯⋯∂y∂xp1∂y∂xp2⋯∂y∂xpq]
上面给出了矩阵求导的表示形式的具体含义,很容易理解。下面给出几个例子,
aa
是实数,
ββ
和
xx
是向量,
AA
、
BB
和
CC
是与
xx
无关的矩阵:
∂βTx∂x=β∂βTx∂x=β
∂xTx∂x=x∂xTx∂x=x
∂xTAx∂x=(A+AT)x∂xTAx∂x=(A+AT)x
如果你能发现这三个式子左边的分子都是一个数,分母都是一个向量,那么你应该很容易理解这几个等式。是在不能理解就自己把左右两边的矩阵运算拆分开来,然后使用多元函数求导的过程将左右两边分别表示出来就行了。以第一个为例:
βTx=∑i=1nβixiβTx=∑i=1nβixi
∂βTx∂x=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂βTx∂x1∂βTx∂x2⋯∂βTx∂xn⎤⎦⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂∑ni=1βixi∂x1∂∑ni=1βixi∂x2⋯∂∑ni=1βixi∂xn⎤⎦⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢β1β2⋯βn⎤⎦⎥⎥⎥=β∂βTx∂x=[∂βTx∂x1∂βTx∂x2⋯∂βTx∂xn]=[∂∑i=1nβixi∂x1∂∑i=1nβixi∂x2⋯∂∑i=1nβixi∂xn]=[β1β2⋯βn]=β
这样就能很清楚的理解矩阵矩阵求导的表示形式的具体含义了。
矩阵求导的表示形式之二:向量函数对值/向量/矩阵变量的导数
下面表达式中,yy表示一个向量函数,xx表示一个值变量,那么他们的矩阵求导含义为:
∂y∂x=⎡⎣⎢⎢⎢⎢⎢⎢∂y1∂x∂y2∂x⋯∂yn∂x⎤⎦⎥⎥⎥⎥⎥⎥∂y∂x=[∂y1∂x∂y2∂x⋯∂yn∂x]
接下来是向量函数
yy
对向量变量
xx
的导数含义为:
∂y∂x=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y1∂x1∂y2∂x2⋯∂ym∂xn∂y1∂x2∂y2∂x2⋯∂ym∂x2⋯⋯⋯⋯∂y1∂xn∂y2∂xn⋯∂ym∂xn⎤⎦⎥⎥⎥⎥⎥⎥⎥∂y∂x=[∂y1∂x1∂y1∂x2⋯∂y1∂xn∂y2∂x2∂y2∂x2⋯∂y2∂xn⋯⋯⋯⋯∂ym∂xn∂ym∂x2⋯∂ym∂xn]
以一个最为简单的例子为例:
y=Wxy=Wx
那么:
∂y∂x=W∂y∂x=W
最后向量函数
yy
对矩阵变量
WW
的导数是一个张量,具体形状为:
∂y∂W=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y1∂W11∂y1∂W21⋯∂y1∂Wm1∂y1∂W12∂y1∂W22⋯∂y1∂Wm2⋯⋯⋯⋯∂y1∂W2n∂y1∂W2n⋯∂y1∂Wmn⎤⎦⎥⎥⎥⎥⎥⎥⎥⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y2∂W11∂y2∂W21⋯∂y2∂Wm1∂y2∂W12∂y2∂W22⋯∂y2∂Wm2⋯⋯⋯⋯∂y2∂W2n∂y2∂W2n⋯∂y2∂Wmn⎤⎦⎥⎥⎥⎥⎥⎥⎥⋯⎡⎣⎢⎢⎢⎢⎢⎢⎢∂yk∂W11∂yk∂W21⋯∂yk∂Wm1∂yk∂W12∂yk∂W22⋯∂yk∂Wm2⋯⋯⋯⋯∂yk∂W2n∂yk∂W2n⋯∂yk∂Wmn⎤⎦⎥⎥⎥⎥⎥⎥⎥∂y∂W=[∂y1∂W11∂y1∂W12⋯∂y1∂W2n∂y1∂W21∂y1∂W22⋯∂y1∂W2n⋯⋯⋯⋯∂y1∂Wm1∂y1∂Wm2⋯∂y1∂Wmn][∂y2∂W11∂y2∂W12⋯∂y2∂W2n∂y2∂W21∂y2∂W22⋯∂y2∂W2n⋯⋯⋯⋯∂y2∂Wm1∂y2∂Wm2⋯∂y2∂Wmn]⋯[∂yk∂W11∂yk∂W12⋯∂yk∂W2n∂yk∂W21∂yk∂W22⋯∂yk∂W2n⋯⋯⋯⋯∂yk∂Wm1∂yk∂Wm2⋯∂yk∂Wmn]
同样举出一个例子说明这个形式的含义:
l=f(y)l=f(y)
其中,
yy
为
mm
维向量,然后
y=Wxy=Wx
,
WW
为
m∗nm∗n
的矩阵,
xx
为
nn
维向量。然后
∂l∂y∂l∂y
为
mm
维向量,
∂y∂W∂y∂W
为
m∗m∗nm∗m∗n
维张量,最后根据链式法则有
∂l∂W=∂l∂y∂y∂W∂l∂W=∂l∂y∂y∂W
,很显然最后的结果
∂l∂W∂l∂W
应该是一个
m∗nm∗n
为的矩阵,而等式另外边为
mm
维向量乘上
m∗m∗nm∗m∗n
维张量,其结果为
m∗nm∗n
维矩阵。将这个过程拆开来看:
∂y∂W=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y∂W11∂y∂W21⋯∂y∂Wm1∂y∂W12∂y∂W22⋯∂y∂Wm2⋯⋯⋯⋯∂y∂W1n∂y∂W2n⋯∂y∂Wmn⎤⎦⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢∑mi=1∂l∂y1∂y1∂W11∑mi=1∂l∂y1∂y1∂W21⋯∑mi=1∂l∂y1∂y1∂Wm1∑mi=1∂l∂y1∂y1∂W12∑mi=1∂l∂y1∂y1∂W22⋯∑mi=1∂l∂y1∂y1∂Wm2⋯⋯⋯⋯∑mi=1∂l∂y1∂y1∂W1n∑mi=1∂l∂y1∂y1∂W2n⋯∑mi=1∂l∂y1∂y1∂Wmn⎤⎦⎥⎥⎥⎥⎥⎥⎥∂y∂W=[∂y∂W11∂y∂W12⋯∂y∂W1n∂y∂W21∂y∂W22⋯∂y∂W2n⋯⋯⋯⋯∂y∂Wm1∂y∂Wm2⋯∂y∂Wmn]=[∑i=1m∂l∂y1∂y1∂W11∑i=1m∂l∂y1∂y1∂W12⋯∑i=1m∂l∂y1∂y1∂W1n∑i=1m∂l∂y1∂y1∂W21∑i=1m∂l∂y1∂y1∂W22⋯∑i=1m∂l∂y1∂y1∂W2n⋯⋯⋯⋯∑i=1m∂l∂y1∂y1∂Wm1∑i=1m∂l∂y1∂y1∂Wm2⋯∑i=1m∂l∂y1∂y1∂Wmn]
矩阵求导的表示形式之三:矩阵函数对值/向量/矩阵变量的导数
首先矩阵函数YY对值变量xx的导数含义为:
∂Y∂x=⎡⎣⎢⎢⎢⎢⎢⎢⎢∂y11∂x∂y21∂x⋯∂yp1∂x∂y12∂x∂y22∂x⋯∂yp2∂x⋯⋯⋯⋯∂y1q∂x∂y2q∂x⋯∂ypq∂x⎤⎦⎥⎥⎥⎥⎥⎥⎥∂Y∂x=[∂y11∂x∂y12∂x⋯∂y1q∂x∂y21∂x∂y22∂x⋯∂y2q∂x⋯⋯⋯⋯∂yp1∂x∂yp2∂x⋯∂ypq∂x]
这个也很容易理解,然后矩阵函数对向量变量的导数是形式上是一个张量,矩阵函数对矩阵变量的导数是一个四阶张量。
这些导数的形式很少用到,但实际上本质还是一样的:
矩阵求导本质上是多元函数求导的矩阵表示形式,其函数由矩阵运算定义,其导数形式是为了同样满足矩阵运算而定义的。
还是那句话,如果不理解矩阵求导过程,直接把矩阵运算转化成基本的多元函数运算,用多元函数求导方法写出其形式就很容易理解了。
当然,上面几个仅仅是非常简单的矩阵求导,更复杂的涉及到求迹(对角线上元素的和)tr(A)tr(A)、行列式det(A)det(A)等就需要去参照《Matrix Cookbook》中的内容自行理解了。了解到上面的内容已经足够让我们来理解神经网络的反向传播了。
神经网络反向传播
讲到神经网络的反向传播首先不得不提一下求导的链式法则:实际上神经网络本质上可以说是一堆向量操作加上激活函数,也可以说是一堆线性函数操作加上激活函数,整个过程最终都可以展开成一个无比大的函数。为了比较好表述神经网络的每一层的正向计算以及反向传播,才表述为矩阵计算与链式法则计算梯度,其本质还是非常简单的多元函数求导。
链式法则
链式法则是多元函数求导基本,通常意义上的链式法则表述如下:
z=f(x,y)x=g(u,v)y=h(u,v)z=f(x,y)x=g(u,v)y=h(u,v)
那么就有:
∂z∂u=∂z∂x∂x∂u+∂z∂y∂y∂u∂z∂v=∂z∂x∂x∂v+∂z∂y∂y∂v∂z∂u=∂z∂x∂x∂u+∂z∂y∂y∂u∂z∂v=∂z∂x∂x∂v+∂z∂y∂y∂v
这个看起来是不是很简单,理解偏导和梯度的含义就应该很容易理解这个过程。那么接下来,重头戏来了:上面过程中
yy
可以是
xx
的函数,甚至可以是
xx
。来我们先举一个简单的例子来看:
z=xxx=u+vz=xxx=u+v
对于这样一个例子,我们先把上面式子中指数项的
xx
记做
yy
,那么上面的式子就转化为:
z=xyx=u+vy=u+vz=xyx=u+vy=u+v
接下来我们来根据链式法则来求导:
∂z∂u=∂z∂x∂x∂u+∂z∂y∂y∂u=yxy−1∂x∂u+xyln(x)∂y∂u=(u+v)u+v+(u+v)u+vln(u+v)∂z∂u=∂z∂x∂x∂u+∂z∂y∂y∂u=yxy−1∂x∂u+xyln(x)∂y∂u=(u+v)u+v+(u+v)u+vln(u+v)
∂z∂v=∂z∂x∂x∂v+∂z∂y∂y∂v=yxy−1∂x∂v+xyln(x)∂y∂v=(u+v)u+v+(u+v)u+vln(u+v)∂z∂v=∂z∂x∂x∂v+∂z∂y∂y∂v=yxy−1∂x∂v+xyln(x)∂y∂v=(u+v)u+v+(u+v)u+vln(u+v)
额,是不是很神奇:
dxxdx=xx+xxln(x)dxxdx=xx+xxln(x)
这个式子也可以通过将两个
xx
看做不同的
xx
分别求偏导然后求全微分而得到其导数,当且仅当原函数可微时才能这样做。
好吧,上面这些内容其实是一些题外话,我们真正需要了解的是:在矩阵操作中,我们可以把例如
y=Wx+by=Wx+b
这样的矩阵操作看做是多元函数
全连接层的反向传播
一层全连接层的神经网络的本质是一个output=f(input)output=f(input)的多元函数,例如一般来说一层全连接以xx表示输入向量,yy表示输出向量,那么一层全连接神经网络可数学表示为:
y=σ(Wx+b)y=σ(Wx+b)
其中
WW
和
bb
是参数,前者是映射矩阵,后者是偏置向量,
σσ
表示激活函数,这是一个数值函数,也就是对矩阵/向量中的每一个值做这样一个函数映射,常用的激活函数有如下几种:
sigmoid
激活函数:
y=11+e−xy=11+e−x
sigmoid
激活函数的导数:
y′=(11+e−x)′=e−x(1+e−x)2=1+e−x−1(1+e−x)2=11+e−x(1−11+e−x)=y(1−y)y′=(11+e−x)′=e−x(1+e−x)2=1+e−x−1(1+e−x)2=11+e−x(1−11+e−x)=y(1−y)
tanh
激活函数:
y=ex−e−xex+e−xy=ex−e−xex+e−x
tanh
激活函数的导数:
y′=(ex−e−xex+e−x)′=(ex+e−x)2−(ex−e−x)2(ex+e−x)2=1−(ex−e−x)2(ex+e−x)2=1−y2y′=(ex−e−xex+e−x)′=(ex+e−x)2−(ex−e−x)2(ex+e−x)2=1−(ex−e−x)2(ex+e−x)2=1−y2
relu
激活函数:
y={x,0,x>0x<=0y={x,x>00,x<=0
relu
激活函数的导数:
y′={1,0,x>0x<=0y′={1,x>00,x<=0
从上面这三种常用激活函数的导数可以看出,激活函数反向求导都非常简单直接。然后,我们将从两种角度来给出全连接层反向传播的导数:矩阵形式和多元函数形式。
全连接层的反向传播的矩阵形式
神经网络反向传播时,我们已知的是∂l∂y∂l∂y,也就是前面层传过来的lossloss对于当前层输出的梯度,然后一方面我们需要知道lossloss对于参数的梯度∂l∂W∂l∂W和∂l∂b∂l∂b,而另一方面我们也需要知道lossloss对于输入的梯度∂l∂x∂l∂x,以便于参数向前面层传播,更新前面层的参数。假设我们以sigmoidsigmoid函数作为激活函数:
y=σ(Wx+b)y=σ(Wx+b)
利用链式法则我们有:
∂l∂W=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂W=∂l∂y∘(y∘(1−y))xT∂l∂W=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂W=∂l∂y∘(y∘(1−y))xT
∂l∂b=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂b=∂l∂y∘(y∘(1−y))∂l∂b=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂b=∂l∂y∘(y∘(1−y))
∂l∂x=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂x=∂l∂y∘(y∘(1−y))W∂l∂x=∂l∂y∂y∂(Wx+b)∂(Wx+b)∂x=∂l∂y∘(y∘(1−y))W
其中
∘∘
表示矩阵对应值相乘。
全连接层的反向传播的多元函数形式
接下来给出全连接层的多元函数形式:
y=σ(Wx+b)y=σ(Wx+b)
记
y=⎡⎣⎢⎢⎢y1y2⋯ym⎤⎦⎥⎥⎥y=[y1y2⋯ym]
则有:
yi=σ(∑j=1nWijxj+bi),i=1,2,...,myi=σ(∑j=1nWijxj+bi),i=1,2,...,m
那么有:(
WijWij
只影响
yiyi
,
bibi
只影响
yiyi
。)
∂l∂Wij=∂l∂yiyi(1−yi)xj,i=1,2,...,m,j=1,2,...n∂l∂Wij=∂l∂yiyi(1−yi)xj,i=1,2,...,m,j=1,2,...n
∂l∂bi=∂l∂yiyi(1−yi),i=1,2,...,m∂l∂bi=∂l∂yiyi(1−yi),i=1,2,...,m
(
xjxj
影响
y1,y2,...,ymy1,y2,...,ym
)
∂l∂xj=∑i=1m∂l∂yiyi(1−yi)Wij,j=1,2,...,n∂l∂xj=∑i=1m∂l∂yiyi(1−yi)Wij,j=1,2,...,n
把上面的东西写进矩阵里面就有:
∂l∂W=⎡⎣⎢⎢⎢⎢⎢⎢∂l∂y1y1(1−y1)x1∂l∂y2y2(1−y2)x1⋯∂l∂ymym(1−ym)x1∂l∂y1y1(1−y1)x2∂l∂y2y2(1−y2)x2⋯∂l∂ymym(1−ym)x2⋯⋯⋯⋯∂l∂y1y1(1−y1)xn∂l∂y2y2(1−y2)xn⋯∂l∂ymym(1−ym)xn⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)⎤⎦⎥⎥⎥⎥⎥⎥[x1x2⋯xn]=⎡⎣⎢⎢⎢⎢⎢⎢∂l∂y1∂l∂y2⋯∂l∂ym⎤⎦⎥⎥⎥⎥⎥⎥∘⎡⎣⎢⎢⎢y1y2⋯ym⎤⎦⎥⎥⎥∘⎡⎣⎢⎢⎢1−y11−y2⋯1−ym⎤⎦⎥⎥⎥[x1x2⋯xn]=∂l∂y∘(y∘(1−y))xT∂l∂W=[∂l∂y1y1(1−y1)x1∂l∂y1y1(1−y1)x2⋯∂l∂y1y1(1−y1)xn∂l∂y2y2(1−y2)x1∂l∂y2y2(1−y2)x2⋯∂l∂y2y2(1−y2)xn⋯⋯⋯⋯∂l∂ymym(1−ym)x1∂l∂ymym(1−ym)x2⋯∂l∂ymym(1−ym)xn]=[∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)][x1x2⋯xn]=[∂l∂y1∂l∂y2⋯∂l∂ym]∘[y1y2⋯ym]∘[1−y11−y2⋯1−ym][x1x2⋯xn]=∂l∂y∘(y∘(1−y))xT
∂l∂b=⎡⎣⎢⎢⎢⎢⎢⎢∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)⋯⋯⋯⋯∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢∂l∂y1∂l∂y2⋯∂l∂ym⎤⎦⎥⎥⎥⎥⎥⎥∘⎡⎣⎢⎢⎢y1y2⋯ym⎤⎦⎥⎥⎥∘⎡⎣⎢⎢⎢1−y11−y2⋯1−ym⎤⎦⎥⎥⎥=∂l∂y∘(y∘(1−y))∂l∂b=[∂l∂y1y1(1−y1)∂l∂y1y1(1−y1)⋯∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)∂l∂y2y2(1−y2)⋯∂l∂y2y2(1−y2)⋯⋯⋯⋯∂l∂ymym(1−ym)∂l∂ymym(1−ym)⋯∂l∂ymym(1−ym)]=[∂l∂y1∂l∂y2⋯∂l∂ym]∘[y1y2⋯ym]∘[1−y11−y2⋯1−ym]=∂l∂y∘(y∘(1−y))
∂l∂x=⎡⎣⎢⎢⎢⎢⎢⎢∑mi=1∂l∂yiyi(1−yi)Wi1∑mi=1∂l∂yiyi(1−yi)Wi2⋯∑mi=1∂l∂yiyi(1−yi)Win⎤⎦⎥⎥⎥⎥⎥⎥=[∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)]⎡⎣⎢⎢⎢W11W21⋯Wm1W12W22⋯Wm2⋯⋯⋯⋯W1nW2n⋯Wmn⎤⎦⎥⎥⎥=[∂l∂y∘(y∘(1−y))]TW∂l∂x=[∑i=1m∂l∂yiyi(1−yi)Wi1∑i=1m∂l∂yiyi(1−yi)Wi2⋯∑i=1m∂l∂yiyi(1−yi)Win]=[∂l∂y1y1(1−y1)∂l∂y2y2(1−y2)⋯∂l∂ymym(1−ym)][W11W12⋯W1nW21W22⋯W2n⋯⋯⋯⋯Wm1Wm2⋯Wmn]=[∂l∂y∘(y∘(1−y))]TW
最后一个貌似转置行列有些对应不上,哈哈哈!!!