很多同學(xué)入門機(jī)器學(xué)習(xí)之后,直接用TensorFlow調(diào)包實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò),對于神經(jīng)網(wǎng)絡(luò)內(nèi)在機(jī)理知之甚少。
編程語言與技術(shù)框架變化更新非常之快,理解背后的原理才是王道。下面文摘菌和大家一起用Numpy實(shí)現(xiàn)一步一步實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)。
此篇文章旨在幫大家梳理神經(jīng)網(wǎng)絡(luò)知識點(diǎn),且此篇文章是第一部分,只是簡單搭一個簡單的框架。暫時不涉及梯度下降、學(xué)習(xí)率調(diào)參等知識點(diǎn)。
最簡單的神經(jīng)網(wǎng)絡(luò)包含三個要素,輸入層,隱藏層以及輸出層。關(guān)于其工作機(jī)理其完全可以類比成一個元函數(shù):Y=W*X+b。
一個簡單的神經(jīng)網(wǎng)絡(luò)可以理解為兩次一元函數(shù)的輸入和輸出。
第一次:Y1=A1(W1*X+b1) ,其中X是原始數(shù)據(jù)的輸入,A1代表激活函數(shù)。
第二次:Y2=A2(W2*Y1+b2),其中Y1是第一次的輸出,A2是激活函數(shù)。參數(shù)W1、W2、b1、b2原則上各不相同。
本篇文章我們用到的激活函數(shù)有兩個,一個是tan(x),另一個是softmax。兩者的函數(shù)曲線如下。
兩個函數(shù)都有相同的特點(diǎn),即函數(shù)值在零點(diǎn)左右變化較大,當(dāng)輸入值遠(yuǎn)離零點(diǎn),其輸出較穩(wěn)定。
首先導(dǎo)入相關(guān)的庫,需要兩個庫,一個用于科學(xué)計(jì)算的Numpy,另一個是math。
然后定義激活函數(shù),
def tanh(x): return np.tanh(x)def softmax(x): exp=np.exp(x-x.max()) return exp/exp.sum()
這兩個激活函數(shù),其中tanh函數(shù),Numpy直接內(nèi)嵌。softmax根據(jù)數(shù)學(xué)定義進(jìn)行設(shè)置。第二個激活函數(shù)因?yàn)槭侵笖?shù)函數(shù),其值會變化較大,所以我們用x-x.max 縮小其變化范圍,這對結(jié)果不影響。
我們使用的圖片大小是 28*28像素。以后會用手寫數(shù)字?jǐn)?shù)據(jù)集訓(xùn)練網(wǎng)絡(luò),所以會有10個數(shù)字輸入,分別是[1,2,3,4,5,6,7,8,9,10]。所以要先定義三個列表。
dinensions=[28*28,10]activation=[tanh,softmax]distribution=[{'b':[0,0]},{'b':[0,0],'w':[-math.sqrt(6/(dinensions[0]+dinensions[1])),math.sqrt(6/(dinensions[0]+dinensions[1]))]}]
dinensions列表里面包含兩個數(shù),第一個是圖片的像素大小,第二個是數(shù)字的輸入變化量。
activation列表包含兩個激活函數(shù),分別為tanh,softmax。
distribution 列表里面對應(yīng)的是字典格式的數(shù)據(jù),分別對應(yīng)神經(jīng)網(wǎng)絡(luò)參數(shù)取值范圍。
其中第一層不包含參數(shù)W。
definit_parameters_b(layer):dist=distribution[layer]['b'] return np.random.rand(dinensions[layer])*(dist[1]-dist[0])+dist[0] #使得生成的隨機(jī)數(shù)在 b 的區(qū)間內(nèi)definit_parameters_w(layer):dist=distribution[layer]['w'] return np.random.rand(dinensions[layer-1],dinensions[layer])*(dist[1]-dist[0])+dist[0] #使得生成的隨機(jī)數(shù)在 b 的區(qū)間內(nèi)
上面代碼是對b和w這兩個參數(shù)初始化,因?yàn)槲覀冚斎氲氖?8*28個數(shù)字,輸出的是10個數(shù)字。所以第一層的 b 也有28*28個數(shù)字組成。根據(jù)矩陣的乘法規(guī)則,第二層的時候,w的維度只有是28*28行,10列才能滿足輸出的10個數(shù)字。因此第二層的b是10個數(shù)字。
dinensions[X] 意思是取切片,dinensions[1] 取得是10,dinensions[0],取得是28*28。
又因?yàn)閚p.random.rand()這一函數(shù)輸出值的范圍在[0,1],括號里面的參數(shù)(即dinensions[layer]只是確保輸出的數(shù)字個數(shù)滿足要求),所以為了讓輸出的值在一開始設(shè)置的 b 的區(qū)間內(nèi),我們設(shè)置先乘(dist[1]-dist[0])然后加上dist[0]。dist[1]和dist[0]分別對應(yīng)參數(shù)的上下限。
definit_parameters():parameters=[]foriinrange(len(distribution)):layer_parameters={}forjindistribution[i].keys():ifj=='b':layer_parameters['b']=init_parameters_b(i)continueifj=='w':layer_parameters['w']=init_parameters_w(i)continueparameters.append(layer_parameters) return parameters
上面代碼是將三個參數(shù)的初始化集成達(dá)到一個函數(shù)里面。
先定義一個空列表(不要寫錯成空字典)是為了將三個參數(shù)統(tǒng)一輸出。
注:字典類型不能用append,列表可以用,列表.append(字典) 也是可以的。
然后從零開始遍歷distribution。用if循環(huán)語句,目的是把參數(shù)全部包含進(jìn)來。
第二層for循環(huán)和if語句是判斷,并正確添加參數(shù)。
parameters=init_parameters() #將參數(shù)賦值給新的變量。defpredict(img,parameters):I0_in=img+parameters[0]['b']I0_out=activation[0](I0_in)I1_in=np.dot(I0_out,parameters[1]['w']+parameters[1]['b'])I1_out=activation[1](I1_in) return I1_out
定義輸出函數(shù),思路是這樣的:輸入數(shù)據(jù)后,根據(jù)函數(shù):y=wx+b,進(jìn)行變換,第一層w全為1。然后經(jīng)過激活函數(shù)(第一個激活函數(shù)是tanh,所以用activation[0]),得出第一層的輸入I0_out。 然后進(jìn)入第二層,第一層的輸出作為輸入,根據(jù)函數(shù):y=wx+b,進(jìn)行變換,第二層的w為parameters[1]['w'],第二層的b為parameters[1]['b']。然后再經(jīng)過激活函數(shù)softmax,得到輸出。
predict(np.random.rand(784),parameters).argmax()
最后,隨便輸入一個784維數(shù)據(jù)(像素),都可以輸出一個圖片標(biāo)簽。
預(yù)測圖片中的數(shù)字
好了,我們第一個簡單的神經(jīng)網(wǎng)絡(luò)就搭建好了,關(guān)于如何使用梯度下降和學(xué)習(xí)率,如何訓(xùn)練網(wǎng)絡(luò)以及如何加載圖片數(shù)據(jù),我們在以后的文章中會介紹。
注:此篇文章受B站up主大野喵渣的啟發(fā),并參考了其代碼,感興趣的同學(xué)可以去B站觀看他關(guān)于神經(jīng)網(wǎng)絡(luò)的教學(xué)視頻。
-
神經(jīng)網(wǎng)絡(luò)
+關(guān)注
關(guān)注
42文章
4733瀏覽量
100417 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4277瀏覽量
62323 -
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8349瀏覽量
132313
原文標(biāo)題:TensorFlow什么的都弱爆了,強(qiáng)者只用Numpy搭建神經(jīng)網(wǎng)絡(luò)
文章出處:【微信號:BigDataDigest,微信公眾號:大數(shù)據(jù)文摘】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論