深度學習二:自己寫java代碼,識別手寫數字

上一節我們自己寫代碼訓練了只有一個神經元的反相器,它雖然只有一點點代碼,但卻讓我們加深了梯度下降算法和反向傳播算法的理解。只要勇敢的邁出這一步後,我們就可以勇敢的嘗試它:深度學習中的hello wold–識別手寫數字。

只有自己寫過的代碼,才能完全的理解它的用意,不管它多爛,多糟糕,它確是完全屬於你的東西。在訓練處反相器以後,我開始大膽的嘗試自己寫一個全連接的神經網絡,來訓練手寫數字。這並不難,也不需要多少代碼,我大概花了半天的時間就寫完了所有的代碼,你也不妨來試試…
你也可以到這裏下載源碼:
mnist-java
代碼結構如下:
這裏寫圖片描述

可以看到,我的思路是這樣的:
神經網絡(NerualNetwork)由層(Layer)構成,層(Layer)由神經元構成(Nerve)。這種思路非常直觀,但它似乎並不是很好的設計,因爲代碼顯得比較繁瑣。希望你能設計出更好的結構,或許取消Nerve對象,所有邏輯都放在Layer中更好,這樣會大量用到二維數組…

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DeepLearn3Test {
	static List<DigitImage> trains = null ;
	static List<DigitImage> tests = null;
	public static void main(String[] args) {
		//load mnist
		ReadFile rf1=new ReadFile("train-labels.idx1-ubyte","train-images.idx3-ubyte");
		ReadFile rf2=new ReadFile("t10k-labels.idx1-ubyte","t10k-images.idx3-ubyte");
		try {
			tests = rf2.loadDigitImages();
			trains =rf1.loadDigitImages();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		

		int size[]={784,40,20,10};
		NeuralNetwork network = new NeuralNetwork(size);
		network.radomInitWandB();
		
		double image[] = new double[784];
		
		for(int kk=0;kk<10;kk++){
			//first: set input
			for(int count=0;count<trains.size();count++){
				for(int i=0;i<784;i++){
					image[i] = (int)(trains.get(count).imageData[i]&0xff);
				}
				network.setInput(image);
				//second: forward cal output
				double[] output = network.forwardProc();
				//third: backward cal delta
				double[] y = new double[10];
				for(int i=0;i<y.length;i++){
					if(i==trains.get(count).label){
						y[i] = 1;
					}else{
						y[i] = 0;
					}
				}
				network.backwarkProc(y);
				//fouth: update w and b
				network.updateWAndB(0.5);
			}
			System.out.println("finished train count: "+kk);
		}


		
		
		boolean isTest = true;
		//test
		if(isTest){
			int countCorrect=0;
			for(int count=0;count<tests.size();count++){
				for(int i=0;i<784;i++){
					image[i] = (int)(tests.get(count).imageData[i]&0xff);
				}
				network.setInput(image);
				//second: forward cal output
				int number = network.testDigitalImage();
				if(number==tests.get(count).label)countCorrect++;
				//System.out.println("count is : "+count+"  number is: "+number+"  label is:  "+tests.get(count).label);
			}	
			System.out.println("countCorrect: "+countCorrect);
		}

	}
}

代碼的思路非常簡單:
1、load mnist
裝在mnist的代碼我是從網上找到的,我不知道怎麼寫,非常感謝牛人的分享。
2、構建神經網絡
這裏構建了一個四層的神經網絡

int size[]={784,40,20,10};

第一層有784個神經元,對應784個像素,中間有兩個隱藏層,輸出層有10個神經元,對應0~9 共10個數字。

2、訓練
2-1 設置輸入

network.setInput(image);

2-1 計算輸出

double[] output = network.forwardProc();

2-2 反向傳播計算誤差

network.backwarkProc(y);

2-3 跟新權重和偏置

network.updateWAndB(0.5);

反覆重複2中的四步,實現對神經網絡的訓練。訓練完成後,進行測試:
測試只需要計算輸出,然後比對輸出是否正確即可。
這裏寫圖片描述

經過訓練以後,這個神經網絡的能正確識別6945個數字,總共是10000個,因此準確率接近70%。對深度學習而言,這並不是值得興奮的結果,但是,也有值得興奮的地方。想想,如果不經過訓練,我們的神經網絡識別的準確率應該是隨機的,應該在10%左右,這意味着,我們的神經網絡會學習了,雖然它還不夠聰明,考試的成績還不夠好,但他似乎已經找到了方向,他變得可以教育了,這讓我對他的未來充滿期待…


我最近重寫的卷積神經網絡CupCnn,在mnist數據集上準確率已經能達到99%了,CupCnn也是用java寫的,但是代碼更規範,更加模塊化,以下是CupCnn在github上的地址,歡迎大家下載:
CupCnn
更多詳情請參考我的博文:
java寫卷積神經網絡—CupCnn簡介

發佈了116 篇原創文章 · 獲贊 247 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章