亦可参看:

http://user.qzone.qq.com/459125872/blog/1367117959

程序效果参看:

http://pan.baidu.com/s/1nt9d7fV(大,下载慢)

 代码下载:

http://download.csdn.net/detail/hzq20081121107/7809827

或http://yun.baidu.com/share/link?shareid=1719680919&uk=3238536701&third=0

原理解释:

http://wenku.baidu.com/link?url=4MV-VUiIJ8Lun6tDmh-ji2OInR7M5dXQzAQdPXkvGxKPt9v-e8YsVEiGcNN_J1FZONOAg_YmNuuU1QiU4MwQt8jrexsLdrB8hA6QsgaDfo_

我的网络结构:


sigmoid及其导数:


sigmoid梯度计算:


BP过程:



三层NN的梯度下降推导:





ANN的表示:

ANN设置为3层网络,每层的神经元数量为784-100-10.

#define N0N 784
#define N1N 100
#define N2N 10
struct neuroNode
{
float I;
float O;
float Err;
float bias;
};
float pic[28*28]={0};
neuroNode node0[N0N];
neuroNode node1[N1N];
neuroNode node2[N2N];
float w01[N0N][N1N]={0};
float w12[N1N][N2N]={0};

ANN的图像保存在pic[28*28]的数组里

主要函数:

//神经网络初始化
void CANNDlg::initNet()
{
	pDC=GetDC();
	int i,j,k;
	//nn bias
	for(i=0;i<N1N;i++)
		node1[i].bias=float(rand()%100)/2000.0;
	for(i=0;i<N2N;i++)
		node2[i].bias=float(rand()%100)/2000.0;
	//nn weight
	for(i=0;i<N0N;i++)
		for(j=0;j<N1N;j++)
			w01[i][j]=float(rand()%100)/2000.0;
	for(i=0;i<N1N;i++)
		for(j=0;j<N2N;j++)
			w12[i][j]=float(rand()%100)/2000.0;
}
//读取图片数据到pic[]
void CANNDlg::getPic(CString imgPath)
{
	int i,j,k;
	BYTE *pchBuf = NULL; 
	FILE *pF  = fopen(imgPath, "rb");
	int nLen=1862;
	pchBuf = (BYTE*) malloc(sizeof(BYTE)*nLen+1); 
	nLen=fread(pchBuf,1,nLen, pF); 
	for(i=0;i<28;i++)
	{
		for(j=0;j<28;j++)
		{
			k=1078+i*28+j;
			if((pchBuf[k])>100)
				pic[j*28+(27-i)]=1;
			else
				pic[j*28+(27-i)]=0;
		}
	}
	fclose(pF);  //关闭文件 
	free(pchBuf); //释放空间
}
//单个图片的训练
void CANNDlg::train(CString img_path, int targetNum, int orderNum)
{
	CString strPicName;
	strPicName.Format("%d_%d.bmp",targetNum,orderNum);
	img_path += strPicName;
	//读入图片数据
	getPic(img_path);
	//BP前向过程
	bpForward();
	//CNN反向过程:
	bpBackward(targetNum);
}
//BP的前向过程
void CANNDlg::bpForward()
{
	int i,j,k;
	//得到输入层
	for(i=0;i<N0N;i++)
		node0[i].O=pic[i];
	//0->1层
	for(j=0;j<N1N;j++)
	{
		node1[j].I=node1[j].bias;
		for(i=0;i<N0N;i++)
		{
			node1[j].I+=w01[i][j]*node0[i].O;
		}
		node1[j].O=1.0/(1.0+exp(-node1[j].I));
	}		
	//1->2层
	for(j=0;j<N2N;j++)
	{
		node2[j].I=node2[j].bias;
		for(i=0;i<N1N;i++)
		{
			node2[j].I+=w12[i][j]*node1[i].O;//w12[i][j]表示1st层第i输入单元到2nd层第j神经单元的权重
		}
		node2[j].O=1.0/(1.0+exp(-node2[j].I));
	}	
}
//BP的反向过程
void CANNDlg::bpBackward(int targetNum)
{
	int i,j;
	//计算错误与偏量
	for(i=0;i<N2N;i++)//2nd层神经元错误计算
	{
		if(i==targetNum)
			node2[i].Err=node2[i].O*(1-node2[i].O)*(1-node2[i].O);
		else
			node2[i].Err=node2[i].O*(1-node2[i].O)*(0-node2[i].O);
		node2[i].bias+=l*node2[i].Err;
	}
	for(i=0;i<N1N;i++)//1st层神经元错误计算
	{
		node1[i].Err=0;
		for(j=0;j<N2N;j++)
		{
			node1[i].Err+=node1[i].O*(1-node1[i].O)*w12[i][j]*node2[j].Err;
		}
		node1[i].bias+=l*node1[i].Err;
	}
	//修订权重
	//w12
	for(i=0;i<N1N;i++)
	{
		for(j=0;j<N2N;j++)
		{
			float wch=0;
			wch=l*node1[i].O*node2[j].Err;
			w12[i][j]+=wch;
		}
	}
	//w01
	for(i=0;i<N0N;i++)
	{
		for(j=0;j<N1N;j++)
		{
			float wch=0;
			wch=l*node0[i].O*node1[j].Err;
			w01[i][j]+=wch;
		}
	}
}
//单个图片识别
int CANNDlg::recogFun(CString img_path, int targetNum, int orderNum)
{
	int i,j,k,ii,jj;
	//读入原图
	CString strPicName;
	strPicName.Format("%d_%d.bmp",targetNum,orderNum);
	img_path += strPicName;
	//读入图片数据
	getPic(img_path);
	//BP前向过程
	bpForward();
	//写入并返回结果
	//freopen("result.txt","a",stdout);
	float bigO = node2[0].O;
	int   bigN = 0;
	for(i=0;i<N2N;i++)
	{
		printf(" %d-%.3lf ",i,node2[i].O);
		if(bigO<node2[i].O)
		{
			bigO=node2[i].O;
			bigN=i;
		}
	}
	printf("%d_%d.bmp :%d\n",targetNum,orderNum,bigN);
	//fclose(stdout);
	return bigN;
}
//训练集验证准确率
float CANNDlg::my_verify(CString m_path)
{
	int i,j,k;
	int right=0;
	for(i=0;i<N2N;i++)
	{
		for(j=beginOrder;j<endOrder;j++)
		{

			int temp=recogFun(m_path,i,j);
			if(temp==i)
				right++;
		}
	}
	float accuracy=float(right)/float((beginOrder-endOrder)*N2N);
	return accuracy;
}
//保存网络到文件
void CANNDlg::saveNet(CString mySavePath)
{
	int i,j,k; 
	freopen(mySavePath,"w",stdout);
	//保存偏量
	printf("biasnode1\n");
	for(i=0;i<N1N;i++)
		printf("%.2f ",node1[i].bias);
	printf("\n");
	printf("biasnode2\n");
	for(i=0;i<N2N;i++)
		printf("%.2f ",node2[i].bias);
	printf("\n");
	//保存权重
	printf("w01[N0N][N1N]\n");
	for(i=0;i<N0N;i++)
	{
		for(j=0;j<N1N;j++)
		{
			printf("%.2f ",w01[i][j]);
		}
		printf("\n");
	}
	printf("w12[N1N][N2N]\n");
	for(i=0;i<N1N;i++)
	{
		for(j=0;j<N2N;j++)
		{
			printf("%.2f ",w12[i][j]);
		}
		printf("\n");
	}
	fclose(stdout);
}
//训练网络
void CANNDlg::OnBnClicked_trainnet()
{
	CString m_path;
	CFileDialog openhclDlg(TRUE,_T("bmp"),NULL,0,_T("bmp位图文件|*.*||"),this);
	if(openhclDlg.DoModal()==IDOK)
	{
		m_path=openhclDlg.GetPathName(); //得到文件目录
	}
	else
		return;
	m_path=m_path.Left(m_path.GetLength()-1);
	//枚举训练样本并进行训练
	int i,j,k;
	int t_start,t_end;
	t_start=t_end=clock();
	float iterationT = 2000;
	for(k=1;k<=iterationT;k++)
	{
		for(i=0;i<N2N;i++)
		{
			for(j=beginOrder;j<endOrder;j++)
			{	
				l=1*(iterationT-k)/iterationT;// + float(rand()%100)/1000.0;
				train(m_path,i,j);
			}
		}
		CString tempk;
		if(k%100==0)
		{
			int t_preEnd=t_end;
			t_end=clock();
			float accuracy=my_verify(m_path);
			tempk.Format("k=%d#time=%ds#%.2f#net.txt",k,(t_end-t_start)/1000,accuracy);
			saveNet(tempk);
		}
	}
}
//识别测试
void CANNDlg::OnBnClicked_recogtest()
{
	int i,j,k;
	//设置路径
	CString m_path;
	CFileDialog openhclDlg(TRUE,_T("bmp"),NULL,0,_T("bmp位图文件|*.*||"),this);
	if(openhclDlg.DoModal()==IDOK)
		m_path=openhclDlg.GetPathName();
	else return;
	m_path=m_path.Left(m_path.GetLength()-1);
	//测试识别并保存结果
	freopen("result.txt","w",stdout);
	int numRight;
	numRight   = 0;
	for(i=0;i<N2N;i++)
	{
		for(j=endOrder;j<800;j++)
		{
			int recRes=recogFun(m_path,i,j);
			printf("%d_%d.bmp :%d\n",i,j,recRes);
			if(recRes==i)
				numRight++;
		}
	}
	int testNum = (800-endOrder)*N2N;
	float accuracy = float(numRight)/float(testNum);
	printf("共%d张图片,正确%d张,准确率%f\n",testNum,numRight,accuracy);
	CString strMsg;
	strMsg.Format("共%d张图片,正确%d张,准确率%f\n",testNum,numRight,accuracy);
	MessageBox("recog done"+strMsg);
	fclose(stdout);
	system("result.txt");
	system("net.txt");
}
//读入网络
void CANNDlg::OnBnClicked_readnet()
{
	freopen("net.txt","r",stdin);
	int i,j,k;
	char cc[1024];
	//node1bias
	cin.getline(cc,1024);
	for(i=0;i<N1N;i++)
		scanf("%f ",&node1[i].bias);
	//node2bias
	cin.getline(cc,1024);
	for(i=0;i<N2N;i++)
		scanf("%f ",&node2[i].bias);
	//w01[N0N][N1N]
	cin.getline(cc,1024);
	for(i=0;i<N0N;i++)
		for(j=0;j<N1N;j++)
			scanf("%f ",&w01[i][j]);
	//w12[N1N][N2N]
	cin.getline(cc,1024);
	for(i=0;i<N1N;i++)
		for(j=0;j<N2N;j++)
			scanf("%f ",&w12[i][j]);
	fclose(stdin);
	MessageBox("read done!");
}
//保存网络
void CANNDlg::OnBnClicked_savenet()
{
	saveNet("net.txt");
}


















































Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐