输入文件为:300*3(两个特征值、三种类别)
// bp1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
//#include "stdafx.h"
#include
#include
#include
using namespace std;
#define innode 2//输入结点数
#define hidenode 8//隐含结点数
#define outnode 1 //输出结点数
class BpNet
{
public:
//FILE *fdata;
//const char*filename;
void train(const char*filename);//Bp训练
//double p[innode]; //输入的一个样本
//double t[outnode]; //样本要输出的值
void recognize(const char*filename, const char*filename1);//Bp识别 filename中数据集,结果保存到filename1
void writetrain(); //写训练完的权值
void readtrain(); //读训练好的权值
BpNet();
virtual ~BpNet();
public:
void init();
double w[innode][hidenode];//隐含结点权值
double w1[hidenode][outnode];//输出结点权值
double b1[hidenode];//隐含结点阀值
double b2[outnode];//输出结点阀值
double rate_w; //权值学习率(输入层-隐含层)
double rate_w1;//权值学习率 (隐含层-输出层)
double rate_b1;//隐含层阀值学习率
double rate_b2;//输出层阀值学习率
double e;//误差计算
double error;//允许的最大误差
double result[outnode];// Bp输出
};
BpNet::BpNet()
{
error = 10;
e = 0.0;
rate_w = 0.1;
//权值学习率(输入层--隐含层)
rate_w1 = 0.1; //权值学习率 (隐含层--输出层)
rate_b1 = 0.1; //隐含层阀值学习率
rate_b2 = 0.1; //输出层阀值学习率
}
BpNet::~BpNet()
{
}
void winit(double w[], int n) //权值初始化
{
for (int i = 0; i < n; i++)
w[i] = (3.0*(double)rand() / RAND_MAX) - 1;
//w[i] = 1 / n;
}
void BpNet::init()
{
winit((double*)w, innode*hidenode);
winit((double*)w1, hidenode*outnode);
winit(b1, hidenode);
winit(b2, outnode);
}
void BpNet::train(const char *filename)
{
double pp[hidenode];//隐含结点的校正误差
double qq[outnode];//希望输出值与实际输出值的偏差
double yd[outnode];//希望输出值
double x[innode]; //输入向量
double x1[hidenode];//隐含结点状态值
double x2[outnode];//输出结点状态值
double o1[hidenode];//隐含层激活值
double o2[hidenode];//输出层激活值
//判断文件读入
//FILE *fp = fopen(filename, "rt");
FILE* fp;
fopen_s(&fp, filename, "rt");
if (fp == NULL)//文件打开失败:返回
{
exit(1);
}
const char *xx2 = "xx.txt";
//FILE * ff = fopen("xx.txt", "w+");
FILE* ff;
fopen_s(&ff, xx2, "w+");
while (!feof(fp)) {
double sample;
int colums = 3;
int i = 0;
int j = 0;
for (int c = 0; c < colums; c++) {
fscanf_s(fp, "%lf", &sample);
//cout << sample << " ";
if (c < innode&&i < innode)
x[i++] = sample;//期望输出的样本
else
if (j < outnode)
yd[j++] = sample; //输入的样本
}
//构造每个样品的输入和输出标准
for (int j = 0; j < hidenode; j++)
{
o1[j] = 0.0;
for (int i = 0; i < innode; i++)
o1[j] = o1[j] + w[i][j] * x[i];//隐含层各单元输入激活值
x1[j] = 1.0 / (1 + exp(-o1[j] - b1[j]));//隐含层各单元的输出
// if(o1[j]+b1[j]>0) x1[j]=1;
//else x1[j]=0;
}
for (int k = 0; k < outnode; k++)
{
o2[k] = 0.0;
for (int j = 0; j < hidenode; j++)
o2[k] = o2[k] + w1[j][k] * x1[j]; //输出层各单元输入激活值
x2[k] = 1.0 / (1.0 + exp(-o2[k] - b2[k])); //输出层各单元输出
fprintf(ff, "%lf\n", x2[k]);
// if(o2[k]+b2[k]>0) x2[k]=1;
// else x2[k]=0;
}
for (int k = 0; k < outnode; k++)
{
qq[k] = (yd[k] - x2[k])*x2[k] * (1 - x2[k]); //希望输出与实际输出的偏差
for (int j = 0; j < hidenode; j++)
w1[j][k] += rate_w1 * qq[k] * x1[j];//下一次的隐含层和输出层之间的新连接权
}
for (int j = 0; j < hidenode; j++)
{
pp[j] = 0.0;
for (int k = 0; k < outnode; k++)
pp[j] = pp[j] + qq[k] * w1[j][k];
pp[j] = pp[j] * x1[j] * (1 - x1[j]); //隐含层的校正误差
for (int i = 0; i < innode; i++)
w[i][j] += rate_w * pp[j] * x[i]; //下一次的输入层和隐含层之间的新连接权
}
for (int k = 0; k < outnode; k++)
{
e += fabs(yd[k] - x2[k])*fabs(yd[k] - x2[k]); //计算均方差
}
error = e / 2.0;
for (int k = 0; k < outnode; k++)
b2[k] = b2[k] + rate_b2 * qq[k]; //下一次的隐含层和输出层之间的新阈值
for (int j = 0; j < hidenode; j++)
b1[j] = b1[j] + rate_b1 * pp[j]; //下一次的输入层和隐含层之间的新阈值
}
fclose(ff);
fclose(fp);
}
void BpNet::recognize(const char*filename, const char*filename1)
{
//FILE *fp = fopen(filename, "rt");
FILE* fp;
fopen_s(&fp, filename, "rt");
if (fp == NULL)exit(1);
FILE *Rrec;
//Rrec = fopen(filename1, "w+");
fopen_s(&Rrec, filename1, "w+");
double x[innode]; //输入向量
double yd[outnode];//希望输出值
double x1[hidenode]; //隐含结点状态值
double x2[outnode]; //输出结点状态值
double o1[hidenode]; //隐含层激活值
double o2[hidenode]; //输出层激活值
int count = 0;//统计准确度
while (!feof(fp)) {
double sample;
int colums = 3;
int i = 0;
int j = 0;
for (int c = 0; c < colums; c++) {
fscanf_s(fp, "%lf", &sample);
//cout << sample << " ";
if (c < innode&&i < innode)
x[i++] = sample;//期望输出的样本
else
if (j < outnode)
yd[j++] = sample; //输入的样本
}
for (int j = 0; j < hidenode; j++)
{
o1[j] = 0.0;
for (int i = 0; i < innode; i++)
o1[j] = o1[j] + w[i][j] * x[i]; //隐含层各单元激活值
x1[j] = 1.0 / (1.0 + exp(-o1[j] - b1[j])); //隐含层各单元输出
//if(o1[j]+b1[j]>0) x1[j]=1;
// else x1[j]=0;
}
for (int k = 0; k < outnode; k++)
{
o2[k] = 0.0;
for (int j = 0; j < hidenode; j++)
o2[k] = o2[k] + w1[j][k] * x1[j];//输出层各单元激活值
x2[k] = 1.0 / (1.0 + exp(-o2[k] - b2[k]));//输出层各单元输出
//if(o2[k]+b2[k]>0) x2[k]=1;
//else x2[k]=0;
}
for (int k = 0; k < outnode; k++)
{
result[k] = x2[k];
}
if (round(result[0]*2) == round(yd[0]*2))
count++;
fprintf(Rrec, "%lf\n", round(result[0]*2));
}
fclose(Rrec);
fclose(fp);
cout << "count:" << count << endl;
}
void BpNet::writetrain()
{
FILE *stream0;
fopen_s(&stream0, "w.txt", "w+");
FILE *stream1;
fopen_s(&stream1, "w1.txt", "w+");
FILE *stream2;
fopen_s(&stream2, "b1.txt", "w+");
FILE *stream3;
fopen_s(&stream3, "b2.txt", "w+");
int i, j;
//隐含结点权值写入
if (stream0 == NULL)
{
cout << "创建文件失败!";
exit(1);
}
for (i = 0; i < innode; i++)
{
for (j = 0; j < hidenode; j++)
{
fprintf(stream0, "%f\n", w[i][j]);
}
}
fclose(stream0);
//输出结点权值写入
if ((stream1) == NULL)
{
cout << "创建文件失败!";
exit(1);
}
for (i = 0; i < hidenode; i++)
{
for (j = 0; j < outnode; j++)
{
fprintf(stream1, "%f\n", w1[i][j]);
}
}
fclose(stream1);
//隐含结点阀值写入
if ((stream2) == NULL)
{
cout << "创建文件失败!";
exit(1);
}
for (i = 0; i < hidenode; i++)
fprintf(stream2, "%f\n", b1[i]);
fclose(stream2);
//输出结点阀值写入
if ((stream3) == NULL)
{
cout << "创建文件失败!";
exit(1);
}
for (i = 0; i < outnode; i++)
fprintf(stream3, "%f\n", b2[i]);
fclose(stream3);
}
void BpNet::readtrain()
{
FILE *stream0;
fopen_s(&stream0, "w.txt", "r");
FILE *stream1;
fopen_s(&stream1, "w1.txt", "r");
FILE *stream2;
fopen_s(&stream2, "b1.txt", "r");
FILE *stream3;
fopen_s(&stream3, "b2.txt", "r");
int i, j;
//隐含结点权值读出
if ((stream0) == NULL)
{
cout << "打开文件失败!";
exit(1);
}
float wx[innode][hidenode];
for (i = 0; i < innode; i++)
{
for (j = 0; j < hidenode; j++)
{
fscanf_s(stream0, "%f", &wx[i][j]);
w[i][j] = wx[i][j];
}
}
fclose(stream0);
//输出结点权值读出
if ((stream1) == NULL)
{
cout << "打开文件失败!";
exit(1);
}
float wx1[hidenode][outnode];
for (i = 0; i < hidenode; i++)
{
for (j = 0; j < outnode; j++)
{
fscanf_s(stream1, "%f", &wx1[i][j]);
w1[i][j] = wx1[i][j];
}
}
fclose(stream1);
//隐含结点阀值读出
if ((stream2) == NULL)
{
cout << "打开文件失败!";
exit(1);
}
float xb1[hidenode];
for (i = 0; i < hidenode; i++)
{
fscanf_s(stream2, "%f", &xb1[i]);
b1[i] = xb1[i];
}
fclose(stream2);
//输出结点阀值读出
if (stream3 == NULL)
{
cout << "打开文件失败!";
exit(1);
}
float xb2[outnode];
for (i = 0; i < outnode; i++)
{
fscanf_s(stream3, "%f", &xb2[i]);
b2[i] = xb2[i];
}
fclose(stream3);
}
int main()
{
//样本文件
const char* filename = "ans.txt";
BpNet bp;
bp.init();
int times = 0;
while (bp.error > 0.01)
{
bp.e = 0.0;
times++;
bp.train(filename);
if(times%1000==0)
cout << "Times=" << times << " error=" << bp.error << endl;
}
//cout << "trainning complete..." << endl;
bp.writetrain();//保存网络
//识别
bp.readtrain();//读入网络
const char*filename1 = "ans.txt";
const char*filename2 = "testResult.txt";
bp.recognize(filename1, filename2);
return 0;
}