如何用C语言编程实现多层前向BP神经网络用来解决逻辑XOR运算和奇偶检验问题.docx
《如何用C语言编程实现多层前向BP神经网络用来解决逻辑XOR运算和奇偶检验问题.docx》由会员分享,可在线阅读,更多相关《如何用C语言编程实现多层前向BP神经网络用来解决逻辑XOR运算和奇偶检验问题.docx(19页珍藏版)》请在冰豆网上搜索。
如何用C语言编程实现多层前向BP神经网络用来解决逻辑XOR运算和奇偶检验问题
6.
(1)试用C语言编程实现多层前向NN的BP算法。
要求:
输入、输出结点数目,隐层数目,及各隐层中结点的数目应为任意整数。
(2)试用所编出的BP算法程序训练出一个实现XOR运算的2层前向网络。
(3)用所编出的BP算法程序训练出输入矢量的维数分别为n=7和n=8的两个实现奇偶检验运算(即如题2.
(2)所述)的2层前向NN。
注:
对第6题的要求:
(i)列表给出训练收敛后的NN权值和所用的迭代次数;
(ii)给出训练收敛后的训练误差和检验误差,及用训练集和检验集做输入时所得到的正确输出率;
(iii)给出NN的学习曲线(即E(W(k))随迭代次数k的变化曲线,该结果应是用计算程序计算和打印出来的曲线,而不要是用手画出的曲线)。
(1)用C语言编程实现前向NN的BP算法
解:
解题思路:
先用C语言编程实现前向NN的BP算法,再将误差保存至文本文件,最后用MATLAB绘制出误差曲线。
(1.1)开发思路
奇偶检验问题可视为XOR问题的推广(由2输入到n输入的推广):
若n个输入中有奇数个1,则输出为1;若n个输入中有偶数个1,则输出为0。
一个2层的NN可实现奇偶检验运算。
本文选用2层神经网络,包括隐含层1层,输出层1层,来设计BP神经网络。
2层神经网络
本文隐含层和输出层的激活函数选用Sigmoid函数,
,
其函数曲线如下所示:
由奇偶检验问题的定义:
可定义如下分类函数:
其中y为BP神经网络的输出值,Y为分类结果。
(1.2)运行流程
本文的多层前向NN的BP算法用C语言编程实现,最后将运行结果保存成数据文件,通过MATLAB绘图显示,其运行流程图如上图所示,其源代码见附录部分。
(1.3)参数设定
输入、输出结点数目,隐层数目,及各隐层中结点的数目应为任意整数,通过宏定义改变相应的值,具体修改方式见《NeuralNetBP.h》文件,在程序运行之前,需要跳转到该文件修改具体的取值。
(2)试用所编出的BP算法程序训练出一个实现XOR运算的2层前向网络。
解:
利用
(1)中BP算法程序训练出XOR运算的2层前向网络。
(2.1)参数设定
首先进入《NeuralNetBP.h》文件通过宏定义改变相应的值,包括输入、输出结点数目,隐层数目,及各隐层中结点的数目。
//XOR2
#defineIN_COUT2//输入向量维数
#defineOUT_COUT1//输出向量维数
#defineIMPLY_NUM1//隐含层层数
#defineSampleTrain4//训练样本数量
#defineSampleTest4//测试样本数量
#defineNN_ImplyCout3//隐含层节点数
#defineNN_Rate0.5//学习速率
#defineNN_Error0.001//精度控制参数
#defineNN_LOOP100000//最大循环次数
(2.1)程序训练结果
对所有样本进行训练,取隐含层节点数为3,运行结果如下:
BP神经网络的学习曲线如下:
可以看出BP神经网络的误差很快收敛至0。
为了测试BP神经网络的有效性,取10次运算的平均值,其正确率如下图所示:
定义正确率:
其中,A为正确率,n=测试值和真实值相等的数量,N为参与测试的样本数量。
由上图可以看出,10次测试的正确率都是A=1,有理由相信,BP神经网络所训练出来的参数是正确的。
(2.3)XOR运算
使用2层BP神经网络,NN的取隐含层节点数为3,示意图如下所示:
两层神经网络实现逻辑异或运算(XOR)的真值表如下所示:
x1
x2
y
0
0
0
0
1
1
1
0
1
1
1
0
计算公式如下:
经过28582次迭代后,可求得其权值取值如下:
(3)用所编出的BP算法程序训练出输入矢量的维数分别为n=7和n=8的两个实现奇偶检验运算(即如题2.
(2)所述)的2层前向NN。
解:
n=7和n=8的两个实现奇偶检验运算的2层前向NN,完全相同,本文以n=7为例进行说明。
(3.1)参数设定
首先进入《NeuralNetBP.h》文件通过宏定义改变相应的值,包括输入、输出结点数目,隐层数目,及各隐层中结点的数目。
//XOR7
#defineIN_COUT7//输入向量维数
#defineOUT_COUT1//输出向量维数
#defineIMPLY_NUM1//隐含层层数
#defineSampleTrain128//训练样本数量用0-127共128组数据全部参加训练
#defineSampleTest128//测试样本数量用0-127共128组数据全部参加测试
#defineNN_ImplyCout25//隐含层节点数
#defineNN_Rate0.4//学习速率
#defineNN_Error0.001//精度控制参数
#defineNN_LOOP100000//最大循环次数
(3.2)程序训练结果
7位2进制数数,共有128个样本,对所有样本进行训练,取隐含层节点数为25,运行结果如下:
经过85857次迭代学习后,收敛至指定误差范围内。
全部样本参加测试,所有的样本的输出值都能完全和真值吻合,正确率为1。
BP神经网络的学习曲线如下:
可以看出BP神经网络的误差很快收敛至0。
为了测试BP神经网络的有效性,取10次运算的平均值,其正确率如下图所示:
定义正确率:
其中,A为正确率,n=测试值和真实值相等的数量,N为参与测试的样本数量。
由上图可以看出,10次测试的正确率均值为0.967,有理由相信,BP神经网络所训练出来的参数是正确的。
附录
一、《"NeuralNetBP.h"》
/*
参数定义
*/
#pragmaonce
#ifndef_NEURALNETBP_H
#define_NEURALNETBP_H
////XOR2
//#defineIN_COUT2//输入向量维数
//#defineOUT_COUT1//输出向量维数
//#defineIMPLY_NUM1//隐含层层数
//
//#defineSampleTrain4//训练样本数量用0-127共128组数据全部参加训练
//#defineSampleTest4//测试样本数量用0-127共128组数据全部参加测试
//
//#defineNN_ImplyCout4//隐含层节点数
//#defineNN_Rate0.5//学习速率
//#defineNN_Error0.001//精度控制参数
//#defineNN_LOOP100000//最大循环次数
/*参数该变量
输入维数改变时,改变IN_COUT的值即可
同时需要修改SampleTrain、SampleTest、NN_ImplyCout的值;
本程序取:
SampleTrain=2^IN_COUT
SampleTest=2^IN_COUT
NN_ImplyCout=(2-4)*IN_COUT
*/
//XOR7
#defineIN_COUT7//输入向量维数
#defineOUT_COUT1//输出向量维数
#defineIMPLY_NUM1//隐含层层数
#defineSampleTrain128//训练样本数量用0-127共128组数据全部参加训练
#defineSampleTest128//测试样本数量用0-127共128组数据全部参加测试
#defineNN_ImplyCout25//隐含层节点数
#defineNN_Rate0.4//学习速率
#defineNN_Error0.001//精度控制参数
#defineNN_LOOP100000//最大循环次数
typedefstruct{//bp人工神经网络结构
inth;//实际使用隐层节点数
doublev[IN_COUT][50];//隐藏层权矩阵i,隐层节点最大数量为50
doublew[50][OUT_COUT];//输出层权矩阵
doublea;//学习率
doubleb;//精度控制参数
intLoopCout;//最大循环次数
intLoopItera;//实际循环次数
doubleError[NN_LOOP];//误差
}bp_nn;
intInitBp(bp_nn*bp);//初始化bp网络
intTrainBp(bp_nn*bp,intx[SampleTrain][IN_COUT],inty[SampleTrain][OUT_COUT]);//训练bp网络,样本为x,理想输出为y
intUseBp(bp_nn*bp,intInput[IN_COUT],doubleOutput[OUT_COUT]);//使用bp网络
doubleTestBp(bp_nn*bp,intx[SampleTest][IN_COUT],inty[SampleTest][OUT_COUT]);//测试bp网络
#endif
二、《"NeuralNetBP.cpp"》
/*
BP人工神经网络基本算法C语言实现
*/
#include
#include
#include
#include
#include"NeuralNetBP.h"
//神经网络激活函数
doublefnet(doublenet){
doubletemp=0;
//Sigmoid函数
temp=1.0/(1+exp(-net));
returntemp;
}
intInitBp(bp_nn*bp){//初始化bp网络
//请输入隐层节点数,最大数为50
(*bp).h=NN_ImplyCout;
//请输入学习率
(*bp).a=NN_Rate;//(*bp).a为double型数据,所以必须是lf
//请输入精度控制参数
(*bp).b=NN_Error;
//请输入最大循环次数
(*bp).LoopCout=NN_LOOP;
//产生随机数初始化权值矩阵
inti,j;
srand((unsigned)time(NULL));
for(i=0;ifor(j=0;j<(*bp).h;j++)
(*bp).v[i][j]=rand()/(double)(RAND_MAX);
for(i=0;i<(*bp).h;i++)
for(j=0;j(*bp).w[i][j]=rand()/(double)(RAND_MAX);
return1;
}
intTrainBp(bp_nn*bp,intx[SampleTrain][IN_COUT],inty[SampleTrain][OUT_COUT])
{
//训练bp网络,样本为x,理想输出为y
doublef=(*bp).b;//精度控制参数
doublea=(*bp).a;//学习率
inth=(*bp).h;//隐层节点数
doublev[IN_COUT][50],w[50][OUT_COUT];//权矩阵
doubleChgH[50],ChgO[OUT_COUT];//修改量矩阵
doubleO1[50],O2[OUT_COUT];//隐层和输出层输出量
intLoopCout=(*bp).LoopCout;//最大循环次数
inti,j,k,n;
doubletemp;
for(i=0;ifor(j=0;jv[i][j]=(*bp).v[i][j];
for(i=0;ifor(j=0;jw[i][j]=(*bp).w[i][j];
doublee=f+1;
for(n=0;e>f&&n{//对每个样本训练网络
e=0;
for(i=0;i{
for(k=0;ktemp=0;
for(j=0;jtemp=temp+x[i][j]*v[j][k];
O1[k]=fnet(temp);
}
for(k=0;ktemp=0;
for(j=0;jtemp=temp+O1[j]*w[j][k];
O2[k]=fnet(temp);
}
for(j=0;jChgO[j]=O2[j]*(1-O2[j])*(y[i][j]-O2[j]);
for(j=0;je=e+(y[i][j]-O2[j])*(y[i][j]-O2[j]);
for(j=0;jtemp=0;
for(k=0;ktemp=temp+w[j][k]*ChgO[k];
ChgH[j]=temp*O1[j]*(1-O1[j]);
}
for(j=0;jfor(k=0;kw[j][k]=w[j][k]+a*O1[j]*ChgO[k];
for(j=0;jfor(k=0;kv[j][k]=v[j][k]+a*x[i][j]*ChgH[k];
}
(*bp).Error[n]=e;//记录误差
if(n%10==0)
{
printf("循环次数:
%d,误差:
%f\n",n,e);
}
}
(*bp).LoopItera=n;//实际循环次数
printf("总共循环次数:
%d\n",n);
printf("调整后的隐层权矩阵:
\n");
for(i=0;ifor(j=0;jprintf("%f",v[i][j]);
printf("\n");
}
printf("调整后的输出层权矩阵:
\n");
for(i=0;ifor(j=0;jprintf("%f",w[i][j]);
printf("\n");
}
for(i=0;ifor(j=0;j(*bp).v[i][j]=v[i][j];
for(i=0;ifor(j=0;j(*bp).w[i][j]=w[i][j];
printf("bp网络训练结束!
\n\n");
return1;
}
intUseBp(bp_nn*bp,intInput[IN_COUT],doubleOutput[OUT_COUT]){//使用bp网络
doubleO1[50];
doubleO2[OUT_COUT];//O1为隐层输出,O2为输出层输出
inti,j;
doubletemp;
for(i=0;i<(*bp).h;i++){
temp=0;
for(j=0;jtemp+=Input[j]*(*bp).v[j][i];
O1[i]=fnet(temp);
}
for(i=0;itemp=0;
for(j=0;j<(*bp).h;j++)
temp+=O1[j]*(*bp).w[j][i];
O2[i]=fnet(temp);
}
//输出值
for(i=0;i{
Output[i]=O2[i];
}
return1;
}
doubleTestBp(bp_nn*bp,intx[SampleTest][IN_COUT],inty[SampleTest][OUT_COUT])
{//使用bp网络
inti,j;
intInput[IN_COUT];
doubleOutput[OUT_COUT];//此处的输出是实际计算输出所以为double型
intyMeasure[SampleTest];
intCorrectN=0;
doubleAccuracy=0;//正确率
for(i=0;i{
for(j=0;j{
Input[j]=x[i][j];
}
UseBp(bp,Input,Output);//测试bp神经网络子函数
//结果分类
if(Output[OUT_COUT-1]>=0.5)
{
yMeasure[i]=1;
}
else
{
yMeasure[i]=0;
}
if(y[i][OUT_COUT-1]==yMeasure[i])//真值=测量值
{
CorrectN++;
}
}
Accuracy=CorrectN*1.0/SampleTest;//计算正确率
//显示测试结果
printf("n=7时,BPNN测试结果为:
\n");
printf("测试样本数:
%d\n",SampleTest);
printf("正确样本数:
%d\n",CorrectN);
printf("正确率为:
%f\n",Accuracy);
printf("\n\n");
returnAccuracy;
}
三、《"main.cpp"》
#include
#include
#include
#include
#include
#include"NeuralNetBP.h"
#include"HandleFile.h"
#include"Sample.h"
/*奇偶性判断
若n个输入中有奇数个1,则输出为1;若n个输入中有偶数个1,则输出为0。
*/
intmain()
{
intTrainX[SampleTrain][IN_COUT];
intTrainY[SampleTrain][OUT_COUT];
intTestX[SampleTest][IN_COUT];
intTestY[SampleTest][OUT_COUT];
bp_nnbp;
constintTrainTimes=1;//训练次数
doubleAccuracy[TrainTimes];//正确率
SampleTrain_Init(TrainX,TrainY);
SampleTest_Init(TestX,TestY);
//InitBp(&bp);//初始化bp网络结构
//TrainBp(&bp,TrainX,TrainY);//训练bp神经网络
//TestBp(&bp,TestX,TestY);//测试bp神经网络
//多次训练取平均值
for(inti=0;i{
InitBp(&bp);//初始化bp网络结构
TrainBp(&bp,TrainX,TrainY);//训练bp神经网络
Accuracy[i]=TestBp(&bp,TestX,TestY);//测试bp神经网络
}
//保存数据
WriteToFile_Error(&bp,"Data\\XOR7_Error.txt");//保存最后一次的误差
WriteToFile_Accuracy("Data\\XOR7_Result.txt",Accuracy,TrainTimes);//保存所有的运行结果
system("pause");
return1;
}
(注:
可编辑下载,若有不当之处,请指正,谢谢!
)