1. 程式人生 > >深度學習神經網路純C語言基礎版【轉】

深度學習神經網路純C語言基礎版【轉】

/*
	深度學習神經網路V1.0
		made by xyt
		2015/7/23
	   使用語言:C

本程式構建多層矩陣形神經網路多輸入單輸出
學習策略:隨機梯度下降
啟用函式:sigmoid
使用前必須用srand((unsigned)time(NULL))取隨機對映初始值
*/
#ifndef _DNN_H
#define _DNN_H
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
#include <time.h>
#define DNN_VEC 8  //輸入訓練組組數
#define DNN_INUM 5  //輸入維度
double dnn_sig(double in){  //sigmoid函式,此處不可變
	return 1.0/(1.0+exp(-1.0*in));
}
struct dnn_cell{  //神經元結構體
	double w[DNN_INUM];
	double wb;
	double in[DNN_INUM];
	double out;
	double error;
	double v;
	void SetCell_Default(){  //預設初始化,權值初始化很小
		int i;
		for(i=0;i<DNN_INUM;i++){
			w[i]=0.000001;
		}
		wb=0.000001;
		v=0.001;
	}
	void SetCell_InitWeight(double Initial){  //權值統一權值初始化
		int i;
		for(i=0;i<DNN_INUM;i++){
			w[i]=Initial;
		}
		wb=Initial;
		v=0.001;
	}
	void SetCell_InitAll(double Initial,double InV){  //權值統一初始化,學習速率初始化
		int i;
		for(i=0;i<DNN_INUM;i++){
			w[i]=Initial;
		}
		wb=Initial;
		v=InV;
	}
	void SetCell_Precise(double *InW,double InWb,double InV){  //權值精確初始化,學習速率初始化
		int i;
		for(i=0;i<DNN_INUM;i++){
			w[i]=InW[i];
		}
		wb=InWb;
		v=InV;
	}
	void SetIn(double *SIn){  //設定神經元輸入
		int i;
		for(i=0;i<DNN_INUM;i++){
			in[i]=SIn[i];
		}
	}
	double GetOut(){  //獲取、設定神經元輸出
		int i;
		double sum=0;
		for(i=0;i<DNN_INUM;i++){
			sum+=w[i]*in[i];
		}
		sum+=wb;
		out=dnn_sig(sum);
		return out;
	}
	void UpdateWeight(){  //更新神經元權值
		int i;
		for(i=0;i<DNN_INUM;i++){
			w[i]-=v*error*out*(1-out)*in[i];
		}
		wb=v*error*out*(1-out);
	}
	void SetError(double InErr){  //設定神經元誤差傳播值
		error=InErr;
	}
	void SetSpeed(double InV){  //設定神經元學習速率
		v=InV;
	}
};
/*  獲得前向傳播得到的輸出值,第一個引數為神經元結構體陣列,第二個引數為神經網路
層數。具體排列為:前0~DNN_INUM神經元為第一層,後面每DNN_INUM個神經元為一層,依次
排列,直至最後一個輸出神經元為單獨一層,如果層數是4,DNN_INUM=5(5輸入)則神經元
數量應為(4-1)*5+1=16個。*in引數為輸入網路的具有DNN_INUM個數據的陣列
*/
double DNN_Cal(dnn_cell *incell,int deep,double *in) 
{
	double out=0;
	int dd=0,i,j,k,count=0;
	double tmp[DNN_INUM];
	for(i=0;i<DNN_INUM;i++)  tmp[i]=in[i];
	for(j=0;j<deep-1;j++)
	{
		for(i=j*DNN_INUM;i<(j*DNN_INUM+DNN_INUM);i++)
		{
			incell[i].SetIn(tmp);
			incell[i].GetOut();
			count++;
		}
		k=0;
		for(i=j*DNN_INUM;i<(j*DNN_INUM+DNN_INUM);i++)  {tmp[k]=incell[i].out; k++;}
	}
	incell[count].SetIn(tmp);
	out=incell[count].GetOut();
	return out;
}
/*
    對輸入矩陣訓練,最後得到更新的神經網路,要求每組資料量限定為DNN_INUM資料組數限定為DNN_VEC
輸入神經原組為按層排列,除了最後一層的節點數為一其他節點數都限定為輸入向量DNN_INUM
deep為網路層數至少2層,算上最後輸出層,n為訓練次數,expect為期望,返回訓練後平均誤差
*/
double DNN_Train(dnn_cell *cell,int deep,double InMat[DNN_VEC][DNN_INUM],double *expect,int n) 
{
	double out,devi,sum;
	double de[DNN_VEC];
	int co=n,kp=-1;
	int i,j,k,tt,l;
	for(i=0;i<DNN_VEC;i++) de[i]=9.9;
	while(co--){
		kp=(int)(rand()*(double)(DNN_VEC)/RAND_MAX);
		out=DNN_Cal(cell,deep,InMat[kp]);
		devi=out-expect[kp];
		de[kp]=devi;
		//printf("%lf  %lf  %lf  %d\n",fabs(de[0]),fabs(de[3]),fabs(de[7]),kp);
		tt=(deep-1)*DNN_INUM;
		cell[tt].error=devi;
		l=0;
		for(i=(deep-2)*DNN_INUM;i<tt;i++) {cell[i].error=cell[tt].error*cell[tt].out*(1-cell[tt].out)*cell[tt].w[l];l++;}
		for(j=deep-2;j>0;j--){
			l=0;
			for(i=(j-1)*DNN_INUM;i<j*DNN_INUM;i++){
				sum=0;
				for(k=j*DNN_INUM;k<(j+1)*DNN_INUM;k++){
					sum+=cell[k].error*cell[k].out*(1-cell[k].out)*cell[k].w[l];
				}
				cell[i].error=sum;
				l++;
			}
		}
		for(i=0;i<=(deep-1)*DNN_INUM;i++){
			cell[i].UpdateWeight();
		}
		//變學習速率,可以自行更改===============================
		for(i=0;i<=(deep-1)*DNN_INUM;i++){
			cell[i].SetSpeed(fabs(devi));
		}
		//=======================================================
	}
	sum=0;
	for(i=0;i<DNN_VEC;i++) sum+=fabs(de[i]);
	return sum/DNN_VEC;
}
#endif