在这篇博文中,我们将利用TensorFlow Eager Execution API来实现一个完整多层感知器(MLP)模型。在具体实现多层感知器模型之前,我们首先来看,怎样用TensorFlow Eager Execution API来求向量与矩阵运算的导数。
我们知道在多层感知器模型中,最基本的运算是由第l−1
l
−
1
层输出信号求出第l
l
层神经元的输入信号,公式如下所示:
zl=Wlal−1+bl(3.2.001)(3.2.001)zl=Wlal−1+bl
为了下面讨论方便,我们假设第l−1
l
−
1
层有3个神经元,第l
l
层有2个神经元,式(3.2.001)中的各个值定义如下。
第l−1l−1层输出信号:
al−1=⎡⎣⎢1.02.03.0⎤⎦⎥(3.2.002) (3.2.002) a l − 1 = [ 1.0 2.0 3.0 ]
第
l−1
l
−
1
层到第
l
l
层连接权值矩阵:
Wl=[4.07.05.08.06.09.0](3.2.003)(3.2.003)Wl=[4.05.06.07.08.09.0]
第
l
l
层偏置值:
bl=[1001.01002.0](3.2.004)(3.2.004)bl=[1001.01002.0]
为了进行学习,我们需要求出以下导数:
∂zl∂al−1
∂
z
l
∂
a
l
−
1
、
∂zl∂bl
∂
z
l
∂
b
l
、
∂zl∂Wl
∂
z
l
∂
W
l
,我们分别来进行讨论。
我们首先来看第一项,根据Jacobian矩阵定义得:
∂zl∂al−1=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢∂zl1∂al−11∂zl2∂al−11...∂zlNl∂al−11∂zl1∂al−12∂zl2∂al−12...∂zlNl∂al−12............∂zl1∂al−1Nl−1∂zl2∂al−1Nl−1...∂zlNl∂al−1Nl−1⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢Wl1,1Wl2,1...WlNl,1Wl1,2Wl2,2...WlNl,2............Wl1,Nl−1Wl2,Nl−1...WlNl,Nl−1⎤⎦⎥⎥⎥⎥⎥=Wl(3.2.005) (3.2.005) ∂ z l ∂ a l − 1 = [ ∂ z 1 l ∂ a 1 l − 1 ∂ z 1 l ∂ a 2 l − 1 . . . ∂ z 1 l ∂ a N l − 1 l − 1 ∂ z 2 l ∂ a 1 l − 1 ∂ z 2 l ∂ a 2 l − 1 . . . ∂ z 2 l ∂ a N l − 1 l − 1 . . . . . . . . . . . . ∂ z N l l ∂ a 1 l − 1 ∂ z N l l ∂ a 2 l − 1 . . . ∂ z N l l ∂ a N l − 1 l − 1 ] = [ W 1 , 1 l W 1 , 2 l . . . W 1 , N l − 1 l W 2 , 1 l W 2 , 2 l . . . W 2 , N l − 1 l . . . . . . . . . . . . W N l , 1 l W N l , 2 l . . . W N l , N l − 1 l ] = W l
我们接下来再来求对第
l
l
层偏置求微分:
∂zlbl=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢∂zl1∂bl1∂zl2∂bl1...∂zlNl∂bl1∂zl1∂bl2∂zl2∂bl2...∂zlNl∂bl2............∂zl1∂blNl∂zl2∂blNl...∂zlNl∂blNl⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢10...001...0............00...1⎤⎦⎥⎥⎥(3.2.006)(3.2.006)∂zlbl=[∂z1l∂b1l∂z1l∂b2l...∂z1l∂bNll∂z2l∂b1l∂z2l∂b2l...∂z2l∂bNll............∂zNll∂b1l∂zNll∂b2l...∂zNll∂bNll]=[10...001...0............00...1]
下面是一个向量对矩阵求偏导,而我们对这个操作没有定义,所以我们需要以一种变通的方式来进行,我们将
Wl
W
l
视为由
w(i)∈RNl−1
w
(
i
)
∈
R
N
l
−
1
的行向量组成:
Wl=⎡⎣⎢⎢⎢⎢(w(1))T(w(2))T...(w(Nl))T⎤⎦⎥⎥⎥⎥=wl∈RNl(3.2.007) (3.2.007) W l = [ ( w ( 1 ) ) T ( w ( 2 ) ) T . . . ( w ( N l ) ) T ] = w l ∈ R N l
其实
w(i)
w
(
i
)
是指向第
l
l
层第ii个神经元所有连接权值组成的向量。
有了式(3.2.007)的定义,我们就可以将
Wl
W
l
视为向量,这样根据Jacobian矩阵定义:
∂zl∂Wl=∂zl∂wl=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢zl1w(1)zl2w(1)...zlNlw(1)zl1w(2)zl2w(2)...zlNlw(2)............zl1w(Nl)zl2w(Nl)...zlNlw(Nl)⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥(3.2.008) (3.2.008) ∂ z l ∂ W l = ∂ z l ∂ w l = [ z 1 l w ( 1 ) z 1 l w ( 2 ) . . . z 1 l w ( N l ) z 2 l w ( 1 ) z 2 l w ( 2 ) . . . z 2 l w ( N l ) . . . . . . . . . . . . z N l l w ( 1 ) z N l l w ( 2 ) . . . z N l l w ( N l ) ]
与前面不同的是,式(3.2.008)的矩阵中的每个元素都是一个标量对向量的求偏导,根据我们上篇博文介绍,标量对向量求偏导,结果为一个行向量,我们以
zliw(j)
z
i
l
w
(
j
)
为例进行讨论。
如果
i≠j
i
≠
j
时,
w(j)
w
(
j
)
是指向第
l
l
层第jj个神经元的,不与第
l
l
行第ii个神经元相接,因此所有偏层均为0,如下所示:
zliw(j)=[00...0]∈RNl−1(3.2.009) (3.2.009) z i l w ( j ) = [ 0 0 . . . 0 ] ∈ R N l − 1
如果
i=j
i
=
j
时,
w(j)
w
(
j
)
是由指向第
l
l
层第ii个神经元的所有连接权值组成的,根据输入信号定义可得:
zliw(j)=[∂zli∂Wlj,1∂zli∂Wlj,2...∂zli∂Wlj,Nl−1]=[al−11al−12...al−1Nl−1](3.2.010) (3.2.010) z i l w ( j ) = [ ∂ z i l ∂ W j , 1 l ∂ z i l ∂ W j , 2 l . . . ∂ z i l ∂ W j , N l − 1 l ] = [ a 1 l − 1 a 2 l − 1 . . . a N l − 1 l − 1 ]
因此式(3.2.008)矩阵的每个元素为指向纸里的
RNl−1
R
N
l
−
1
向量,当不在对角线上时,所有元素值为零,当在对角线上时,元素为第
l−1
l
−
1
层输出值。
下面我们来看,怎样通过TensorFlow Eager Excecution API来求出这些偏导的值。
在上面的代码中,需要说明的是第16行,将向量a
a
定义为3行1列的矩阵形式,这是为了与连接权值矩阵做矩阵相乘。
在前向计算阶段,可以直接调用TensorFlow的矩阵乘法和加法,我们就可以取得正确的结果,但是在反向求导阶段,如果我们直接利用TensorFlow进行求导,例如求∂zl∂al−1
∂
z
l
∂
a
l
−
1
时,TensorFlow返回结果维数与al−1
a
l
−
1
相同,而Jacobian矩阵的维数为RNl×Nl−1
R
N
l
×
N
l
−
1
,所以我们需要自己定义求导函数,根据上面的理论分析,∂zl∂Wl
∂
z
l
∂
W
l
是一个3维的张量,维数为RNl×Nl×Nl−1
R
N
l
×
N
l
×
N
l
−
1
,我们可以将其视为一个RNl×Nl
R
N
l
×
N
l
的矩阵,矩阵中每个元素均为一个数组,长度为Nl−1
N
l
−
1
,且除对角线上的元素外,数组元素为0,而对角线上的元素,数组元素为第l−1
l
−
1
导神经元的输出值。∂zl∂al−1
∂
z
l
∂
a
l
−
1
为第l−1
l
−
1
层到第l
l
层的连接权值矩阵WlWl,而∂zl∂bl
∂
z
l
∂
b
l
为RNl×Nl
R
N
l
×
N
l
的单位阵,运行结果如下所示:
至此我们完成了第l−1
l
−
1
层到第l
l
<script type="math/tex" id="MathJax-Element-58">l</script>层正向传输和反向求导工作,基本上按照数学理论要求,我们就可以完全处理一个多层感知器模型了。