像素原本的取值范圍是0~255。
二值化就是將大于閾值(通常設為中間值127)的數值看做1,否則看做0,這樣圖片數據就轉換成了由0或者1組成的陣列。
歸一化也比較簡單,只需要將每個像素的取值除以最大值255,那么每個像素的取值空間,就變成了介于0和1之間的浮點數。
兩種手段各有利弊,江寒決定每種都試一下,看看在實踐中,哪個表現更好一些。
由于江寒使用的是全連接網絡,而不是卷積神經網絡,所以還要將2維的圖片,轉換成1維的向量。
這個步驟非常簡單,將二維的圖片像素信息,一行接一行按順序存入一維數組就行。
事實上,在解析數據文件的時候,已經順便完成了這一步,所以并不需要額外的操作。
20萬張圖片,就是20萬行數據。
將這些數據按順序放入一個200000×784的二維數組里,就得到了Feature。
Lable的處理比較簡單,定義一個具有20萬個元素的一維整形數組,按順序讀入即可。
江寒根據這次的任務需求,將20萬條訓練數據劃分成了2類。
隨機挑選了18萬個數據,作為訓練集,剩余2萬個數據,則作為驗證集validate。
這樣一來,就可以先用訓練集訓練神經網絡,學習算法,然后再用未學習過的驗證集進行測試。
根據F網絡在陌生數據上的表現,就能大體推斷出提交給主辦方后,在真正的測試集上的表現。
寫完數據文件解析函數,接下來,就可以構建“帶隱藏層的全連接人工神經網絡”F了。
類似的程序,江寒當初為了寫論文,編寫過許多次。
可這一次有所不同。
這是真正的實戰,必須將理論上的性能優勢,轉化為實實在在、有說服力的成績。
因此必須認真一些。
打造一個神經網絡,首先需要確定模型的拓撲結構。
輸入層有多少個神經元?
輸出層有多少個神經元?
設置多少個隱藏層?
每個隱藏層容納多少個神經元?
這都是在初始設計階段,就要確定的問題。
放在MNIST數據集上,輸入層毫無疑問,應該與每張圖片的大小相同。
也就是說,一共有784個輸入神經元,每個神經元負責讀取一個像素的取值。
輸出層的神經元個數,一般應該與輸出結果的分類數相同。
數字手寫識別,是一個10分類任務,共有10種不同的輸出,因此,輸出層就應該擁有10個神經元。
當輸出層的某個神經元被激活時,就代表圖片被識別為其所代表的數字。
這里一般用softmax函數實現多分類。
先把來自上一層的輸入,映射為0~1之間的實數,進行歸一化處理,保證多分類的概率之和剛好為1。
然后用softmax分別計算10個數字的概率,選擇其中最大的一個,激活對應的神經元,完成整個網絡的輸出。
至于隱藏層的數量,以及其中包含的神經元數目,并沒有什么一定的規范,完全可以隨意設置。
隱藏層越多,模型的學習能力和表現力就越強,但也更加容易產生過擬合。
所以需要權衡利弊,選取一個最優的方案。
起步階段,暫時先設定一個隱藏層,其中包含100個神經元,然后在實踐中,根據反饋效果慢慢調整……
確定了網絡的拓撲結構后,接下來就可以編寫代碼并調試了。
調試通過,就加載數據集,進行訓練,最后用訓練好的網絡,進行預測。
就是這么一個過程。
江寒先寫了一個標準的F模板,讓其能利用訓練數據集,進行基本的訓練。
理論上來說,可以將18萬條數據,整體放進網絡中進行訓練。
但這種做法有很多缺點。
一來消耗內存太多,二來運算壓力很大,訓練起來速度極慢。
更嚴重的是,容易發生嚴重的過擬合。
要想避免這些問題,就要采取隨機批次訓練法。