神經(jīng)網(wǎng)絡(luò)中的梯度計算以及python代碼實現(xiàn)

在學(xué)習(xí)斯坦福大學(xué)的 cs231遇到了不少問題,這一篇主要是來自己對于神經(jīng)網(wǎng)絡(luò)中的梯度計算和其實現(xiàn)的python代碼。

目前我所學(xué)習(xí)到的有關(guān)梯度的計算的方法有兩種,第一種是根據(jù)網(wǎng)絡(luò)的反向傳播,可以得到網(wǎng)絡(luò)輸出的導(dǎo)數(shù)dout與輸入dx,dw,db的關(guān)系(這里所說的神經(jīng)網(wǎng)絡(luò)是比較簡單的全連接神經(jīng)網(wǎng)絡(luò),激活層為sotmax或者relu等函數(shù)),這一部分將在下篇blog里進(jìn)行推導(dǎo)計算;第二種就是利用基本公式(一個點號代表求一階導(dǎo)數(shù)):

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

一個簡單的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示(具體的不多解釋):

簡單神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)

下面貼出代碼:

import numpy as np
from random import randrange

def eval_numerical_gradient(f,x,verbose=True,h=0.0001):
  #計算f在x的梯度,其中f是接收一個參數(shù)的函數(shù),返回一個數(shù)字,如loss
  fx = f(x)
  grad = np.zeros_like(x)
  it = np.nditer(x,flags=['multi_index'],op_flags=['readwrite'])
  #當(dāng)?shù)鷽]有結(jié)束的時候
  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數(shù)組并返回numpy數(shù)組的函數(shù),并求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

上述的兩個函數(shù)都是計算導(dǎo)數(shù),其中第一個函數(shù)eval_numerical_gradient是用來計算簡單函數(shù)的導(dǎo)數(shù),第二個函數(shù)eval_numerical_gradient_array則是用來計算矩陣中對應(yīng)元素的導(dǎo)數(shù)。第一個函數(shù)好理解,現(xiàn)在來看第二個函數(shù),原理一樣,但是會發(fā)現(xiàn)在計算導(dǎo)數(shù)的時候分子多乘了一個df,這個是為什么?

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

下面給出矩陣求導(dǎo)的公式d{x_{ij}}^{ } = \frac{\partial L}{\partial x_{ij}}=\sum_{p}^\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ì)說明矩陣對元素的求導(dǎo)
矩陣中某個元素的梯度,分為兩個方向:x和y,因此矩陣某個元素的梯度也就由兩部分相加而成。

image.png

在這個例子里,上面矩陣導(dǎo)數(shù)的公式可以簡化為:即為該元素在y1和y2方向上的導(dǎo)數(shù)和。

grad[ix] = np.sum((pos - neg) * df) / (2 * h)

在這條執(zhí)行語句中,公式中的{\partial y_{k}}即為元素在x和y方向上所對應(yīng)的行向量和列向量的變化,因為只有一個元素變化了2h,其他元素都沒有變化,所以{\partial y_{k}}=2h,df則為\frac{\partial y_{k}}{\partial x_{ij}}。

個人理解:

矩陣對梯度的求導(dǎo)本質(zhì)上是一個復(fù)合求導(dǎo),即矩陣先對行/列向量求導(dǎo),行/列向量最后再對該元素進(jìn)行求導(dǎo)。

下篇預(yù)告:神經(jīng)網(wǎng)絡(luò)導(dǎo)數(shù)的推導(dǎo)并計算與本篇公式所得到的導(dǎo)數(shù)之間的誤差

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容