大四做毕设,编不出来来不及了,求有耐心高手帮忙(关于用C语言做BP神经网络算法)
程序代码:
/****************************************************************************** ******************************************************************************/ /****************************************************************************** 声明 ******************************************************************************/ #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #include <conio.h> /****************************************************************************** 宏定义 ******************************************************************************/ typedef int BOOL; //BOOL为INT型,它是一个三值逻辑 TRUE返回>0的整数,FALSE返回0,ERROR返回-1 typedef int INT; typedef double REAL; #define FALSE 0 #define TRUE 1 #define NOT ! #define AND && #define OR || #define MIN_REAL -HUGE_VAL #define MAX_REAL +HUGE_VAL #define MIN(x,y) ((x)<(y) ? (x) : (y)) #define MAX(x,y) ((x)>(y) ? (x) : (y)) #define LO 0.1 #define HI 0.9 #define BIAS 1 #define sqr(x) ((x)*(x)) /****************************************************************************** 结构变量声明 ******************************************************************************/ typedef struct { INT Units; //层神经元数量 REAL* Output; //输出数 (即输出个矢量元素个数) REAL* Error; //本层误差 REAL** Weight; //连接权 REAL** WeightSave; //保存训练调整后的连接权 REAL** dWeight; //调整量 } LAYER; //神经网络层结构 typedef struct { LAYER** Layer; //神经网络各层指针 LAYER* InputLayer; //输入层 LAYER* OutputLayer; //输出层 REAL Alpha; //冲量参数 REAL Eta; //学习率 REAL Error; //总误差 REAL Gain; //gain of sigmoid function } NET; //神经网络 /****************************************************************************** 随机函数 ******************************************************************************/ //设置伪随机数种子 void InitializeRandoms() { srand(4711); } //产生一个LOW - High之间的伪随机整数 INT RandomEqualINT(INT Low, INT High) { return rand() % (High-Low+1) + Low; } //产生一个LOW - High之间的伪随机浮点数 REAL RandomEqualREAL(REAL Low, REAL High) { return ((REAL) rand() / RAND_MAX) * (High-Low) + Low; } /****************************************************************************** 专用代码 ******************************************************************************/ #define NUM_LAYERS 3 //网络层数 INT N=30, Hidden=20, M=1;//输入层、隐藏层、输出层神经元个数 INT Units[NUM_LAYERS]={30,20,1};//用一维数组记录各层神经元个数 #define FIRST_YEAR 1700 #define LAST_YEAR 1979 #define NUM_YEARS 280 #define TARGET_ERROR 0.0008 //目标误差 #define MAXEPOCHS 400 //最大迭代次数 #define TrainSetRate 0.75 REAL TrainError; REAL TestError; INT DataAmount; INT DataSetCount; INT TrainSetCount; INT TestSetCount; REAL** TrainInput; REAL** TrainTarget; REAL** TestInput; REAL** TestTarget; REAL* Max; REAL* Min; FILE* f;//声明文件指针 BOOL ReadData() /* Read the Data File*/ { FILE* Dataf; char DataFileName[20]; char SaveFileName[30]={"BasicBPN_"}; INT p,q; REAL ForCount; REAL data; printf("Please input the datefile name (for example sunspot.txt) and press ENTER key \n: "); scanf("%s",DataFileName); if ((Dataf = fopen(DataFileName, "r")) == NULL) { printf("Cannot open %s\n", DataFileName); return FALSE; } DataAmount =0; DataSetCount =0; while(NOT feof(Dataf)) { if(DataAmount < 3){ fscanf(Dataf, "%d", &N); fscanf(Dataf, "%d", &Hidden); fscanf(Dataf, "%d", &M); Units[0] = N; Units[1] = Hidden; Units[2] = M; DataAmount +=3; }else{ fscanf(Dataf,"%lf",&ForCount); DataAmount++; } } if((DataAmount-3)%(N+M)!=0) { printf("Your datafile format is wrong,please check it."); return FALSE; } DataSetCount = (DataAmount-3)/(N+M); TrainSetCount = (INT) floor(DataSetCount*TrainSetRate); TestSetCount = DataSetCount-TrainSetCount; TrainInput = (REAL**) calloc(TrainSetCount+1, sizeof(REAL*)); TrainTarget = (REAL**) calloc(TrainSetCount+1, sizeof(REAL*)); TestInput = (REAL**) calloc(TestSetCount+1, sizeof(REAL*)); TestTarget = (REAL**) calloc(TestSetCount+1, sizeof(REAL*)); for (p=1;p<=TrainSetCount;p++){ TrainInput[p] = (REAL*) calloc(N+1, sizeof(REAL)); TrainTarget[p] = (REAL*) calloc(M+1, sizeof(REAL)); } for (p=1;p<=TestSetCount;p++){ TestInput[p] = (REAL*) calloc(N+1, sizeof(REAL)); TestTarget[p] = (REAL*) calloc(M+1, sizeof(REAL)); } rewind(Dataf); fscanf(Dataf, "%d", &N); fscanf(Dataf, "%d", &Hidden); fscanf(Dataf, "%d", &M); while(NOT feof(Dataf)){ for (p=1; p<=TrainSetCount; p++){ for (q=1; q<=N; q++){ fscanf(Dataf,"%lf",&data); TrainInput[p][q]=data; } for (q=1; q<=M; q++){ fscanf(Dataf,"%lf",&data); TrainTarget[p][q]=data; } } for (p=1; p<=TestSetCount; p++){ for (q=1; q<=N; q++){ fscanf(Dataf,"%lf",&data); TestInput[p][q]=data; } for (q=1; q<=M; q++){ fscanf(Dataf,"%lf",&data); TestTarget[p][q]=data; } } } fclose(Dataf); strcat(SaveFileName,DataFileName); f = fopen(SaveFileName, "w"); return TRUE; } void NormalizeData() /*normalize the date of sunspots*/ { INT p,q; Max = (REAL*) calloc((N+M+1), sizeof(REAL)); Min = (REAL*) calloc((N+M+1), sizeof(REAL)); for (q=1; q<=(N+M); q++){ Max[q] = MIN_REAL; Min[q] = MAX_REAL; } for (q=1; q<=N; q++){ for (p=1; p<=TrainSetCount; p++){ Max[q] = MAX(Max[q],TrainInput[p][q]); Min[q] = MIN(Min[q],TrainInput[p][q]); } for (p=1; p<=TestSetCount; p++){ Max[q] = MAX(Max[q],TestInput[p][q]); Min[q] = MIN(Min[q],TestInput[p][q]); } } for (q=N+1; q<=N+M; q++){ for (p=1; p<TrainSetCount; p++){ Max[q] = MAX(Max[q],TrainTarget[p][q-N]); Min[q] = MIN(Min[q],TrainTarget[p][q-N]); } for (p=1; p<TestSetCount; p++){ Max[q] = MAX(Max[q],TestTarget[p][q-N]); Min[q] = MIN(Min[q],TestTarget[p][q-N]); } } for (q=1; q<=N; q++){ for (p=1; p<=TrainSetCount; p++){ TrainInput[p][q] = (TrainInput[p][q] - Min[q])/(Max[q] - Min[q])*(HI - LO) + LO; } for (p=1; p<=TestSetCount; p++){ TestInput[p][q] = ( TestInput[p][q] - Min[q])/(Max[q] - Min[q])*(HI - LO) + LO; } } for (q=N+1; q<=N+M; q++){ for (p=1; p<=TrainSetCount; p++){ TrainTarget[p][q-N] = (TrainTarget[p][q-N] - Min[q])/(Max[q] - Min[q])*(HI - LO) + LO; } for (p=1; p<=TestSetCount; p++){ TestTarget[p][q-N] = (TestTarget[p][q-N] - Min[q])/(Max[q] - Min[q])*(HI - LO)+ LO; } } } void ReverseNormalizeData(REAL* Data, INT tag) { INT q; if(tag==1){ for (q=1; q<=M; q++){ Data[q] = (Data[q] - LO)/(HI - LO) * (Max[q+N] - Min[q+N]) + Min[q+N]; } }else{ for (q=0; q<M; q++){ Data[q] = (Data[q] - LO)/(HI - LO) * (Max[q+N+1] - Min[q+N+1]) + Min[q+N+1]; } } } void InitializeApplication(NET* Net) { Net->Alpha = 0.5; Net->Eta = 0.05; Net->Gain = 1; NormalizeData(); } /****************************************************************************** //关闭文件 ******************************************************************************/ void FinalizeApplication(NET* Net) { fclose(f); } /****************************************************************************** 初始化:创建网络,为网络分配空间 ******************************************************************************/ void GenerateNetwork(NET* Net) { INT l,i; Net->Layer = (LAYER**) calloc(NUM_LAYERS, sizeof(LAYER*)); for (l=0; l<NUM_LAYERS; l++) { Net->Layer[l] = (LAYER*) malloc(sizeof(LAYER)); Net->Layer[l]->Units = Units[l]; Net->Layer[l]->Output = (REAL*) calloc(Units[l]+1, sizeof(REAL)); Net->Layer[l]->Error = (REAL*) calloc(Units[l]+1, sizeof(REAL)); Net->Layer[l]->Weight = (REAL**) calloc(Units[l]+1, sizeof(REAL*)); Net->Layer[l]->WeightSave = (REAL**) calloc(Units[l]+1, sizeof(REAL*)); Net->Layer[l]->dWeight = (REAL**) calloc(Units[l]+1, sizeof(REAL*)); Net->Layer[l]->Output[0] = BIAS; if (l != 0) { for (i=1; i<=Units[l]; i++) { Net->Layer[l]->Weight[i] = (REAL*) calloc(Units[l-1]+1, sizeof(REAL)); Net->Layer[l]->WeightSave[i] = (REAL*) calloc(Units[l-1]+1, sizeof(REAL)); Net->Layer[l]->dWeight[i] = (REAL*) calloc(Units[l-1]+1, sizeof(REAL)); } } } Net->InputLayer = Net->Layer[0];//为输入层分配指针 Net->OutputLayer = Net->Layer[NUM_LAYERS - 1];//为输出层分配指针 Net->Alpha = 0.9;//冲量参数 Net->Eta = 0.25;//学习率 Net->Gain = 1;//始终不知道是啥…… } /****************************************************************************** //随机生成联接权 ******************************************************************************/ void RandomWeights(NET* Net) { INT l,i,j; for (l=1; l<NUM_LAYERS; 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] = RandomEqualREAL(-0.5, 0.5);//随机值 } } } } /****************************************************************************** 获得输入层的输出 ******************************************************************************/ void SetInput(NET* Net, REAL* Input) { INT i; for (i=1; i<=Net->InputLayer->Units; i++) { Net->InputLayer->Output[i] = Input[i]; } } /****************************************************************************** 获得输出层的输出 ******************************************************************************/ void GetOutput(NET* Net, REAL* Output) { INT i; for (i=1; i<=Net->OutputLayer->Units; i++) { Output[i-1] = Net->OutputLayer->Output[i]; } } /****************************************************************************** 停止训练:保存连接权,防止丢失宝贵的联接权 ******************************************************************************/ void SaveWeights(NET* Net) { INT l,i,j; for (l=1; l<NUM_LAYERS; l++) { for (i=1; i<=Net->Layer[l]->Units; i++) { for (j=0; j<=Net->Layer[l-1]->Units; j++) { Net->Layer[l]->WeightSave[i][j] = Net->Layer[l]->Weight[i][j]; } } } } /****************************************************************************** 停止训练:恢复连接权,以便需要的时候可以重新调用,重组网络 ******************************************************************************/ void RestoreWeights(NET* Net) { INT l,i,j; for (l=1; l<NUM_LAYERS; 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] = Net->Layer[l]->WeightSave[i][j]; } } } } /****************************************************************************** 传播信号 ******************************************************************************/ /****************************************************************************** //计算当前层的网络输出,upper 为当前层,LOWER为前一层 ******************************************************************************/ void PropagateLayer(NET* Net, LAYER* Lower, LAYER* Upper) { INT i,j; REAL Sum; for (i=1; i<=Upper->Units; i++) { Sum = 0; for (j=0; j<=Lower->Units; j++) { Sum += Upper->Weight[i][j] * Lower->Output[j];//计算本层的净输入 } Upper->Output[i] = 1 / (1 + exp(-Net->Gain * Sum)); } } /****************************************************************************** //计算整个网络各层的输出 ******************************************************************************/ void PropagateNet(NET* Net) { INT l; for (l=0; l<NUM_LAYERS-1; l++) { PropagateLayer(Net, Net->Layer[l], Net->Layer[l+1]); } } /****************************************************************************** 传回错误 ******************************************************************************/ /****************************************************************************** //计算输出层误差,* Target是导师信号 ******************************************************************************/ void ComputeOutputError(NET* Net, REAL* Target) { INT i; REAL Out, Err; Net->Error = 0; for (i=1; i<=Net->OutputLayer->Units; i++) { Out = Net->OutputLayer->Output[i];//输出层的输出 Err = Target[i]-Out;//误差计算 Net->OutputLayer->Error[i] = Net->Gain * Out * (1-Out) * Err; //用delta规则计算误差,因为用了可导的s形函数 Net->Error += 0.5 * sqr(Err);//平方差公式 } } /****************************************************************************** 传回错误:误差反向传播 Upper 为前层,Lower为后层 ,层数值大的为前层 ******************************************************************************/ void BackpropagateLayer(NET* Net, LAYER* Upper, LAYER* Lower) { INT i,j;//循环变量 REAL 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];//误差的反馈,通过已经处理的前层的delta值和联接权去估计,有理论基础 } Lower->Error[i] = Net->Gain * Out * (1-Out) * Err;//delta规则 } } /****************************************************************************** 传回错误:整个网络误差的后传 ******************************************************************************/ void BackpropagateNet(NET* Net) { INT l;//循环变量 for (l=NUM_LAYERS-1; l>1; l--) { BackpropagateLayer(Net, Net->Layer[l], Net->Layer[l-1]);//对每层处理 } } /****************************************************************************** 传回错误:调整网络每一层的联接权 ******************************************************************************/ void AdjustWeights(NET* Net) { INT l,i,j;//循环变量 REAL Out, Err, dWeight; //记录后层的输出、当前层的输出误差、当前神经元联接权上次的调整量 for (l=1; l<NUM_LAYERS; 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];//当前层的输出误差 dWeight = Net->Layer[l]->dWeight[i][j]; //将本神经元联接权上次的调整量取出,初始值为0,初始化网络时赋值的 Net->Layer[l]->Weight[i][j] += Net->Eta * Err * Out + Net->Alpha * dWeight; //Alpha为冲量参数,加快网络的收敛速度 Net->Layer[l]->dWeight[i][j] = Net->Eta * Err * Out; //记录本次神经元联接权的调整量 } } } } /****************************************************************************** 模拟网络 ******************************************************************************/ /****************************************************************************** 训练网络 //将每个样本投入网络运作,Input是转换后的输入模式,Target为导师信号,通过布尔型 //的Training值控制是否训练 ******************************************************************************/ void SimulateNet(NET* Net, REAL* Input, REAL* Output, REAL* Target, BOOL Training) { SetInput(Net, Input);//设置输入层,获得输入层的输出 PropagateNet(Net);//计算网络各层的输出 GetOutput(Net, Output);//获得输出层的输出 ComputeOutputError(Net, Target);//计算输出层误差 if (Training) { BackpropagateNet(Net);//误差反向传播 AdjustWeights(Net);//调整联接权 } } void TrainNet(NET* Net, INT Epochs) { INT p, n; REAL* Output; Output = (REAL*) calloc(M, sizeof(REAL)); for (n=0; n<Epochs*TrainSetCount; n++) { p = RandomEqualINT(1, TrainSetCount); SimulateNet(Net, TrainInput[p], Output, TrainTarget[p], TRUE); } free (Output); } void TestNet(NET* Net) { INT Count; REAL* Output; Output = (REAL*) calloc(M, sizeof(REAL)); TrainError = 0; for (Count=1; Count<=TrainSetCount; Count++) { SimulateNet(Net, TrainInput[Count], Output, TrainTarget[Count], FALSE); TrainError += Net->Error; } TestError = 0; for (Count=1; Count<=TestSetCount; Count++) { SimulateNet(Net, TestInput[Count], Output, TestTarget[Count], FALSE); TestError += Net->Error; } fprintf(f, "\nMSE is %0.8f on Training Set and %0.8f on Test Set", TrainError/TrainSetCount, TestError/TestSetCount); free (Output); } void EvaluateNet(NET* Net) { INT Count,Begin; REAL* Output; REAL EvaluateError; Output = (REAL*) calloc(M, sizeof(REAL)); fprintf(f, "\n\n\n"); fprintf(f, "number fact Prediction \n"); fprintf(f, "\n"); EvaluateError=0; Begin =(INT) floor(TestSetCount*0.5); for (Count=Begin; Count<=TestSetCount; Count++) { SimulateNet(Net, TestInput[Count], Output, TestTarget[Count], FALSE); ReverseNormalizeData(TestTarget[Count],1); ReverseNormalizeData(Output,0); fprintf(f, "%3d %0.8f %0.8f\n", Count-Begin+1, TestTarget[Count][1], Output [0]); EvaluateError +=sqr(TestTarget[Count][1] - Output[0]); } fprintf(f, "The MSE = %0.7f \n",EvaluateError/(TestSetCount-Begin+1)); free (Output); } /* void EvaluateNet(NET* Net) { INT Year; REAL Output [M]; REAL Output_[M]; fprintf(f, "\n\n\n"); fprintf(f, "Year Sunspots Open-Loop Prediction Closed-Loop Prediction\n"); fprintf(f, "\n"); for (Year=EVAL_LWB; Year<=EVAL_UPB; Year++) { SimulateNet(Net, &(Sunspots [Year-N]), Output, &(Sunspots [Year]), FALSE); SimulateNet(Net, &(Sunspots_[Year-N]), Output_, &(Sunspots_[Year]), FALSE); Sunspots_[Year] = Output_[0]; fprintf(f, "%d %0.3f %0.3f %0.3f\n", FIRST_YEAR + Year, Sunspots[Year], Output [0], Output_[0]); } } */ /****************************************************************************** 主函数 ******************************************************************************/ /* void main() { NET Net; BOOL Stop; REAL MinTestError; InitializeRandoms(); GenerateNetwork(&Net); RandomWeights(&Net); InitializeApplication(&Net); Stop = FALSE; MinTestError = MAX_REAL; do { TrainNet(&Net, 10); TestNet(&Net); if (TestError < MinTestError) { fprintf(f, " - saving Weights ..."); MinTestError = TestError; SaveWeights(&Net); } else if (TestError > 1.2 * MinTestError) { fprintf(f, " - stopping Training and restoring Weights ..."); Stop = TRUE; RestoreWeights(&Net); } } while (NOT Stop); TestNet(&Net); EvaluateNet(&Net); FinalizeApplication(&Net); } */ int main() { NET Net;//网络变量声明 BOOL Stop;//学习是否结束的控制变量 REAL MinTestError, MinTrainMSE; INT Epoch; if(ReadData()==FALSE){ printf(" Please press any key to ESC."); getch(); return 0; } InitializeRandoms();//生成随机数 GenerateNetwork(&Net);//创建网络并初始化网络,分配空间 RandomWeights(&Net);//初始化网络联接权 InitializeApplication(&Net);//初始化输入层,将学习样本转换成输入模式 Stop = FALSE; MinTestError = MAX_REAL; MinTrainMSE = MAX_REAL; Epoch=0; printf("Begin to train BP net,please wait....\n"); do { TrainNet(&Net, 10); TestNet(&Net); if (TestError < MinTestError) { fprintf(f, " - saving Parameters ..."); MinTestError = TestError; SaveWeights(&Net);//学习结束后保存宝贵的联接权 } else if (TestError > 1.2 * MinTestError) { } MinTrainMSE = TrainError /TrainSetCount; Epoch++; Stop=(MinTrainMSE <= TARGET_ERROR) || (Epoch >= MAXEPOCHS); } while (!Stop); fprintf(f, "\n - stopping Training at %d epoch and restoring Parameters ...",Epoch); RestoreWeights(&Net); TestNet(&Net); EvaluateNet(&Net); FinalizeApplication(&Net);//关闭文件 printf("It is over. The result is in BasicBPN.txt. \nPlease enter any key .....\n"); getch(); return 1; }先说一下我的毕设题目:RNAi片段的设计
我要做的编程分为3步:
第一步:读入一个txt文档,里面是长度可能几千的RNA序列:acgun……之类。根据MPI准则筛选出每条aa开头长度19并符合一定条件的序列放入另一个txt中。
第二步:读入刚才的结果,对每一条长度19的序列进行计算,得到6个特征值,输出到一个新的txt中,格式如:1.1 2.2 3.3 4.4 5.5 6.6
第三步:将刚才的特征向量作为输入进到BP神经网络里,这里还要分为2步:训练和测试。
前两步我做完了,现在有问题的是第三步,关于BP神经网络中的问题,纠结死我了……不会发图,好心人麻烦自己百度一下BP神经网络的结构吧……感觉我自己的问题也说不清楚了……
然后,现在我有了一个别人应用BP神经网络预测太阳黑子的框架,我要改动它的几个部分,但我自己做的有一堆错,希望好心人帮我改改看:
1.一个是读文件部分:我需要改成三个读文件的子程序,一个用于训练,两个用于测试。用于训练的子程序读的txt文件中格式是1.1 2.2 3.3 4.4 5.5 6.6 1(最后一个数字是BP神经网络的实际输出),用于测试的子程序读的就是第二步出来的txt和记载权值的txt(见2)。
2.一个是输出文件的部分:我需要改成2个输出子程序:训练之后要输出一个记载权值的txt文档,用于之后测试的时候载入权值。测试之后要输出一个带有序列编号和预测评分的txt文档。
3.自然是主函数,把刚才一系列理顺……
然后那个太阳黑子预测的程序我贴出来,我打了一些主要的注释。
我也觉得这个让大家看很考验大家,麻烦了……应该会有很多不懂吧,可以上QQ找我413084331,谢谢了!