BP神经网络

输入文件为: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;
}

你可能感兴趣的:(BP神经网络)