以下代码实现了只包含一个隐层的BP前馈神经网络。使用方法如下:
1.编写配置文件
配置文件为TXT文档,内容如下:
Layers: 3
Layer1: 2
Layer2: 2
Layer3: 2
Group: 1000
Groupt: 1000
Learningrate: 0.9
Accuracy: 0.95
iterations_outer: 100000
iter_show: 50000
xdata.txt
ydata.txt
xdata_t.txt
ydata_t.txt
其中Layers为神经网络的层数,由于只包含一个隐层,所以目前只能为3;
其后的Layer1~Layer3为各层神经元的数目;
Group为训练数据的组数;
Groupt为测试数据的组数;
Learningrate为学习率
Accuracy为设置的精度,暂时未用到
iterations_outer为训练迭代次数
iter_show为显示间隔
xdata.txt为训练用输入数据
ydata.txt为训练用输出数据
xdata_t.txt为测试用输入数据
ydata_t.txt为测试用输出数据
2.生成训练数据
用程序生成1000例训练数据以及1000例测试数据。随机产生0~10的随机数,保留两位小数。这里利用y=x这条直线将点分成两类,用1,0表示。也就是说输入数据是x,y;对应的输出是1
,0或者0,1向量。即输入层和输出层都有两个神经元,隐层神经元数目需要调试。
代码如下:
/*************************************************
COPYRIGHT NOTICE
Copyright (c) 2016.10.19, GPH
All rights reserved.
Description: 生成训练数据
*************************************************/
#include <stdio.h>
#include <time.h>
#include <fstream>
using namespace std;
/******************************************
此函数计算设计的函数的返回值
*******************************************/
double compute(double x)
{
return x;
}
/******************************************
此函数产生0到10之间的随机数,保留两位小数
*******************************************/
double random(void)
{
return rand() % 1001 / 100.0;
}
int main(int argc, char** argv)
{
srand((int)time(0));
ofstream xfile("xdata.txt");
ofstream yfile("ydata.txt");
double x, y;
x = random();
y = random();
if (y > compute(x))
{
xfile
<< x
<< endl << y;
yfile
<< 1
<< endl << 0;
}
else
{
xfile
<< x
<< endl << y;
yfile
<< 0
<< endl << 1;
}
for (int i = 1; i < 1000; i++)
{
x = random();
y = random();
if (y > compute(x))
{
xfile
<< endl << x
<< endl << y;
yfile
<< endl << 1
<< endl << 0;
}
else
{
xfile
<< endl << x
<< endl << y;
yfile
<< endl << 0
<< endl << 1;
}
}
return 0;
}
3.运行程序
函数定义了一个NN类进行处理,定义如下:
//定义神经元结构体
typedef struct Neuron {
double output; //神经元输出
double treshold; // 神经元阈值
double weight[MaxNeuronNumber]; // 与上一层个神经元的连接权重向量
double g; // 梯度向量
} Neuron;
//定义NN类
class NN {
public:
int Layers; // 模型层数
int Layer[MaxLayerNumber]; // 各层神经元数目
int group_num; //训练数据组数
int groupt_num; //测试数据组数
double learningrate; // 学习率
double accuracy; // 准确率
int inLayernum; // 输入层神经元数目
int outLayernum; // 输出层神经元数目
string xfilename; // 训练数据x数据文件名
string yfilename; // 训练数据y数据文件名
string xtfilename; // 测试数据x数据文件名
string ytfilename; // 测试数据y数据文件名
public:
int iterations_outer; // 循环次数
int iter_show; // 显示间隔
public:
Neuron neuron[MaxNeuronNumber][MaxLayerNumber]; // 神经元定义
public:
bool readmodel(char* modlefile); // 从模型文件中读入模型
bool getTraindata(void); // 从文本文件中读入训练数据
void initmodel(void); // 始化各层权值
void compute_g(int i_); // 根据一组输入计算各层输出以及梯度项
void compute_t(int i_); // 根据一组测试输入计算各层输出
void updateweights(int i_); // 更新权值
};
主函数如下:
int main(int argc, char** argv)
{
NN nn; // 定义类
// 读取模型设置
if (!nn.readmodel("model.txt")) {
cout << "Wrong model!\n";
system("pause");
return 0;
}
// 输出模型配置,等待确认
cout
<< "模型配置如下(按空格键继续):\n"
<< "Layers: " << nn.Layers << endl
<< "Layer1: " << nn.Layer[0] << endl
<< "Layer2: " << nn.Layer[1] << endl
<< "Layer3: " << nn.Layer[2] << endl
<< "Group: " << nn.group_num << endl
<< "Groupt: " << nn.groupt_num << endl
<< "xfile: " << nn.xfilename << endl
<< "yfile: " << nn.yfilename << endl
<< "xtfile: " << nn.xtfilename << endl
<< "ytfile: " << nn.ytfilename << endl;
// 监听键盘按键,退出等待
while (1)
{
if (GetAsyncKeyState(' ') && 0x8000)
{
break;
}
}
// 获取数据
if (!nn.getTraindata())
{
system("pause");
return 0;
}
nn.initmodel(); // 初始化模型
int flag_count = 1;
bool flag_return = false;
int all = nn.iterations_outer * nn.group_num / 100;
// 开始训练
for (int i = 0; i < nn.iterations_outer; i++)
{
for (int g = 0; g < nn.group_num; g++)
{
nn.compute_g(g);// 计算梯度项
nn.updateweights(g); // 更新权重
flag_count++;
// 显示训练进度
if (flag_count > nn.iter_show)
{
flag_count = 1;
double y = 0, y6 = 0;
for (int j = 0; j < nn.outLayernum; j++)
{
y += ydataarry[j][g];
y6 += nn.neuron[j][nn.Layers - 1].output;
}
cout << "Iterations %" << (double)((i * nn.group_num + g) / all) << endl;
}
// 键盘终止训练
if (GetAsyncKeyState(VK_ESCAPE) && 0x8000)
{
flag_return = true;
cout << "Keyboard interrupt!\n";
break;
}
}
if (flag_return == true)
break;
}
// 开始测试
double count_right = 0;
flag_count = 1;
int i;
for (i = 0; i < nn.groupt_num; i++)
{
flag_count++;
nn.compute_t(i); // 根据输入计算模型输出
if ( (nn.neuron[0][nn.Layers - 1].output - nn.neuron[1][nn.Layers - 1].output) * (ytdataarry[0][i] - ytdataarry[1][i]) > 0 )
{
count_right++; // 输出正确则记录
}
// 显示进度
if (flag_count > nn.iter_show)
{
flag_count = 1;
cout << "Accuracy is %" << count_right * 100.0 / i << " at iteration %" << i * 100.0 / nn.groupt_num << endl;
}
// 键盘控制退出
if (GetAsyncKeyState(' ') && 0x8000)
{
flag_return = true;
cout << "Keyboard interrupt!\n";
break;
}
}
cout << "Accuracy is %" << count_right * 100.0 / i << " at iteration %" << i * 100.0 / nn.groupt_num << endl;
system("pause");
return 0;
}// end for main()
4.附录
相关VS工程在这里下载。欢迎交流^_^