為何從零開始?
有許多深度學(xué)習(xí)庫(Keras、TensorFlow和PyTorch等)可僅用幾行代碼構(gòu)建一個神經(jīng)網(wǎng)絡(luò)。然而,如果你真想了解神經(jīng)網(wǎng)絡(luò)的底層運(yùn)作,建議學(xué)習(xí)如何使用Python或任何其他編程語言從零開始為神經(jīng)網(wǎng)絡(luò)編程。
不妨創(chuàng)建某個隨機(jī)數(shù)據(jù)集:
圖1. 為簡單起見,隨機(jī)數(shù)據(jù)集帶二進(jìn)制值
上面表格有五列:Person、X1、X2、X3和Y。1表示true,0表示false。我們的任務(wù)是創(chuàng)建一個能夠基于X1、X2和X3的值來預(yù)測Y值的人工神經(jīng)網(wǎng)絡(luò)。
我們將創(chuàng)建一個有1個輸入層、1個輸出層而沒有隱藏層的人工神經(jīng)網(wǎng)絡(luò)。開始編程前,先不妨看看我們的神經(jīng)網(wǎng)絡(luò)在理論上將如何執(zhí)行:
ANN理論
人工神經(jīng)網(wǎng)絡(luò)是一種監(jiān)督式學(xué)習(xí)算法,這意味著我們?yōu)樗峁┖凶宰兞康妮斎霐?shù)據(jù)和含有因變量的輸出數(shù)據(jù)。比如在該示例中,自變量是X1、X2和X3,因變量是Y。
首先,ANN進(jìn)行一些隨機(jī)預(yù)測,將這些預(yù)測與正確的輸出進(jìn)行比較,計(jì)算出誤差(預(yù)測值與實(shí)際值之間的差)。找出實(shí)際值與傳播值之間的差異的函數(shù)名為成本函數(shù)(cost function)。這里的成本指誤差。我們的目標(biāo)是使成本函數(shù)最小化。訓(xùn)練神經(jīng)網(wǎng)絡(luò)基本上是指使成本函數(shù)最小化。下面會介紹如何執(zhí)行此任務(wù)。
神經(jīng)網(wǎng)絡(luò)分兩個階段執(zhí)行:前饋階段和反向傳播階段。下面詳細(xì)介紹這兩個步驟。
前饋
圖2
來源:單層神經(jīng)網(wǎng)絡(luò),又叫Perceptron
在ANN的前饋階段,基于輸入節(jié)點(diǎn)中的值和權(quán)重進(jìn)行預(yù)測。如果看一下上圖中的神經(jīng)網(wǎng)絡(luò),會看到數(shù)據(jù)集中有三個特征:X1、X2和X3,因此第一層(又叫輸入層)中有三個節(jié)點(diǎn)。
神經(jīng)網(wǎng)絡(luò)的權(quán)重基本上是我們要調(diào)整的字符串,以便能夠正確預(yù)測輸出。請記住,每個輸入特性只有一個權(quán)重。
以下是在ANN的前饋階段所執(zhí)行的步驟:
第1步:計(jì)算輸入和權(quán)重之間的點(diǎn)積
輸入層中的節(jié)點(diǎn)通過三個權(quán)重參數(shù)與輸出層連接。在輸出層中,輸入節(jié)點(diǎn)中的值與對應(yīng)的權(quán)重相乘并相加。最后,偏置項(xiàng)b添加到總和。
為什么需要偏置項(xiàng)?
假設(shè)某個人有輸入值(0,0,0),輸入節(jié)點(diǎn)和權(quán)重的乘積之和將為零。在這種情況下,無論我們怎么訓(xùn)練算法,輸出都將始終為零。因此,為了能夠做出預(yù)測,即使我們沒有關(guān)于該人的任何非零信息,也需要一個偏置項(xiàng)。偏置項(xiàng)對于構(gòu)建穩(wěn)健的神經(jīng)網(wǎng)絡(luò)而言必不可少。
數(shù)學(xué)上,點(diǎn)積的總和:
X.W=x1.w1 + x2.w2 + x3.w3 + b
第2步:通過激活函數(shù)傳遞點(diǎn)積(X.W)的總和
點(diǎn)積XW可以生成任何一組值。然而在我們的輸出中,我們有1和0形式的值。我們希望輸出有同樣的格式。為此,我們需要一個激活函數(shù)(Activation Function),它將輸入值限制在0到1之間。因此,我們當(dāng)然會使用Sigmoid激活函數(shù)。
圖3. Sigmoid激活函數(shù)
輸入為0時(shí),Sigmoid函數(shù)返回0.5。如果輸入是大正數(shù),返回接近1的值。負(fù)輸入的情況下,Sigmoid函數(shù)輸出的值接近零。
因此,它特別適用于我們要預(yù)測概率作為輸出的模型。由于概念只存在于0到1之間,Sigmoid函數(shù)是適合我們這個問題的選擇。
上圖中z是點(diǎn)積X.W的總和。
數(shù)學(xué)上,Sigmoid激活函數(shù)是:
圖4. Sigmoid激活函數(shù)
總結(jié)一下到目前為止所做的工作。首先,我們要找到帶權(quán)重的輸入特征(自變量矩陣)的點(diǎn)積。接著,通過激活函數(shù)傳遞點(diǎn)積的總和。激活函數(shù)的結(jié)果基本上是輸入特征的預(yù)測輸出。
反向傳播
一開始,進(jìn)行任何訓(xùn)練之前,神經(jīng)網(wǎng)絡(luò)進(jìn)行隨機(jī)預(yù)測,這種預(yù)測當(dāng)然是不正確的。
我們先讓網(wǎng)絡(luò)做出隨機(jī)輸出預(yù)測。然后,我們將神經(jīng)網(wǎng)絡(luò)的預(yù)測輸出與實(shí)際輸出進(jìn)行比較。接下來,我們更新權(quán)重和偏置,并確保預(yù)測輸出更接近實(shí)際輸出。在這個階段,我們訓(xùn)練算法。不妨看一下反向傳播階段涉及的步驟。
第1步:計(jì)算成本
此階段的第一步是找到預(yù)測成本??梢酝ㄟ^找到預(yù)測輸出值和實(shí)際輸出值之間的差來計(jì)算預(yù)測成本。如果差很大,成本也將很大。
我們將使用均方誤差即MSE成本函數(shù)。成本函數(shù)是找到給定輸出預(yù)測成本的函數(shù)。
圖5. 均方誤差
這里,Yi是實(shí)際輸出值,i是預(yù)測輸出值,n是觀察次數(shù)。
第2步:使成本最小化
我們的最終目的是微調(diào)神經(jīng)網(wǎng)絡(luò)的權(quán)重,并使成本最小化。如果你觀察仔細(xì),會了解到我們只能控制權(quán)重和偏置,其他一切不在控制范圍之內(nèi)。我們無法控制輸入,無法控制點(diǎn)積,無法操縱Sigmoid函數(shù)。
為了使成本最小化,我們需要找到權(quán)重和偏置值,確保成本函數(shù)返回最小值。成本越小,預(yù)測就越正確。
要找到函數(shù)的最小值,我們可以使用梯度下降算法。梯度下降可以用數(shù)學(xué)表示為:
圖6. 使用梯度下降更新權(quán)重
Error是成本函數(shù)。上面的等式告訴我們找到關(guān)于每個權(quán)重和偏置的成本函數(shù)的偏導(dǎo)數(shù),然后從現(xiàn)有權(quán)重中減去結(jié)果以得到新的權(quán)重。
函數(shù)的導(dǎo)數(shù)給出了在任何給定點(diǎn)的斜率。為了找到成本是增加還是減少,給定權(quán)重值,我們可以找到該特定權(quán)重值的函數(shù)導(dǎo)數(shù)。如果成本隨重量增加而增加,導(dǎo)數(shù)將返回正值,然后將其從現(xiàn)有值中減去。
另一方面,如果成本隨重量增加而降低,將返回負(fù)值,該值將被添加到現(xiàn)有的權(quán)重值中,因?yàn)樨?fù)負(fù)得正。
在上面公式中,a名為學(xué)習(xí)速率,乘以導(dǎo)數(shù)。學(xué)習(xí)速率決定了我們的算法學(xué)習(xí)的速度。
我們需要對所有權(quán)重和偏置重復(fù)執(zhí)行梯度下降操作,直到成本最小化,并且成本函數(shù)返回的值接近零。
現(xiàn)在是實(shí)現(xiàn)我們迄今為止研究的人工神經(jīng)網(wǎng)絡(luò)的時(shí)候了。我們將用Python創(chuàng)建一個簡單的神經(jīng)網(wǎng)絡(luò),有1個輸入層和1個輸出層。
使用numpy實(shí)現(xiàn)人工神經(jīng)網(wǎng)絡(luò)
圖7
圖片來源:hackernoon.com
要采取的步驟:
1.定義自變量和因變量
2.定義超參數(shù)
3.定義激活函數(shù)及其導(dǎo)數(shù)
4.訓(xùn)練模型
5.做出預(yù)測
第1步:先創(chuàng)建自變量或輸入特征集以及相應(yīng)的因變量或標(biāo)簽。
#Independent variables
input_set = np.array([[0,1,0],
[0,0,1],
[1,0,0],
[1,1,0],
[1,1,1],
[0,1,1],
[0,1,0]])#Dependent variable
labels = np.array([[1,
0,
0,
1,
1,
0,
1]])
labels = labels.reshape(7,1) #toconvert labels to vector
我們的輸入集含有七個記錄。同樣,我們還創(chuàng)建了一個標(biāo)簽集,含有輸入集中每個記錄的對應(yīng)標(biāo)簽。標(biāo)簽是我們希望ANN預(yù)測的值。
第2步:定義超參數(shù)。
我們將使用numpy的random.seed函數(shù),以便在執(zhí)行以下代碼時(shí)可以獲得同樣的隨機(jī)值。
接下來,我們使用正態(tài)分布的隨機(jī)數(shù)初始化權(quán)重。由于輸入中有三個特征,因此我們有三個權(quán)重的向量。然后,我們使用另一個隨機(jī)數(shù)初始化偏置值。最后,我們將學(xué)習(xí)速率設(shè)置為0.05。
np.random.seed(42)
weights = np.random.rand(3,1)
bias = np.random.rand(1)
lr = 0.05 #learning rate
第3步:定義激活函數(shù)及其導(dǎo)數(shù):我們的激活函數(shù)是Sigmoid函數(shù)。
def sigmoid(x):
return 1/(1+np.exp(-x))
現(xiàn)在定義計(jì)算Sigmoid函數(shù)導(dǎo)數(shù)的函數(shù)。
def sigmoid_derivative(x):
return sigmoid(x)*(1-sigmoid(x))
第4步:是時(shí)候訓(xùn)練ANN模型了。
我們將從定義輪次(epoch)數(shù)量開始。輪次是我們想針對數(shù)據(jù)集訓(xùn)練算法的次數(shù)。我們將針對數(shù)據(jù)訓(xùn)練算法25000次,因此epoch將為25000??梢試L試不同的數(shù)字以進(jìn)一步降低成本。
for epoch in range(25000):
inputs = input_set
XW = np.dot(inputs, weights)+ bias
z = sigmoid(XW)
error = z - labels
print(error.sum())
dcost = error
dpred = sigmoid_derivative(z)
z_del = dcost * dpred
inputs = input_set.T
weights = weights - lr*np.dot(inputs, z_del)
for num in z_del:
bias = bias - lr*num
不妨了解每個步驟,然后進(jìn)入到預(yù)測的最后一步。
我們將輸入input_set中的值存儲到input變量中,以便在每次迭代中都保留input_set的值不變。
inputs = input_set
接下來,我們找到輸入和權(quán)重的點(diǎn)積,并為其添加偏置。(前饋階段的第1步)
XW = np.dot(inputs, weights)+ bias
接下來,我們通過Sigmoid激活函數(shù)傳遞點(diǎn)積。(前饋階段的第2步)
z = sigmoid(XW)
這就完成了算法的前饋部分,現(xiàn)在是開始反向傳播的時(shí)候了。
變量z含有預(yù)測的輸出。反向傳播的第一步是找到誤差。
error = z - labels
print(error.sum())
我們知道成本函數(shù)是:
圖8
我們需要從每個權(quán)重方面求該函數(shù)的微分,這可以使用微分鏈?zhǔn)椒▌t(chain rule of differentiation)來輕松完成。我將跳過推導(dǎo)部分,但如果有人感興趣,請留言。
因此,就任何權(quán)重而言,成本函數(shù)的最終導(dǎo)數(shù)是:
slope = input x dcost x dpred
現(xiàn)在,斜率可以簡化為:
dcost = error
dpred = sigmoid_derivative(z)
z_del = dcost * dpred
inputs = input_set.T
weights = weight-lr*np.dot(inputs, z_del)
我們有z_del變量,含有dcost和dpred的乘積。我們拿輸入特征矩陣的轉(zhuǎn)置與z_del相乘,而不是遍歷每個記錄并拿輸入與對應(yīng)的z_del相乘。
最后,我們將學(xué)習(xí)速率變量lr與導(dǎo)數(shù)相乘,以加快學(xué)習(xí)速度。
除了更新權(quán)重外,我們還要更新偏置項(xiàng)。
for num in z_del:
bias = bias - lr*num
一旦循環(huán)開始,你會看到總誤差開始減小;訓(xùn)練結(jié)束時(shí),誤差將保留為很小的值。
-0.001415035616137969
-0.0014150128584959256
-0.0014149901015685952
-0.0014149673453557714
-0.0014149445898578358
-0.00141492183507419
-0.0014148990810050437
-0.0014148763276499686
-0.0014148535750089977
-0.0014148308230825385
-0.0014148080718707524
-0.0014147853213728624
-0.0014147625715897338
-0.0014147398225201734
-0.0014147170741648386
-0.001414694326523502
-0.001414671579597255
-0.0014146488333842064
-0.0014146260878853782
-0.0014146033431002465
-0.001414580599029179
-0.0014145578556723406
-0.0014145351130293877
-0.0014145123710998
-0.0014144896298846701
-0.0014144668893831067
-0.001414444149595611
-0.0014144214105213174
-0.0014143986721605849
-0.0014143759345140276
-0.0014143531975805163
-0.001414330461361444
-0.0014143077258557749
-0.0014142849910631708
-0.00141426225698401
-0.0014142395236186895
-0.0014142167909661323
-0.001414194059027955
-0.001414171327803089
-0.001414148597290995
-0.0014141258674925626
-0.0014141031384067547
-0.0014140804100348098
-0.0014140576823759854
-0.0014140349554301636
-0.0014140122291978665
-0.001413989503678362
-0.001413966778871751
-0.001413944054778446
-0.0014139213313983257
-0.0014138986087308195
-0.0014138758867765552
-0.0014138531655347973
-0.001413830445006264
-0.0014138077251906606
-0.001413785006087985
-0.0014137622876977014
-0.0014137395700206355
-0.0014137168530558228
-0.0014136941368045382
-0.0014136714212651114
-0.0014136487064390219
-0.0014136259923249635
-0.001413603278923519
-0.0014135805662344007
-0.0014135578542581566
-0.0014135351429944293
-0.0014135124324428719
-0.0014134897226037203
-0.0014134670134771238
-0.0014134443050626295
-0.0014134215973605428
-0.0014133988903706311
第5步:作出預(yù)測
是時(shí)候作出一些預(yù)測了。先用[1,0,0]試一下:
single_pt = np.array([1,0,0])
result = sigmoid(np.dot(single_pt, weights) + bias)
print(result)
輸出:
[0.01031463]
如你所見,輸出更接近0而不是1,因此分類為0。
不妨再用[0,1,0]試一下:
single_pt = np.array([0,1,0])
result = sigmoid(np.dot(single_pt, weights) + bias)
print(result)
輸出:
[0.99440207]
如你所見,輸出更接近1而不是0,因此分類為1。
結(jié)論
我們在本文中學(xué)習(xí)了如何使用numpy Python庫,從零開始創(chuàng)建一個很簡單的人工神經(jīng)網(wǎng)絡(luò),只有1個輸入層和1個輸出層。該ANN能夠?qū)€性可分離數(shù)據(jù)進(jìn)行分類。
如果我們有非線性可分離的數(shù)據(jù),我們的ANN就無法對這種類型的數(shù)據(jù)進(jìn)行分類。下篇將介紹如何構(gòu)建這樣的ANN。
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4814瀏覽量
103604 -
編程語言
+關(guān)注
關(guān)注
10文章
1956瀏覽量
36649 -
深度學(xué)習(xí)
+關(guān)注
關(guān)注
73文章
5561瀏覽量
122794
發(fā)布評論請先 登錄
無刷電機(jī)小波神經(jīng)網(wǎng)絡(luò)轉(zhuǎn)子位置檢測方法的研究
低功耗+AI識別:基于樹莓派的 LoRa 神經(jīng)網(wǎng)絡(luò)安防系統(tǒng)!

基于FPGA搭建神經(jīng)網(wǎng)絡(luò)的步驟解析

BP神經(jīng)網(wǎng)絡(luò)與卷積神經(jīng)網(wǎng)絡(luò)的比較
BP神經(jīng)網(wǎng)絡(luò)的優(yōu)缺點(diǎn)分析
深度學(xué)習(xí)入門:簡單神經(jīng)網(wǎng)絡(luò)的構(gòu)建與實(shí)現(xiàn)
人工神經(jīng)網(wǎng)絡(luò)的原理和多種神經(jīng)網(wǎng)絡(luò)架構(gòu)方法

卷積神經(jīng)網(wǎng)絡(luò)與傳統(tǒng)神經(jīng)網(wǎng)絡(luò)的比較
RNN模型與傳統(tǒng)神經(jīng)網(wǎng)絡(luò)的區(qū)別
如何使用Python構(gòu)建LSTM神經(jīng)網(wǎng)絡(luò)模型
Moku人工神經(jīng)網(wǎng)絡(luò)101

評論