【机器学习基础】数学推导+纯Python实现机器学习算法7:神经网络
Python機器學(xué)習(xí)算法實現(xiàn)
Author:louwill
? ? ?
???? 上一節(jié)中筆者和大家了解了感知機的基本原理及其Python實現(xiàn)。本節(jié)筆者將在感知機的基礎(chǔ)上繼續(xù)介紹神經(jīng)網(wǎng)絡(luò)模型。從上一講我們知道,感知機是一種線性模型,對于非線性問題很難給出解決方案。
???? 比如咱們熟知的這種異或問題(XOR),就是一種典型的線性不可分問題,普通的感知機很難處理:
(來自周志華 機器學(xué)習(xí))
???? 因此,在普通的感知機基礎(chǔ)上,我們對感知機結(jié)構(gòu)進(jìn)行了延申,通過添加隱藏層的方式來使得感知機能夠擬合非線性問題。這種包含隱藏層結(jié)構(gòu)的感知機模型就是神經(jīng)網(wǎng)絡(luò),也叫多層感知機(Multilayer Perceptron)。
???? 關(guān)于神經(jīng)網(wǎng)絡(luò)的眾多概念和知識:包括輸入層、隱藏層、輸出層、激活函數(shù)、前向傳播、反向傳播、梯度下降、權(quán)值更新等概念筆者不再贅述。在筆者的另一個系列推文——深度學(xué)習(xí)60講中有詳細(xì)介紹:深度學(xué)習(xí)第60講:深度學(xué)習(xí)筆記系列總結(jié)與感悟。
生成數(shù)據(jù)
???? 本節(jié)筆者以一個兩層網(wǎng)絡(luò),即單隱層網(wǎng)絡(luò)為例,來看看如何利用numpy實現(xiàn)一個神經(jīng)網(wǎng)絡(luò)模型。正式搭建神經(jīng)網(wǎng)絡(luò)之前我們先來準(zhǔn)備一下數(shù)據(jù)。定義一個數(shù)據(jù)生成函數(shù):
def?create_dataset():np.random.seed(1)m = 400 # 數(shù)據(jù)量N = int(m/2) # 每個標(biāo)簽的實例數(shù)D = 2 # 數(shù)據(jù)維度X = np.zeros((m,D)) # 數(shù)據(jù)矩陣Y = np.zeros((m,1), dtype='uint8') # 標(biāo)簽維度a?=?4?for j in range(2):ix = range(N*j,N*(j+1))t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # thetar = a*np.sin(4*t) + np.random.randn(N)*0.2 # radiusX[ix] = np.c_[r*np.sin(t), r*np.cos(t)]Y[ix] = jX = X.TY = Y.Treturn X, Y???? 數(shù)據(jù)可視化展示如下:
???? 繼續(xù)回顧一下搭建一個神經(jīng)網(wǎng)絡(luò)的基本思路和步驟:
定義網(wǎng)絡(luò)結(jié)構(gòu)(指定輸出層、隱藏層、輸出層的大小)
初始化模型參數(shù)
循環(huán)操作:執(zhí)行前向傳播/計算損失/執(zhí)行后向傳播/權(quán)值更新
定義網(wǎng)絡(luò)結(jié)構(gòu)
???? 假設(shè)X為神經(jīng)網(wǎng)絡(luò)的輸入特征矩陣,y為標(biāo)簽向量。則含單隱層的神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)如下所示:
????網(wǎng)絡(luò)結(jié)構(gòu)的函數(shù)定義如下:
????其中輸入層和輸出層的大小分別與X和 y的shape有關(guān)。而隱層的大小可由我們手動指定。這里我們指定隱層的大小為4。
初始化模型參數(shù)
????假設(shè)W1為輸入層到隱層的權(quán)重數(shù)組、b1為輸入層到隱層的偏置數(shù)組;W2為隱層到輸出層的權(quán)重數(shù)組,b2為隱層到輸出層的偏置數(shù)組。于是我們定義參數(shù)初始化函數(shù)如下:
def initialize_parameters(n_x, n_h, n_y):W1 = np.random.randn(n_h, n_x)*0.01b1 = np.zeros((n_h, 1))W2 = np.random.randn(n_y, n_h)*0.01b2 = np.zeros((n_y, 1)) assert (W1.shape == (n_h, n_x)) assert (b1.shape == (n_h, 1)) assert (W2.shape == (n_y, n_h)) assert (b2.shape == (n_y, 1))parameters = {"W1": W1, "b1": b1, "W2": W2, "b2": b2} return parameters????其中對權(quán)值的初始化我們利用了numpy中的生成隨機數(shù)的模塊np.random.randn,偏置的初始化則使用了 np.zeros模塊。通過設(shè)置一個字典進(jìn)行封裝并返回包含初始化參數(shù)之后的結(jié)果。
前向傳播
????在定義好網(wǎng)絡(luò)結(jié)構(gòu)并初始化參數(shù)完成之后,就要開始執(zhí)行神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程了。而訓(xùn)練的第一步則是執(zhí)行前向傳播計算。假設(shè)隱層的激活函數(shù)為tanh函數(shù), 輸出層的激活函數(shù)為sigmoid函數(shù)。則前向傳播計算表示為:
????定義前向傳播計算函數(shù)為:
def forward_propagation(X, parameters):# 獲取各參數(shù)初始值W1 = parameters['W1']b1 = parameters['b1']W2 = parameters['W2']b2 = parameters['b2'] # 執(zhí)行前向計算Z1 = np.dot(W1, X) + b1A1 = np.tanh(Z1)Z2 = np.dot(W2, A1) + b2A2 = sigmoid(Z2) assert(A2.shape == (1, X.shape[1]))cache = {"Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2} return A2, cache???? 從參數(shù)初始化結(jié)果字典里取到各自的參數(shù),然后執(zhí)行一次前向傳播計算,將前向傳播計算的結(jié)果保存到cache這個字典中, 其中A2為經(jīng)過sigmoid激活函數(shù)激活后的輸出層的結(jié)果。
計算當(dāng)前訓(xùn)練損失
???? 前向傳播計算完成后我們需要確定以當(dāng)前參數(shù)執(zhí)行計算后的的輸出與標(biāo)簽值之間的損失大小。與筆記1一樣,損失函數(shù)同樣選擇為交叉熵?fù)p失:
? ? ?定義計算損失函數(shù)為:
執(zhí)行反向傳播
???? 當(dāng)前向傳播和當(dāng)前損失確定之后,就需要繼續(xù)執(zhí)行反向傳播過程來調(diào)整權(quán)值了。中間涉及到各個參數(shù)的梯度計算,具體如下圖所示:
????根據(jù)上述梯度計算公式定義反向傳播函數(shù):
???? 將各參數(shù)的求導(dǎo)計算結(jié)果放入字典grad進(jìn)行返回。
???? 這里需要提一下的是涉及到的關(guān)于數(shù)值優(yōu)化方面的知識。在機器學(xué)習(xí)中,當(dāng)所學(xué)問題有了具體的形式之后,機器學(xué)習(xí)就會形式化為一個求優(yōu)化的問題。不論是梯度下降法、隨機梯度下降、牛頓法、擬牛頓法,抑或是 Adam 之類的高級的優(yōu)化算法,這些都需要花時間掌握去掌握其數(shù)學(xué)原理。
權(quán)值更新
???? 迭代計算的最后一步就是根據(jù)反向傳播的結(jié)果來更新權(quán)值了,更新公式如下:
???? 由該公式可以定義權(quán)值更新函數(shù)為:
???? 這樣,前向傳播-計算損失-反向傳播-權(quán)值更新的神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程就算部署完成了。當(dāng)前了,跟之前幾講一樣,為了更加pythonic一點,我們也將各個模塊組合起來,定義一個神經(jīng)網(wǎng)絡(luò)模型:
def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):np.random.seed(3)n_x = layer_sizes(X, Y)[0]n_y = layer_sizes(X, Y)[2] # 初始化模型參數(shù)parameters = initialize_parameters(n_x, n_h, n_y)W1 = parameters['W1']b1 = parameters['b1']W2 = parameters['W2']b2 = parameters['b2'] # 梯度下降和參數(shù)更新循環(huán)for i in range(0, num_iterations): # 前向傳播計算A2, cache = forward_propagation(X, parameters) # 計算當(dāng)前損失cost = compute_cost(A2, Y, parameters) # 反向傳播grads = backward_propagation(parameters, cache, X, Y) # 參數(shù)更新parameters = update_parameters(parameters, grads, learning_rate=1.2) # 打印損失if print_cost and i % 1000 == 0: print ("Cost after iteration %i: %f" %(i, cost)) return parameters???? 模型主體完成之后也可以再定義一個基于訓(xùn)練結(jié)果的預(yù)測函數(shù):
def?predict(parameters,?X):?A2, cache = forward_propagation(X, parameters)predictions?=?(A2>0.5)return predictions?????
???? 下面我們便基于之前生成的數(shù)據(jù)來測試一下模型:
???? 經(jīng)過9000次迭代后損失下降到了0.21。我們再來看一下測試預(yù)測準(zhǔn)確率:
???? 測試準(zhǔn)確率達(dá)到0.9。
???? 繪制神經(jīng)網(wǎng)絡(luò)的決策邊界效果如下:
???? 以上便是本節(jié)的主要內(nèi)容,利用numpy手動搭建一個單隱層的神經(jīng)網(wǎng)路。本例來自于Andrew NG deeplearningai深度學(xué)習(xí)系列課程第一門課的assignment3,感興趣的朋友可查找相關(guān)資料進(jìn)行學(xué)習(xí)。完整代碼文件和數(shù)據(jù)可參考我的GitHub地址:
https://github.com/luwill/machine-learning-code-writing
參考資料:
https://www.deeplearning.ai/
往期精彩:
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法6:感知機
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法5:決策樹之CART算法
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法4:決策樹之ID3算法
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法3:k近鄰
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法2:邏輯回歸
數(shù)學(xué)推導(dǎo)+純Python實現(xiàn)機器學(xué)習(xí)算法1:線性回歸
往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載機器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機器學(xué)習(xí)在線手冊深度學(xué)習(xí)筆記專輯《統(tǒng)計學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載機器學(xué)習(xí)的數(shù)學(xué)基礎(chǔ)專輯獲取一折本站知識星球優(yōu)惠券,復(fù)制鏈接直接打開:https://t.zsxq.com/yFQV7am本站qq群1003271085。加入微信群請掃碼進(jìn)群:
總結(jié)
以上是生活随笔為你收集整理的【机器学习基础】数学推导+纯Python实现机器学习算法7:神经网络的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 【机器学习基础】数学推导+纯Python
 - 下一篇: 【机器学习基础】数学推导+纯Python