BP神经网络 c++实现

来源:互联网 发布:刀剑乱舞极化数据 编辑:程序博客网 时间:2024/05/17 13:10

这里写图片描述

#include <iostream>#include <cmath>#include "stdio.h"#include "stdlib.h"#include "time.h"using namespace std;#define  innode 8       //输入结点数#define  hidenode 4     //隐含结点数#define  outnode 8      //输出结点数#define  trainsample 8  //BP训练样本数class BpNet{public:    void train(double p[trainsample][innode], double t[trainsample][outnode]);//Bp训练    double p[trainsample][innode];     //输入的样本    double t[trainsample][outnode];    //样本要输出的    double *recognize(double *p);      //Bp识别    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=1.0;    e=0.0;    rate_w = 0.1;   //权值学习率(输入层--隐含层)    rate_w1 = 0.1;  //权值学习率 (隐含层--输出层)    rate_b1 = 0.1;  //隐含层阀值学习率    rate_b2 = 0.1;  //输出层阀值学习率}BpNet::~BpNet(){}//产生[low, high)之间的随机数double randval(double low, double high)  {       double val;       val = ((double)(rand() % RAND_MAX)/(double)RAND_MAX) * (high - low) + low;       return(val);   }void winit(double w[], int n) //权值初始化{    for(int i=0; i<n; i++)        w[i] = randval(-0.01, 0.01);}//初始化void BpNet::init(){    winit((double*)w, innode * hidenode);    winit((double*)w1, hidenode * outnode);    winit(b1, hidenode);    winit(b2, outnode);}//训练void BpNet::train(double p[trainsample][innode], double t[trainsample][outnode]){    double pp[hidenode];    //隐含结点的校正误差    double qq[outnode];     //希望输出值与实际输出值的偏差    double yd[outnode];     //希望输出值    double x[innode];       //输入向量    double x1[hidenode];    //隐含结点状态值    double x2[outnode];     //输出结点状态值    double o1[hidenode];    //隐含层激活值    double o2[hidenode];    //输出层激活值    for(int isamp=0; isamp<trainsample; isamp++)  //循环训练一次样品    {        int i, j, k;        for(i=0; i<innode; i++)            x[i] = p[isamp][i];     //输入的样本        for(i=0; i<outnode; i++)            yd[i] = t[isamp][i];    //希望输出的样本        //正向传播        //构造每个样品的输入和输出标准        for(j=0; j<hidenode; j++)        {            o1[j] = 0.0;            for(i=0; i< innode; i++)                o1[j] += w[i][j] * x[i];                //隐含层各单元输入激活值            x1[j] = 1.0 / (1.0 + exp(-o1[j] - b1[j]));  //隐含层各单元的输出        }        for(k=0; k<outnode; k++)        {            o2[k] = 0.0;            for(int j=0; j<hidenode; j++)                o2[k] += w1[j][k] * x1[j];              //输出层各单元输入激活值            x2[k] = 1.0 / (1.0 + exp(-o2[k] - b2[k]));  //输出层各单元输出        }        //误差反向传播        for(k=0; k<outnode; k++)  //对于网络中每个输出单元,计算误差项,并更新权值        {            qq[k] = (yd[k] - x2[k]) * x2[k] * (1-x2[k]);    //希望输出与实际输出的偏差            for(j=0; j<hidenode; j++)                w1[j][k] += rate_w1 * qq[k] * x1[j];        //更新隐含层和输出层之间的连接权        }        for(j=0; j<hidenode; j++) //对于网络中每个隐藏单元,计算误差项,并更新权值        {            pp[j] = 0.0;            for(k=0; k<outnode; k++)                pp[j] += qq[k] * w1[j][k];            pp[j] = pp[j] * x1[j] * (1 - x1[j]);    //隐含层的校正误差            for(i=0; i<innode; i++)                w[i][j] += rate_w * pp[j] * x[i];   //更新输入层和隐含层之间的连接权        }        for(k=0; k<outnode; k++)        {            e += pow(yd[k] - x2[k], 2);  //计算均方差        }        error = e/2.0;        for(k=0; k<outnode; k++)            b2[k] += rate_b2 * qq[k]; //更新隐含层和输出层之间的阈值        for(j=0; j<hidenode; j++)            b1[j] += rate_b1 * pp[j]; //更新输入层和隐含层之间的阈值    }}//识别double *BpNet::recognize(double *p){    double x[innode];       //输入向量    double x1[hidenode];    //隐含结点状态值    double x2[outnode];     //输出结点状态值    double o1[hidenode];    //隐含层激活值    double o2[hidenode];    //输出层激活值    int i, j, k;    for(i=0; i<innode; i++)        x[i] = p[i];    for(j=0; j<hidenode; j++)    {        o1[j] = 0.0;        for(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]));  //隐含层各单元输出    }    for(k=0; k<outnode; k++)    {        o2[k] = 0.0;        for(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]));  //输出层各单元输出    }    for(k=0; k<outnode; k++)    {        result[k] = x2[k];    }    return result;}//输入样本double X[trainsample][innode] = {    {1,0,0,0,0,0,0,0},    {0,1,0,0,0,0,0,0},    {0,0,1,0,0,0,0,0},    {0,0,0,1,0,0,0,0},    {0,0,0,0,1,0,0,0},    {0,0,0,0,0,1,0,0},    {0,0,0,0,0,0,1,0},    {0,0,0,0,0,0,0,1}};int main(){    srand(time(NULL));    int i, j, k;    BpNet bp;    bp.init();    int times = 0;    while(bp.error > 0.0001 && times < 5000)    {        bp.e = 0.0;        times++;        bp.train(X, X);    }    double m[innode] = {0,0,1,0,0,0,0,0};    bp.recognize(m);    for(i=0; i<innode; ++i)        cout << m[i];    cout << " is ";    for(i=0; i<outnode; i++)        printf("%d", (int)floor(bp.result[i] + 0.5));    cout << endl;    return 0;}

这里写图片描述

当将隐藏结点数设置为:13,可以识别任意2个位置为1的二进制数
这里写图片描述

这里写图片描述

这里写图片描述

参考资料:
http://www.cnblogs.com/luxiaoxun/archive/2012/12/10/2811309.html
机器学习. Tom M.Mitchell

1 0