zoukankan      html  css  js  c++  java
  • 神经网络从基础到改进+源程序

    神经网络初步学习总结:(对神经网络的模型有一定的了解,如果从未接触有点看不懂)

    第一点:以下是最简单的神经网络模型了

    x:  输入参数

    a0: 输入偏置

    a1: 输入权重

    b0: 隐藏层偏置

    b1: 隐藏层输入权重

    y:  隐藏层输入参数(经过激励函数的输出,下面会讲解激励函数)

    Z:  隐藏层输出(经过激励的输出)

     

    各个参数的展开式如下:不用介绍了,都很简单的函数,不懂得话去百度一些模型看看

     

     

    激励函数:经过sigmoid()函数之后的数值,这是常见的分类函数。

              如果是用于函数逼近,使用Y = X 作为激励函数即可。

    第二点:公式的相关介绍

    首先明确梯度下降法:字面的理解是沿着切线的方向,可以更快更准确的找出最小值

                        我们使用这个规则只需要知道,梯度下降=偏导数,其中

                        偏导数=k*变化量  抓住这两个点,这是BP神经网络的核心之一

                        例如:  :比例系数,W:权值,E:误差

    明白Delta学习规则:有监督的学习,是利用误差作为判断的标准。

                       形式:  y:隐藏层的输出

                                    Z:实际输出,t:期望输出(实际值)

                       基于这个学习规则进行BP的反向调整权重,核心之二

    结合上面两个公式Delta规则的误差作为标准,误差利用整体的平方可以减少误差波动的

                      影响下面为了计算方便多乘以一个1/2,求导之后消去,    

                     没意义只是为了计算方便:BP神经网络的权值和偏置调整就可以利用这

                     个公式,例如:  等等

     

    神经网络的权值和偏置计算

      因为误差E和隐藏层偏置没有直接关系,

    所以需要链式求偏导,返回去看一下模型的参数定义就知道了。

    ‚  因为误差E和输入层的输入数据没有直接联系,所以需要链式求偏导

    很简单的链式求导,看一下高数就知道的。

    剩下的公式大家自己推导吧。。。。这是核心之三

    第三点:BP神经网络的改进

    1.批量学习:顾名思义批量学习就是梯度成批量的计算, 总梯度的含义

              例如:批量数是10个样本,那就是W1的梯度是十个样本加起来。和一个一个        

              的计算是一样的,这里不过是选几个样本加起来求平均数而已。

    2.遍历学习(在线):本文中使用的改进就是动量法,当前权值的更新需要上一次的和这一次   

              同时作用,达到平滑高效的作用。公式:,注意这

              里的是没有叠加的,因为上面w存在。是有叠加的,因为是所有的w项。核心之四

    第四点:BP神经网络的程序

    核心算法就是更新权值w和更新偏置b,参考了网上程序,但是基本都是有漏洞,可能没下载到好的程序吧,结合了部分网上历程还有一本书《神经网络在应用科学和工程中的应用-----从基本原理到复杂的模式识别》。我弄了一个星期,就是由于公式编写成代码出现很多问题,多细心一点可以减少很多未知的错误!!!

           BP神经网络下载

    注意:看了Ng的视频,Sigmoid函数<tanh函数<ReLu函数<Leak ReLu函数

     

     

    CPP文件:

      1 #include "BP.h"
      2 
      3 BP_network::BP_network()
      4 {
      5     srand((unsigned)time(NULL));
      6     memset(w, 0, sizeof(w));
      7     memset(b, 0, sizeof(b));
      8     memset(Yout, 0, sizeof(Yout));
      9     memset(DataIn, 0, sizeof(DataIn));
     10     memset(DataOut, 0, sizeof(DataOut));
     11     memset(dv, 0, sizeof(dv));
     12     memset(dw, 0, sizeof(dw));
     13 }
     14 
     15 BP_network::~BP_network()
     16 {
     17 
     18 }
     19 
     20 double BP_network::Random()
     21 {
     22     double Rand;
     23     Rand = (1.0*rand()) / (RAND_MAX + 1);
     24     return Rand;
     25 }
     26 //--------------写入数据-------------------//
     27 void BP_network::FwriteData()
     28 {
     29     FILE *fp1, *fp2;
     30     double data1 = 0.0, data2;
     31     if ((fp1 = fopen("G:\in.txt", "w")) == NULL) printf("can't open in.txt");
     32     if ((fp2 = fopen("G:\out.txt", "w")) == NULL) printf("can't open out.txt");
     33     for (int i = 0; i < SampleCount; i++)
     34     {
     35         //data1 = Random() % 1000 / 100;
     36         data1 = double(int(Random() * 1000) % 1000) / 100;
     37         data2 = double(int(Random() * 1000) % 1000) / 100;
     38         fprintf(fp1,"%lf %lf
    ", data1, data2);
     39         data1 = data1 * data2;
     40         fprintf(fp2,"%lf 
    ", data1);
     41     }
     42     fclose(fp1);
     43     fclose(fp2);
     44 }
     45 //--------------读入数据-------------------//
     46 void BP_network::FreadData()
     47 {
     48     FILE *fp1, *fp2;
     49     if (((fp1 = fopen("G:\in.txt", "r")) == NULL))
     50         printf("can't open in.txt");
     51     if((fp2 = fopen("G:\out.txt", "r")) == NULL)
     52         printf("can't open in.txt");;
     53     for (int i = 0; i < SampleCount; i++)
     54     {
     55         for (int j = 0; j < InCount; j++)
     56         {
     57             fscanf(fp1, "%lf", &DataIn[i][j]);
     58         }
     59         fscanf(fp2, "%lf", &DataOut[i][0]);
     60     }
     61     fclose(fp1);
     62     fclose(fp2);
     63 }
     64 //---------归一化输入和输出的数值,随机化权值和偏置的值---------//
     65 //****************   对于隐藏层->输出层=w[i][j][k]     *************//
     66 //------------------  i:层数,j:输出层个数,k:隐藏层个数    ------//
     67 void BP_network::Init_network()
     68 {
     69     double InMax, InMin, OutMax, OutMin;
     70     InMax = DataIn[0][0];
     71     InMin = DataIn[0][0];
     72     OutMax = DataOut[0][0];
     73     OutMin = DataOut[0][0];
     74 
     75     for (int i = 0; i < SampleCount; i++)
     76     {
     77         for (int j = 0; j < InCount; j++)
     78         {
     79             InMax = InMax > DataIn[i][j] ? InMax : DataIn[i][j];
     80             InMin = InMin < DataIn[i][j] ? InMin : DataIn[i][j];
     81         }
     82         OutMax = OutMax > DataOut[i][0] ? OutMax : DataOut[i][0];
     83         OutMin = OutMin < DataOut[i][0] ? OutMin : DataOut[i][0];
     84     }
     85     for (int i = 0; i < SampleCount; i++)
     86     {
     87         for (int j = 0; j < InCount; j++)
     88         {
     89             DataIn[i][j] = (DataIn[i][j] - InMin + 1) / (InMax - InMin + 1);
     90         }
     91         DataOut[i][0] = (DataOut[i][0] - OutMin + 1) / (OutMax - OutMin + 1);
     92     }
     93     for (int j = 0; j < HiddenCount; j++)
     94     {
     95         //----------随机化W和B的值------------//
     96         for (int i = 0; i < LayerCount - 1; i++)
     97         {
     98             if (i == 0)//第一层
     99             {
    100                 for (int k = 0; k < InCount; k++)  w[i][k][j] = 2 * (0.5 - Random());
    101             }
    102             if (i == 1)//第二层
    103             {
    104                 w[i][j][0] = 2 * (0.5 - Random());
    105             }
    106         }
    107         b[0][j] = 1;//由于数比较少,不需要做循环,直接赋值
    108         b[1][0] = 1;
    109     }    
    110     inMax = InMax;
    111     inMin = InMin;
    112     outMax = OutMax;
    113     outMin = OutMin;
    114 }
    115 //---------激励函数输出----------//
    116 void BP_network::DrivingOut(int m)
    117 {
    118     Yout[1][0] = 0.0;//!!!!!!!!!!!!!注释:未能清除数据,导致检查两天!!!!!!!!!!!!!!!!!!!!!
    119     for (int j = 0; j < HiddenCount; j++)
    120     {
    121         Yout[0][j] = 0.0;
    122         for (int k = 0; k < 2; k++)
    123         {
    124             Yout[0][j] += DataIn[m][k] * w[0][k][j];    
    125         }
    126         Yout[0][j] += b[0][j];
    127         Yout[0][j] = Sigmoid(Yout[0][j]);
    128         Yout[1][0] += Yout[0][j] * w[1][j][0];
    129     }
    130     Yout[1][0] += b[1][0];
    131     Yout[1][0] = Sigmoid(Yout[1][0]);
    132 }
    133 //-----------对W和B进行调整---------------//
    134 void BP_network::BackAdjust(int m)
    135 {
    136 #if 1//加动量法
    137     double StudyRate = 0.0, f = 0.0;
    138     double Sum = 0.0;
    139     StudyRate = (Yout[1][0] - DataOut[m][0]) * Yout[1][0] * (1 - Yout[1][0]);
    140     db0[1][0] = U1*db0[1][0] + (1 - U1)*B_Rate*StudyRate;
    141     b[1][0] -= db0[1][0];
    142     for (int i = 0; i < HiddenCount; i++)
    143     {
    144         dv[0][i] = U1*dv[0][i] + (1 - U1)*W_Rate * StudyRate * Yout[0][i];
    145         w[1][i][0] -= dv[0][i];
    146     }
    147     for (int i = 0; i < HiddenCount; i++)
    148     {
    149         f = 0.0;
    150         f = StudyRate * w[1][i][0] * Yout[0][i] * (1 - Yout[0][i]);//改正之后
    151         for (int j = 0; j < InCount; j++)
    152         {
    153             dw[j][i] = U1*dw[j][i] + (1 - U1)*W_Rate * f * DataIn[m][j];
    154             w[0][j][i] -= dw[j][i];
    155         }
    156         db1[0][i] = U1*db0[0][i] + (1 - U1)*B_Rate*f;
    157         b[0][i] -= db1[0][i];
    158     }
    159 #endif
    160 #if 0//网上找到的加了一点动量,但是程序不稳定
    161     int i, j;
    162     double t;
    163     for (i = 0; i < HiddenCount; ++i)
    164     {
    165         t = 0;
    166         for (j = 0; j < OutCount; ++j) {
    167             t += (Yout[1][j] - DataOut[m][j])*w[1][i][j];
    168             dv[i][j] = U1*dv[i][j] + (1-U1)*W_Rate*(Yout[1][j] - DataOut[m][j])*Yout[0][i];
    169             w[1][i][j] -= dv[i][j];
    170         }
    171         for (j = 0; j < InCount; ++j) {
    172             dw[j][i] = U1*dw[j][i] + (1 - U1)*W_Rate*t*Yout[0][i] * (1 - Yout[0][i])*DataIn[m][j];
    173             w[0][j][i] -= dw[j][i];
    174         }
    175 }
    176 #endif
    177 #if 0//未加动量法
    178     double StudyRate = 0.0, f = 0.0;
    179     double Sum = 0.0;
    180     StudyRate = ( Yout[1][0] - DataOut[m][0]) * Yout[1][0] * (1 - Yout[1][0]);
    181     b[1][0] -= ETA_W*StudyRate;
    182     for (int i = 0; i < HiddenCount; i++)  
    183         w[1][i][0] -= W_Rate * StudyRate * Yout[0][i];
    184     for (int i = 0; i < HiddenCount; i++)
    185     {        
    186         f = 0.0;
    187         f = StudyRate * w[1][i][0] * Yout[0][i] * (1 - Yout[0][i]);//改正之后
    188         for (int j = 0; j < InCount; j++)
    189         {
    190             w[0][j][i] -= W_Rate* f *DataIn[m][j];
    191         }
    192        b[0][i] -= ETA_B * f;
    193     }
    194 #endif
    195 }
    196 //-----------训练神经网络-----------------//
    197 void BP_network::Train_network()
    198 {
    199     int Tcount = 0;
    200     double e = 1.0;
    201     while (Tcount<TrainCount && e>Accuracy)
    202     {
    203         e = 0;
    204         for (int i = 0; i < SampleCount; i++)
    205         {
    206             DrivingOut(i);
    207             e += fabs((Yout[1][0]-DataOut[i][0])/ DataOut[i][0]);
    208             BackAdjust(i);
    209         }
    210         Tcount++;
    211         e = e / SampleCount;
    212         cout << "" << Tcount << "代精度为:" << e << endl;
    213     }
    214 }
    215 
    216 double BP_network::Calculate(double x, double y)
    217 {
    218     x = (x - inMin + 1) / (inMax - inMin + 1);
    219     y = (y - inMin + 1) / (inMax - inMin + 1);
    220 #if true
    221     double sum = 0.0, Tout = 0.0;
    222     for (int i = 0; i < HiddenCount; i++)
    223     {
    224         Yout[0][i] = w[0][0][i] * x + w[0][1][i] * y + b[0][i];
    225         Yout[0][i] = Sigmoid(Yout[0][i]);
    226         Tout += Yout[0][i] * w[1][i][0];
    227     }
    228     Tout += b[1][0];
    229     Tout = Sigmoid(Tout);
    230     return (Tout * (outMax - outMin + 1) + outMin - 1);
    231 #endif
    232 }
    233 
    234 double BP_network::Sigmoid(double t)
    235 {
    236     double sum;
    237     sum = 1.0 / (1.0+exp(-t));
    238     return sum;
    239 }

     

    H文件:

     1 #pragma once
     2 #define _CRT_SECURE_NO_WARNINGS
     3 
     4 #include <iostream>
     5 #include <vector>
     6 #include "time.h"
     7 #include "math.h"
     8 
     9 using namespace std;
    10 
    11 const int SampleCount = 820;//定义样本个数
    12 const int InCount = 2;//输入神经元个数
    13 const int OutCount = 1;//输出神经元个数
    14 const int HiddenCount = 45;//隐藏层神经元个数
    15 const int TrainCount = 6000;//训练次数
    16 const int LayerCount = 3;//神经网络层数
    17 const int NeuronMax = 45;//每层最多的神经元个数(也可以直接定义个数)
    18 
    19 const double U0 = 0.15;
    20 const double U1 = 0.0;//0.15
    21 const double W_Rate = 0.8;//权值调整率//0.8
    22 const double B_Rate = 0.8;//阈值调整率
    23 const double Accuracy = 0.01;
    24 
    25 #define ETA_W 0.2
    26 #define ETA_B 0.1
    27 
    28 class BP_network
    29 {
    30 public:
    31     BP_network();
    32     ~BP_network();    
    33     void FwriteData();
    34     void FreadData();
    35     void Init_network();
    36     void Train_network();
    37     double Calculate(double x, double y);
    38 private:
    39     double DataIn[SampleCount][InCount];//输入的数据
    40     double DataOut[SampleCount][OutCount];//输出的数据
    41     double w[LayerCount-1][HiddenCount][HiddenCount];//权值(定义的是最大范围,为了移植方便,用不完)
    42     double b[LayerCount-1][NeuronMax];//偏置(第几层,第几个神经元,对应的下一的神经元)
    43     double Yout[LayerCount-1][NeuronMax];//经过激励函数的输出
    44     double inMax, outMax, inMin, outMin;
    45     double dv[HiddenCount][HiddenCount], dw[HiddenCount][HiddenCount];
    46     double db0[2][2], db1[HiddenCount][HiddenCount];
    47 
    48 
    49     double Sigmoid(double t);
    50     void DrivingOut(int i);
    51     void BackAdjust(int t);
    52     double Random();
    53 };

    main文件:

     1 #include "BP.h"
     2 
     3 int main(int argc, char*argv)
     4 {
     5     BP_network test;
     6     test.FwriteData();
     7     test.FreadData();
     8     test.Init_network();
     9     test.Train_network();
    10     cout << test.Calculate(5,5);
    11     while (1);return 0;
    12 }

    不训练直接使用文件:

    注:这是没有经过测试,可能程序有点小Bug,主题思路是没问题的!

     1 //----@InData:    输入为一维的数据 
     2 //----@Weight:    权重
     3 //                []        :层数, 
     4 //                            [0]:      输入层到隐藏层的权重
     5 //                            [1]:      隐藏层到输出层的权重
     6 //                [][]    :每层个数
     7 //                            [0][i]:      输入层的个数
     8 //                            [1][h]:      隐藏层个数
     9 //                [][][]    :每层个数        
    10 //                            [0][i][h]:隐藏层个数        
    11 //                            [1][h][o]:输出层个数
    12 //----@Bias:    偏置
    13 //                [0][h]    :隐藏层偏置
    14 //                [1][o]    :输出层偏置
    15 //----@OutData:    输出为一维数据                        
    16 void Calculate(double* InData,double*** Weight,double* Bias ,char* OutData)
    17 {
    18     double HidData[HiddenCount][OutCount],HidData_Temp=0;//HidData:存放临时隐藏层到输出层的数据,HidData_Temp:存放临时输入层到隐藏层的单个数据
    19     unsigned char flag = 1;//加输出层偏置
    20     for (char h = 0; h < HiddenCount; h++)
    21     {
    22         for(unsigned char i=0; i<sizeof(InData)/sizeof(double); i++)//单个隐藏层的输出
    23         {
    24             HidData_Temp += Weight[0][i][h] *InData[i];
    25         }
    26         HidData_Temp += Bias[0][h];
    27         HidData_Temp = Sigmoid(HidData_Temp);
    28         for(unsigned char o=0; o<sizeof(OutData)/sizeof(char); o++)//单个隐藏层对输出层的输出
    29         {
    30             HidData[h][o] = Weight[1][h][o]*HidData_Temp;
    31             OutData[o] += HidData[h][o];
    32             //OutData[o] = flag==1?(OutData[o]+Bias[1][o]):OutData[o];
    33             if(flag) OutData[o]+=Bias[1][o];//只能加一次偏置,顾用标志位
    34         }
    35         flag=0;
    36     }
    37 }
    38 //----@InData:    输入为一维的数据 
    39 //----@MinMax:    数据最值
    40 //                [0] :Maximun data
    41 //                [1]    :Minimun data
    42 //----@OutData:    输出为一维数据    
    43 void Normlize(double* InDta,double* MinMax,double* OutData)
    44 {
    45     for(unsigned char i=0;i<sizeof(InData)/sizeof(double);i++)
    46     {
    47         OutData[i] = (InDta[i] - MinMax[0] + 1) / (MinMax[1] - MinMax[0] + 1);
    48     }
    49 }
    50 //----Sigmoid函数
    51 double Sigmoid(double t)
    52 {
    53     double sum;
    54     sum = 1.0 / (1.0+exp(-t));
    55     return sum;
    56 }

     

  • 相关阅读:
    对数值计算numpy的一些总结,感兴趣的朋友可以看看
    mysql基础语法(部分)
    python_内建结构
    07_go语言基础
    06_go语言基础
    05_go语言基础常量
    04_go语言基础
    03_go语言基础
    02_go语言基础
    01_go语言基础
  • 原文地址:https://www.cnblogs.com/wjy-lulu/p/6547542.html
Copyright © 2011-2022 走看看