大家好,我是林季劼
今天我要來分享如何使用python 實作 神經網路的dense layer
一般神經網路會有
- forward: 前饋階段,將資料都進這層網路,輸出新的資料
- backward: 倒傳遞階段,將從後面的網路傳回來的gradients做運算,算出這層網路權重的gradients,藉此更新權重
所以我的文章會以下的順序介紹,有需要的人就可以直接跳到想要的部分囉
那我們就開始囉!
首先我們先來看一張很常見的圖
在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的部分了!!
在上面講解公式的部分已經講解的很清晰了,我們就先直接看code吧!!
可以看到我們的code就是非常的簡潔!
- 也只有簡單的import numpy 而已喔
- 在一開始,就把W和B 根據要求的輸入大小n_inputs 和多少個感知機n_units 初始化
- 通過上面的運算 Y = X * W + B的運算
- 就完成dense layer啦!!
- 注意到我們這邊有寫
- self.last_inputs = inputs
- 把輸入記住,原因是在backward的時候會再用到這個input喔!
- 不要忘了這步
- 那我們就來看神經網路最重要的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/dW = X^T * (dE/dY)
- 再來我們看 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 / db2 = (dE/dy1) * (dy1/db2) + (dE/dy2) * (dy2/db2) + .... + (dE/dyj) * (dyj/db2)
- 通過上面的推倒算出了
- 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
- 我們要算出 dE/dX 回傳給這層的前一層
- 接下來就是實作的部分囉
- dE / dw23好了
我們就不多說直接先看code吧!
可以看到也只有幾行就完成啦!
- 其中我們回顧上面我們推導的公式
- 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
- 將網路的一層一層結構安排好
- 最後可以一次訓練整個神經網路這樣!
- 如果要自己實作跟設計,可以多看上面的部份挑戰完成像是
- 然後如果我哪邊有錯誤也可以跟我說喔,那就加油囉
文章標籤
全站熱搜