大四做毕设,编不出来来不及了,求有耐心高手帮忙(关于用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,谢谢了!









