亦可参看:
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
node1[i].bias=float(rand()%100)/2000.0;
for(i=0;i
node2[i].bias=float(rand()%100)/2000.0;
//nn weight
for(i=0;i
for(j=0;j
w01[i][j]=float(rand()%100)/2000.0;
for(i=0;i
for(j=0;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
node0[i].O=pic[i];
//0->1层
for(j=0;j
{
node1[j].I=node1[j].bias;
for(i=0;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
{
node2[j].I=node2[j].bias;
for(i=0;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
{
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
{
node1[i].Err=0;
for(j=0;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
{
for(j=0;j
{
float wch=0;
wch=l*node1[i].O*node2[j].Err;
w12[i][j]+=wch;
}
}
//w01
for(i=0;i
{
for(j=0;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
{
printf(" %d-%.3lf ",i,node2[i].O);
if(bigO
{
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
{
for(j=beginOrder;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
printf("%.2f ",node1[i].bias);
printf("\n");
printf("biasnode2\n");
for(i=0;i
printf("%.2f ",node2[i].bias);
printf("\n");
//保存权重
printf("w01[N0N][N1N]\n");
for(i=0;i
{
for(j=0;j
{
printf("%.2f ",w01[i][j]);
}
printf("\n");
}
printf("w12[N1N][N2N]\n");
for(i=0;i
{
for(j=0;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
{
for(j=beginOrder;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
{
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
scanf("%f ",&node1[i].bias);
//node2bias
cin.getline(cc,1024);
for(i=0;i
scanf("%f ",&node2[i].bias);
//w01[N0N][N1N]
cin.getline(cc,1024);
for(i=0;i
for(j=0;j
scanf("%f ",&w01[i][j]);
//w12[N1N][N2N]
cin.getline(cc,1024);
for(i=0;i
for(j=0;j
scanf("%f ",&w12[i][j]);
fclose(stdin);
MessageBox("read done!");
}
//保存网络
void CANNDlg::OnBnClicked_savenet()
{
saveNet("net.txt");
}