神经网络的参数梯度推导以及python代码实现

2020-02-17  本文已影响0人  Thunder_Storm

此篇博客承接上一篇的内容,在上一篇博客中,通过基本定义以及公式实现了对一个简单网络的梯度求解,在这篇博客将,将会更多的利用网络图来实现参数梯度的求解。

要完成此篇网络图的梯度推导需要有一定的基础知识,下面给出知乎中对于softmax的损失函数的讲解以及网络图推导梯度所需要的一些基础。这里给出比较重要的内容:
softmax的损失函数loss公式

image
回传流中的模式
加法门单元把输出的梯度相等地分发给它所有的输入,这一行为与输入值在前向传播时的值无关。这是因为加法操作的局部梯度都是简单的+1,所以所有输入的梯度实际上就等于输出的梯度,因为乘以1.0保持不变。上例中,加法门把梯度2.00不变且相等地路由给了两个输入。
取最大值门单元对梯度做路由。和加法门不同,取最大值门将梯度转给其中一个输入,这个输入是在前向传播中值最大的那个输入。这是因为在取最大值门中,最高值的局部梯度是1.0,其余的是0。上例中,取最大值门将梯度2.00转给了z变量,因为z的值比w高,于是w的梯度保持为0。
乘法门单元相对不容易解释。它的局部梯度就是输入值,但是是相互交换之后的,然后根据链式法则乘以输出值的梯度。

下面来看网络中的数据流向(黑实线为前向传播,红虚线为反向传播过程):

神经网络数据流向

这里我省略了softmax的Loss函数对全连接网络输出\mathrm{f}=\mathrm{X}^{*} \mathrm{W}+\mathrm{b}的求导,如果不了解可以查看前面给出的链接。

现在假设我们求出了\frac{\partial Loss}{\partial f}并命名为df(以分母命名,代表Loss值对f进行求导,后面的命名也是类似的意思,方便表示)。根据数据网络梯度推算的原理,因为\mathrm{f}=\mathrm{X}^{*} \mathrm{W}+\mathrm{b},所以可以算出X*W的梯度和b的梯度db,进而求得X和W的梯度dX和dW。要注意的是,因为是矩阵相乘,在程序中需要注意维度问题

代码中的维度细节

假设输入X的维度为(N,D),W的维度为(D,H),b的维度为(,H),那么容易得fscoreLoss的维度都相同且为(N,H),df为(N,H),因为是加法,所以X*Wdb的梯度都完全相同且为df,在求X的梯度时,因为要涉及矩阵乘法,所以需要注意维度,df*dW.T从维度上看即为(N,H)*(H,D) = (N,D),符合X的维度,dW的解法类似,这里不再给出。

代码如下:

def affine_backward(dout, cache):
  """
  Computes the backward pass for an affine layer.
  Inputs:
  - dout: Upstream derivative, of shape (N, M)
  - cache: Tuple of:
    - x: Input data, of shape (N, d_1, ... d_k)
    - w: Weights, of shape (D, M)

  Returns a tuple of:
  - dx: Gradient with respect to x, of shape (N, d1, ..., d_k)          
  - dw: Gradient with respect to w, of shape (D, M)
  - db: Gradient with respect to b, of shape (M,)
  """
  x, w, b = cache
  dx, dw, db = None, None, None
  x_rsp = x.reshape(N , -1)  
  dx = dout.dot(w.T)
  dx = dx.reshape(*x.shape)
  dw = x_rsp.T.dot(dout)
  db = np.sum(dout, axis = 0)
  return dx, dw, db
这里给出基于流量图和数学公式两种方法算出的参数导数的误差,接近可以忽略不计。 算法误差

总结

了解了以上导数的推导,后面更复杂的神经网络导数的推导也是类似的,比较不同的也只是不同的层的处理方法的不同,依然可以用这两种方法来求解,为了验证前两次的方法,下一篇将基于批量标准化来对参数的梯度使用两种方法进行求解。

下篇预告:基于批量标准化(Batch Normalization)的梯度的求解

上一篇下一篇

猜你喜欢

热点阅读