動(dòng)態(tài)網(wǎng)站建設(shè)優(yōu)缺點(diǎn)排超聯(lián)賽積分榜
神經(jīng)網(wǎng)絡(luò)基礎(chǔ)
神經(jīng)網(wǎng)絡(luò)可以處理結(jié)構(gòu)化數(shù)據(jù)(表格、數(shù)據(jù)庫(kù)等)和非結(jié)構(gòu)化數(shù)據(jù)(圖像、音頻等),并用于訓(xùn)練如房子特征和房?jī)r(jià)之間的函數(shù)、訓(xùn)練圖像和類(lèi)別之間的函數(shù)、訓(xùn)練語(yǔ)音和文本之間的函數(shù)等,從而實(shí)現(xiàn)房?jī)r(jià)預(yù)測(cè)、圖像分類(lèi)、語(yǔ)音識(shí)別等功能。
為何最近神經(jīng)網(wǎng)絡(luò)崛起了呢,下面引用吳恩達(dá)的一幅圖片進(jìn)行解釋。當(dāng)數(shù)據(jù)(帶標(biāo)簽的)量比較小的時(shí)候,傳統(tǒng)學(xué)習(xí)算法的效果和神經(jīng)網(wǎng)絡(luò)的效果差異不大,當(dāng)數(shù)據(jù)量變大之后,神經(jīng)網(wǎng)絡(luò)的效果要明顯好于傳統(tǒng)學(xué)習(xí)算法(支持向量機(jī)、邏輯回歸等),得益于廉價(jià)相機(jī)的推廣和物聯(lián)網(wǎng)的發(fā)展,傳感器不斷生成各種數(shù)據(jù),數(shù)據(jù)量越來(lái)越大,此時(shí)神經(jīng)網(wǎng)絡(luò)的表現(xiàn)就要好于傳統(tǒng)學(xué)習(xí)算法。
神經(jīng)元
如下圖,假設(shè)現(xiàn)在有兩類(lèi)數(shù)據(jù)分別代表貓、狗,區(qū)分這兩類(lèi)數(shù)據(jù)最簡(jiǎn)單的方法就是在中間畫(huà)一條直線把數(shù)據(jù)分成兩類(lèi),新的向量只要在直線下方的就是貓,直線上方的是狗,神經(jīng)元就是把特征空間一切兩半,認(rèn)為兩半分別屬兩個(gè)類(lèi)。神經(jīng)元一刀把空間切成兩半
在上一篇文章《python實(shí)現(xiàn)手寫(xiě)數(shù)字識(shí)別》里已經(jīng)講過(guò),這個(gè)就是邏輯回歸,
,一個(gè)神經(jīng)元其實(shí)就是邏輯回歸分類(lèi)器,如下圖。神經(jīng)元
神經(jīng)網(wǎng)絡(luò)
神經(jīng)元(邏輯回歸)雖然簡(jiǎn)單好用,但是有個(gè)缺點(diǎn),就是只能切一刀,如果遇到復(fù)雜的情況就處理不了了。如下圖就無(wú)法用一條直線把兩類(lèi)分開(kāi)。一刀無(wú)法切開(kāi)兩類(lèi)數(shù)據(jù)
這時(shí)候你會(huì)想,如果能過(guò)多切幾刀就好了,沒(méi)錯(cuò)!這種復(fù)雜情況的分類(lèi)方法就是通過(guò)多層神經(jīng)網(wǎng)絡(luò),每切一刀其實(shí)就是使用一個(gè)神經(jīng)元,只要你切足夠多刀,理論上你可以表示很復(fù)雜的函數(shù)分布。下面就是神經(jīng)網(wǎng)絡(luò)的表示圖,每一個(gè)神經(jīng)元的輸出作為下一層神經(jīng)元的輸入。神經(jīng)網(wǎng)絡(luò)模型
用python實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)由于篇幅所限,此處不展開(kāi)介紹反向傳播算法及其數(shù)學(xué)推導(dǎo)、正則化、梯度檢測(cè),后續(xù)將單獨(dú)寫(xiě)一篇文章來(lái)介紹。
我們繼續(xù)選擇手寫(xiě)數(shù)字識(shí)別問(wèn)題作為例子建立神經(jīng)網(wǎng)絡(luò),并檢驗(yàn)其預(yù)測(cè)的準(zhǔn)確率。每一條數(shù)據(jù)是長(zhǎng)度為400的向量。
1.選擇神經(jīng)網(wǎng)絡(luò)框架以及隨機(jī)初始化權(quán)重
因?yàn)檩斎氲氖情L(zhǎng)度400的向量,輸出是0-9的數(shù)字分類(lèi)結(jié)果,因此輸入層神經(jīng)元數(shù)量是400,輸出層神經(jīng)元數(shù)量是10,隱藏層神經(jīng)元的數(shù)量我們選擇40個(gè),Hidden Layer與Input Layer之間的聯(lián)系定義為權(quán)重Θ1(包含了bias unit),Output Layer與Hidden Layer之間的權(quán)重定義為Θ2(包含了bias unit),則Θ1是形狀為(25,401)的矩陣,Θ2是形狀為(10,62)的矩陣。
當(dāng)將所有參數(shù)初始化為零的時(shí)候,會(huì)使所有的節(jié)點(diǎn)變得相同,在訓(xùn)練過(guò)程中只能學(xué)到相同的特征,而無(wú)法學(xué)到多層級(jí)、多樣化的特征。解決辦法是隨機(jī)初始化所有參數(shù),但僅需少量的方差就行。這里我們給Θ1,Θ2分別初始化一個(gè)很小的初始值。
#神經(jīng)網(wǎng)絡(luò)框架為400*25*10
input_layer_size = 400
hidden_layer_size = 25
output_layer_size = 10
n_training_samples = X_train.shape[0]
#隨機(jī)初始化Thetas
def genRandThetas():
epsilon_init = 0.12
theta1_shape = (hidden_layer_size, input_layer_size+1)
theta2_shape = (output_layer_size, hidden_layer_size+1)
rand_thetas = [np.random.rand( *theta1_shape ) * 2 * epsilon_init - epsilon_init,
np.random.rand( *theta2_shape ) * 2 * epsilon_init - epsilon_init]
return rand_thetas
2.執(zhí)行前向傳播,計(jì)算每一個(gè)x對(duì)應(yīng)的h(x)
第一步我們已經(jīng)建立了如下的三層神經(jīng)網(wǎng)絡(luò)如下圖:
如上圖,
代表第l層第i個(gè)神經(jīng)元指向第l+1層第j個(gè)神經(jīng)元的權(quán)重,x是特征值,
是第l層的輸出。下面我們來(lái)從第一層開(kāi)始計(jì)算神經(jīng)元的輸出值(忽略bias unit),知道計(jì)算出h(x)。
第一層各神經(jīng)元的輸出就是各特征值,即:
第二層各個(gè)神經(jīng)元的輸出如下,p為第一層神經(jīng)元的個(gè)數(shù)400,q為第二層神經(jīng)元的個(gè)數(shù)40:
...
寫(xiě)成向量化形式為:
同理,第三層各神經(jīng)元的輸出向量化為:
def propagateForward(row,Thetas):
feature = row
zs_as_per_layer = [] #儲(chǔ)存各層神經(jīng)網(wǎng)絡(luò)的z值和a值
for i in range(len(Thetas)):
theta = Thetas[i]
z = np.dot(feature,theta.T).reshape(theta.shape[0],1)
a = expit(z)
zs_as_per_layer.append((z, a))
if i == len(Thetas)-1:
return np.array(zs_as_per_layer)
a = np.insert(a,0,1) #Add bias unit
feature = a.T
3.計(jì)算損失函數(shù)
損失函數(shù)Cost function是預(yù)測(cè)值與真實(shí)值之間的偏差的總和,我們回憶一下邏輯回歸中的損失函數(shù):
神經(jīng)網(wǎng)絡(luò)的損失函數(shù)也是類(lèi)似的,神經(jīng)網(wǎng)絡(luò)的輸出層有K個(gè)神經(jīng)元(邏輯回歸),因此損失函數(shù)為:
def computeCost(myThetas,myX,myy):
myThetas = reshapeParams(myThetas)
myX = reshapeX(myX)
m = n_training_samples
total_cost = 0.
for i in range(m):
myrow = myX[i]
myhs = propagateForward(myrow,myThetas)[-1][1]
tmpy = np.zeros((10,1))
tmpy[myy[i]-1] = 1
mycost = -tmpy.T.dot(np.log(myhs))-(1-tmpy.T).dot(np.log(1-myhs))
total_cost += mycost
total_cost = float(total_cost)/m
return total_cost
4.使用反向傳播算法計(jì)算梯度
使用梯度下降或者其他高級(jí)最優(yōu)化算法,總是要求出C關(guān)于θ的導(dǎo)數(shù),即
。使用前向傳播求導(dǎo)計(jì)算量非常大,而反向傳播算法求梯度可以大大減少計(jì)算的次數(shù)。
如下圖,首先通過(guò)前向傳播傳遞信息直到產(chǎn)生誤差(低了、高了),再通過(guò)反向傳播傳遞誤差信息,更新權(quán)重矩陣。由于反向傳播算法比較復(fù)雜,此處就直接使用了,原理及數(shù)學(xué)推導(dǎo)后續(xù)會(huì)單獨(dú)寫(xiě)一篇,有興趣的同學(xué)可以期待一下哦
首先記損失函數(shù)C關(guān)于l層的第j個(gè)元素的偏導(dǎo)為:
根據(jù)反向傳播四大公式,即可求出梯度
def backPropagate(myThetas,myX,myy):
myThetas = reshapeParams(myThetas)
m = n_training_samples
myX = reshapeX(myX)
Delta1 = np.zeros((hidden_layer_size,input_layer_size+1))
Delta2 = np.zeros((output_layer_size,hidden_layer_size+1))
for i in range(m):
myrow = myX[i]
a1 = myrow.reshape((input_layer_size+1,1))
temp = propagateForward(myrow,myThetas)
z2 = temp[0][0]
a2 = temp[0][1]
z3 = temp[1][0]
a3 = temp[1][1]
tmpy = np.zeros((10,1))
tmpy[myy[i]-1] = 1
delta3 = a3 - tmpy
delta2 = myThetas[1].T[1:,:].dot(delta3)*sigmoidGradient(z2)
a2 = np.insert(a2,0,1,axis=0)
Delta1 += delta2.dot(a1.T)
Delta2 += delta3.dot(a2.T)
D1 = Delta1/float(m)
D2 = Delta2/float(m)
return flattenParams([D1, D2]).flatten()
5.利用最優(yōu)化算法最小化損失函數(shù)
根據(jù)損失函數(shù)以及梯度,使用最優(yōu)化算法如梯度下降等,即可求解Θ,得到預(yù)測(cè)函數(shù)h(x)。
def trainNN():
randomThetas_unrolled = flattenParams(genRandThetas())
result = scipy.optimize.fmin_cg(computeCost,x0=randomThetas_unrolled,
fprime=backPropagate,args(X_train,y_train),
maxiter=50,disp=True,full_output=True)
return reshapeParams(result[0])
6.計(jì)算手寫(xiě)數(shù)字識(shí)別的準(zhǔn)確度
使用測(cè)試集得到我們的神經(jīng)網(wǎng)絡(luò)預(yù)測(cè)準(zhǔn)確度為93.9%,對(duì)比我們上一期的邏輯回歸的預(yù)測(cè)準(zhǔn)確率89.1%,有了明顯的提高,神經(jīng)網(wǎng)絡(luò)的強(qiáng)大可見(jiàn)一斑。
歡迎關(guān)注我的專(zhuān)欄:python實(shí)現(xiàn)機(jī)器學(xué)習(xí)算法?zhuanlan.zhihu.com