美文网首页
神经网络中的梯度计算以及python代码实现

神经网络中的梯度计算以及python代码实现

作者: Thunder_Storm | 来源:发表于2020-02-15 09:19 被阅读0次

    在学习斯坦福大学的 cs231遇到了不少问题,这一篇主要是来自己对于神经网络中的梯度计算和其实现的python代码。

    目前我所学习到的有关梯度的计算的方法有两种,第一种是根据网络的反向传播,可以得到网络输出的导数dout与输入dx,dw,db的关系(这里所说的神经网络是比较简单的全连接神经网络,激活层为sotmax或者relu等函数),这一部分将在下篇blog里进行推导计算;第二种就是利用基本公式(一个点号代表求一阶导数):

    f(x)'=\lim_{h\rightarrow 0}\frac{f(x+h)-f(x-h)}{2h}

    一个简单的神经网络结构如下图所示(具体的不多解释):

    简单神经网络结构

    下面贴出代码:

    import numpy as np
    from random import randrange
    
    def eval_numerical_gradient(f,x,verbose=True,h=0.0001):
      #计算f在x的梯度,其中f是接收一个参数的函数,返回一个数字,如loss
      fx = f(x)
      grad = np.zeros_like(x)
      it = np.nditer(x,flags=['multi_index'],op_flags=['readwrite'])
      #当迭代没有结束的时候
      while not it.finished:
        ix = it.multi_index
        oldval = x[ix]
        x[ix] = oldval+h
        f1 = f(x)
        x[ix] = oldval-h
        f2 = f(x)
        grad[ix] = (f1-f2)/(2*h)
        if verbose:
          print(ix,grad[ix])
        it.iternext()
      return grad
    
    def eval_numerical_gradient_array(f,x,df,h=1e-5):
      #f为接受numpy数组并返回numpy数组的函数,并求f在x的梯度
      grad = np.zeros_like(x)
      it = np.nditer(x,flags=['multi_index'],op_flags=['readwrite'])
      while not it.finished:
        ix = it.multi_index
        oldval = x[ix]
        x[ix] = oldval + h
        pos = f(x).copy()
        x[ix] = oldval - h
        neg = f(x).copy()
        x[ix] = oldval
        
        grad[ix] = np.sum((pos - neg) * df) / (2 * h)
        it.iternext()
      return grad
    

    上述的两个函数都是计算导数,其中第一个函数eval_numerical_gradient是用来计算简单函数的导数,第二个函数eval_numerical_gradient_array则是用来计算矩阵中对应元素的导数。第一个函数好理解,现在来看第二个函数,原理一样,但是会发现在计算导数的时候分子多乘了一个df,这个是为什么?

    #eval_numerical_gradien
    grad[ix] = (f1-f2)/(2*h)
    #eval_numerical_gradient_array
    grad[ix] = np.sum((pos - neg) * df) / (2 * h)
    

    下面给出矩阵求导的公式d{x_{ij}}^{ } = \frac{\partial L}{\partial x_{ij}}=\sum_{p}^{b}\sum_{q}^{a}\frac{\partial L}{\partial y_{pq}}\frac{\partial y_{pq}}{\partial x_{ij}}公式来源:https://blog.csdn.net/xiezongsheng1990/article/details/86709575

    个人觉得这个公式不太好理解,接下来详细说明矩阵对元素的求导
    矩阵中某个元素的梯度,分为两个方向:x和y,因此矩阵某个元素的梯度也就由两部分相加而成。

    image.png
    在这个例子里,上面矩阵导数的公式可以简化为:即为该元素在y1和y2方向上的导数和。
    grad[ix] = np.sum((pos - neg) * df) / (2 * h)
    

    在这条执行语句中,公式中的{\partial y_{k}}即为元素在x和y方向上所对应的行向量和列向量的变化,因为只有一个元素变化了2h,其他元素都没有变化,所以{\partial y_{k}}=2h,df则为\frac{\partial y_{k}}{\partial x_{ij}}

    个人理解:

    矩阵对梯度的求导本质上是一个复合求导,即矩阵先对行/列向量求导,行/列向量最后再对该元素进行求导。

    下篇预告:神经网络导数的推导并计算与本篇公式所得到的导数之间的误差

    相关文章

      网友评论

          本文标题:神经网络中的梯度计算以及python代码实现

          本文链接:https://www.haomeiwen.com/subject/uefefhtx.html