什么是神經(jīng)網(wǎng)絡(luò)? 在我們開始之前與如何建立一個神經(jīng)網(wǎng)絡(luò),我們需要了解什么第一。 神經(jīng)網(wǎng)絡(luò)可能會讓人感到恐懼,特別是對于新手機(jī)器學(xué)習(xí)的人來說。但是,本教程將分解神經(jīng)網(wǎng)絡(luò)的工作原理,最終您將擁有靈活的神經(jīng)網(wǎng)絡(luò)。讓我們開始吧! 了解過程 擁有大約100億個神經(jīng)元,人類大腦以268英里的速度處理數(shù)據(jù)!實質(zhì)上,神經(jīng)網(wǎng)絡(luò)是由突觸連接的神經(jīng)元集合。該集合分為三個主要層:輸入層,隱藏層和輸出層。你可以有許多隱藏層,這就是深度學(xué)習(xí)這個術(shù)語的起源。在人造神經(jīng)網(wǎng)絡(luò)中,有幾個輸入,稱為特征,并產(chǎn)生單個輸出,稱為標(biāo)簽。
圓圈表示神經(jīng)元,而線條表示突觸。突觸的作用是將輸入和權(quán)重相乘。你可以將體重看作神經(jīng)元之間連接的“強(qiáng)度”。權(quán)重主要定義了神經(jīng)網(wǎng)絡(luò)的輸出。但是,他們非常靈活。之后,應(yīng)用激活功能返回輸出。 以下簡要介紹一個簡單的前饋神經(jīng)網(wǎng)絡(luò)的工作原理: 1.將輸入作為矩陣(數(shù)字的二維數(shù)組) 2.將輸入乘以設(shè)定權(quán)重(執(zhí)行點積乘以矩陣乘法) 3.應(yīng)用激活功能 4.返回一個輸出 5.通過從數(shù)據(jù)的期望輸出和預(yù)測輸出的差異來計算誤差。這創(chuàng)建了我們的漸變下降,我們可以使用它來改變權(quán)重 6.然后根據(jù)錯誤輕微改變權(quán)重。 7.為了訓(xùn)練,這個過程重復(fù)1000次以上。數(shù)據(jù)訓(xùn)練得越多,我們的輸出結(jié)果就越準(zhǔn)確。 神經(jīng)網(wǎng)絡(luò)的核心是簡單的。他們只是使用輸入和權(quán)重執(zhí)行點積并應(yīng)用激活函數(shù)。當(dāng)權(quán)重通過損失函數(shù)的梯度進(jìn)行調(diào)整時,網(wǎng)絡(luò)適應(yīng)變化以產(chǎn)生更準(zhǔn)確的輸出。 我們的神經(jīng)網(wǎng)絡(luò)將模擬一個具有三個輸入和一個輸出的隱藏層。在網(wǎng)絡(luò)中,我們將根據(jù)我們研究多少小時以及我們前一天睡了多少小時的輸入來預(yù)測考試成績。我們的測試分?jǐn)?shù)是輸出。以下是我們將在以下方面培訓(xùn)我們的神經(jīng)網(wǎng)絡(luò)的示例數(shù)據(jù):
正如你可能已經(jīng)注意到的那樣,?在這種情況下代表了我們希望我們的神經(jīng)網(wǎng)絡(luò)預(yù)測的東西。在這種情況下,我們預(yù)測根據(jù)他們之前的表現(xiàn),學(xué)習(xí)了四個小時并睡了八個小時的人的測試分?jǐn)?shù)。 向前傳播 讓我們開始編碼這個壞男孩!打開一個新的python文件。您需要導(dǎo)入,numpy因為它可以幫助我們進(jìn)行某些計算。 首先,讓我們使用numpy數(shù)組導(dǎo)入我們的數(shù)據(jù)np.array。我們也希望我們的單位標(biāo)準(zhǔn)化,因為我們的輸入是以小時為單位的,但是我們的輸出是從0到100的測試分?jǐn)?shù)。因此,我們需要通過除以每個變量的最大值來縮放數(shù)據(jù)。
接下來,讓我們定義一個pythonclass并寫一個init函數(shù),我們將在其中指定我們的參數(shù),如輸入層,隱藏層和輸出層。 現(xiàn)在是我們第一次計算的時候了。請記住,我們的突觸執(zhí)行點積或輸入和權(quán)重的矩陣乘法。請注意,權(quán)重是隨機(jī)生成的,介于0和1之間。 我們網(wǎng)絡(luò)背后的計算 在數(shù)據(jù)集中,我們的輸入數(shù)據(jù)X是一個3x2的矩陣。我們的輸出數(shù)據(jù)y是一個3x1矩陣。矩陣中的每個元素X需要乘以相應(yīng)的權(quán)重,然后與隱藏層中每個神經(jīng)元的所有其他結(jié)果一起添加。以下是第一個輸入數(shù)據(jù)元素(2小時學(xué)習(xí)和9小時睡眠)將如何計算網(wǎng)絡(luò)中的輸出: 這張圖片分解了我們的神經(jīng)網(wǎng)絡(luò)實際上產(chǎn)生輸出的過程。首先,將每個突觸上隨機(jī)生成的權(quán)重(.2,.6,.1,.8,.3,.7)和相應(yīng)輸入的乘積相加,作為隱層的第一個值。這些總和字體較小,因為它們不是隱藏層的最終值。 (2*.2)+(9*.8)=7.6 (2*.6)+(9*.3)=3.9 (2*.1)+(9*.7)=6.5 為了獲得隱藏層的最終值,我們需要應(yīng)用激活函數(shù)。激活函數(shù)的作用是引入非線性。這樣做的一個優(yōu)點是輸出從0到1的范圍映射,使得將來更容易改變權(quán)重。 那里有很多激活功能。在這種情況下,我們將堅持一個更受歡迎的--Sigmoid函數(shù)。 現(xiàn)在,我們需要再次使用矩陣乘法和另一組隨機(jī)權(quán)重來計算我們的輸出圖層值。 (.9994*.4)+(1.000*.5)+(.9984*.9)=1.79832 最后,為了標(biāo)準(zhǔn)化輸出,我們再次應(yīng)用激活函數(shù)。 S(1.79832)=.8579443067 而且,你去了!理論上,用這些權(quán)重,out神經(jīng)網(wǎng)絡(luò)將計算.85為我們的測試分?jǐn)?shù)!但是,我們的目標(biāo)是.92。我們的結(jié)果并不差,但它不是最好的。當(dāng)我為這個例子選擇隨機(jī)權(quán)重時,我們有點幸運。 我們?nèi)绾斡?xùn)練我們的模型來學(xué)習(xí)?那么,我們很快就會發(fā)現(xiàn)。現(xiàn)在,我們來統(tǒng)計我們的網(wǎng)絡(luò)編碼。 如果您仍然感到困惑,我強(qiáng)烈建議您查看這個帶有相同示例的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)的信息性視頻。 實施計算 現(xiàn)在,讓我們隨機(jī)生成我們的權(quán)重np.random.randn()。請記住,我們需要兩組權(quán)重。一個從輸入到隱藏層,另一個從隱藏層到輸出層。 #weights self.W1=np.random.randn(self.inputSize,self.hiddenSize)#(3x2)weightmatrixfrominputtohiddenlayer self.W2=np.random.randn(self.hiddenSize,self.outputSize)#(3x1)weightmatrixfromhiddentooutputlayer 一旦我們有了所有的變量,我們就可以編寫我們的forward傳播函數(shù)了。讓我們傳入我們的輸入,X在這個例子中,我們可以使用變量z來模擬輸入層和輸出層之間的活動。正如所解釋的那樣,我們需要獲取輸入和權(quán)重的點積,應(yīng)用激活函數(shù),取另一個隱藏層的點積和第二組權(quán)重,最后應(yīng)用最終激活函數(shù)來接收我們的輸出: defforward(self,X): #forwardpropagationthroughournetwork self.z=np.dot(X,self.W1)#dotproductofX(input)andfirstsetof3x2weights self.z2=self.sigmoid(self.z)#activationfunction self.z3=np.dot(self.z2,self.W2)#dotproductofhiddenlayer(z2)andsecondsetof3x1weights o=self.sigmoid(self.z3)#finalactivationfunction returno 最后,我們需要定義我們的sigmoid函數(shù): defsigmoid(self,s): #activationfunction return1/(1+np.exp(-s)) 我們終于得到它了!一個能夠產(chǎn)生輸出的(未經(jīng)訓(xùn)練的)神經(jīng)網(wǎng)絡(luò)。 importnumpyasnp #X=(hourssleeping,hoursstudying),y=scoreontest X=np.array(([2,9],[1,5],[3,6]),dtype=float) y=np.array(([92],[86],[89]),dtype=float) #scaleunits X=X/np.amax(X,axis=0)#maximumofXarray y=y/100#maxtestscoreis100 classNeural_Network(object): def__init__(self): #parameters self.inputSize=2 self.outputSize=1 self.hiddenSize=3 #weights self.W1=np.random.randn(self.inputSize,self.hiddenSize)#(3x2)weightmatrixfrominputtohiddenlayer self.W2=np.random.randn(self.hiddenSize,self.outputSize)#(3x1)weightmatrixfromhiddentooutputlayer defforward(self,X): #forwardpropagationthroughournetwork self.z=np.dot(X,self.W1)#dotproductofX(input)andfirstsetof3x2weights self.z2=self.sigmoid(self.z)#activationfunction self.z3=np.dot(self.z2,self.W2)#dotproductofhiddenlayer(z2)andsecondsetof3x1weights o=self.sigmoid(self.z3)#finalactivationfunction returno defsigmoid(self,s): #activationfunction return1/(1+np.exp(-s)) NN=Neural_Network() #definingouroutput o=NN.forward(X) print"PredictedOutput:\n"+str(o) print"ActualOutput:\n"+str(y) 正如您可能已經(jīng)注意到的那樣,我們需要訓(xùn)練我們的網(wǎng)絡(luò)來計算更準(zhǔn)確的結(jié)果。 反向傳播 由于我們有一組隨機(jī)的權(quán)重,我們需要對它們進(jìn)行修改,以使我們的輸入等于我們數(shù)據(jù)集的相應(yīng)輸出。這是通過一種稱為反向傳播的方法完成的。 反向傳播通過使用丟失函數(shù)來計算網(wǎng)絡(luò)與目標(biāo)輸出的距離。 在這個函數(shù)中,o是我們的預(yù)測輸出,并且y是我們的實際輸出。既然我們有損失函數(shù),那么我們的目標(biāo)就是盡可能接近零。這意味著我們將需要接近完全沒有損失。當(dāng)我們正在訓(xùn)練我們的網(wǎng)絡(luò)時,我們所做的一切就是盡量減少損失。 為了找出改變我們的權(quán)重的方向,我們需要找出我們的損失相對于權(quán)重的變化率。換句話說,我們需要使用損失函數(shù)的導(dǎo)數(shù)來理解權(quán)重如何影響輸入。 在這種情況下,我們將使用偏導(dǎo)數(shù)來允許我們考慮另一個變量。 ? 這種方法被稱為梯度下降。通過知道哪種方式來改變我們的權(quán)重,我們的輸出只能得到更準(zhǔn)確的結(jié)果。 以下是我們將如何計算對權(quán)重的增量更改: 通過計算預(yù)測輸出和實際輸出(y)的差值來找出輸出層(o)的誤差幅度, 將sigmoid激活函數(shù)的導(dǎo)數(shù)應(yīng)用于輸出圖層錯誤。我們把這個結(jié)果稱為delta輸出和。 使用輸出層誤差的delta輸出總和來計算我們的z2(隱藏)層通過使用我們的第二個權(quán)重矩陣執(zhí)行點積來導(dǎo)致輸出誤差的程度。我們可以稱之為z2錯誤。 應(yīng)用我們的sigmoid激活函數(shù)的導(dǎo)數(shù)(與第2步一樣),計算z2層的delta輸出和。 通過執(zhí)行輸入層與隱藏(z2)增量輸出和的點積來調(diào)整第一層的權(quán)重。對于第二層,執(zhí)行隱藏(z2)圖層和輸出(o)delta輸出和的點積。 計算delta輸出和然后應(yīng)用sigmoid函數(shù)的導(dǎo)數(shù)對于反向傳播非常重要。S型的衍生物,也被稱為S型素數(shù),將給我們輸出和的激活函數(shù)的變化率或斜率。 讓我們繼續(xù)Neural_Network通過添加sigmoidPrime(sigmoid的衍生)函數(shù)來編寫我們的類: defsigmoidPrime(self,s): #derivativeofsigmoid returns*(1-s) 然后,我們要創(chuàng)建我們的backward傳播函數(shù),它執(zhí)行上述四個步驟中指定的所有內(nèi)容: defbackward(self,X,y,o): #backwardpropgatethroughthenetwork self.o_error=y-o#errorinoutput self.o_delta=self.o_error*self.sigmoidPrime(o)#applyingderivativeofsigmoidtoerror self.z2_error=self.o_delta.dot(self.W2.T)#z2error:howmuchourhiddenlayerweightscontributedtooutputerror self.z2_delta=self.z2_error*self.sigmoidPrime(self.z2)#applyingderivativeofsigmoidtoz2error self.W1+=X.T.dot(self.z2_delta)#adjustingfirstset(input-->hidden)weights self.W2+=self.z2.T.dot(self.o_delta)#adjustingsecondset(hidden-->output)weights 我們現(xiàn)在可以通過啟動前向傳播來定義我們的輸出,并通過在函數(shù)中調(diào)用后向函數(shù)來啟動它train: deftrain(self,X,y): o=self.forward(X) self.backward(X,y,o) 為了運行網(wǎng)絡(luò),我們所要做的就是運行該train功能。當(dāng)然,我們會想要做到這一點,甚至可能是成千上萬次。所以,我們將使用一個for循環(huán)。 NN=Neural_Network() foriinxrange(1000):#trainstheNN1,000times print"Input:\n"+str(X) print"ActualOutput:\n"+str(y) print"PredictedOutput:\n"+str(NN.forward(X)) print"Loss:\n"+str(np.mean(np.square(y-NN.forward(X))))#meansumsquaredloss print"\n" NN.train(X,y) 太棒了,我們現(xiàn)在有一個神經(jīng)網(wǎng)絡(luò)!如何使用這些訓(xùn)練后的權(quán)重來預(yù)測我們不知道的測試分?jǐn)?shù)? 預(yù)測 為了預(yù)測我們的輸入測試分?jǐn)?shù)[4,8],我們需要創(chuàng)建一個新的數(shù)組來存儲這些數(shù)據(jù)xPredicted。 xPredicted=np.array(([4,8]),dtype=float) 我們還需要按照我們對輸入和輸出變量所做的那樣進(jìn)行擴(kuò)展: xPredicted=xPredicted/np.amax(xPredicted,axis=0)#maximumofxPredicted(ourinputdatafortheprediction) 然后,我們將創(chuàng)建一個打印我們的預(yù)測輸出的新函數(shù)xPredicted。相信與否,我們必須運行的是forward(xPredicted)返回輸出! defpredict(self): print"Predicteddatabasedontrainedweights:"; print"Input(scaled):\n"+str(xPredicted); print"Output:\n"+str(self.forward(xPredicted)); 要運行這個函數(shù),只需在for循環(huán)中調(diào)用它。 NN.predict() 如果你想保存你的訓(xùn)練重量,你可以這樣做np.savetxt: defsaveWeights(self): np.savetxt("w1.txt",self.W1,fmt="%s") np.savetxt("w2.txt",self.W2,fmt="%s") 最終的結(jié)果如下: importnumpyasnp #X=(hoursstudying,hourssleeping),y=scoreontest,xPredicted=4hoursstudying&8hourssleeping(inputdataforprediction) X=np.array(([2,9],[1,5],[3,6]),dtype=float) y=np.array(([92],[86],[89]),dtype=float) xPredicted=np.array(([4,8]),dtype=float) #scaleunits X=X/np.amax(X,axis=0)#maximumofXarray xPredicted=xPredicted/np.amax(xPredicted,axis=0)#maximumofxPredicted(ourinputdatafortheprediction) y=y/100#maxtestscoreis100 classNeural_Network(object): def__init__(self): #parameters self.inputSize=2 self.outputSize=1 self.hiddenSize=3 #weights self.W1=np.random.randn(self.inputSize,self.hiddenSize)#(3x2)weightmatrixfrominputtohiddenlayer self.W2=np.random.randn(self.hiddenSize,self.outputSize)#(3x1)weightmatrixfromhiddentooutputlayer defforward(self,X): #forwardpropagationthroughournetwork self.z=np.dot(X,self.W1)#dotproductofX(input)andfirstsetof3x2weights self.z2=self.sigmoid(self.z)#activationfunction self.z3=np.dot(self.z2,self.W2)#dotproductofhiddenlayer(z2)andsecondsetof3x1weights o=self.sigmoid(self.z3)#finalactivationfunction returno defsigmoid(self,s): #activationfunction return1/(1+np.exp(-s)) defsigmoidPrime(self,s): #derivativeofsigmoid returns*(1-s) defbackward(self,X,y,o): #backwardpropgatethroughthenetwork self.o_error=y-o#errorinoutput self.o_delta=self.o_error*self.sigmoidPrime(o)#applyingderivativeofsigmoidtoerror self.z2_error=self.o_delta.dot(self.W2.T)#z2error:howmuchourhiddenlayerweightscontributedtooutputerror self.z2_delta=self.z2_error*self.sigmoidPrime(self.z2)#applyingderivativeofsigmoidtoz2error self.W1+=X.T.dot(self.z2_delta)#adjustingfirstset(input-->hidden)weights self.W2+=self.z2.T.dot(self.o_delta)#adjustingsecondset(hidden-->output)weights deftrain(self,X,y): o=self.forward(X) self.backward(X,y,o) defsaveWeights(self): np.savetxt("w1.txt",self.W1,fmt="%s") np.savetxt("w2.txt",self.W2,fmt="%s") defpredict(self): print"Predicteddatabasedontrainedweights:"; print"Input(scaled):\n"+str(xPredicted); print"Output:\n"+str(self.forward(xPredicted)); NN=Neural_Network() foriinxrange(1000):#trainstheNN1,000times print"#"+str(i)+"\n" print"Input(scaled):\n"+str(X) print"ActualOutput:\n"+str(y) print"PredictedOutput:\n"+str(NN.forward(X)) print"Loss:\n"+str(np.mean(np.square(y-NN.forward(X))))#meansumsquaredloss print"\n" NN.train(X,y) NN.saveWeights() NN.predict() 為了看到網(wǎng)絡(luò)的實際準(zhǔn)確程度,我跑了10萬次訓(xùn)練,看看能否得到完全正確的輸出結(jié)果。這就是我得到的: #99999 Input(scaled): [[0.666666671.] [0.333333330.55555556] [1.0.66666667]] ActualOutput: [[0.92] [0.86] [0.89]] PredictedOutput: [[0.92] [0.86] [0.89]] Loss: 1.94136958194e-18 Predicteddatabasedontrainedweights: Input(scaled): [0.51.] Output: [0.91882413] 你有它!一個完整的神經(jīng)網(wǎng)絡(luò),可以學(xué)習(xí)和適應(yīng)產(chǎn)生準(zhǔn)確的輸出。雖然我們將我們的輸入視為學(xué)習(xí)和睡眠的小時數(shù),并將我們的輸出視為測試分?jǐn)?shù),但隨時可以將這些輸入更改為任何您喜歡的內(nèi)容,并觀察網(wǎng)絡(luò)的適應(yīng)情況!畢竟,所有的網(wǎng)絡(luò)都是數(shù)字。我們所做的計算雖然很復(fù)雜,但都在我們的學(xué)習(xí)模型中發(fā)揮了重要作用。(黑客周刊) |
|