大家好,我是林季劼

今天我要來分享如何使用python 實作 神經網路的dense layer

一般神經網路會有

  1. forward: 前饋階段,將資料都進這層網路,輸出新的資料
  2. backward: 倒傳遞階段,將從後面的網路傳回來的gradients做運算,算出這層網路權重的gradients,藉此更新權重

 

所以我的文章會以下的順序介紹,有需要的人就可以直接跳到想要的部分囉

  1. forward的講解
  2. forward的實作
  3. backward的講解
  4. backward的實作

那我們就開始囉!

Forward的講解

首先我們先來看一張很常見的圖

DenseLayer示意圖

在dense layer輸入的部分,要求的輸入是一個

  • 向量X = [x1, x2, x3]
  • 經過紅色多個感知機之後輸出
  • 向量Y = [y1, y2, y3, y4, y5]
  • 也就是這層有5個感知機,就會輸出5維的向量
  • 然後就傳給下一層做其他運算了

那最重要的就是了解 Y 中的每一個  yj 怎麼算出來的,可以看到圖片上

  • 每個xi 都用一個顏色的線連接到"所有的感知機"
  • 每一條線都代表一個wij
    • wij 代表xi的對應上輸出 yj 的感知機,一個權重值wij
  • 所以表示這層會有 i x j 個 w 值 (之後就可以用矩陣紀錄,所以 i x j 要記住喔)
  • 而輸出 yj 的感知機通過運算:  yj = w1j * x1 + w2j * x2 + ... + wij * xi + bj
    • 注意到每一個感知機 yj 都會加上一個 bj 喔
  • 其實就是一個線性組合而已(所以通常下一層會是activation激活函數,將線性的特性轉換成非線性)

​​​​​​​了解上面的算法後就會發現,我們可以設計簡單的運算式子,表示dense layer

  • 為了方便計算,以及實作,這邊的X,Y,B向量都是row vector
    • 也就是X看成是 1 x i 的矩陣,Y: 1 x j, B: 1 x j
    • 而W則是 i x j 的矩陣
  • Y = X * W + B
  • 會發現從輸入到輸出
    • ​​​​​​​1 x i 變 1 x j
    • 還是一樣的row vector,這就是多層可以不斷傳下去的地方喔
    • 可以再丟給下一層
    • 使得 1 x j 變 1 x k
    • 很方便吧! 
    • 甚至可以處理多筆輸出,假設有n筆輸入
    • 輸入X = n x i
    • 輸出Y = n x j
    • 又下一層 Z = n x k
    • 這就是一次處理一批次資料的小技巧喔!
  • ​​​​​​​那我們了解了上面,就可以開始時做Forward的部分了!!

 

 


 

​​​​​​​Forward的實作

在上面講解公式的部分已經講解的很清晰了,我們就先直接看code吧!!

image

可以看到我們的code就是非常的簡潔!

  • 也只有簡單的import numpy 而已喔
  • 在一開始,就把W和B 根據要求的輸入大小n_inputs 和多少個感知機n_units 初始化
  • 通過上面的運算 Y = X * W + B的運算
  • 就完成dense layer啦!!
  • 注意到我們這邊有寫
    • self.last_inputs = inputs
    • 把輸入記住,原因是在backward的時候會再用到這個input喔!
    • 不要忘了這步
  • 那我們就來看神經網路最重要的Backward的部分啦

 


Backward的講解

那我們就來看神經網路最重要的Backward的部分啦

  • 在神經網路中backward想要
    • 透過地就是網路輸出的Y和答案target T
    • 通過一個差距函數E = f(Y, T) 算出最終離答案的差距
    • 透過這個差距更新我們的網路權重 W和B!
    • 所以我們的目標是要算出
      • 所有的 dE / dWij
      • 所有的 dE / dBj
        • 把這個E當作函數g(w, b)的輸出
        • E通過"當前的"W和B
          • E= g(w11, w12, ...., b1, b2....)
          • 把當前的E當成目前W和B組成的空間地某個函數值
          • 我們目標就是找出這個空間中可以使得E往下走的所有wij和bj的梯度
  • 所以我們要先定義一些東西喔
    • dE / dY = [dE/dy1, dE/dy2, ..., dE/dyj] , 大小為( 1 x j )的矩陣
    • dE / dX = [dE/dx1, dE/dx2, ..., dE/dxi] , 大小為( 1 x i )的矩陣
    • dE / dW = [dE/dwij], 大小為( i x j )的矩陣
    • dE / dB = [dE/db1, dE/db2, ..., dE/dbj] , 大小為( 1 x j )的矩陣
  • 再來我們目前會用到一些偏微分的概念喔
    • 想要了解更仔細可以先去複習一下再回來
    • 主要我們會用簡單的一個概念而已
  • 我們先來看
    • dE / dw23好了
      • 複習一下w23是對應到 x2 及 y3的 w
    • 通過偏微分的概念我們可以知道
    • dE / dw23 = (dE/dy1) * (dy1/dw23) + (dE/dy2) * (dy2/dw23) + .... + (dE/dyj) * (dyj/dw23)
      • E原本由多少個 yj 組成就要加幾項 (dE/dyj) * (dyj/dw23)
      • 我們會發現 dE/dyj 很好算,就是 將原本的 E = f(Y, T)函數對 yj 做微分而已
        • 例如 least squared error = f(Y, T) = [(y1-t1)^2/2,  (y2-t2)^2/2, ..., (yj-tj)^2/2]
        • 對每一個yj做微分就是 dE/dY = [y1-t1, y2-t2, ... , yj - tj]
        • 而在倒傳遞演算法(backward)的精隨就在於 dE/dY是這層網路的"下一層"傳回來的
          • 這層的輸出Y,則是下一層的輸入X
          • 我們由下一層傳回來的是其實是他的dE/dX
          • 來到了這層就是我們需要的dE / dY
            • 所以我們這層只要了解我們從下一層得到了 dE / dY
            • 我們透過 dE / dY 要算出dE / dW,dE/dB,dE / dX
            • 透過dE / dW,dE/dB 更新權重
            • 將dE / dX給上一層即可
            • 我們在這層不需要知道dE / dY是如何求得的喔!!!!
      • 回過頭來看dE / dw23
        • 仔細回想一下w23只有出現在 y3 的公式裡面
        • 所以其實,所有的dyj / dw23 = 0,只要j !=3
        • 所以 dE / dw23 = (dE/dy3) * (dy3/dw23)
        • 那 dy3/dw23是什麼呢
          • y3 = w13*x1 + w23*x2 + ... + wi3*xi + b3
          • dy3/dw23 = x2
          • 這就是為甚麼我們要把inputs記下來的原因
          • 因為我們還會用到X
        • 所以最後我們的 dE / dw23 = (dE/dy3) * x2
        • 仔細對應數字就會發現 dE / dwij = (dE/dyj) * xi
        • 那我們就發現它可以是一個矩陣
        • 仔細想會發現它等於
          • dE/dW = X^T * (dE/dY)
            • X^T 是 i x 1 的矩陣 ( X的轉置矩陣 )
            • (dE/dY) 是 1 x j 的矩陣
            • 相乘 剛好就等於 i x j 的矩陣!
            • 很方便吧!
    • 再來我們看 dE / db2
      • 一樣dE / db2 = (dE/dy1) * (dy1/db2) + (dE/dy2) * (dy2/db2) + .... + (dE/dyj) * (dyj/db2)
        • 一樣 b2只有出現在 y2的公式
        • 所以 所有的dyj / db2 = 0,只要j !=2
        • dE / db2 = (dE/dy2) * (dy2/db2)
          • 而 y2 = w12*x1 + w22*x2 + ... + wi2*xi + b2
          • 表示 (dy2/db2) = 1
          • 所以 dE / db2 = dE/dy2
          • 最後就算出dE/dB = dE/dY 這個結論!!
    • 通過上面的推倒算出了
      • dE/dW,dE/dB
      • 我們就可以透過
        • W -= learning_rate * dE/dW
        • B -= learning_rate * dE/dB
        • 算出新的W,B啦
        • 這個新的W和B就是跟舊的W,B相比最後求得E比較小的新的值喔!
    • 最後一步就是backward(倒傳遞演算法)的精隨了
      • 我們要算出 dE/dX 回傳給這層的前一層
        • 讓前一層得到dE/dY,又可以更新前一層的權重啦!
      • 一樣我們先來看 dE/dx2
        • 再用上面同樣的方法展開
      • dE / dx2 = (dE/dy1) * (dy1/dx2) + (dE/dy2) * (dy2/dx2) + .... + (dE/dyj) * (dyj/dx2)
      • 一樣是E吃進去幾個yj就又幾個  (dE/dyj) * (dyj/dx2)
      • 仔細想原本的yj的公式
        • 我們的x2,他跟所有的yj都有關係所以這次不能為0了
        • yj = w1j*x1 + w2j*x2 + ... + wij*xi + bj
        • 我們會發現 dyj/dx2 = w2j
        • 所以 dE / dx2  = (dE/dy1) * w21 + (dE/dy2) * w22 + .... + (dE/dyj) * w2j
        • 然後仔細想想這個關係
          • 其實又可以是矩陣乘法!!
          • 我們可以算出 dE/dX = (dE/dY) * W^T
          • 記憶的方式很簡單
            • (dE/dY) 是 1 x j 的矩陣
            • W 是 i x j 的矩陣
            • 而我們要算的 dE/dX 是 1 x i 的矩陣
              • 心機一點 把數字對應一下 1 x j * j x i 變成 1 x i
              • 所以我們才使用W^T的啦!!
        • 如此一來,我們就可以把dE/dX往前一層傳,這層dense layer就大功告成了
      • 還不清楚地就可以回去多看幾次
        • 看如何求出 dE/W,dE/B,dE/X
    • 接下來就是實作的部分囉

 

 


 

Backward實作

我們就不多說直接先看code吧!

image

可以看到也只有幾行就完成啦!

  • 其中我們回顧上面我們推導的公式
    • dE/dW = X^T * dE/dY
    • dE/dB = dE/dY
      • b_grads這邊之所以有sum是因為我預計不只1筆輸入,而是n筆可以批次輸入喔!
    • dE/dX = (dE/dY) * W^T
  • 寫到這邊我們就完成dense layer了啦!
  • 但是在整個神經網路中是有很多層的包括activation,error
  • 我打算陸續慢慢出囉,但是上面也把神經網路的精隨部分都講了
    • 如果要自己實作跟設計,可以多看上面的部份挑戰完成像是
      • tensorflow Sequential或是pytorch Sequential的class
      • 將網路的一層一層結構安排好
      • 最後可以一次訓練整個神經網路這樣!
  • 然後如果我哪邊有錯誤也可以跟我說喔,那就加油囉
arrow
arrow
    創作者介紹
    創作者 林季劼JIJIELIN 的頭像
    林季劼JIJIELIN

    季劼在這邊 JIJIE Here

    林季劼JIJIELIN 發表在 痞客邦 留言(0) 人氣()