详解神经网络中矩阵实现的梯度计算

  • Post author:
  • Post category:其他


对神经网络有一定了解的同学知道:一般的神经网络的具体实现都是通过矩阵实现的,包括误差反向传导,梯度计算和更新等等,比如



y

=

w

x

+

b

y=w*x+b






y




=








w













x




+








b





,这里的所有变量都是矩阵,我们通常会叫



w

w






w









b

b






b





为参数矩阵,矩阵相乘首先效率比较高,然后也比较好操作,那么对于矩阵形式的导数该怎么计算?比如



w

w






w





矩阵的具体导数



d

w

dw






d


w





应该如何计算?

首先我们来看一个只有输入和输出层的网络,我们输入



X

X






X





矩阵大小为



N

D

N*D






N













D









N

N






N





为batch的大小,也就是一次性输入的样本数,



D

D






D





为输入数据的维度,也就是输入层神经元的个数,输出矩阵



Y

Y






Y





大小为



N

M

N*M






N













M









M

M






M





为输出数据的维度,也就是输出层神经元的个数, 可以看成输入数据X经过这个网络的变换,数据维度由



D

D






D





映射到了



M

M






M





维,那么



w

w






w





矩阵的大小自然就是



D

M

D*M






D













M






1. 当前层



d

x

dx






d


x





的求法

这里写图片描述

上图中



X

j

,

1

X_{j,1}







X











j


,


1






















表示第j个样本输入数据的第一个值,我们现在就考虑这个值的梯度要如何求,



d

Y

j

,

1

dY_{j,1}






d



Y











j


,


1






















表示第j个样本回传梯度的第一个值(通过链式法则,梯度是一层一层向后传递,你可以理解这个



d

Y

dY






d


Y





就是从下一层的网络传回的梯度),现在我们已知



w

w






w





和传回的



d

Y

dY






d


Y





,那么这个理论上分析



d

x

dx






d


x





肯定等于



w

d

Y

w*dY






w













d


Y





(因为



Y

Y






Y









X

X






X





的导数就是



w

w






w





,而回传的梯度



d

Y

dY






d


Y





其实是损失函数



L

L






L









Y

Y






Y





的导数, 即



d

L

/

d

x

=

d

L

/

d

Y

d

Y

/

d

x

dL/dx=dL/dY * dY/dx






d


L


/


d


x




=








d


L


/


d


Y













d


Y


/


d


x





,对于



d

X

j

,

1

dX_{j,1}






d



X











j


,


1






















来说,它的梯度为跟它连接的



w

w






w





参数与第j个样本所有



d

Y

dY






d


Y





乘积的求和

那么我们把在公式中关于计算



d

X

j

,

1

d_{Xj,1}







d











X


j


,


1






















梯度需要的w参数和



d

Y

dY






d


Y





在正向传播的矩阵计算中标示出来如下,根据计算公式,我们发现



d

X

j

,

1

dX_{j,1}






d



X











j


,


1






















的值正好等于



d

Y

dY






d


Y





矩阵与



w

w






w





转置矩阵相乘后的第一行第一列的值,这不是偶然,其实



d

Y

dY






d


Y





矩阵与



w

w






w





转置矩阵的相乘正好就是



d

X

dX






d


X





梯度矩阵

这里写图片描述

那么我们得出结论:

当前



d

x

dx






d


x





矩阵由下一层传回的



d

Y

dY






d


Y





矩阵与当前参数矩阵



w

w






w





的乘积

用python实现就是:

   dx = np.dot(dY, w.T)  # (N,D)



2. 当前层



d

w

dw






d


w









d

b

db






d


b





的求法





d

x

dx






d


x





的公式类似,



d

w

1

,

1

dw_{1,1}






d



w











1


,


1






















的计算公式我们也可以推出,因为



w

1

,

1

w_{1,1}







w











1


,


1






















参数每次只与这个样本的第一个输入数据发生相乘关系,因此如果有



N

N






N





个样本,那么



d

w

1

,

1

dw_{1,1}






d



w











1


,


1






















就等于相应样本的



d

Y

dY






d


Y





与此样本第一个输入数据的乘积然后求和

这里写图片描述

这里写图片描述

我们将计算



d

w

1

,

1

dw_{1,1}






d



w











1


,


1






















所有相关的值在正向传播中标示出来如下,我们也正好发现



d

w

1

,

1

dw_{1,1}






d



w











1


,


1






















的值就等于



X

X






X





的转置矩阵与



d

Y

dY






d


Y





相乘后矩阵的第一行第一列值,

因此:当前



d

w

dw






d


w





矩阵等于当前



X

X






X





转置矩阵与下一层传回的



d

Y

dY






d


Y





矩阵的乘积

对于



d

b

1

db_1






d



b










1





















来说,

它的梯度直接为所有相应样本的



d

Y

dY






d


Y





的求和

, 因此直接对



d

Y

dY






d


Y





矩阵进行在维度为0的求和操作即可

我们用python实现即为:

dw = np.dot(X.T, dY)  # (D,M)
db = np.sum(dY, axis=0)  # (M,)

关于更加详细的实现请看这里:https://github.com/PENGZhaoqing/cs231n-assignment2/blob/master/cs231n/layers.py



思考- 使用mini-batch的优点

其实



d

w

dw






d


w





的计算可以这么理解,是这批(batch)样本里每个样本损失函数对w的梯度向量的累加,如下图所示,蓝线代表各个样本损失函数对



w

w






w





的梯度向量,红线代表这些梯度向量的求和,也就是我们最终更新



w

w






w





的方向,这个方向很好综合了所有单个样本更新的方向,因此更新的效果要比单个样本一个一个来更新要好的多,每次单个的更新会让整个更新过程非常动荡(每个样本的方向基本都不一样),而使用mini-batch的方法每次更新的方向是所有这些样本更新方向的折中,减少了每次更新的差异性:

这里写图片描述

那是不是batch的size越大越好呢,当然不是,当batch的样本数量过大后,



d

w

dw






d


w





会淹没一些少数的样本的方向,比如下图, 假设黑线代表某个样本更新



w

w






w





的梯度方向,这个方向会被其他蓝线方向覆盖,所以最终的



d

w

dw






d


w





方向基本上不会反映出这个样本的更新方向,当batch_size过大后,在每次epoch迭代中,黑线代表的样本都有很大可能性被覆盖,会导致精度会上不去

这里写图片描述



版权声明:本文为ppp8300885原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。