CupCnn 添加rnn的實現

github地址:

CupDnn地址(給個小星星唄^~^)

RNN的原理?

。。。。嗯。。。不想多說,很多介紹其原理的文章,所以這裏就不囉嗦了。

爲什麼推薦CupDnn中實現的rnn?

足夠簡單,可能是最簡單的實現吧,很容易學習。

有例子嗎?

有的。給的例子是計算兩個數相加。比如1+1=2 , 0.5+0.5=1。。。。

額????這需要用深度學習?不需要,但是用rnn來實現別有一番刺激。

大家可以看看使用rnn測試輸出信息:

begin load model
load model finished
please input two numbers(-1~1),input q to quit
please input first one:
0.3
please input second one:
0.3
0.3 + 0.3 = 0.6348119
please input two numbers(-1~1),input q to quit
please input first one:
0.34
please input second one:
0.12
0.34 + 0.12 = 0.49013773
please input two numbers(-1~1),input q to quit
please input first one:
0.56
please input second one:
0.91
0.56 + 0.91 = 1.44746

可以看到很明顯的是對的,雖然有一點誤差。

rnn複雜嗎?重要嗎?

不復雜,就是比全連接多了幾個狀態而已。

重要,自然語言相關的ai場景基本靠的就是rnn,用rnn搞個聊天機器人,ai寫詩,翻譯都是用rnn及其變體,把rnn原理徹底搞明白了,這些貌似很炫酷的東西都很簡單。

實現lstm,gru了嗎?

沒有,原理差不多,只是複雜點而已。

CupCnn爲什麼改名CupDnn

添加了rnn後,已經不止於搭建卷積神經網絡了,所以改名爲深度神經網絡。

實現CupDnn有什麼意義?

就是爲了學習。

CupDnn如何搭建rnn

public void buildAddNetwork() {
		InputLayer layer1 =  new InputLayer(network,2,1,1);
		network.addLayer(layer1);
		RecurrentLayer rl = new RecurrentLayer(network,RecurrentLayer.RecurrentType.RNN,2,2,100);
		network.addLayer(rl);
		FullConnectionLayer fc = new FullConnectionLayer(network,100,2);
		network.addLayer(fc);
	}
	public void buildNetwork(){
		network = new Network();
		network.setThreadNum(4);
		network.setBatch(20);
		network.setLrDecay(0.7f);
		
		network.setLoss(new MSELoss());//CrossEntropyLoss
		optimizer = new SGDOptimizer(0.9f);
		network.setOptimizer(optimizer);
		
		buildAddNetwork();

		network.prepare();
	}
	public void train(List<DataAndLabel> trainLists,int epoes) {
		network.fit(trainLists, epoes,null);
	}

	public Blob predict(Blob in) {
		return network.predict(in);
	}
	
	public void saveModel(String name){
		network.saveModel(name);
	}
	
	public void loadModel(String name){
		network = new Network();
		network.setBatch(2);
		network.loadModel(name);
		network.prepare();
	}

爲什麼用fit?沒什麼,就是train換了個名字,爲什麼不繼續用train?參數變了,必須要換名字。prdict也是一樣。

簡單介紹下這個rnn的例子?

public static Vector<DataAndLabel>genDatas(int samples) {
		Vector<DataAndLabel> dals = new Vector<DataAndLabel>();
		Random random = new Random();
		for(int i=0;i<samples;i++) {
			float a = random.nextFloat();
			if(random.nextBoolean()) {
				a = -a;
			}
			float b = random.nextFloat();
			if(random.nextBoolean()) {
				b = -b;
			}
			float[] data = new float[2];
			data[0] = a;
			data[1] = b;
			float[] label = new float[2];
			label[0] = a;
			label[1] = a+b;
			DataAndLabel tmp = new DataAndLabel(2,2);
			tmp.setData(data, label);
			dals.add(tmp);
		}
		return dals;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		AddNetwork aw = new AddNetwork();	
		aw.buildNetwork();
		aw.train(genDatas(10000), 20);
		aw.saveModel("model/rnn_add.model");
	
		aw.loadModel("model/rnn_add.model");
        Scanner sc = new Scanner(System.in);   
        while(true) {
		    System.out.println("please input two numbers(-1~1),input q to quit");  
			System.out.println("please input first one:");
			String tmp = sc.next();
			if(tmp.equals("q")) {
				break;
			}
		    float a = Float.parseFloat(tmp);
		    System.out.println("please input second one:");
		    tmp = sc.next();
			if(tmp.equals("q")) {
				break;
			}
		    float b = Float.parseFloat(tmp);
		    
		    Blob in = new Blob(1,1,1,2);
		    float[] inData = in.getData();
		    inData[0] = a;
		    inData[1] = b;
		    Blob result = aw.predict(in);
		    float[] resultData = result.getData();
		    System.out.println(a+" + "+b+" = "+resultData[1]);
        }
        System.out.println("rnn done");
	}

首先,genDatas用來生成-1~1之間的隨機數。

每次生成兩個數:(a,b)。好的,(a,b)會被送入rnn,因此rnn的seq也就是序列長度爲2。那邊標籤呢?標籤爲(a,a+b),因爲我們要計算兩個數的和。

然後構建神經網絡。

構建神經網絡的時候請注意,這裏每次送入的是(a,b)兩個數,標籤是(a,a+b),rnn的batch的神經網絡的bath/seq。

有點懵逼嗎?

public void buildAddNetwork() {
		InputLayer layer1 =  new InputLayer(network,2,1,1);
		network.addLayer(layer1);
		RecurrentLayer rl = new RecurrentLayer(network,RecurrentLayer.RecurrentType.RNN,2,2,100);
		network.addLayer(rl);
		FullConnectionLayer fc = new FullConnectionLayer(network,100,2);
		network.addLayer(fc);
	}
	public void buildNetwork(){
		network = new Network();
		network.setThreadNum(4);
		network.setBatch(20);
		network.setLrDecay(0.7f);
		
		network.setLoss(new MSELoss());//CrossEntropyLoss
		optimizer = new SGDOptimizer(0.9f);
		network.setOptimizer(optimizer);
		
		buildAddNetwork();

		network.prepare();
	}

這裏,network的batch爲20,如果是圖片,就意味着一次輸入20張圖片。但是對於rnn,因爲他的序列長度爲2,也就是它一次處理兩張圖片,所以相當於batch等於10了。所以創建rnn的時候,這裏,不要把網絡的batch設置爲奇數。不要問我爲什麼,就是這麼實現的。

因爲rnn後面接了全連接,必須把兩者兼容起來。rnn是有序列長度的,而全連接是沒有序列長度的。

我有沒有參考別人的代碼

主要參考tiny_dnn和darknet。

darknet是什麼?

darknet太棒了。用darknet實現alpha go的算法,做個圍棋機器人?是的,作者已經做了。yolo?yolo是極好的多目標檢測模型.....還可以訓練寫詩機器人,還有炫酷的nightmare。。。。作者碼代碼的能力太強了,沒有任何依賴,純c+cuda實現......

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章