編者按:和Daphne Cornelisse一起基于NumPy從頭搭建神經(jīng)網(wǎng)絡(luò),包含分步驟詳細(xì)講解,并在這一過程中介紹神經(jīng)網(wǎng)絡(luò)的基本概念。
本文將介紹創(chuàng)建一個(gè)三層神經(jīng)網(wǎng)絡(luò)所需的步驟。我將在求解問題的過程中,一邊和你解釋這一過程,一邊介紹一些最重要的概念。
需要求解的問題
意大利的一個(gè)農(nóng)夫的標(biāo)簽機(jī)出故障了:將三種不同品種的葡萄酒的標(biāo)簽弄混了?,F(xiàn)在剩下178瓶酒,沒人知道每瓶酒是什么品種!為了幫助這個(gè)可憐人,我們將創(chuàng)建一個(gè)分類器,基于葡萄酒的13個(gè)屬性識(shí)別其品種。
我們的數(shù)據(jù)是有標(biāo)簽的(三種品種之一),這一事實(shí)意味著我們面臨的是一個(gè)監(jiān)督學(xué)習(xí)問題。基本上,我們想要做的是使用我們的輸入數(shù)據(jù)(178瓶未分類的酒),通過神經(jīng)網(wǎng)絡(luò),輸出每瓶酒的正確標(biāo)簽。
我們將訓(xùn)練算法,使其預(yù)測(cè)每瓶酒屬于哪個(gè)標(biāo)簽的能力越來越強(qiáng)。
現(xiàn)在是時(shí)候開始創(chuàng)建神經(jīng)網(wǎng)絡(luò)了!
方法
創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò)類似編寫一個(gè)非常復(fù)雜的函數(shù),或者料理一道非常困難的菜肴。剛開始,你需要考慮的原料和步驟看起來很嚇人。但是,如果你把一切分解開來,一步一步地進(jìn)行,會(huì)很順利。
三層神經(jīng)網(wǎng)絡(luò)概覽
簡(jiǎn)單來說:
輸入層(x)包含178個(gè)神經(jīng)元。
A1,第一層,包含8個(gè)神經(jīng)元。
A2,第二層,包含5個(gè)神經(jīng)元。
A3,第三層,也是輸出層,包含3個(gè)神經(jīng)元。
第一步:預(yù)備
導(dǎo)入所有需要的庫(NumPy、scikit-learn、pandas)和數(shù)據(jù)集,定義x和y.
# 導(dǎo)入庫和數(shù)據(jù)集
import pandas as pd
import numpy as np
df = pd.read_csv('../input/W1data.csv')
df.head()
# Matplotlib是一個(gè)繪圖庫
import matplotlib
import matplotlib.pyplot as plt
# scikit-learn是一個(gè)機(jī)器學(xué)習(xí)工具庫
import sklearn
import sklearn.datasets
import sklearn.linear_model
from sklearn.preprocessing importOneHotEncoder
from sklearn.metrics import accuracy_score
第二步:初始化
在使用權(quán)重之前,我們需要初始化權(quán)重。由于我們目前還沒有用于權(quán)重的值,我們使用0到1之間的隨機(jī)值。
在Python中,random.seed函數(shù)生成“隨機(jī)數(shù)字”。然而,隨機(jī)數(shù)字并不是真隨機(jī)。這些生成的數(shù)字是偽隨機(jī)的,意思是,這些數(shù)字是通過非常復(fù)雜的公式生成的,看起來像是隨機(jī)的。為了生成數(shù)字,公式需要之前生成的值作為輸入。如果之前沒有生成過數(shù)字,公式常常接受時(shí)間作為輸入。
所以這里我們給生成器設(shè)置了一個(gè)種子——確保我們總是得到同樣的隨機(jī)數(shù)字。我們提供了一個(gè)固定值,這里我們選擇了零。
np.random.seed(0)
第三步:前向傳播
訓(xùn)練一個(gè)神經(jīng)網(wǎng)絡(luò)大致可以分為兩部分。首先,前向傳播通過網(wǎng)絡(luò)。也就是說,前向“步進(jìn)”,并比較結(jié)果和真實(shí)值。
使用偽隨機(jī)數(shù)初始化權(quán)重后,我們進(jìn)行一個(gè)線性的前向步驟。我們將輸入A0和隨機(jī)初始化的權(quán)重的點(diǎn)積加上一個(gè)偏置。剛開始,我們的偏置取值為0.
接著我們將z1(線性步驟)傳給第一個(gè)激活函數(shù)。激活函數(shù)是神經(jīng)網(wǎng)絡(luò)中非常重要的部分。通過將線性輸入轉(zhuǎn)換為非線性輸出,激活函數(shù)給我們的函數(shù)引入了非線性,使它得以表示更復(fù)雜的函數(shù)。
有許多不同種類的激活函數(shù)(這篇文章詳細(xì)介紹了它們)。這一模型中,我們?yōu)閮蓚€(gè)隱藏層——A1和A2——選擇了tanh激活函數(shù),該函數(shù)的輸出范圍為-1到1.
由于這是一個(gè)多類分類問題(我們有3個(gè)輸出標(biāo)簽),我們將在輸出層A3使用softmax函數(shù),它將計(jì)算分類的概率,也就是每瓶酒屬于3個(gè)分類的概率,并確保3個(gè)概率之和為1.
讓z1通過激活函數(shù),我們創(chuàng)建了第一個(gè)隱藏層——A1——輸出值可以作為下一個(gè)線性步驟z2的輸入。
在Python中,這一步驟看起來是這樣的:
# 前向傳播函數(shù)
def forward_prop(model,a0):
# 加載模型參數(shù)
W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'], model['W3'],model['b3']
# 第一個(gè)線性步驟
z1 = a0.dot(W1) + b1
# 讓它通過第一個(gè)激活函數(shù)
a1 = np.tanh(z1)
# 第二個(gè)線性步驟
z2 = a1.dot(W2) + b2
# 讓它通過第二個(gè)激活函數(shù)
a2 = np.tanh(z2)
# 第三個(gè)線性步驟
z3 = a2.dot(W3) + b3
# 第三個(gè)激活函數(shù)使用softmax
a3 = softmax(z3)
# 保存所有計(jì)算所得值
cache = {'a0':a0,'z1':z1,'a1':a1,'z2':z2,'a2':a2,'a3':a3,'z3':z3}
return cache
第四步:反向傳播
正向傳播之后,我們反向傳播誤差梯度以更新權(quán)重參數(shù)。
我們通過計(jì)算誤差函數(shù)對(duì)網(wǎng)絡(luò)權(quán)重(W)的導(dǎo)數(shù),也就是梯度下降進(jìn)行反向傳播。
讓我們通過一個(gè)類比可視化這一過程。
想象一下,你在午后到山上徒步。過了一個(gè)小時(shí)后,你有點(diǎn)餓了,是時(shí)候回家了。唯一的問題是天變黑了,山上還有很多樹,你看不到家在何處,也搞不清楚自己在哪里。噢,你還把手機(jī)忘在家里了。
不過,你還記得你的房子在山谷中,整個(gè)區(qū)域的最低點(diǎn)。所以,如果你一步一步地沿著山勢(shì)朝下走,直到你感覺不到任何坡度,理論上你就到家了。
所以你就小心地一步一步朝下走?,F(xiàn)在,將山想象成損失函數(shù),將你想象成試圖找到家(即,最低點(diǎn))的算法。每次你向下走一步,我們更新你的位置坐標(biāo)(算法更新它的參數(shù))。
山表示損失函數(shù)。為了得到較低的損失,算法沿著損失函數(shù)的坡度——也就是導(dǎo)數(shù)——下降。
當(dāng)我們沿著山勢(shì)朝下走的時(shí)候,我們更新位置的坐標(biāo)。算法更新神經(jīng)網(wǎng)絡(luò)的權(quán)重。通過接近最小值,來接近我們的目標(biāo)——最小化誤差。
在現(xiàn)實(shí)中,梯度下降看起來是這樣的:
我們總是從計(jì)算損失函數(shù)的坡度(相對(duì)于線性步驟z)開始。
我們使用如下的記號(hào):dv是損失函數(shù)對(duì)變量v的導(dǎo)數(shù)。
接著我們計(jì)算損失函數(shù)相對(duì)于權(quán)重和偏置的坡度。因?yàn)檫@是一個(gè)3層神經(jīng)網(wǎng)絡(luò),我們將在z3,2,1、W3,2,1、b3,2,1上迭代這一過程。從輸出層反向傳播到輸入層。
在Python中,這一過程是這樣的:
# 這是反向傳播函數(shù)
def backward_prop(model,cache,y):
# 從模型中加載參數(shù)
W1, b1, W2, b2, W3, b3 = model['W1'], model['b1'], model['W2'], model['b2'],model['W3'],model['b3']
# 加載前向傳播結(jié)果
a0,a1, a2,a3 = cache['a0'],cache['a1'],cache['a2'],cache['a3']
# 獲取樣本數(shù)
m = y.shape[0]
# 計(jì)算損失函數(shù)對(duì)輸出的導(dǎo)數(shù)
dz3 = loss_derivative(y=y,y_hat=a3)
# 計(jì)算損失函數(shù)對(duì)第二層權(quán)重的導(dǎo)數(shù)
dW3 = 1/m*(a2.T).dot(dz3)
# 計(jì)算損失函數(shù)對(duì)第二層偏置的導(dǎo)數(shù)
db3 = 1/m*np.sum(dz3, axis=0)
# 計(jì)算損失函數(shù)對(duì)第一層的導(dǎo)數(shù)
dz2 = np.multiply(dz3.dot(W3.T) ,tanh_derivative(a2))
# 計(jì)算損失函數(shù)對(duì)第一層權(quán)重的導(dǎo)數(shù)
dW2 = 1/m*np.dot(a1.T, dz2)
# 計(jì)算損失函數(shù)對(duì)第一層偏置的導(dǎo)數(shù)
db2 = 1/m*np.sum(dz2, axis=0)
dz1 = np.multiply(dz2.dot(W2.T),tanh_derivative(a1))
dW1 = 1/m*np.dot(a0.T,dz1)
db1 = 1/m*np.sum(dz1,axis=0)
# 儲(chǔ)存梯度
grads = {'dW3':dW3, 'db3':db3, 'dW2':dW2,'db2':db2,'dW1':dW1,'db1':db1}
return grads
第五步:訓(xùn)練階段
為了達(dá)到可以給我們想要的輸出(三種葡萄酒品種)的最佳權(quán)重和偏置,我們需要訓(xùn)練我們的神經(jīng)網(wǎng)絡(luò)。
我認(rèn)為這非常符合直覺。生活中幾乎每件事情,你都需要訓(xùn)練和練習(xí)許多次,才可能擅長做這件事。類似地,神經(jīng)網(wǎng)絡(luò)需要經(jīng)歷許多個(gè)epoch或迭代,才可能給出精確的預(yù)測(cè)。
當(dāng)你學(xué)習(xí)任何事情時(shí),比如閱讀一本書,你都有一個(gè)特定的節(jié)奏。節(jié)奏不應(yīng)該太慢,否則要花好些年才能讀完一本書。但節(jié)奏也不能太快,否則你可能會(huì)錯(cuò)過書中非常重要的內(nèi)容。
同理,你需要為模型指定一個(gè)“學(xué)習(xí)率”。學(xué)習(xí)率是更新參數(shù)時(shí)乘上的系數(shù)。它決定參數(shù)的變動(dòng)有多快。如果學(xué)習(xí)率很低,訓(xùn)練將花更多時(shí)間。然而,如果學(xué)習(xí)率太高,我們可能錯(cuò)過極小值。
:=意味著這是一個(gè)定義,不是一個(gè)等式,或證明的結(jié)論。
a是學(xué)習(xí)率(稱為alpha)。
dL(w)是總損失對(duì)權(quán)重w的導(dǎo)數(shù)。
da是alpha的導(dǎo)數(shù)。
我們?cè)谝恍┰囼?yàn)之后將學(xué)習(xí)率定為0.07.
# 這是我們最后返回的東西
model = initialise_parameters(nn_input_dim=13, nn_hdim= 5, nn_output_dim= 3)
model = train(model,X,y,learning_rate=0.07,epochs=4500,print_loss=True)
plt.plot(losses)
最后,這是我們的圖像。你可以繪制精確度和/或損失以得到預(yù)測(cè)表現(xiàn)的圖像。4500個(gè)epoch之后,我們的算法達(dá)到了99.4382022472 %的精確度。
簡(jiǎn)短總結(jié)
我們從將數(shù)據(jù)傳入神經(jīng)網(wǎng)絡(luò)開始,并對(duì)輸入數(shù)據(jù)逐層進(jìn)行一些矩陣操作。在三個(gè)網(wǎng)絡(luò)層的每一層上,我們將輸入和權(quán)重的點(diǎn)積加上偏置,接著將輸出傳給選擇的激活函數(shù)。
激活函數(shù)的輸出接著作為下一層的輸入,并重復(fù)前面的過程。這一過程迭代三次,因?yàn)槲覀冇腥齻€(gè)網(wǎng)絡(luò)層。我們的最終輸出是哪瓶酒屬于哪個(gè)品種的預(yù)測(cè),這是前向傳播過程的終點(diǎn)。
我們接著計(jì)算預(yù)測(cè)和期望輸出之間的差距,并在反向傳播過程中使用這一誤差值。
在反向傳播過程中,我們將誤差通過某種數(shù)學(xué)方式在網(wǎng)絡(luò)上進(jìn)行反方向傳播。我們從錯(cuò)誤中學(xué)習(xí)。
通過計(jì)算我們?cè)谇跋騻鞑ミ^程中使用的函數(shù)的導(dǎo)數(shù),我們?cè)噲D發(fā)現(xiàn)我們應(yīng)該給權(quán)重什么值,以做出盡可能好的預(yù)測(cè)?;旧?,我們想要知道權(quán)重值和我們所得結(jié)果的誤差之間的關(guān)系。
在許多個(gè)epoch或迭代之后,神經(jīng)網(wǎng)絡(luò)的參數(shù)逐漸適配我們的數(shù)據(jù)集,學(xué)習(xí)給出更精確的預(yù)測(cè)。
本文基于Bletchley Machine Learning訓(xùn)練營第一周的挑戰(zhàn)。在這一訓(xùn)練營中,我們每周討論一個(gè)不同的主題,并完成一項(xiàng)挑戰(zhàn)(需要真正理解討論的材料才能做到)。
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4814瀏覽量
103724 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4381瀏覽量
64947 -
網(wǎng)絡(luò)層
+關(guān)注
關(guān)注
0文章
40瀏覽量
10696
原文標(biāo)題:從頭開始搭建三層神經(jīng)網(wǎng)絡(luò)
文章出處:【微信號(hào):jqr_AI,微信公眾號(hào):論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
labview BP神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn)
【PYNQ-Z2試用體驗(yàn)】神經(jīng)網(wǎng)絡(luò)基礎(chǔ)知識(shí)
【PYNQ-Z2試用體驗(yàn)】基于PYNQ-Z2的神經(jīng)網(wǎng)絡(luò)圖形識(shí)別[結(jié)項(xiàng)]
使用keras搭建神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)基于深度學(xué)習(xí)算法的股票價(jià)格預(yù)測(cè)
基于Numpy實(shí)現(xiàn)同態(tài)加密神經(jīng)網(wǎng)絡(luò)

基于Numpy實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò):反向傳播

如何使用numpy搭建一個(gè)卷積神經(jīng)網(wǎng)絡(luò)詳細(xì)方法和程序概述
如何使用Numpy搭建神經(jīng)網(wǎng)絡(luò)

用Python從頭實(shí)現(xiàn)一個(gè)神經(jīng)網(wǎng)絡(luò)來理解神經(jīng)網(wǎng)絡(luò)的原理1

用Python從頭實(shí)現(xiàn)一個(gè)神經(jīng)網(wǎng)絡(luò)來理解神經(jīng)網(wǎng)絡(luò)的原理2

用Python從頭實(shí)現(xiàn)一個(gè)神經(jīng)網(wǎng)絡(luò)來理解神經(jīng)網(wǎng)絡(luò)的原理3

用Python從頭實(shí)現(xiàn)一個(gè)神經(jīng)網(wǎng)絡(luò)來理解神經(jīng)網(wǎng)絡(luò)的原理4

評(píng)論