忘记转载的哪里的了,见谅
// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "atltime.h"
#include<iostream>
#include<cmath>
#include<fstream>
using namespace std;
#define innode 9 //输入结点数
#define hidenode 10//隐含结点数
#define sample 8//BP样本数
double allow_e = 0.001;//允许误差
class BpNet
{
public:
void train(double p[sample][innode], double t[sample]);//Bp训练
double p[sample][innode]; //输入的样本
double t[sample]; //样本要输出的
double test(double *p);//Bp识别
BpNet();
virtual ~BpNet();
public:
void init();
double w1[innode][hidenode];//隐含结点权值
double w2[hidenode];//输出结点权值
double rate_w1; //权值学习率(输入层-隐含层)
double rate_w2;//权值学习率 (隐含层-输出层)
double e;//单个样本误差计算
double error;//误差均值
double result;// Bp输出
};
BpNet::BpNet()
{
error = 0.1;
e = 0.0;
rate_w1 = 0.6; //权值学习率(输入层--隐含层)
rate_w2 = 0.6; //权值学习率 (隐含层--输出层)
}
BpNet::~BpNet()
{
}
void winit(double w[], int n) //权值初始化
{
for (int i = 0; i < n; i++)
w[i] = (rand() % 10)*0.1 - 0.5;
}
void BpNet::init()
{
winit((double*)w1, innode*hidenode);
winit((double*)w2, hidenode);
}
void BpNet::train(double p[sample][innode], double t[sample])
{
double pp[hidenode];//隐含结点的校正误差
double qq;//希望输出值与实际输出值的偏差
double yd;//希望输出值
double x[innode]; //输入向量
double x1[hidenode];//隐含结点状态值
double x2;//输出结点状态值
double o1[hidenode];//隐含层激活值
double o2;//输出层激活值
for (int isamp = 0; isamp < sample; isamp++)//循环训练一次样品
{
for (int i = 0; i < innode; i++)
x[i] = p[isamp][i]; //输入的样本
yd = t[isamp]; //期望输出的样本
//构造每个样品的输入和输出标准 ///输入层到隐层
for (int j = 0; j < hidenode; j++)
{
o1[j] = 0.0;
for (int i = 0; i < innode; i++)
o1[j] = o1[j] + w1[i][j] * x[i];//隐含层各单元输入激活值
x1[j] = 1.0 / (1 + exp(-o1[j]));//隐含层各单元的输出
}
///隐层到输出层
o2 = 0.0;
for (int j = 0; j < hidenode; j++)
o2 = o2 + w2[j] * x1[j];
x2 = 1.0 / (1.0 + exp(-o2)); //输出层各单元输出
/计算偏差并调整权值
qq = (yd - x2)*x2*(1 - x2); //希望输出与实际输出的偏差
for (int j = 0; j < hidenode; j++)
w2[j] += rate_w2*qq*x1[j]; //下一次的隐含层和输出层之间的新连接权
for (int j = 0; j < hidenode; j++)
{
pp[j] = 0.0;
pp[j] = pp[j] + qq * w2[j];
pp[j] = pp[j] * x1[j] * (1 - x1[j]); //隐含层的校正误差
for (int i = 0; i < innode; i++)
w1[i][j] += rate_w1 * pp[j] * x[i]; //下一次的输入层和隐含层之间的新连接权
}
e += fabs(yd - x2)*fabs(yd - x2) / 2;
}
error = double(e / double(sample));//计算误差均值
}
double BpNet::test(double *p)
{
double x[innode]; //输入向量
double x1[hidenode]; //隐含结点状态值
double x2; //输出结点状态值
double o1[hidenode]; //隐含层激活值
double o2; //输出层激活值
for (int i = 0; i < innode; i++)
x[i] = p[i];
for (int j = 0; j < hidenode; j++)
{
o1[j] = 0.0;
for (int i = 0; i < innode; i++)
o1[j] = o1[j] + w1[i][j] * x[i]; //隐含层各单元激活值
x1[j] = 1.0 / (1 + exp(-o1[j]));//x1[j]=1.0/(1.0+exp(-o1[j]-b1[j])); //隐含层各单元输出
}
o2 = 0.0;
for (int j = 0; j < hidenode; j++)
o2 = o2 + w2[j] * x1[j];//输出层各单元激活值
x2 = 1.0 / (1.0 + exp(-o2)); // x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
result = x2;
return result;
}
//输入样本 可改变,以实现不同函数的模拟
double X[sample][innode] = {
{ 1,1,1,-1,1,-1,-1,1,-1 },
{ 1,-1,-1,1,1,1,1,-1,-1 },
{ -1,1,-1,-1,1,-1,1,1,1 },
{ -1,-1,1,1,1,1,-1,-1,1 },
{ 1,-1,-1,1,-1,-1,1,1,1 },
{ -1,-1,1,-1,-1,1,1,1,1 },
{ 1,1,1,-1,-1,1,-1,-1,1 },
{ 1,1,1,1,-1,-1,1,-1,-1 }
};
//期望输出样本
double Y[sample] = { 1,1,1,1,0,0,0,0 };
int main()
{
BpNet bp;
bp.init();
int times = 0;
ofstream out("error.txt");
ofstream Result("result.txt");
进行训练,直到误差小于等于allow_e
while (bp.error > allow_e)
{
bp.e = 0.0;
times++;
bp.train(X, Y);
cout << "Times=" << times << " error=" << bp.error << endl;
out << bp.error << endl;
}
out.close();
cout << "trainning complete..." << endl;
进行验证
for (int k = 0; k < sample; k++)
{
double r = bp.test(X[k]);
for (int i = 0; i < innode; ++i)
{
if (X[k][i] == 1)
cout << "* ";
if (X[k][i] == -1)
cout << " ";
if ((i + 1) % 3 == 0)
cout << endl;
}
cout << "的训练结果为";
cout << bp.result << " ";
Result << bp.result << endl;
double cha[sample];
double mi = 100;
double index;
for (int i = 0; i < sample; i++)
{
//找差值最小的那个样本
cha[i] = (double)(fabs(Y[i] - bp.result));
if (cha[i] < mi)
{
mi = cha[i];
index = Y[i]; //得到对应的期望输出
}
}
cout << " 期望输出为 " << index << endl;
cout << "-------------------------------------" << endl;
}
return 0;
}