05.08 啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

上一節,我們完成了網絡訓練代碼的實現,還有一些問題需要做進一步的確認。網絡的最終目標是,輸入一張手寫數字圖片後,網絡輸出該圖片對應的數字。由於網絡需要從0到9一共十個數字中挑選出一個,於是我們的網絡最終輸出層應該有十個節點,每個節點對應一個數字。假設圖片對應的是數字0,那麼輸出層網絡中,第一個節點應該輸出一個高百分比,其他節點輸出低百分比,如果圖片對應的數字是9,那麼輸出層最後一個節點應該輸出高百分比,其他節點輸出低百分比,例如下圖:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

當神經網絡認為圖片數字是5,那麼編號為5的輸出節點會給出0.99的高比率,如果網絡認為圖片對應的數字是0,那麼編號為0的節點輸出0.95的高比率。最後一個例子是很有意思,編號為4和9的神經元都輸出一個不低的比率,這表明圖片對應的數字很像4和9,但神經網絡認為是9的概率是4的概率的兩倍以上。

還記得上一節我們準備好要輸入網絡的數據嗎:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

數據的第一個值代表圖片對應的數字,我們需要把這種對應信息通過代碼表現出來:

#最外層有10個輸出節點
onodes = 10
targets = numpy.zeros(onodes) + 0.01
targets[int(all_values[0])] = 0.99
print(targets)

上面代碼的輸出結果為:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

targets第8個元素的值是0.99,這表示圖片對應的數字是7,記住數組是從編號0開始的。根據這種做法,我們就能把輸入圖片給對應的正確數字建立聯繫,這種聯繫就可以用於輸入到網絡中,進行訓練。由於一張圖片總共有28*28 = 764個數值,因此我們需要讓網絡的輸入層具備764個輸入節點,於是網絡的初始化以及將數據輸入網絡進行訓練的實現代碼為:

#初始化網絡
input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learning_rate = 0.3
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)
#讀入訓練數據
#open函數里的路徑根據數據存儲的路徑來設定
training_data_file = open("/Users/chenyi/Documents/人工智能/mnist_train_100.csv")
trainning_data_list = training_data_file.readlines()
training_data_file.close()
#把數據依靠','區分,並分別讀入
for record in trainning_data_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:]))/255.0 * 0.99 + 0.01
#設置圖片與數值的對應關係
targets = numpy.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99
n.train(inputs, targets)

這裡需要注意的是,中間層的節點我們選擇了100個神經元,這個選擇其實是經驗值,也就是中間層的節點數其實沒有專門的辦法去規定,其數量會根據不同的問題而變化,確定中間層神經元節點數最好的辦法是實驗,你不停的選取各種數量,看看那種數量能使得網絡的表現最好就行。

上面代碼把一百條數據輸入網絡進行訓練,現在我們看看訓練後的網絡它的表現怎樣。我們先從加載另一組數據,取出其中一張手寫數字圖片,將其輸入到網絡中,看看網絡的判斷結果如何:

test_data_file = open("/Users/chenyi/Documents/人工智能/mnist_test_10.csv")
test_data_list = test_data_file.readlines()
test_data_file.close()
import numpy
import matplotlib.pyplot
%matplotlib inline
#把數據依靠','區分,並分別讀入
all_values = data_list[0].split(',')
#第一個值對應的是圖片的表示的數字,所以我們讀取圖片數據時要去掉第一個數值
image_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
matplotlib.pyplot.imshow(image_array, cmap='Greys', interpolation='None')

這段代碼我們在上一節講解過,我們把測試數據裡面的第一張手寫數字圖片先繪製出來,代碼運行結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

通過人眼觀察,我們基本確定這種圖片對應的是數字7,那麼網絡識別它的結果如何呢,我們將這張圖片的數字輸入到網絡看看其識別結果:

n.query(numpy.asfarray(all_values[1:]) / 255.0 * 0.99 + 0.01)

上面這行代碼運行後結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

前面我們討論過最外層節點輸出的意義,最外層節點有十個,分別對應0到9十個數字,哪個節點輸出的數值高,那意味著網絡認為圖片對應哪個數字,我們看到網絡輸出中,對應編號為7的節點輸出值最大,為0.68,也就是說網絡把圖片識別為數字7,這與我們的觀察是一致的,這麼說我們辛辛苦苦打造的網絡是有效的,前面那麼多的鋪墊到現在終於有了收穫。

我們原來給網絡輸入的訓練數據來自trainning_set,而現在給網絡判斷的圖片來自testing_set,因此網絡從未見過這張圖片,它能識別這張圖片是數字7,這種能力是通過分析訓練圖片,不斷改進鏈路權重值的結果。實現網絡的Python代碼不過百來行,他居然就能實現了我們所認為的人工智能,如此看來人工智能似乎並非那麼神秘。

接著我們把所有測試圖片都輸入網絡,看看它檢測的效果如何,代碼如下:

scores = []
for record in test_data_list:
all_values = record.split(',')
correct_number = int(all_values[0])
print("該圖片對應的數字為:",correct_number)
#預處理數字圖片
inputs = (numpy.asfarray(all_values[1:])) / 255.0 * 0.99 + 0.01
#讓網絡判斷圖片對應的數字
outputs = n.query(inputs)
#找到數值最大的神經元對應的編號
label = numpy.argmax(outputs)
print("out put reslut is : ", label)
#print("網絡認為圖片的數字是:", label)
if label == correct_number:
scores.append(1)
else:
scores.append(0)
print(scores)

上面代碼把測試數據集裡的10張圖片全部加載,然後輸入到網絡中,看看網絡對每張數字圖片的識別效果如何,上面代碼運行後結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

從輸出結果看,有些圖片網絡還是識別錯了,最後代碼打印出一個數組,裡面的1表示識別正確,0表示識別錯誤,從數組內容看,有4張圖片網絡給出了錯誤答案。這次的結果多少令人有些沮喪,我們計算一下圖片判斷的成功率:

scores_array = numpy.asarray(scores)
print("perfermance = ", scores_array.sum() / scores_array.size)

代碼運行後結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

由此看來,網絡識別的成功率只有六成。為了提升成功率,我們必須加大網絡的訓練力度,原來我們訓練網絡時只使用了100條數據,現在我們使用60000條數據,然後用10000條數據作為測試集,我們從以下兩個鏈接獲取相應的數據集:

http://www.pjreddie.com/media/files/mnist_train.csv
http://www.pjreddie.com/media/files/mnist_test.csv

然後我們把原來代碼做一點小修改,加載上面的數據來對網絡進行訓練和測試:

#初始化網絡 

input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learning_rate = 0.3
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)
#讀入訓練數據
#open函數里的路徑根據數據存儲的路徑來設定
training_data_file = open("/Users/chenyi/Documents/人工智能/mnist_train.csv")
trainning_data_list = training_data_file.readlines()
print(len(trainning_data_list))
training_data_file.close()
#把數據依靠','區分,並分別讀入
for record in trainning_data_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:]))/255.0 * 0.99 + 0.01
#設置圖片與數值的對應關係
targets = numpy.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99
n.train(inputs, targets)
test_data_file = open("/Users/chenyi/Documents/人工智能/mnist_test.csv")
test_data_list = test_data_file.readlines()
test_data_file.close()
scores = []
for record in test_data_list:
all_values = record.split(',')
correct_number = int(all_values[0])
#預處理數字圖片
inputs = (numpy.asfarray(all_values[1:])) / 255.0 * 0.99 + 0.01
#讓網絡判斷圖片對應的數字
outputs = n.query(inputs)
#找到數值最大的神經元對應的編號
label = numpy.argmax(outputs)
if label == correct_number:
scores.append(1)
else:
scores.append(0)
scores_array = numpy.asarray(scores)
print("perfermance = ", scores_array.sum() / scores_array.size)

上面代碼跟以前是一樣的,只不過加載的數據文件不同而已,這次我們用60000條數據來訓練網絡,然後用10000條數據來檢測網絡的準確性,上面代碼執行後結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

從結果上看,當訓練網絡的數據流增大後,網絡識別的正確性由原來的0.6提升到0.9,我們再次用新訓練後的網絡識別原來那十張數字圖片,得到結果如下:

啟動網絡的自我訓練流程,展示網絡數字圖片識別效果

經過大數據訓練後的網絡,對圖片的識別率達到了百分之百,這意味著當用於訓練網絡的數據越多,網絡識別的效果就越好,這就是為何在某種程度上說,人工智能也是大公司的大殺器,因為只有大公司才能擁有足量的數據。

在整個過程,我們一直保持著學習率不變,實際上學習率的大小對網絡的訓練效果有很大影響,大家可以把該參數改成0.6,0.1等不同的值去看看結果,另外也可以修改中間層的節點數看看有什麼效果。

這裡我們引入在第一節時提到的一個概念叫epocs,它表示網絡進行幾次訓練循環,對其使用的代碼如下:

#加入epocs,設定網絡的訓練循環次數
epochs = 10
for e in range(epochs):
#把數據依靠','區分,並分別讀入
for record in trainning_data_list:
all_values = record.split(',')
inputs = (numpy.asfarray(all_values[1:]))/255.0 * 0.99 + 0.01
#設置圖片與數值的對應關係
targets = numpy.zeros(output_nodes) + 0.01
targets[int(all_values[0])] = 0.99
n.train(inputs, targets)

也就是在原來網絡訓練的基礎上再加上一層外循環,上面代碼運行後執行的對於普通電腦而言執行的時間會很長。一般來說,epochs 的數值越大,網絡被訓練的就越精準,但如果超過一個閾值,網絡就會引發一個過渡擬合的問題,也就是網絡會對老數據識別的很精準,但對新數據識別的效率反而變得越來越低,大家可以自行嘗試一下不同的學習率和epochs組合,看看網絡的識別精度是否有所提高,另外大家也可以修改中間層的節點數看看其對網絡的識別精度是否有顯著影響,在我電腦上把epochs設置成7時,成功率能提升到95%。


分享到:


相關文章: