BP.h
#ifndef _BP_H_
#define _BP_H_
#include
#define LAYER 3 //三层神经网络
#define NUM 10 //每层的最多节点数
#define A 30.0
#define B 10.0 //A和B是S型函数的参数
#define ITERS 1000 //最大训练次数
#define ETA_W 0.0035 //权值调整率
#define ETA_B 0.001 //阀值调整率
#define ERROR 0.002 //单个样本允许的误差
#define ACCU 0.005 //每次迭代允许的误差
#define Type double
#define Vector std::vector
struct Data
{
Vector x; //输入数据
Vector y; //输出数据
};
class BP{
public:
void GetData(const Vector);
void Train();
Vector ForeCast(const Vector);
private:
void InitNetWork(); //初始化网络
void GetNums(); //获取输入、输出和隐含层节点数
void ForwardTransfer(); //正向传播子过程
void ReverseTransfer(int); //逆向传播子过程
void CalcDelta(int); //计算w和b的调整量
void UpdateNetWork(); //更新权值和阀值
Type GetError(int); //计算单个样本的误差
Type GetAccu(); //计算所有样本的精度
Type Sigmoid(const Type); //计算Sigmoid的值
private:
int in_num; //输入层节点数
int ou_num; //输出层节点数
int hd_num; //隐含层节点数
Vector data; //输入输出数据
Type w[LAYER][NUM][NUM]; //BP网络的权值
Type b[LAYER][NUM]; //BP网络节点的阀值
Type x[LAYER][NUM]; //每个神经元的值经S型函数转化后的输出值,输入层就为原值
Type d[LAYER][NUM]; //记录delta学习规则中delta的值
};
#endif //_BP_H_
BP.CPP
#include
#include
#include
#include
#include "BP.h"
//获取训练所有样本数据
void BP::GetData(const Vector _data)
{
data = _data;
}
//开始进行训练
void BP::Train()
{
printf("Begin to train BP NetWork!\n");
GetNums();
InitNetWork();
int num = data.size();
for(int iter = 0; iter <= ITERS; iter++)
{
for(int cnt = 0; cnt < num; cnt++)
{
//第一层输入节点赋值
for(int i = 0; i < in_num; i++)
x[0][i] = data.at(cnt).x[i];
while(1)
{
ForwardTransfer();
if(GetError(cnt) < ERROR) //如果误差比较小,则针对单个样本跳出循环
break;
ReverseTransfer(cnt);
}
}
printf("This is the %d th trainning NetWork !\n", iter);
Type accu = GetAccu();
printf("All Samples Accuracy is %lf\n", accu);
if(accu < ACCU) break;
}
printf("The BP NetWork train End!\n");
}
//根据训练好的网络来预测输出值
Vector BP::ForeCast(const Vector data)
{
int n = data.size();
assert(n == in_num);
for(int i = 0; i < in_num; i++)
x[0][i] = data[i];
ForwardTransfer();
Vector v;
for(int i = 0; i < ou_num; i++)
v.push_back(x[2][i]);
return v;
}
//获取网络节点数
void BP::GetNums()
{
in_num = data[0].x.size(); //获取输入层节点数
ou_num = data[0].y.size(); //获取输出层节点数
hd_num = (int)sqrt((in_num + ou_num) * 1.0) + 5; //获取隐含层节点数
if(hd_num > NUM) hd_num = NUM; //隐含层数目不能超过最大设置
}
//初始化网络
void BP::InitNetWork()
{
memset(w, 0, sizeof(w)); //初始化权值和阀值为0,也可以初始化随机值
memset(b, 0, sizeof(b));
}
//工作信号正向传递子过程
void BP::ForwardTransfer()
{
//计算隐含层各个节点的输出值
for(int j = 0; j < hd_num; j++)
{
Type t = 0;
for(int i = 0; i < in_num; i++)
t += w[1][i][j] * x[0][i];
t += b[1][j];
x[1][j] = Sigmoid(t);
}
//计算输出层各节点的输出值
for(int j = 0; j < ou_num; j++)
{
Type t = 0;
for(int i = 0; i < hd_num; i++)
t += w[2][i][j] * x[1][i];
t += b[2][j];
x[2][j] = Sigmoid(t);
}
}
//计算单个样本的误差
Type BP::GetError(int cnt)
{
Type ans = 0;
for(int i = 0; i < ou_num; i++)
ans += 0.5 * (x[2][i] - data.at(cnt).y[i]) * (x[2][i] - data.at(cnt).y[i]);
return ans;
}
//误差信号反向传递子过程
void BP::ReverseTransfer(int cnt)
{
CalcDelta(cnt);
UpdateNetWork();
}
//计算所有样本的精度
Type BP::GetAccu()
{
Type ans = 0;
int num = data.size();
for(int i = 0; i < num; i++)
{
int m = data.at(i).x.size();
for(int j = 0; j < m; j++)
x[0][j] = data.at(i).x[j];
ForwardTransfer();
int n = data.at(i).y.size();
for(int j = 0; j < n; j++)
ans += 0.5 * (x[2][j] - data.at(i).y[j]) * (x[2][j] - data.at(i).y[j]);
}
return ans / num;
}
//计算调整量
void BP::CalcDelta(int cnt)
{
//计算输出层的delta值
for(int i = 0; i < ou_num; i++)
d[2][i] = (x[2][i] - data.at(cnt).y[i]) * x[2][i] * (A - x[2][i]) / (A * B);
//计算隐含层的delta值
for(int i = 0; i < hd_num; i++)
{
Type t = 0;
for(int j = 0; j < ou_num; j++)
t += w[2][i][j] * d[2][j];
d[1][i] = t * x[1][i] * (A - x[1][i]) / (A * B);
}
}
//根据计算出的调整量对BP网络进行调整
void BP::UpdateNetWork()
{
//隐含层和输出层之间权值和阀值调整
for(int i = 0; i < hd_num; i++)
{
for(int j = 0; j < ou_num; j++)
w[2][i][j] -= ETA_W * d[2][j] * x[1][i];
}
for(int i = 0; i < ou_num; i++)
b[2][i] -= ETA_B * d[2][i];
//输入层和隐含层之间权值和阀值调整
for(int i = 0; i < in_num; i++)
{
for(int j = 0; j < hd_num; j++)
w[1][i][j] -= ETA_W * d[1][j] * x[0][i];
}
for(int i = 0; i < hd_num; i++)
b[1][i] -= ETA_B * d[1][i];
}
//计算Sigmoid函数的值
Type BP::Sigmoid(const Type x)
{
return A / (1 + exp(-x / B));
}
Test.CPP
#include
#include
#include
#include "BP.h"
using namespace std;
double sample[41][4]=
{
{0,0,0,0},
{5,1,4,19.020},
{5,3,3,14.150},
{5,5,2,14.360},
{5,3,3,14.150},
{5,3,2,15.390},
{5,3,2,15.390},
{5,5,1,19.680},
{5,1,2,21.060},
{5,3,3,14.150},
{5,5,4,12.680},
{5,5,2,14.360},
{5,1,3,19.610},
{5,3,4,13.650},
{5,5,5,12.430},
{5,1,4,19.020},
{5,1,4,19.020},
{5,3,5,13.390},
{5,5,4,12.680},
{5,1,3,19.610},
{5,3,2,15.390},
{1,3,1,11.110},
{1,5,2,6.521},
{1,1,3,10.190},
{1,3,4,6.043},
{1,5,5,5.242},
{1,5,3,5.724},
{1,1,4,9.766},
{1,3,5,5.870},
{1,5,4,5.406},
{1,1,3,10.190},
{1,1,5,9.545},
{1,3,4,6.043},
{1,5,3,5.724},
{1,1,2,11.250},
{1,3,1,11.110},
{1,3,3,6.380},
{1,5,2,6.521},
{1,1,1,16.000},
{1,3,2,7.219},
{1,5,3,5.724}
};
int main()
{
Vector data;
for(int i = 0; i < 41; i++)
{
Data t;
for(int j = 0; j < 3; j++)
t.x.push_back(sample[i][j]);
t.y.push_back(sample[i][3]);
data.push_back(t);
}
BP *bp = new BP();
bp->GetData(data);
bp->Train();
while(1)
{
Vector in;
for(int i = 0; i < 3; i++)
{
Type v;
scanf("%lf", &v);
in.push_back(v);
}
Vector ou;
ou = bp->ForeCast(in);
printf("%lf\n", ou[0]);
}
return 0;
}