在该题的程序设计中采用了文件相关的操作,记录了相关学习和测试信息数据。权值用伪随机数函数随机产生(范围是(0,0.5))
采用结构体及链表来实现神经网络的结构
分为实例结构体、层结构体和网络结构体
数据结构的设计参照了《人工神经网络原理》(马锐编著,北京:机械工业出版社,2010,7)一书
学习算法的优化也参照该书
采用学习效率自适应调整算法优化源程序的学习算法,以减少学习次数
由于能力和知识有限,该程序存在较大漏洞误差,在调整学习率时,不好掌握调节系数
初始权值的限定范围适中,则程序的学习次数将明显减少
在随机赋初始权值(0,0.5)时,学习次数可调节至135,但对测试数据的判别效果不理想,没有采用
#include
#include
#include
#include
#define TRUE 1
#define FALSE 0
#define NUM_LAYERS 4
#define NUM 20 //训练实例个数
#define N 2 //输入层单元数
#define M 2 //输出层单元数
int Units[NUM_LAYERS] = {N,3,3,M}; //每层单元数
FILE *fp,*fb;
typedef struct //训练实例
{
float x[N];
float y[M];
}TRAIN;
typedef struct //网络层结构
{
int Units; //该层中单元的个数
float *Output; //第 i 个单元的输出
float *Error; //第 i 个单元的校正误差
float **Weight; //第 i 个单元的连接权值
}LAYER;
typedef struct //网络
{
LAYER **Layer; //隐层定义
LAYER *Inputlayer; //输入层
LAYER *Outputlayer; //输出层
float Error; //允许误差
float Eta; //学习率
}NET;
//初始化伪随机数发生器
void InitializeRandoms()
{
srand(4711);
return;
}
//产生随机实数并规范化
float RandomReal() //产生(-0.5,0.5)之间的随机数
{
return (float)((rand()%100)/200.0);
}
//初始化训练数据
void InitializeTrainingData(TRAIN *training)
{
int i,j;
char filename[20];
printf("\n请输入训练实例的数据文件名: \n");
gets(filename);
fb = fopen(filename,"r");
fprintf(fp,"\n\n--Saving initialization training datas ...\n");
for(i=0;i { for(j=0;j { fscanf(fb,"%f",&(training+i)->x[j]); fprintf(fp,"%10.4f",(training+i)->x[j]); } for(j=0;j { fscanf(fb,"%f",&(training+i)->y[j]); fprintf(fp,"%10.4f",(training+i)->y[j]); } fprintf(fp,"\n"); } fclose(fb); return; } //应用程序初始化 void InitializeApplication(NET *Net) { Net->Eta = (float)0.3; Net->Error = (float)0.0001; fp = fopen("BPResultData.txt","w+"); return; } //应用程序关闭时终止打开的文件 void FinalizeApplication(NET *Net) { fclose(fp); return; } //分配内存,建立网络 void GenerateNetwork(NET *Net) { int l,i; Net->Layer = (LAYER **)calloc(NUM_LAYERS,sizeof(LAYER *)); for(l=0;l { Net->Layer[l] = (LAYER *)malloc(sizeof(LAYER)); Net->Layer[l]->Units = Units[l]; Net->Layer[l]->Output = (float *) calloc(Units[l]+1,sizeof(float)); Net->Layer[l]->Error = (float *) calloc(Units[l]+1,sizeof(float)); Net->Layer[l]->Weight = (float **)calloc(Units[l]+1,sizeof(float *)); Net->Layer[l]->Output[0] = 1; if(l != 0) for(i=1;i <= Units[l];i++) //下标从"1"开始 Net->Layer[l]->Weight[i] = (float *)calloc(Units[l-1]+1,sizeof(float)); } Net->Inputlayer = Net->Layer[0]; Net->Outputlayer = Net->Layer[NUM_LAYERS - 1]; return; } //产生随机实数作为初始连接权值 void RandomWeights(NET *Net) { int l,i,j; for(l=1;l for(i=1;i <= Net->Layer[l]->Units;i++) for(j=0;j <= Net->Layer[l-1]->Units;j++) Net->Layer[l]->Weight[i][j] = RandomReal(); return; } //设置输入层的输出值 void SetInput(NET *Net,float *Input) { int i; for(i=1;i <= Net->Inputlayer->Units;i++) Net->Inputlayer->Output[i] = Input[i-1]; //输入层采用 u(x) = x return; } //设置输出层的输出值 void GetOutput(NET *Net,float *Output) { int i; for(i=1;i <= Net->Outputlayer->Units;i++) Output[i-1] = (float)(1/(1 + exp(-Net->Outputlayer->Output[i]))); //输出层采用 f(x)=1/(1+e^(-x)) return; } //层间顺传播 void PropagateLayer(NET *Net,LAYER *Lower,LAYER *Upper) { int i,j; float sum; for(i=1;i <= Upper->Units;i++) { sum = 0; for(j=1;j <= Lower->Units;j++) sum += (Upper->Weight[i][j] * Lower->Output[j]); Upper->Output[i] = (float)(1/(1 + exp(-sum))); } return; } //整个网络所有层间的顺传播 void PropagateNet(NET *Net) { int l; for(l=0;l < NUM_LAYERS-1;l++) PropagateLayer(Net,Net->Layer[l],Net->Layer[l+1]); return; } //计算输出层误差 void ComputeOutputError(NET *Net,float *target) { int i; float Out,Err; for(i=1;i <= Net->Outputlayer->Units;i++) { Out = Net->Outputlayer->Output[i]; Err = target[i-1] - Out; Net->Outputlayer->Error[i] = Out*(1-Out)*Err; } return; } //层间逆传播 void BackpropagateLayer(NET *Net,LAYER *Upper,LAYER *Lower) { int i,j; float Out,Err; for(i=1;i <= Lower->Units;i++) { Out = Lower->Output[i]; Err = 0; for(j=1;j <= Upper->Units;j++) Err += (Upper->Weight[j][i] * Upper->Error[j]); Lower->Error[i] = Out*(1-Out)*Err; } return; } //整个网络所有层间的逆传播 void BackpropagateNet(NET *Net) { int l; for(l=NUM_LAYERS-1;l>1;l--) BackpropagateLayer(Net,Net->Layer[l],Net->Layer[l-1]); return; } //权值调整 void AdjustWeights(NET *Net) { int l,i,j; float Out,Err; for(l=1;l for(i=1;i <= Net->Layer[l]->Units;i++) for(j=0;j <= Net->Layer[l-1]->Units;j++) { Out = Net->Layer[l-1]->Output[j]; Err = Net->Layer[l]->Error[i]; Net->Layer[l]->Weight[i][j] += (Net->Eta*Err*Out); } return; } //网络处理过程 void SimulateNet(NET *Net,float *Input,float *Output,float *target,int TrainOrNot) { SetInput(Net,Input); //输入数据 PropagateNet(Net); //模式顺传播 GetOutput(Net,Output); //形成输出 ComputeOutputError(Net,target); //计算输出误差 if(TrainOrNot) { BackpropagateNet(Net); //误差逆传播 AdjustWeights(Net); //调整权值 } return; } //训练过程 void TrainNet(NET *Net,TRAIN *training) { int l,i,j,k; int count=0,flag=0; float Output[M],outputfront[M],ERR,err,sum; do { flag = 0; sum = 0; ERR = 0; if(count >= 1) for(j=0;j outputfront[j]=Output[j]; SimulateNet(Net,(training+(count%NUM))->x,Output,(training+(count%NUM))->y,TRUE); if(count >= 1) { k = count%NUM; for(i=1;i <= Net->Outputlayer->Units;i++) { sum += Net->Outputlayer->Error[i]; err = (training+k-1)->y[i-1] - outputfront[i-1]; ERR += (outputfront[i-1] * (1 - outputfront[i-1]) * err); } if(sum <= ERR) Net->Eta = (float)(0.9999 * Net->Eta); else Net->Eta = (float)(1.0015 * Net->Eta); } if(count >= NUM) { for(k=1;k <= M;k++) if(Net->Outputlayer->Error[k] > Net->Error) { flag=1; break; } if(k>M) flag=0; } count++; }while(flag || count <= NUM); fprintf(fp,"\n\n\n"); fprintf(fp,"--training results ... \n"); fprintf(fp,"training times: %d\n",count); fprintf(fp,"\n*****the final weights*****\n"); for(l=1;l { for(i=1;i <= Net->Layer[l]->Units;i++) { for(j=1;j <= Net->Layer[l-1]->Units;j++) fprintf(fp,"%15.6f",Net->Layer[l]->Weight[i][j]); fprintf(fp,"\n"); } fprintf(fp,"\n\n"); } } //评估过程 void EvaluateNet(NET *Net) { int i; printf("\n\n("); fprintf(fp,"\n\n("); for(i=1;i <= Net->Inputlayer->Units;i++) { printf(" %.4f",Net->Inputlayer->Output[i]); fprintf(fp,"%10.4f",Net->Inputlayer->Output[i]); } printf(")\t"); fprintf(fp,")\t"); for(i=1;i <= Net->Outputlayer->Units;i++) { if(fabs(Net->Outputlayer->Output[i] - 1.0) <= 0.0499) { printf("肯定是第 %d 类, ",i); fprintf(fp,"肯定是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.9) <= 0.0499) { printf("几乎是第 %d 类, ",i); fprintf(fp,"几乎是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.8) <= 0.0499) { printf("极是第 %d 类, ",i); fprintf(fp,"极是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.7) <= 0.0499) { printf("很是第 %d 类, ",i); fprintf(fp,"很是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.6) <= 0.0499) { printf("相当是第 %d 类, ",i); fprintf(fp,"相当是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.5) <= 0.0499) { printf("差不多是第 %d 类, ",i); fprintf(fp,"差不多是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.4) <= 0.0499) { printf("比较像是第 %d 类, ",i); fprintf(fp,"比较像是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.3) <= 0.0499) { printf("有些像是第 %d 类, ",i); fprintf(fp,"有些像是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.2) <= 0.0499) { printf("有点像是第 %d 类, ",i); fprintf(fp,"有点像是第 %d 类, ",i); } if(fabs(Net->Outputlayer->Output[i] - 0.1) <= 0.0499) { printf("稍稍像是第 %d 类, ",i); fprintf(fp,"稍稍像是第 %d 类, ",i); } if(Net->Outputlayer->Output[i] <= 0.0499) { printf("肯定不是第 %d 类, ",i); fprintf(fp,"肯定不是第 %d 类, ",i); } } printf("\n\n"); fprintf(fp,"\n\n\n"); return; } //测试过程 void TestNet(NET *Net) { TRAIN Testdata; float Output[M]; int i,j,flag=0; char select; fprintf(fp,"\n\n--Saving test datas ...\n"); do { printf("\n请输入测试数据(x1 x2 ... y1 y2 ...): \n"); for(j=0;j { scanf("%f",&Testdata.x[j]); fprintf(fp,"%10.4f",Testdata.x[j]); } for(j=0;j { scanf("%f",&Testdata.y[j]); fprintf(fp,"%10.4f",Testdata.y[j]); } fprintf(fp,"\n"); SimulateNet(Net,Testdata.x,Output,Testdata.y,FALSE); fprintf(fp,"\n--NET Output and Error of the Test Data ....\n"); for(i=1;i <= Net->Outputlayer->Units;i++) fprintf(fp,"%10.6f %10.6f\n",Net->Outputlayer->Output[i],Net->Outputlayer->Error[i]); EvaluateNet(Net); printf("\n继续测试?(y/n):\n"); getchar(); scanf("%c",&select); printf("\n"); if((select == 'y')||(select == 'Y')) flag = 1; else flag=0; }while(flag); return; } //主函数 void main() { TRAIN TrainingData[NUM]; NET Net; InitializeRandoms(); //初始化伪随机数发生器 GenerateNetwork(&Net); //建立网络 RandomWeights(&Net); //形成初始权值 InitializeApplication(&Net); //应用程序初始化,准备运行 InitializeTrainingData(TrainingData); //记录训练数据 TrainNet(&Net,TrainingData); //开始训练 TestNet(&Net); FinalizeApplication(&Net); //程序关闭,完成善后工作 return; }