神经网络 c++ 源码 可以直接复制运行,提供数据集,操作简单,最少仅需4行代码

神经网络 c++ 源码 可以直接复制运行,提供数据集,操作简单,最少仅需4行代码

本文的神经网络,让你省去Python那些花里胡哨的变量名,最少仅需4行代码即可完成自己的神经网络**

本文章采用c++ 编写神经网络,隐藏层提供了sigmoid 和 Relu方法,输出层采用了Softmax方法。

采用了数据集 ,http://archive.ics.uci.edu/ml/datasets/Letter+Recognition
验证集和训练集我都给你们分好了。
训练集
链接: https://pan.baidu.com/s/1BbbHuHtHhjgqBFhypzkuFQ 提取码: bgqq
测试集
链接: https://pan.baidu.com/s/1EdmMdNn_mYfxBlFn9_4rrQ 提取码: c3gc

本文就不太具体介绍神经网络如何运行了,因为网上全都是详细简介,但还是会基于少许的神经网络知识。

不好意思之前忘记,将权重优化加进去了,我使用了momentum

简介介绍

神经网络运作

如果你看过神经网络的图片,你会看见有几个点,然后用线连接着就可以运作了

点和线是什么?

.
我们根据下图讲解在这里插入图片描述

我们可以从图片看到,点被分成了3种不同颜色的类型,每种颜色代表一个层。
红:代表输入层
绿:代表隐藏层
紫:代表输出层

输入层是什么?

比如: 0,0 代表A,0,1 代表B 1,0代表 C 1,1D ,我们拿A举例;那么输入层就应该输入x = 0 ,y = 0。

隐藏层是什么?

将你输入的一系列值采用非线性的方法在隐藏层中计算,隐藏层中的值都需要使用一次激活函数。激活函数的值将去向下一个隐藏层

输出层是什么

最后一层的隐藏层的激活函数得到的值将会去向输出层,然后输出层也使用一个激活函数,最终得到4个不同的概率(因为我采用的softmax作为输出层的激活函数)。

前向传播

每一层的值如何去向下一层

这里就需要说一下线是什么了,因为每一层的点都会被上一层的点用线连接着。

为什么要用线连接着

比如我们去一个超市,我们是不是要通过一条路才能去呢。那么每一个值去向下一个地方也需要一个通道。那就是图中每个点互相连接的线,只有互相连线了值才可以互通。

但是每个点去向下一个与他互通的点的时候,他们的道路都需要一个值。比如你去超市的路的长度. 在神经网络中我们称作权重,后面我也继续用这个词语描述。

如何计算点的值

除了输入层的点不需要计算的点的值,因为它的值是你输入进去的。
在神经网络中点的值计算是通过每个可以去向它的点的值乘权重,然后累加到一起与偏移值,再使用使用激活函数。
X:是点的值
W:去向下一个点的权重
b:偏移值 (除了输入层,每一层都有一个偏移值连向所有点,偏移值永远是1,只有偏移值的权重会变)
在这里插入图片描述

什么是激活函数

激活函数就是让点的值变成非线性

为什么要使用激活函数

因为不使用激活函数所有的值都是线性,线性就一条直线,那最终得到的值将毫无意义,直线要么上升要么就是下降。所以实际上点的值应该是最终使用激活函数得到的值。
代码中隐藏层使用了Relu或sigmoid激活函数,输出层使用了softmax激活函数.

~~到此就完成了前向传播的所有事情。

后向传播

向后传播就是优化你的权重,为什么要向后传播,因为你不可能第一次输入值神经网络就可以正确的将它分类把。神经网络也是一个需要不断学习的东西,它不断改进的方法就是在后向传播的时候实现。

神经网络如何不断改进自己的错误

通过判断最终得到的值,是不是和真实值相等,要是不相等就,搭配激活函数的导数和损失函数,反向传播回去。反向传播的主要目的就是更新权重,使得下一次正向传播的时候可以获得更好的结果。

~~这里就不过多做反向传播的讲解了,反正都是一堆导数,要是你没学过高等数学或者忘记了或者随便混过的就同等于看天书,然后还浪费我时间在这里讲,直接看代码,反正其他人也介绍了每个激活函数的导数如何搭配损失函数用。反正代码中也有导数的代码,直接上源码。

提示

作者测试过代码无论多少层,每层不同的节点都是可以完美运行的。
如果想要加不同的层,或者改动层的节点个数,请看清楚加层的方法名在使用。因为输入层和输出层连接隐藏层的方法是不同的。

QT

作者弄了个QT界面的效果,你们可以看到训练的效果,下面代码不含qt代码纯c++,qt界面就不给了,做的有点垃圾,你们喜欢可以自己搭建一个。
16000训练集,4000测试集, 对了3175个,只迭代了10次。3层128,64,32;
作者测试最大准确率可以达到百分之95%
在这里插入图片描述

测试单条数据,你们可以看到分类效果,最终结果吻合是U
在这里插入图片描述

globalVariable.hpp
#ifndef GLOBALVARIABLES_H
#define GLOBALVARIABLES_H
#include <vector>
#include <map>
#include <iostream>
#include <cmath>
#include <algorithm>
#define sqr(x)    ((x) * (x))
using namespace std;

struct hiddenNode;
struct outputNode;


extern double n;
extern double alpha;
extern int HIDALOG;

extern int SIGMOID;
extern int RELU;
extern int TANH;



struct biasNode
{
    double activation_vals;
    vector<hiddenNode*>hidConnection;
    vector<outputNode*>outConeection;
};

struct inputNode
{
    int ID;
    double curr_val;
    vector<double> activation_vals;
    vector<hiddenNode*> hidConnection;
    vector<double> linkToHidden;
    vector<double> vLinkToHO;
};

struct hiddenNode
{
    int ID;
    double activation_vals;
    double z;
    double error;
    vector<outputNode*> outConnection;
    vector<inputNode*> intConnection;
    vector<hiddenNode*> hidUpConnection;
    vector<hiddenNode*> hidDownConnectino;
    biasNode* biasConnectino;
    vector<double> linkToHO;
    vector<double> vLinkToHO;
    double linkTobias;
    double vLinkTobias;
};


struct outputNode
{
    int ID;
    vector<double> actual_val;
    double z;
    double activation_vals;
    double error;
    vector<hiddenNode*> hidConnection;
    biasNode* biasConnectino;
    double linkTobias;
    double vLinkTobias;
};


#endif /* Header_h */


Nerual.hpp
#ifndef BACKPROPAGATION_H
#define BACKPROPAGATION_H
#include "globalVariable.hpp"

class Nerual
{
public:
    void setInputLayer(int num,vector<vector<double>> vals);
    void setInputToHidden(int num);
    void setHiddenToHidden(int num);
    void setOutToHidden(int num,vector<vector<double>> vals);

public:
    double sigmod(double sum);
    double Relu(double sum);
    double Softmax(double sum,double f);
    
    double SoftmaxDerivative(double i,double j);
    double sigmodDerivative(double act);
    bool ReluDerivative(double act);
    
    double weightUpdate(double act,double second_act);
    double RAND_WEIGHT();
    
public:
    void feedForward(int i);
    void backPropagate(int i);
    double Trainning_Network();
    void testOneLine(double x[]);
    void testSet(vector<vector<double>> vals,vector<string> tital);
private:
    vector<inputNode*> input;
    vector<vector<hiddenNode*>> hiddens;
    vector<biasNode*> bias;
    vector<outputNode*> output;
    double tmp_sum;
    double max;
};

#endif /* Nerual_hpp */

Nerual.cpp
//
//  Nerual.cpp
//  infrastructure
//
//  Created by User on 2020/9/17.
//  Copyright © 2020 User. All rights reserved.
//

#include "Nerual.hpp"

void Nerual::setInputLayer(int num,vector<vector<double>> vals)
{
    for (int i=0; i<num; i++)
    {
        inputNode *tmp = new inputNode;
        tmp->ID=i;
        tmp->activation_vals = vals[i];
        input.push_back(tmp);
    }
}

double Nerual::RAND_WEIGHT()
{
    return ( (static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 0.5) );
}

void Nerual::setInputToHidden(int num)
{
    vector<hiddenNode*> hidden;
    biasNode *bia = new biasNode;
    hiddenNode *tmp = new hiddenNode[num];
    bia->activation_vals=1;
    for (int i=0; i<input.size(); i++)
    {
        
        for (int j=0; j<num; j++)
        {
            input[i]->linkToHidden.push_back(RAND_WEIGHT());
            input[i]->vLinkToHO.push_back(0);
            input[i]->hidConnection.push_back(&tmp[j]);
            tmp[j].intConnection.push_back(input[i]);
        }
    }
    for (int i=0; i<num; i++)
    {
        tmp[i].ID = i;
        tmp[i].biasConnectino=bia;
        tmp[i].linkTobias=RAND_WEIGHT();
        tmp[i].vLinkTobias=0.0;
        bia->hidConnection.push_back(&tmp[i]);
        hidden.push_back(&tmp[i]);
    }
    bias.push_back(bia);
    hiddens.push_back(hidden);
}
void Nerual::setHiddenToHidden(int num)
{
    vector<hiddenNode*> lastLayer = hiddens[hiddens.size()-1];
    vector<hiddenNode*> hidden;
    hiddenNode *tmp = new hiddenNode[num];
    biasNode *bia = new biasNode;
    bia->activation_vals=1;
    for (int i=0; i<lastLayer.size(); i++)
    {
        
       for (int j=0; j<num; j++)
       {
            lastLayer[i]->linkToHO.push_back(RAND_WEIGHT());
            lastLayer[i]->vLinkToHO.push_back(0);
            lastLayer[i]->hidUpConnection.push_back(&tmp[j]);
            tmp[j].hidDownConnectino.push_back(lastLayer[i]);
        }
    }
    for (int i=0; i<num; i++)
    {
        tmp[i].ID = i;
        tmp[i].biasConnectino=bia;
        tmp[i].linkTobias=RAND_WEIGHT();
        tmp[i].vLinkTobias=0.0;
        bia->hidConnection.push_back(&tmp[i]);
        hidden.push_back(&tmp[i]);
    }
    bias.push_back(bia);
    hiddens.push_back(hidden);
}

void Nerual::setOutToHidden(int num,vector<vector<double>> vals)
{
    vector<hiddenNode*> lastLayer = hiddens[hiddens.size()-1];
    biasNode *bia = new biasNode;
    outputNode *tmp = new outputNode[num];
    bia->activation_vals=1;
    for (int i=0; i<lastLayer.size(); i++)
    {
        for (int j=0; j<num; j++)
        {
            lastLayer[i]->linkToHO.push_back(RAND_WEIGHT());
            lastLayer[i]->vLinkToHO.push_back(0);
            lastLayer[i]->outConnection.push_back(&tmp[j]);
            tmp[j].hidConnection.push_back(lastLayer[i]);
        }
    }
    for (int i=0; i<num; i++) {
        tmp[i].ID = i;
        tmp[i].actual_val = vals[i];
        tmp[i].biasConnectino=bia;
        tmp[i].linkTobias=RAND_WEIGHT();
        tmp[i].vLinkTobias=0.0;
        bia->outConeection.push_back(&tmp[i]);
        output.push_back(&tmp[i]);
    }
    bias.push_back(bia);
}

double Nerual::sigmod(double sum)
{
       
        double val = 1.0 / (1.0+exp(-sum));
        return val;
}
double Nerual::Relu(double sum)
{
    double val  = std::max(0.0,sum);
    return val;
}

double Nerual::Softmax(double sum,double f)
{
        double val = f / sum;
        return val;
}

double Nerual::SoftmaxDerivative(double z,double t)
{
        double val = z -t;
        return val;
}

double Nerual::sigmodDerivative(double act)
{
        double val = act*(1-act);
        return val;
}
bool Nerual::ReluDerivative(double act)
{
    if(act<=0)
        return 1;
    return 0;
}


double Nerual::weightUpdate(double error,double act)
{
    double val = n*error*act;
    return val;
}

void Nerual::feedForward(int i)
{
    vector<hiddenNode*> bottomLayer = hiddens[0];
    //求连接input的hidden值
    for (int j=0; j<bottomLayer.size(); j++)
    {
        double sum=0;
        vector<inputNode*> inputLayer =bottomLayer[j]->intConnection;
        for (int k=0; k<inputLayer.size(); k++)
        {
            inputLayer[k]->curr_val = inputLayer[k]->activation_vals[i];
            //求值
            sum += inputLayer[k]->curr_val*inputLayer[k]->linkToHidden[j];
        }
        sum+=bottomLayer[j]->biasConnectino->activation_vals*bottomLayer[j]->linkTobias;
         //状态值
        bottomLayer[j]->z = sum;
        //使用激活函数
        bottomLayer[j]->activation_vals = sigmod(sum);
//        bottomLayer[j]->activation_vals=Relu(sum);
    }

    //求hidden连接hidden的值
    for (int j=1; j<hiddens.size(); j++)
    {
        vector<hiddenNode*> nextLayer = hiddens[j];
        for (int k=0; k<nextLayer.size(); k++)
        {
            double sum=0;
            for (int z=0; z<bottomLayer.size(); z++)
            {
                  //求值
                sum+=bottomLayer[z]->activation_vals*bottomLayer[z]->linkToHO[k];
            }
            sum+=nextLayer[k]->biasConnectino->activation_vals*nextLayer[k]->linkTobias;
            //状态值
            nextLayer[k]->z = sum;
            //使用激活函数
            nextLayer[k]->activation_vals = sigmod(sum);
//            nextLayer[k]->activation_vals = Relu(sum);
        }
        bottomLayer = nextLayer;
    }
    //求output值
    tmp_sum=0;
    max=0;
    double *sums = new double[output.size()];
    for (int j=0; j<output.size();j++)
    {
        double sum=0;
        for (int k=0; k<bottomLayer.size(); k++)
        {
            sum += bottomLayer[k]->activation_vals*bottomLayer[k]->linkToHO[j];
        }
        sum+=output[j]->biasConnectino->activation_vals*output[j]->linkTobias;
        //状态值
        output[j]->z = sum;
        if(max<sum)
        {
            max = sum;
        }
        sums[j]=sum;
    }
    //防止溢出
    for (int j=0; j<output.size(); j++)
    {
        sums[j]-=max;
        tmp_sum+=exp(sums[j]);
    }
    //预测值
    for (int j=0; j<output.size(); j++)
    {
        output[j]->activation_vals  = Softmax(tmp_sum,exp(sums[j]));
    }
    delete[] sums;
}
void Nerual::backPropagate(int i)
{
    vector<hiddenNode*> upHiddenLayer= hiddens[hiddens.size()-1];
    //output错误率
    for (int j=0; j<output.size();j++)
    {
        output[j]->error=SoftmaxDerivative(output[j]->activation_vals,output[j]->actual_val[i]);
        //momentum
        double *v = &output[j]->vLinkTobias;
        *v= alpha*(*v)-weightUpdate(output[j]->error, output[j]->biasConnectino->activation_vals);
        output[j]->linkTobias += (*v);
    }
    
    //求hidden错误率
    for (int j=0; j<upHiddenLayer.size(); j++)
    {
        double sum=0;
        double *v;
        vector<outputNode*> outputLayer = upHiddenLayer[j]->outConnection;
        for (int k=0; k<outputLayer.size(); k++)
        {
            sum+=upHiddenLayer[j]->linkToHO[k]*outputLayer[k]->error;
            
            //momentum
            v = &upHiddenLayer[j]->vLinkToHO[k];
            *v = alpha*(*v)-weightUpdate(output[k]->error, upHiddenLayer[j]->activation_vals);
            upHiddenLayer[j]->linkToHO[k]+=(*v);
        }
//      upHiddenLayer[j]->error = ReluDerivative(upHiddenLayer[j]->activation_vals)==1?0:sum;
        upHiddenLayer[j]->error = sigmodDerivative(upHiddenLayer[j]->activation_vals)*sum;
        //momentum
        v = &upHiddenLayer[j]->vLinkTobias;
        *v = alpha*(*v)-weightUpdate(upHiddenLayer[j]->error, upHiddenLayer[j]->biasConnectino->activation_vals);
        upHiddenLayer[j]->linkTobias+=(*v);
    }
    
    //更新hidden到hidden的错误率和权重
    for (int j=static_cast<int>(hiddens.size()-2); j>=0; j--)
    {
        vector<hiddenNode*> downLayer= hiddens[j];
        for (int k=0; k<downLayer.size(); k++)
        {
            double sum=0;
            double *v;
            for (int z=0; z<upHiddenLayer.size(); z++)
            {
                sum+=downLayer[k]->linkToHO[z]*upHiddenLayer[z]->error;
                //momentum
                v = &downLayer[k]->vLinkToHO[z];
                *v = alpha*(*v)-weightUpdate( upHiddenLayer[z]->error, downLayer[k]->activation_vals);
                downLayer[k]->linkToHO[z]+=(*v);
            }
//          downLayer[k]->error = ReluDerivative(downLayer[k]->activation_vals)==1?0:sum;
            downLayer[k]->error = sigmodDerivative(downLayer[k]->activation_vals)*sum;
            //momentum
            v = &downLayer[k]->vLinkTobias;
            *v = alpha*(*v)-weightUpdate(downLayer[k]->error, downLayer[k]->biasConnectino->activation_vals);
            downLayer[k]->linkTobias+=(*v);
        }
        upHiddenLayer = downLayer;
    }
    
    //更新连接input的hidden的权重
    for (int j=0; j<input.size(); j++)
    {
        double *v;
        for (int k=0; k<upHiddenLayer.size(); k++)
        {
            //momentum
            v = &input[j]->vLinkToHO[k];
            *v = alpha*(*v)-weightUpdate(upHiddenLayer[k]->error, input[j]->curr_val);
            input[j]->linkToHidden[k]+=(*v);
        }
    }
}

double Nerual::Trainning_Network()
{
    double accumulatedErr=0.0;
    double err;
    for (int i=0; i<input[0]->activation_vals.size(); i++)
    {
        feedForward(i);
        err = 0.0;
        for (int j=0; j<output.size(); j++) {
            err +=sqr(output[j]->activation_vals-output[j]->actual_val[i]);
        }
        err = 0.5 * err;
        accumulatedErr += err;
        backPropagate(i);
    }
    return accumulatedErr;
}

void Nerual::testOneLine(double x[])
{
    for (int i=0; i<input.size(); i++)
    {
        input[i]->activation_vals.clear();
        input[i]->activation_vals.push_back(x[i]);
    }
    max=0;
    int iindex=0;
    feedForward(0);
    for (int j=0; j<output.size();j++)
    {
        if(max<output[j]->activation_vals)
        {
            max=output[j]->activation_vals;
            iindex=j;
        }
    }
    
    char word = iindex+65;
    cout<<word<<endl;
}

void Nerual::testSet(vector<vector<double>> vals,vector<string> tital)
{
    int correct=0;
    for (int j=0; j<vals.size(); j++)
    {
        input[j]->activation_vals.clear();
        input[j]->activation_vals = vals[j];
    }
    for (int i=0; i<tital.size(); i++)
    {
        feedForward(i);
        max=0;
        int iindex=0;
        for (int j=0; j<output.size();j++)
        {
             if(max<output[j]->activation_vals)
             {
                 max=output[j]->activation_vals;
                 iindex=j;
             }
        }
        char word = iindex+65;
        char *tw =(char*)tital[i].c_str();
        if(word==*tw)
        {
            correct++;
        }
        cout<<*tw<<" "<<word<<endl;
    }
    cout<<"correctively: "<<correct<<endl;
}

main.cpp
#include<iostream>
#include <fstream>
#include <sstream>
#include "Nerual.hpp"
double n=0.02;
double alpha =0.02;
int HIDALOG=0;
int SIGMOID=0;
int RELU=1;
int TANH=2;
int main()
{
    string myText;
    stringstream ss;
    ifstream MyFile("/Users/user/Desktop/intelligenc system /CNN/6/infrastructure/lib/Training_Data.txt");
    string tmp;
    vector<vector<double>> trainData(16);
    vector<vector<double>> actualData(26);
    vector<string> tital2;
    for (int i=0;i<actualData.size(); i++) {
        actualData[i].resize(16000);
    }
    int move=0;
    int shift=0;
    while (getline (MyFile, myText)) {
      // Output the text from the file
        ss.str(myText);
        getline(ss,tmp,',');
        tital2.push_back(tmp);
        char *p = (char*)tmp.c_str();
        int num = *p-65;
        actualData[num][move]=1;
        while (getline(ss,tmp,','))
        {
            trainData[shift].push_back(stoi(tmp));
            shift++;
        }
        ss.clear();
        shift=0;
        move++;
    }
    MyFile.close();
    
    ifstream TestFile("/Users/user/Desktop/intelligenc system /CNN/6/infrastructure/lib/Test_Data.txt");
    vector<vector<double>> testData(16);
    vector<string> tital;
    while (getline (TestFile, myText)) {
        ss.str(myText);
        getline(ss,tmp,',');
        tital.push_back(tmp);
        while (getline(ss,tmp,','))
        {
            testData[shift].push_back(stoi(tmp));
            shift++;
        }
        ss.clear();
        shift=0;
    }
    TestFile.close();
    srand(static_cast<unsigned int>(123));
    Nerual *bp = new Nerual;
    bp->setInputLayer(16, trainData);
    bp->setInputToHidden(128);
    bp->setHiddenToHidden(64);
    bp->setHiddenToHidden(32);
    bp->setOutToHidden(26,actualData);
    double SSE=0.0;
    for (int i=0; i<50; i++) {
        SSE=bp->Trainning_Network();
        cout<<"times "<<i << " SSE "<<SSE<<endl;
    }
    double t[] ={2,8,3,5,1,8,13,0,6,6,10,8,0,8,0,8};
    bp->testOneLine(t);
    bp->testSet(testData,tital);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值