BP神经网络+c代码

BP神经网络的设计应注意以下几个问题:

1.  网络的层数。一般三层网络结构就可以逼近任何有理函数。增加网络层数虽然可以提高计算精度,减少误差,但也使得网络复杂化,增加网络训练时间。如果实在想增加层数,应优先增加隐含层的神经数。

2.  隐含层的神经单元数。网络训练精度的提高,可以通过采用一个隐含层而增加神经元数的方法获得。具体设计上可以使隐含层是输入层的2倍,然后再适当增加一点余量。

3.  初始权值选择。一般区随机权值是(-1, 1)的随机数。

4.  学习速率。学习速率决定每一次循环训练所产生的权值变化量。高的学习速率可能导致系统的不稳定性,但低的学习速率导致较长的训练时间,可能收敛变慢。一般取0.01~08。可以通过比较不同速率所得到误差选择合适的值。

5.  误差选取。在网络的训练过程中,误差的选取也应当通过对比训练后确定一个合适的值,也即相对于所需要的隐含层的节点数确定。


计算步骤和原理如下图:



测试数据如下:

114.6 1.1 0.71 85.0 346
132.4 0.97 0.54 73.0 410
103.5 0.96 0.66 67.0 385
179.3 0.88 0.59 89.0 446
92.7 1.15 0.44 154.0 300
115.0 0.74 0.65 252.0 453
163.6 0.85 0.58 220.0 495
139.5 0.70 0.59 217.0 478
76.7 0.95 0.51 162.0 341
42.1 1.08 0.47 110.0 326
77.8 1.19 0.57 91.0 364
100.6 0.82 0.59 83.0 456
55.3 0.96 0.4 69.0 300
152.1 1.04 0.49 77.0 433
81.0 1.08 0.54 96.0 336
29.8 0.83 0.49 120.0 289
248.6 0.79 0.5 147.0 483
64.9 0.59 0.5 147.0 483
95.7 1.02 0.48 160.0 384
89.9 0.96 0.39 105.0 314
121.8 0.83 0.60 140.0 401
78.5 0.89 0.44 94.0 280
90.0 0.95 0.43 89.0 301


代码如下:

#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#include "vector"
using namespace std;


#define noiseVar 0.01   //噪声强度(防止过度拟合)
#define errorVar  0.001  //误差设置 
#define alpha 0.35   //学习效率
#define loopNum 10000  //最大的循环次数
#define hideNum 10  //中间层隐节点数
#define dimNum 5  //维数
#define dimIn 4   //输入层维数
#define dimOut 1   //输出层维数
#define INF 99999


typedef vector<double> doubleVector;
doubleVector maxSamp;
doubleVector minSamp;


vector<doubleVector> getFileInf(char *File);  //获取训练样本
vector<doubleVector> Normalization(vector<doubleVector> sample);  //样本归一化
double getRandNum();  //获取随机数
void startTrain(vector<doubleVector> sample);  //开始训练
void useBP(vector<doubleVector> WX, vector<doubleVector> WY);  //使用BP神经网络


void main()
{
char *File = "BP.txt";
vector<doubleVector> sample;


sample = getFileInf(File);   //获取样本
sample = Normalization(sample);  //样本归一化


startTrain(sample);  //开始训练


}




//开始训练
void startTrain(vector<doubleVector> sample)
{
int i, j, k, l ,m ,n;
vector<doubleVector> WX;  //输入层与隐层间的权值
vector<doubleVector> WY;  //隐层间与输出层的权值
doubleVector ThreX;    //输入层与隐含层之间的阈值 
doubleVector ThreY;    //输出层与隐含层之间的阈值
doubleVector temp;


//获取随机权重(0.01~0.8)
srand(time(NULL));
//输入层与隐层间的权值
for(i=0; i<hideNum; i++)
{
temp.clear();
for(j=0; j<dimIn; j++)
temp.push_back(getRandNum());
WX.push_back(temp);
}


//隐层间与输出层的权值
for(i=0; i<dimOut; i++)
{
temp.clear();
for(j=0; j<hideNum; j++)
temp.push_back(getRandNum());
WY.push_back(temp);
}


//输入层与隐含层之间的阈值 
for(i=0; i<hideNum; i++)
ThreX.push_back(getRandNum());


//输出层与隐含层之间的阈值
for(i=0; i<dimOut; i++)
ThreY.push_back(getRandNum());




//开始循环训练
double sum;
doubleVector hideOut(hideNum);  //隐含层输出
doubleVector oOut(dimOut);   //输出层输出
double oldE, newE;   //希望输出与计算输出的偏方差的均方值
doubleVector outError;  //输出层的误差
doubleVector hideError;  //隐含层的误差
int flag = 0;


oldE = newE = 0;
for(i=0; i<loopNum; i++)
{
oldE = newE;
newE = 0;
for(j=0; j<sample.size(); j++)
{
outError.clear();
outError.clear();
hideOut.clear();
oOut.clear();
//隐含层各节点的输入、输出
for(k=0; k<hideNum; k++)
{
sum = 0;
for(l=0; l<dimIn; l++)
sum += sample[j][l]*WX[l][k];
hideOut.push_back(1/(1+exp(-(sum-ThreX[k]))));
}




//输出层各节点的输入、输出
for(k=0; k<dimOut; k++)
{
sum = 0;
for(l=0; l<hideNum; l++)
sum += hideOut[l]*WY[k][l];
oOut.push_back(1/(1+exp(-sum-ThreY[k])));
}


//计算希望输出与计算输出的偏方差的均方值
for(k=0; k<dimOut; k++)
newE += (sample[j][dimIn+k]-oOut[k])*(sample[j][dimIn+k]-oOut[k])/2.0;




//计算输出层各节点的误差
for(k=0; k<dimOut; k++)
outError.push_back((sample[j][dimIn+k]-oOut[k])*oOut[k]*(1-oOut[k]));


//计算隐含层各节点误差
for(k=0; k<hideNum; k++)
{
sum = 0;
for(l=0; l<dimOut; l++)
sum += outError[l]*WY[l][k];


hideError.push_back(sum*hideOut[k]*(1-hideOut[k]));
}




//修正输入层与隐含层权值
for(m=0; m<hideNum; m++)
for(n=0; n<dimIn; n++)
WX[m][n] = WX[m][n]+alpha*hideError[m]*sample[j][n];


//修正隐层间与输出层的权值
for(m=0; m<dimOut; m++)
for(n=0; n<hideNum; n++)
WY[m][n] = WY[m][n]+alpha*outError[m]*hideOut[n];


//修正输入层与隐含层阀值
for(m=0; m<hideNum; m++)
ThreX[m] = ThreX[m]-alpha*hideError[m];


//修正隐层间与输出层的阀值
for(m=0; m<dimOut; m++)
ThreX[m] = ThreY[m]-alpha*outError[m];

}

//误差判断
if(newE/sample.size()<errorVar)
{
printf("训练结束!\n训练次数为: %d  %lf\n", i, newE);
break;
}
}


printf("隐含层权值:\n");
for(i=0; i<hideNum; i++)
{
for(j=0; j<dimIn; j++)
printf("%lf  ", WX[i][j]);
printf("\n");
}

printf("\n");


printf("输出层权值:\n");
for(i=0; i<hideNum; i++)
{
for(j=0; j<dimOut; j++)
printf("%lf  ", WX[i][j]);
printf("\n");
}


useBP(WX, WY);


}




//使用BP神经网络
void useBP(vector<doubleVector> WX, vector<doubleVector> WY)
{
int i, j;


double Input[dimIn];
doubleVector hideOut;
doubleVector oOut;
double sum;


while(1)
{
hideOut.clear();
oOut.clear();


printf("\n输入数据:\n");
for(i=0; i<dimIn; i++)
scanf("%lf", &Input[i]);


//待测样本归一化
for(i=0; i<dimIn; i++)
Input[i] = (0.002+0.996*(Input[i]-minSamp[i]))/(maxSamp[i]-minSamp[i]);




//隐含层各节点的输入、输出
for(i=0; i<hideNum; i++)
{
sum = 0;
for(j=0; j<dimIn; j++)
sum += Input[j]+WX[j][i];
hideOut.push_back(1/(1+exp(-sum)));
}

//输出层各节点的输入、输出
for(i=0; i<dimOut; i++)
{
sum = 0;
for(j=0; j<hideNum; j++)
sum += hideOut[j]*WY[i][j];
oOut.push_back(1/(1+exp(-sum)));
}


for(i=0; i<oOut.size(); i++)
oOut[i] = (oOut[i]*(maxSamp[dimIn+i]-minSamp[dimIn+i])-0.02)/0.996+minSamp[dimIn+i];


printf("期望结果:\n");
for(i=0; i<oOut.size(); i++)
printf("%lf   ", oOut[i]);
printf("\n\n");


}


}






//样本归一化
vector<doubleVector> Normalization(vector<doubleVector> sample)
{
vector<doubleVector> dst;
int i, j;


doubleVector max(dimNum, 0);
doubleVector min(dimNum, INF);
doubleVector temp;


//寻找样本最大值和最小值
for(i=0; i<dimNum; i++)
for (j=0; j<sample.size(); j++)
{
if(max[i]<sample[j][i])
max[i] = sample[j][i];
if(min[i]>sample[j][i])
min[i] = sample[j][i];
}


minSamp = min;
maxSamp = max;


//样本归一化
for(i=0; i<sample.size(); i++)
{
temp.clear();
for(j=0; j<dimNum; j++)
temp.push_back((0.002+0.996*(sample[i][j]-min[j]))/(max[j]-min[j]));


dst.push_back(temp);
}

return dst;
}




//获取文件数据
vector<doubleVector> getFileInf(char *File)
{
int i=1;
vector<doubleVector> dst;
doubleVector temp;
double num;

FILE *fp;

fp = fopen(File, "r");

if(fp == NULL)
{
printf("Open file error!\n");
exit(0);
}

//读取文件的数据
while(fscanf(fp, "%lf", &num)!=EOF)
{
temp.push_back(num);
if(i%dimNum==0)
{
dst.push_back(temp);
temp.clear();
}
i++;
}

fclose(fp);

return dst;
}




//获取随机数
double getRandNum()
{
double num;


num = rand()%RAND_MAX;
num = 0.8*num/RAND_MAX;


return num;
}


  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值