以下代码实现了只包含一个隐层的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工程在这里下载。欢迎交流^_^