手把手教你用Python創(chuàng)建簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)(附代碼)
了解神經(jīng)網(wǎng)絡(luò)工作方式的***途徑莫過(guò)于親自創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò),本文將演示如何做到這一點(diǎn)。
神經(jīng)網(wǎng)絡(luò)(NN)又稱人工神經(jīng)網(wǎng)絡(luò)(ANN),是機(jī)器學(xué)習(xí)領(lǐng)域中基于生物神經(jīng)網(wǎng)絡(luò)概念的學(xué)習(xí)算法的一個(gè)子集。
擁有五年以上經(jīng)驗(yàn)的德國(guó)機(jī)器學(xué)習(xí)專家Andrey Bulezyuk聲稱:“神經(jīng)網(wǎng)絡(luò)正在徹底改變機(jī)器學(xué)習(xí),因?yàn)樗鼈兡軌蛟趶V泛的學(xué)科和行業(yè)中為抽象對(duì)象高效建模。”
人工神經(jīng)網(wǎng)絡(luò)基本上由以下組件組成:
- 輸入層:接收并傳遞數(shù)據(jù)
- 隱藏層
- 輸出層
- 各層之間的權(quán)重
- 每個(gè)隱藏層都有一個(gè)激活函數(shù)。在這個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)Python教程中,我們將使用Sigmoid激活函數(shù)。
神經(jīng)網(wǎng)絡(luò)有多種類型。在本項(xiàng)目中,我們將創(chuàng)建前饋或感知神經(jīng)網(wǎng)絡(luò)。這種類型的ANN直接將數(shù)據(jù)從前向后傳遞。
前饋神經(jīng)元的訓(xùn)練往往需要反向傳播,它為網(wǎng)絡(luò)提供了相應(yīng)的輸入和輸出集。當(dāng)輸入數(shù)據(jù)被傳送到神經(jīng)元時(shí),經(jīng)過(guò)處理后,產(chǎn)生一個(gè)輸出。
下面的圖表顯示了一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu):
了解神經(jīng)網(wǎng)絡(luò)如何工作的***方法是學(xué)習(xí)如何從頭開(kāi)始構(gòu)建神經(jīng)網(wǎng)絡(luò)(而不是采用任何庫(kù))。
在本文中,我們將演示如何利用Python編程語(yǔ)言創(chuàng)建一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)。
問(wèn)題
如下是一個(gè)展示問(wèn)題的表格。
我們將提供一個(gè)新的數(shù)據(jù)集,利用它訓(xùn)練神經(jīng)網(wǎng)絡(luò),從而能夠預(yù)測(cè)正確的輸出值。
正如上表所示,輸出值總是等于輸入部分中的***個(gè)值。因此,我們期望輸出的值為1。
讓我們看看是否可以使用Python代碼來(lái)得出相同的結(jié)果(你可以在本文末尾仔細(xì)閱讀這個(gè)項(xiàng)目的代碼,然后再繼續(xù)閱讀本文)。
創(chuàng)建一個(gè)NeuralNetwork類
我們將用Python創(chuàng)建一個(gè)NeuralNetwork類來(lái)訓(xùn)練神經(jīng)元,以期給出準(zhǔn)確的預(yù)測(cè)。這個(gè)類還會(huì)有其他的幫助函數(shù)。
即使我們不會(huì)在這個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)示例中使用神經(jīng)網(wǎng)絡(luò)庫(kù),我們也將導(dǎo)入numpy庫(kù)來(lái)輔助計(jì)算。
numpy庫(kù)提供了以下四種重要方法:
- exp—用于生成自然指數(shù)
- array—用于生成矩陣
- dot—用于矩陣相乘
- random—用于生成隨機(jī)數(shù)。請(qǐng)注意,我們將生成隨機(jī)數(shù),以確保它們的有效分布。
1. 應(yīng)用Sigmoid函數(shù)
我們將使用Sigmoid函數(shù),來(lái)繪制一個(gè)特征“S”型曲線,作為神經(jīng)網(wǎng)絡(luò)的激活函數(shù)。
此函數(shù)可以將任何值映射到0到1之間的值,它將有助于我們對(duì)輸入的加權(quán)和歸一化。
此后,我們將創(chuàng)建Sigmoid函數(shù)的導(dǎo)數(shù),以幫助計(jì)算權(quán)重的調(diào)整參數(shù)。
可以利用Sigmoid函數(shù)的輸出來(lái)生成它的導(dǎo)數(shù)。例如,如果輸出變量為“x”,則其導(dǎo)數(shù)為x*(1-x)。
2. 訓(xùn)練模型
這是我們教神經(jīng)網(wǎng)絡(luò)做出準(zhǔn)確預(yù)測(cè)的階段。每個(gè)輸入都有一個(gè)權(quán)重-可為正值或負(fù)值。這意味著:有較大的正權(quán)重或負(fù)權(quán)重的輸入會(huì)對(duì)結(jié)果的輸出產(chǎn)生更大的影響。請(qǐng)記住,我們最初是通過(guò)為每個(gè)隨機(jī)數(shù)分配一個(gè)權(quán)重后開(kāi)始的。
下面是這個(gè)神經(jīng)網(wǎng)絡(luò)示例的訓(xùn)練過(guò)程:
***步:從訓(xùn)練數(shù)據(jù)集中提取輸入,根據(jù)訓(xùn)練數(shù)據(jù)集的權(quán)重進(jìn)行調(diào)整,并通過(guò)一種計(jì)算神經(jīng)網(wǎng)絡(luò)輸出的方法對(duì)其進(jìn)行篩選。
第二步:計(jì)算反向傳播錯(cuò)誤率。在這種情況下,它是神經(jīng)元的預(yù)測(cè)輸出與訓(xùn)練數(shù)據(jù)集的期望輸出之間的差異。
第三步:利用誤差加權(quán)導(dǎo)數(shù)公式,根據(jù)所得到的誤差范圍,進(jìn)行了一些較小的權(quán)值調(diào)整。
第四步:對(duì)這一過(guò)程進(jìn)行15000次迭代。在每次迭代中,整個(gè)訓(xùn)練集被同時(shí)處理。
我們使用“.T”函數(shù)將矩陣從水平位置轉(zhuǎn)換為垂直位置。因此,數(shù)字將以如下方式存儲(chǔ):
最終,神經(jīng)元的權(quán)重將根據(jù)所提供的訓(xùn)練數(shù)據(jù)進(jìn)行優(yōu)化。隨后,如果讓神經(jīng)元考慮一個(gè)新的狀態(tài),與先前的狀態(tài)相同,它便可以作出一個(gè)準(zhǔn)確的預(yù)測(cè)。這就是反向傳播的方式。
打包運(yùn)行
***,NeuralNetwork類初始化成功后,可以運(yùn)行代碼了。
下面是如何在Python項(xiàng)目中創(chuàng)建神經(jīng)網(wǎng)絡(luò)的完整代碼:
- import numpy as np
- class NeuralNetwork():
- def __init__(self):
- # seeding for random number generation
- np.random.seed(1)
- #converting weights to a 3 by 1 matrix with values from -1 to 1 and mean of 0
- self.synaptic_weights = 2 * np.random.random((3, 1)) - 1
- def sigmoid(self, x):
- #applying the sigmoid function
- return 1 / (1 + np.exp(-x))
- def sigmoid_derivative(self, x):
- #computing derivative to the Sigmoid function
- return x * (1 - x)
- def train(self, training_inputs, training_outputs, training_iterations):
- #training the model to make accurate predictions while adjusting weights continually
- for iteration in range(training_iterations):
- #siphon the training data via the neuron
- output = self.think(training_inputs)
- #computing error rate for back-propagation
- error = training_outputs - output
- #performing weight adjustments
- adjustments = np.dot(training_inputs.T, error * self.sigmoid_derivative(output))
- self.synaptic_weights += adjustments
- def think(self, inputs):
- #passing the inputs via the neuron to get output
- #converting values to floats
- inputsinputs = inputs.astype(float)
- output = self.sigmoid(np.dot(inputs, self.synaptic_weights))
- return output
- if __name__ == "__main__":
- #initializing the neuron class
- neural_network = NeuralNetwork()
- print("Beginning Randomly Generated Weights: ")
- print(neural_network.synaptic_weights)
- #training data consisting of 4 examples--3 input values and 1 output
- training_inputs = np.array([[0,0,1],
- [1,1,1],
- [1,0,1],
- [0,1,1]])
- training_outputs = np.array([[0,1,1,0]]).T
- #training taking place
- neural_network.train(training_inputs, training_outputs, 15000)
- print("Ending Weights After Training: ")
- print(neural_network.synaptic_weights)
- user_input_one = str(input("User Input One: "))
- user_input_two = str(input("User Input Two: "))
- user_input_three = str(input("User Input Three: "))
- print("Considering New Situation: ", user_input_one, user_input_two, user_input_three)
- print("New Output data: ")
- print(neural_network.think(np.array([user_input_one, user_input_two, user_input_three])))
- print("Wow, we did it!")
運(yùn)行代碼之后的輸出:
這樣,我們便成功地創(chuàng)建了一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)。
神經(jīng)元首先給自己分配一些隨機(jī)權(quán)重,接著,利用訓(xùn)練實(shí)例進(jìn)行了自我訓(xùn)練。
之后,如果出現(xiàn)新的狀態(tài)[1,0,0],則它得出的數(shù)值為0.9999584。
還記得我們想要的正確答案是1嗎?
這個(gè)數(shù)值非常接近,Sigmoid函數(shù)輸出值在0到1之間。
當(dāng)然,在這個(gè)例子中,我們只使用一個(gè)神經(jīng)元網(wǎng)絡(luò)來(lái)完成簡(jiǎn)單的任務(wù)。如果我們把幾千個(gè)人工神經(jīng)網(wǎng)絡(luò)連接在一起,情況將會(huì)是怎樣呢?我們能不能完全模仿人類的思維方式呢?