姓名:張博奇
學(xué)號:2014301020063
班級:物基一班
摘要:本文利用BP算法思想構(gòu)建二層神經(jīng)網(wǎng)絡(luò)和更復(fù)雜的三層神經(jīng)網(wǎng)絡(luò),訓(xùn)練神經(jīng)網(wǎng)絡(luò)根據(jù)輸入數(shù)據(jù)集預(yù)測輸出數(shù)據(jù),對神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)有了初步的認識,闡述了權(quán)重矩陣(網(wǎng)絡(luò)參數(shù))在神經(jīng)網(wǎng)絡(luò)中的核心作用。并在此基礎(chǔ)上用三層神經(jīng)網(wǎng)絡(luò)訓(xùn)練機器學(xué)習(xí)分類器,進而預(yù)測正確的分類,并討論隱藏層維度對分類結(jié)果的大致影響。
關(guān)鍵詞:神經(jīng)網(wǎng)絡(luò)、預(yù)測、機器學(xué)習(xí)、權(quán)重矩陣
引言
機器學(xué)習(xí),是如今最令人振奮的計算機領(lǐng)域之一。國際著名的互聯(lián)網(wǎng)公司,諸如Google、Facebook、Apple、Amazon早已展開了一場關(guān)于機器學(xué)習(xí)的軍備競賽。從手機上的語音助手、垃圾郵件過濾到逛淘寶時的物品推薦,無一不用到機器學(xué)習(xí)技術(shù)。2016年在圍棋界大放異彩的AlphaGo也是機器學(xué)習(xí)的成功案例。
背景知識
在20世紀下半葉,機器學(xué)習(xí)作為人工智能的子領(lǐng)域誕生了,其目標(biāo)是通過自學(xué)習(xí)算法從數(shù)據(jù)中獲取知識,然后對未來世界進行預(yù)測。無需借助人力從數(shù)據(jù)中得到規(guī)則,機器學(xué)習(xí)能夠自動建立模型進行預(yù)測。
機器學(xué)習(xí)是從對大腦的工作原理的研究逐步發(fā)展起來的。Warren McCullock和Walter Pitts 在1943年首次提出了一個簡化版大腦細胞的概念,即McCullock-Pitts(MCP)神經(jīng)元(W.S.McCulloch and W.Pitts. A Logical Calculus of the IdeasImmanent in Nervous Activity.)。
神經(jīng)元是大腦中內(nèi)部連接的神經(jīng)細胞,作用是處理和傳播化學(xué)和電信號。McCullock和Pitts描述了如下的神經(jīng)細胞:可以看做帶有兩個輸出的簡單邏輯門;即有多個輸入傳遞到樹突(Dentrity),然后在神經(jīng)元(Cell nucleus)內(nèi)部進行輸入整合,如果累積的信號量超過某個閾值,會產(chǎn)生一個輸出信號并且通過軸突(Axon)進行傳遞。十幾年后,基于MCP神經(jīng)元模型,F(xiàn)rank Rosenblatt發(fā)表了第一個感知機學(xué)習(xí)規(guī)則(F.Rosenblatt, The Perceptron, a Perceiving and Recognizing Automaton. Cornell Aeronautical Laboratory, 1957)。基于此感知機規(guī)則,Rosenblatt提出了能夠自動學(xué)習(xí)最優(yōu)權(quán)重參數(shù)的算法,權(quán)重即輸入特征的系數(shù)。后文中會有具體闡述。
構(gòu)建二層神經(jīng)網(wǎng)絡(luò)
BP算法,即誤差反向傳播(Error Back Propagation, BP)算法。BP算法的基本思想是,學(xué)習(xí)過程由信號的正向傳播與誤差的反向傳播兩個過程組成。由于多層前饋網(wǎng)絡(luò)的訓(xùn)練經(jīng)常采用誤差反向傳播算法,人們也常把將多層前饋網(wǎng)絡(luò)直接稱為BP網(wǎng)絡(luò)。
下面嘗試著用BP算法訓(xùn)練的神經(jīng)網(wǎng)絡(luò)根據(jù)輸入數(shù)據(jù)預(yù)測輸出數(shù)據(jù)。從二層神經(jīng)開始入手,輸入X和輸出Y數(shù)據(jù)集均以矩陣的形式給出。每一行代表一個訓(xùn)練樣本(即相當(dāng)于對大腦施加一次刺激),每一列代表一個輸入結(jié)點(即相當(dāng)于接受刺激的部位)。l0和l1分別代表輸入網(wǎng)絡(luò)層和中間隱藏層,顯然有數(shù)據(jù)集X等于輸入網(wǎng)絡(luò)層l0。syn0表示連接l0和l1層的突觸,也即上文提到的權(quán)重。
取4次訓(xùn)練樣本[0,0,1],[0,1,1],[1,0,1],[1,1,1]和擬定的輸出結(jié)果[0,0,1,1].T代碼如下:
import numpy as np
# sigmoid 函數(shù)
def nonlin(x,deriv=False):
if(deriv==True):
return x*(1-x)
return 1/(1+np.exp(-x))
# 輸入數(shù)據(jù)集
X = np.array([ [0,0,1],
[0,1,1],
[1,0,1],
[1,1,1] ])
# 輸出數(shù)據(jù)集
y = np.array([[0,0,1,1]]).T
np.random.seed(1)
# 隨機初始化權(quán)重并使均值為零
syn0 = 2*np.random.random((3,1)) - 1
for i in range(10000):
l0 = X
l1 = nonlin(np.dot(l0,syn0))
#誤差
l1_error = y - l1
l1_delta = l1_error * nonlin(l1,True)
# 更新權(quán)重
syn0 += np.dot(l0.T,l1_delta)
print (l1)
點擊查看代碼
輸出結(jié)果為:
[[ 0.00966449]
[ 0.00786506]
[ 0.99358898]
[ 0.99211957]]
從輸出結(jié)果可以看出,其值與每個訓(xùn)練樣本第一個結(jié)點的值是相近的,但第二與第三個結(jié)點的作用使得輸出結(jié)果有偏差。我們成功地利用輸入的訓(xùn)練樣本預(yù)測了輸出。
其中,Sigmoid 函數(shù)
可以將任何值都映射到一個位于 0 到 1 范圍內(nèi)的值。通過它,我們可以將實數(shù)轉(zhuǎn)化為概率值。通過 “nonlin” 函數(shù)體還能得到 sigmod 函數(shù)的導(dǎo)數(shù)(當(dāng)形參 deriv 為 True 時)。由于Sigmoid函數(shù)是非線性的,允許我們擬合非線性假設(shè),類似的函數(shù)還有tanh、ReLUs等。
權(quán)重syn0是隨機生成的一個3行一列矩陣,與輸入X相乘后得到一個數(shù)值,經(jīng)過nolin函數(shù)作用后得到對應(yīng)的概率值,也就是猜測結(jié)果。l1_error則評估預(yù)測值l1與初始設(shè)定的Y值差值。nolin函數(shù)形參 deriv 為 True 時得到Sigmoid 函數(shù)導(dǎo)數(shù)。
由上圖可以看出導(dǎo)數(shù)值在X絕對值較大時很小,在X絕對值較小時很大,但可以計算其導(dǎo)數(shù)值始終小于1。這個特性導(dǎo)致l1絕對值很大時其nolin函數(shù)值很小,l1_error相乘是一個較小值;l1絕對值很小時其nolin函數(shù)值很大,l1_error相乘是一個較大值。從統(tǒng)計學(xué)角度而言,我們對較為確定的事件賦予小的權(quán)重,對不確定的事件賦予大的權(quán)重。將nolin函數(shù)值乘上誤差時,實際上就在以高確信度減小預(yù)測誤差,更新權(quán)重后得到更進一步的準(zhǔn)確的權(quán)重值。從這里我們就可以看出,神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程,實際上就是對一個隨機權(quán)重不斷訓(xùn)練,最后使輸入數(shù)據(jù)集在權(quán)重的作用下越來越接近輸出值的過程。神經(jīng)網(wǎng)絡(luò)是基于輸入與輸出間的聯(lián)系進行學(xué)習(xí)的。
構(gòu)建三層神經(jīng)網(wǎng)絡(luò)
在構(gòu)建二層神經(jīng)網(wǎng)絡(luò)時,我們將輸出數(shù)據(jù)集定為[0,0,1,1].T,但是如果我們將輸出數(shù)據(jù)集改為[0,1,1,0].T,重新執(zhí)行上述代碼,可以發(fā)現(xiàn)輸出的l1為:
[[ 0.5]
[ 0.5]
[ 0.5]
[ 0.5]]
這和我們的擬定輸出數(shù)據(jù)集不一致,神經(jīng)網(wǎng)絡(luò)并沒有按照輸入與輸出間的關(guān)系預(yù)測輸出值。這是因為不一定總是單個輸入與輸出間存在一對一的關(guān)系,也可能是兩個輸入對應(yīng)一個輸出,甚至更復(fù)雜。輸入與輸出不一定是呈線性相關(guān)。或者說,輸入的組合與輸出間存在著一對一的關(guān)系。
為了解決這種更復(fù)雜的對應(yīng)關(guān)系,需要額外增加一個網(wǎng)絡(luò)層。第一層對輸入進行組合,然后以第一層的輸出作為輸入,通過第二層的映射得到最終的輸出結(jié)果。通過增加更多的中間層,以對更多關(guān)系的組合進行建模。這一策略正是人們所熟知的“深度學(xué)習(xí)”。
三層神經(jīng)網(wǎng)絡(luò)中,l0作為輸入層,l1作為中間隱藏層,l2作為輸出層。增加l2層和連接l1與l2間的權(quán)重syn1,并使l1_error等于l2誤差更新值乘權(quán)重(這種做法也稱作“貢獻度加權(quán)誤差”),可以寫出三層神經(jīng)網(wǎng)絡(luò)的代碼:
import numpy as np
# sigmoid 函數(shù)
def nonlin(x,deriv=False):
if(deriv==True):
return x*(1-x)
return 1/(1+np.exp(-x))
# 輸入數(shù)據(jù)集
X = np.array([[0,0,1],
[0,1,1],
[1,0,1],
[1,1,1]])
# 輸出數(shù)據(jù)集
y = np.array([[0],
[1],
[1],
[0]])
np.random.seed(1)
# 隨機初始化權(quán)重并使均值為零
syn0 = 2*np.random.random((3,5)) - 1
syn1 = 2*np.random.random((5,1)) - 1
for j in range(50000):
l0 = X
l1 = nonlin(np.dot(l0,syn0))
l2 = nonlin(np.dot(l1,syn1))
#l2層
l2_error = y - l2
l2_delta = l2_error*nonlin(l2,deriv=True)
#l1層
l1_error = l2_delta.dot(syn1.T)
l1_delta = l1_error * nonlin(l1,deriv=True)
# 更新權(quán)重
syn1 += l1.T.dot(l2_delta)
syn0 += l0.T.dot(l1_delta)
print(l2)
點擊查看代碼
輸出結(jié)果為:
[[ 0.00248611]
[ 0.99693818]
[ 0.99597714]
[ 0.00503275]]
可見已經(jīng)較好的得到了與擬定輸出結(jié)果相近的預(yù)測值。三層神經(jīng)網(wǎng)絡(luò)構(gòu)建成功。
利用三層神經(jīng)網(wǎng)絡(luò)預(yù)測分類
-
產(chǎn)生數(shù)據(jù)集
利用scikit-learn可以產(chǎn)生很多有趣的數(shù)據(jù)集。
swiss_roll
circle
這里采用整體較好分辨又具有一定難度分辨全部數(shù)據(jù)集的半月形數(shù)據(jù)集。
- 構(gòu)建三層神經(jīng)網(wǎng)絡(luò)并訓(xùn)練機器學(xué)習(xí)分類器
由于圖形是彎曲的,我們無法直接畫一條直線以區(qū)分紅點與藍點這兩類數(shù)據(jù)。因此需要構(gòu)建一個具有輸入層、隱藏層、輸出層的三層神經(jīng)網(wǎng)絡(luò)來分辨。由于是二維圖像,輸入結(jié)點選擇為兩個,兩類需要分辨的數(shù)據(jù),輸出結(jié)點也選擇為兩個。隱藏層的結(jié)點數(shù)不是固定的,比如在上文構(gòu)建三層神經(jīng)網(wǎng)絡(luò)中選擇了(5×1)矩陣,也就是五結(jié)點數(shù)(五維)隱藏層。結(jié)點數(shù)對數(shù)據(jù)篩選的影響會在后面討論。
zi是輸入層、ai是輸出層。W1,b1,W2,b2是需要從訓(xùn)練數(shù)據(jù)中學(xué)習(xí)的網(wǎng)絡(luò)參數(shù),也就是上文提到的權(quán)重(矩陣)。依然選擇sigmoid函數(shù)在z1與a1間進行映射,z2與a2間則采用Softmax函數(shù)進行映射(Softmax函數(shù)也是轉(zhuǎn)化成概率的一種方法,關(guān)于Softmax函數(shù)可查看維基百科)。
向前傳播進行預(yù)測:
為了找到使誤差函數(shù)最小時權(quán)重W1,b1,W2,b2的值,可以使用梯度下降方法,這里采用有固定學(xué)習(xí)速率的批量梯度下降法。梯度下降需要一個與參數(shù)相關(guān)的損失函數(shù)的梯度。先定義:
與參數(shù)相關(guān)的損失函數(shù)的梯度:
利用后向傳播導(dǎo)數(shù)實現(xiàn)批量梯度下降,進而更新網(wǎng)絡(luò)參數(shù)W1,b1,W2,b2,減小誤差。
-
對數(shù)據(jù)集進行分類
運行程序,最終實現(xiàn)了將半月形中藍色數(shù)據(jù)集與紅色數(shù)據(jù)集分離:
點擊查看源代碼
可以看出絕大多數(shù)紅色數(shù)據(jù)集與藍色數(shù)據(jù)集實現(xiàn)了分離,只有極少數(shù)數(shù)據(jù)集被分在了錯誤的位置,神經(jīng)網(wǎng)絡(luò)能夠找到成功區(qū)分不同數(shù)據(jù)集的決策邊界,數(shù)據(jù)集的分類獲得成功。下面改變隱藏層維度,來評估不同隱藏層維度會對數(shù)據(jù)分離結(jié)果造成的影響:
可以看出隱藏層為一維時相當(dāng)于線性分割兩種數(shù)據(jù)集,隨著維度增加分割效果得到提高,在隱藏層達到十維時只有一個本方數(shù)據(jù)集被排除在外,分割效果最好,隱藏層增加到五十維時沒有明顯的變化,這就需要改進算法實現(xiàn)更優(yōu)的數(shù)據(jù)篩選效果,包括采用其他的層間映射函數(shù)、更有效的梯度計算方法(顯然有固定學(xué)習(xí)速率的批量梯度下降法不是最高效的方法)、更多層次的神經(jīng)網(wǎng)絡(luò)等。
結(jié)論
一個基本的三層神經(jīng)網(wǎng)絡(luò)由輸入層、隱藏層、輸出層構(gòu)成,相鄰兩層間由權(quán)重矩陣(網(wǎng)絡(luò)參數(shù))連接。通過不斷提供訓(xùn)練樣本,神經(jīng)網(wǎng)絡(luò)會學(xué)習(xí)最優(yōu)權(quán)重參數(shù),從而減小誤差,利用輸入數(shù)據(jù)建立模型并模擬輸出。輸入層與輸出層結(jié)點數(shù)、隱藏層維度、層間映射函數(shù)、梯度計算方法都會對神經(jīng)網(wǎng)絡(luò)的準(zhǔn)確性造成影響。本文僅對神經(jīng)網(wǎng)絡(luò)與機器學(xué)習(xí)做了基于個人能力的粗淺分析,更具有生產(chǎn)力的神經(jīng)網(wǎng)絡(luò)遠比本文所述復(fù)雜。相信隨著科技的發(fā)展,未來人工智能會豐富每個人的生活!
致謝
Python機器學(xué)習(xí)
Implementing a Neural Network from Scratch in Python – An Introduction
Computational Physics, Nicholas J.Giordano, Hisao Nakanishi