C++语言实现:BP神经网络
Vivian 2018-06-04 来源 : 阅读 690 评论 0

摘要:本文主要向大家介绍了C++语言的BP神经网络,BP神经网络是通过反向传播来逐渐修正层之间的权值和每个节点的阈值,可以通过学习率避免走入局部最优解,希望对大家学习C++语言有所帮助。

    本文主要向大家介绍了C++语言的BP神经网络,BP神经网络是通过反向传播来逐渐修正层之间的权值和每个节点的阈值,可以通过学习率避免走入局部最优解,希望对大家学习C++语言有所帮助。

#include <stdio.h>
#include <math.h>
#include
#include <iostream>
#include <string.h>
#include <vector>
#include <math.h>
 
using namespace std;
 
#define LAYER    3        //三层神经网络
#define NUM      10       //每层的最多节点数
 
#define A        30.0
#define B        10.0     //A和B是S型函数的参数
#define ITERS    10000     //最大训练次数
#define LR       0.0013   //学习率
#define ERROR    0.1    //单个样本允许的误差
 
struct Data {
    vector<double> x;       //输入数据
    vector<double> y;       //输出数据
};
 
class BP{
 
public:
 
    void GetData(const vector<data>);
    void Train();
    vector<double> ForeCast(const vector<double>);
 
private:
 
    void InitNetWork();         //初始化网络
    void GetNums();             //获取输入、输出和隐含层节点数
    void ForwardTransfer();     //正向传播子过程
    void ReverseTransfer(int);  //逆向传播子过程
    void CalcDelta(int);        //计算w和b的调整量
    void UpdateNetWork();       //更新权值和阀值
    double GetError(int);         //计算单个样本的误差
    double GetAccu();             //计算所有样本的精度
    double Sigmoid(const double);   //计算Sigmoid的值
 
private:
    int in_num;                 //输入层节点数
    int ou_num;                 //输出层节点数
    int hd_num;                 //隐含层节点数
 
    vector<data> data;          //输入输出数据
 
    double w[LAYER][NUM][NUM];    //BP网络的权值
    double b[LAYER][NUM];         //BP网络节点的阀值
 
    double x[LAYER][NUM];         //每个神经元的值经S型函数转化后的输出值,输入层就为原值
    double d[LAYER][NUM];         //记录delta学习规则中delta的值
};
 
//获取训练所有样本数据
void BP::GetData(const vector<data> _data) {
    data = _data;
}
 
//开始进行训练
void BP::Train() {
    printf("Begin to train BP NetWork!\n");
    GetNums();
    InitNetWork();
    int num = data.size();
 
    for(int iter = 0; iter <= ITERS; iter++) {
        for(int cnt = 0; cnt < num; cnt++) {
            //第一层输入节点赋值
            for(int i = 0; i < in_num; i++)
                x[0][i] = data[cnt].x[i];
 
            while(1) {
                ForwardTransfer();
                if(GetError(cnt) < ERROR)    //如果误差比较小,则针对单个样本跳出循环
                    break;
                ReverseTransfer(cnt);
            }
        }
        printf("This is the %d th trainning NetWork !\n", iter);
 
        double accu = GetAccu();
        printf("All Samples Accuracy is %lf\n", accu);
    }
    printf("The BP NetWork train End!\n");
}
 
//根据训练好的网络来预测输出值
vector<double> BP::ForeCast(const vector<double> data) {
    int n = data.size();
    assert(n == in_num);
    for(int i = 0; i < in_num; i++)
        x[0][i] = data[i];
 
    ForwardTransfer();
    vector<double> v;
    for(int i = 0; i < ou_num; i++)
        v.push_back(x[2][i]);
    return v;
}
 
//获取网络节点数
void BP::GetNums() {
    in_num = data[0].x.size();                         //获取输入层节点数
    ou_num = data[0].y.size();                         //获取输出层节点数
    hd_num = (int)sqrt((in_num + ou_num) * 1.0) + 5;   //获取隐含层节点数
    if(hd_num > NUM) hd_num = NUM;                     //隐含层数目不能超过最大设置
}
 
//初始化网络
void BP::InitNetWork() {
    memset(w, 0, sizeof(w));      //初始化权值和阈值为0,也可以初始化随机值
    memset(b, 0, sizeof(b));
}
 
//工作信号正向传递子过程
void BP::ForwardTransfer() {
    //计算隐含层各个节点的输出值
    for(int j = 0; j < hd_num; j++) {
        double t = 0;
        for(int i = 0; i < in_num; i++)
            t += w[1][i][j] * x[0][i];
        t += b[1][j];
        x[1][j] = Sigmoid(t);
    }
 
    //计算输出层各节点的输出值
    for(int j = 0; j < ou_num; j++) {
        double t = 0;
        for(int i = 0; i < hd_num; i++)
            t += w[2][i][j] * x[1][i];
        t += b[2][j];
        x[2][j] = Sigmoid(t);
    }
}
 
//计算单个样本的误差
double BP::GetError(int cnt) {
    double ans = 0;
    for(int i = 0; i < ou_num; i++)
        ans += 0.5 * (x[2][i] - data[cnt].y[i]) * (x[2][i] - data[cnt].y[i]);
    return ans;
}
 
//误差信号反向传递子过程
void BP::ReverseTransfer(int cnt) {
    CalcDelta(cnt);//计算调整量
    UpdateNetWork();//根据调整量调节权值和阈值
}
 
//计算所有样本的精度
double BP::GetAccu() {
    double ans = 0;
    int num = data.size();
    for(int i = 0; i < num; i++) {
        int m = data[i].x.size();
        for(int j = 0; j < m; j++)
            x[0][j] = data[i].x[j];
        ForwardTransfer();
        ans += fabs(x[2][0] - data[i].y[0]) <= 0.5 ? 1 : 0;
    }
    return ans / num;
}
 
//计算调整量
void BP::CalcDelta(int cnt) {
    //计算输出层的delta值
    for(int i = 0; i < ou_num; i++)
        d[2][i] = (x[2][i] - data[cnt].y[i]) * x[2][i] * (A - x[2][i]) / (A * B);
    //计算隐含层的delta值
    for(int i = 0; i < hd_num; i++) {
        double t = 0;
        for(int j = 0; j < ou_num; j++)
            t += w[2][i][j] * d[2][j];
        d[1][i] = t * x[1][i] * (A - x[1][i]) / (A * B);
    }
}
 
//根据计算出的调整量对BP网络进行调整
void BP::UpdateNetWork() {
    //隐含层和输出层之间权值和阈值调整
    for(int i = 0; i < hd_num; i++) {
        for(int j = 0; j < ou_num; j++)
            w[2][i][j] -= LR * d[2][j] * x[1][i];
    }
    for(int i = 0; i < ou_num; i++)
        b[2][i] -= LR * d[2][i];
 
    //输入层和隐含层之间权值和阈值调整
    for(int i = 0; i < in_num; i++)
        for(int j = 0; j < hd_num; j++)
            w[1][i][j] -= LR * d[1][j] * x[0][i];
    for(int i = 0; i < hd_num; i++)
        b[1][i] -= LR * d[1][i];
}
 
//计算Sigmoid激活函数的值
double BP::Sigmoid(const double x) {
    return A / (1 + exp(-x / B));
}
 
int main() {
    FILE *fpTrain = fopen("/Users/really/Desktop/student_train.csv", "r");
    FILE *fpTest = fopen("/Users/really/Desktop/student_test.csv", "r");
 
    vector<data> data;
    double maxA = -1, minA = 1000, maxB = -1, minB = 1000;
    for(int i = 0; i < 200; i++) {
        double a, b, c;
        Data t;
        fscanf(fpTrain, "%lf,%lf,%lf", &a, &b, &c);
        t.x.push_back(a);  t.x.push_back(b);
        t.y.push_back(c);
 
        maxA = max(maxA, a);
        minA = min(minA, a);
        maxB = max(maxB, b);
        minB = min(minB, b);
 
        data.push_back(t);
    }
 
    for(int i = 0; i < 200; i++) {
        data[i].x[0] = (data[i].x[0] - minA) / (maxA - minA);
        data[i].x[1] = (data[i].x[1] - minB) / (maxB - minB);
    }
 
    fclose(fpTrain);
 
    BP *bp = new BP();
    bp->GetData(data);
    bp->Train();
 
    for(int i = 0; i < 60; i++) {
        vector<double> in;
        double a, b;
        fscanf(fpTest, "%lf,%lf", &a, &b);
        a = (a - minA) / (maxA - minA);
        b = (b - minB) / (maxB - minB);
        in.push_back(a);  in.push_back(b);
 
        vector<double> ou;
        ou = bp->ForeCast(in);
 
        if(ou[0] >= 0.5)
            ou[0] = 1;
        else
            ou[0] = 0;
 
        printf("%d\n", (int)ou[0]);
    }
 
    fclose(fpTest);
 
    return 0;
}
</double></double></data></double></double></double></data></data></doub

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @Vivian 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程