深度学习笔记:利用numpy从零搭建一个神经网络
很多人說深度學習就是個黑箱子,把圖像預處理之后丟進 tensorflow 就能出來預測結果,簡單有效又省時省力。但正如我在上一篇推送中所說,如果你已是一名功力純厚的深度學習工程師,這么做當然沒問題。但我想大多數人也和我一樣,都是走在學習深度學習的路上,一上來就上框架并沒有什么特別不妥之處,但總歸是對你理解深度學習的黑箱機制是了無裨益的。所以,我建議在學習深度學習的路上,從最簡單的感知機開始寫起,一步一步捋清神經網絡的結構,以至于激活函數怎么寫、采用何種損失函數、前向傳播怎么寫、后向傳播又怎么寫,權值如何迭代更新,都需要你自己去實現。若在一開始就直接調用框架,小的 demo 可以跑起來,糊弄一時,看起來就像是鳩摩智在內力未到的情形下強行練習少林寺的 72 絕技,最后走火入魔。
無論你是在看那本深度學習的花書,還是在學習 Adrew NG 的 deeplearningai,或者是在cs231n 課程,對神經網絡的基本理論了如指掌的你一定想親手用 python 來實現它。筆記1就在不借助任何深度學習框架的基礎上,利用 python 的科學計算庫 numpy 由最初級的感知機開始,從零搭建一個神經網絡模型。
感知機結構
對于感知機模型、神經網絡理論這里就不再敘述,相信志在精通深度學習的你對此一定很熟練了。至于對于神經網絡中的輸入層、隱藏層、輸出層、權重與偏置、激活函數、損失函數、前向傳播、反向傳播、權值更新、梯度下降、微積分中的鏈式求導、方向梯度等概念,我也假設你很熟練了。所以,接下來就讓我們從零搭建一個最初級的神經網絡模型。
在寫代碼前,必須先捋一下思路,咱們先要什么,然后再寫什么,你心中必須有個數。要從零開始寫一個神經網絡,通常的方法是:
- 定義網絡結構(指定輸出層、隱藏層、輸出層的大小)
- 初始化模型參數
- 循環操作:執行前向傳播/計算損失/執行后向傳播/權值更新
有了上面這個思路,我們就可以開始寫了。當然了,本節是寫一個最簡單的感知機模型,所以網絡結構就無需特別定義。首先來定義我們的激活函數,激活函數有很多種,這里我們使用大名鼎鼎的 sigmoid 函數:
直接利用 numpy 進行定義 sigmoid()
import numpy as np def sigmoid(x):return 1 / (1 + np.exp(-x))在無需定義網絡結構的情形下,第二步我們就可以直接對模型參數進行初始化。模型參數主要包括權值w 和偏置 b ,這也是神經網絡學習過程要學的東西。繼續利用 numpy 對參數進行初始化:
def initilize_with_zeros(dim):w = np.zeros((dim, 1))b = 0.0#assert(w.shape == (dim, 1))#assert(isinstance(b, float) or isinstance(b, int))return w, b接下來就要進入模型的主體部分,執行最后一步那個大的循環操作,這個循環中包括前向傳播和計算損失、反向傳播和權值更新。這也是神經網絡訓練過程中每一次需要迭代的部分。這里簡單說一下,很多初學者容易被這兩個概念繞住,前向傳播簡單而言就是計算預測 y 的過程,而后向傳播則是根據預測值和實際值之間的誤差不斷往回推更新權值和偏置的過程。
前后傳播與后向傳播
下面我們來定義一個大的前向傳播函數,預測值y為模型從輸入到經過激活函數處理后的輸出的結果。損失函數我們采用交叉熵損失,利用 numpy 定義如下函數:
def propagate(w, b, X, Y):m = X.shape[1]A = sigmoid(np.dot(w.T, X) + b)cost = -1/m * np.sum(Y*np.log(A) + (1-Y)*np.log(1-A))dw = np.dot(X, (A-Y).T)/mdb = np.sum(A-Y)/m assert(dw.shape == w.shape) assert(db.dtype == float)cost = np.squeeze(cost) assert(cost.shape == ())grads = { 'dw': dw, 'db': db} return grads, cost在上面的前向傳播函數中,我們先是通過激活函數直接表示了感知機輸出的預測值,然后通過定義的交叉熵損失函數計算了損失,最后根據損失函數計算了權值 w 和偏置 b的梯度,將參數梯度結果以字典和損失一起作為函數的輸出進行返回。這就是前向傳播的編寫思路。
接下來循環操作的第二步就是進行反向傳播操作,計算每一步的當前損失根據損失對權值進行更新。同樣定義一個函數 backward_propagation :
def backward_propagation(w, b, X, Y, num_iterations, learning_rate, print_cost=False):cost = [] for i in range(num_iterations):grad, cost = propagate(w, b, X, Y)dw = grad['dw']db = grad['db']w = w - learing_rate * dwb = b - learning_rate * db if i % 100 == 0:cost.append(cost) if print_cost and i % 100 == 0:print("cost after iteration %i: %f" %(i, cost))params = {"dw": w,"db": b}grads = {"dw": dw,"db": db} return params, grads, costs在上述函數中,我們先是建立了一個損失列表容器,然后將前一步定義的前向傳播函數放進去執行迭代操作,計算每一步的當前損失和梯度,利用梯度下降法對權值進行更新,并用字典封裝迭代結束時的參數和梯度進行返回。
如上所示,一個簡單的神經網絡模型(感知機)就搭建起來了。通常模型建好之后我們還需要對測試數據進行預測,所以我們也定義一個預測函數 predict,將模型的概率輸出轉化為0/1值。
def predict(w, b, X):m = X.shape[1]Y_prediction = np.zeros((1, m))w = w.reshape(X.shape[0], 1)A = sigmoid(np.dot(w.T, X)+b) for i in range(A.shape[1]): if A[:, i] > 0.5:Y_prediction[:, i] = 1else:Y_prediction[:, i] = 0assert(Y_prediction.shape == (1, m)) return Y_prediction到這里整個模型算是寫完了,但是我們定義了這么多函數,調用起來太麻煩,所以致力于要寫出 pythonic的代碼的你們肯定想對這些函數進行一下簡單的封裝:
def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.5, print_cost = False):# initialize parameters with zeros (≈ 1 line of code)w, b = initialize_with_zeros(X_train.shape[0]) # Gradient descent (≈ 1 line of code)parameters, grads, costs = backwize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost) # Retrieve parameters w and b from dictionary "parameters"w = parameters["w"]b = parameters["b"] # Predict test/train set examples (≈ 2 lines of code)Y_prediction_train = predict(w, b, X_train)Y_prediction_test = predict(w, b, X_test) # Print train/test Errorsprint("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))print("test accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100))d = {"costs": costs, "Y_prediction_test": Y_prediction_test, "Y_prediction_train" : Y_prediction_train, "w" : w, "b" : b, "learning_rate" : learning_rate,"num_iterations": num_iterations} return d如此這般一個簡易的神經網絡就被你用 numpy就寫出來了。現在社會浮躁,很多人學習都沒有耐心,總是抱著鳩摩智的心態想要一步登天。學習機器學習和深度學習方法很多,但我相信,只有對基本的算法原理每一步都捋清楚,每一步都用最基礎的庫去實現,你成為一名優秀的機器學習工程師只是時間問題。深度學習第一次推送筆記,加油吧各位!
參考資料:
https://www.coursera.org/learn/machine-learning
https://www.deeplearning.ai/
總結
以上是生活随笔為你收集整理的深度学习笔记:利用numpy从零搭建一个神经网络的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习表征的不合理有效性——从头开始构
- 下一篇: Java并发编程:volatile的使用