国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

BP神經(jīng)網(wǎng)絡(luò)(完整的理論和經(jīng)驗(yàn)公式)

2019-11-10 23:45:40
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

http://blog.csdn.net/runatworld/article/details/50774215

BP神經(jīng)網(wǎng)絡(luò)

2016-03-01 17:27 271人閱讀 評(píng)論(0) 收藏 舉報(bào) 分類: 

今天來(lái)講BP神經(jīng)網(wǎng)絡(luò),神經(jīng)網(wǎng)絡(luò)在機(jī)器學(xué)習(xí)中應(yīng)用比較廣泛,比如函數(shù)逼近,模式識(shí)別,分類,數(shù)據(jù)壓縮,數(shù)據(jù)

挖掘等領(lǐng)域。接下來(lái)介紹BP神經(jīng)網(wǎng)絡(luò)的原理及實(shí)現(xiàn)。

 

Contents

 

  1. BP神經(jīng)網(wǎng)絡(luò)的認(rèn)識(shí)

  2. 隱含層的選取

  3. 正向傳遞子過(guò)程

  4. 反向傳遞子過(guò)程

  5. BP神經(jīng)網(wǎng)絡(luò)的注意點(diǎn)

  6. BP神經(jīng)網(wǎng)絡(luò)的C++實(shí)現(xiàn)

 

 

1. BP神經(jīng)網(wǎng)絡(luò)的認(rèn)識(shí)

 

   BP(Back PRopagation)神經(jīng)網(wǎng)絡(luò)分為兩個(gè)過(guò)程

 

      (1)工作信號(hào)正向傳遞子過(guò)程

      (2)誤差信號(hào)反向傳遞子過(guò)程

 

   在BP神經(jīng)網(wǎng)絡(luò)中,單個(gè)樣本有個(gè)輸入,有個(gè)輸出,在輸入層和輸出層之間通常還有若干個(gè)隱含層。實(shí)際

   上,1989Robert Hecht-Nielsen證明了對(duì)于任何閉區(qū)間內(nèi)的一個(gè)連續(xù)函數(shù)都可以用一個(gè)隱含層的BP網(wǎng)

   絡(luò)來(lái)逼近,這就是萬(wàn)能逼近定理。所以一個(gè)三層的BP網(wǎng)絡(luò)就可以完成任意的維到維的映射。即這三層分

   別是輸入層(I),隱含層(H),輸出層(O)。如下圖示

 

        

 

 

2. 隱含層的選取

 

   在BP神經(jīng)網(wǎng)絡(luò)中,輸入層和輸出層的節(jié)點(diǎn)個(gè)數(shù)都是確定的,而隱含層節(jié)點(diǎn)個(gè)數(shù)不確定,那么應(yīng)該設(shè)置為多少

   才合適呢?實(shí)際上,隱含層節(jié)點(diǎn)個(gè)數(shù)的多少對(duì)神經(jīng)網(wǎng)絡(luò)的性能是有影響的,有一個(gè)經(jīng)驗(yàn)公式可以確定隱含層

   節(jié)點(diǎn)數(shù)目,如下

 

                

 

   其中為隱含層節(jié)點(diǎn)數(shù)目,為輸入層節(jié)點(diǎn)數(shù)目,為輸出層節(jié)點(diǎn)數(shù)目,之間的調(diào)節(jié)常數(shù)。

 

 

3. 正向傳遞子過(guò)程

 

   現(xiàn)在設(shè)節(jié)點(diǎn)和節(jié)點(diǎn)之間的權(quán)值為,節(jié)點(diǎn)的閥值為,每個(gè)節(jié)點(diǎn)的輸出值為,而每個(gè)節(jié)點(diǎn)的輸出

   值是根據(jù)上層所有節(jié)點(diǎn)的輸出值、當(dāng)前節(jié)點(diǎn)與上一層所有節(jié)點(diǎn)的權(quán)值和當(dāng)前節(jié)點(diǎn)的閥值還有激活函數(shù)來(lái)實(shí)現(xiàn)

   的。具體計(jì)算方法如下

 

                    

 

   其中為激活函數(shù),一般選取S型函數(shù)或者線性函數(shù)。

 

   正向傳遞的過(guò)程比較簡(jiǎn)單,按照上述公式計(jì)算即可。在BP神經(jīng)網(wǎng)絡(luò)中,輸入層節(jié)點(diǎn)沒(méi)有閥值。

 

 

4. 反向傳遞子過(guò)程

 

   在BP神經(jīng)網(wǎng)絡(luò)中,誤差信號(hào)反向傳遞子過(guò)程比較復(fù)雜,它是基于Widrow-Hoff學(xué)習(xí)規(guī)則的。假設(shè)輸出層

   的所有結(jié)果為,誤差函數(shù)如下

 

                    

 

   而BP神經(jīng)網(wǎng)絡(luò)的主要目的是反復(fù)修正權(quán)值和閥值,使得誤差函數(shù)值達(dá)到最小。Widrow-Hoff學(xué)習(xí)規(guī)則

   是通過(guò)沿著相對(duì)誤差平方和的最速下降方向,連續(xù)調(diào)整網(wǎng)絡(luò)的權(quán)值和閥值,根據(jù)梯度下降法,權(quán)值矢量

   的修正正比于當(dāng)前位置上E(w,b)的梯度,對(duì)于第個(gè)輸出節(jié)點(diǎn)有

 

                    

   假設(shè)選擇激活函數(shù)為

 

                    

 

   對(duì)激活函數(shù)求導(dǎo),得到

 

                   

 

   那么接下來(lái)針對(duì)

 

                   

 

   其中有

                            

 

   同樣對(duì)于

 

                 

 

   這就是著名的學(xué)習(xí)規(guī)則,通過(guò)改變神經(jīng)元之間的連接權(quán)值來(lái)減少系統(tǒng)實(shí)際輸出和期望輸出的誤差,這個(gè)規(guī)

   則又叫做Widrow-Hoff學(xué)習(xí)規(guī)則或者糾錯(cuò)學(xué)習(xí)規(guī)則

  

   上面是對(duì)隱含層和輸出層之間的權(quán)值和輸出層的閥值計(jì)算調(diào)整量,而針對(duì)輸入層和隱含層和隱含層的閥值調(diào)

   整量的計(jì)算更為復(fù)雜。假設(shè)是輸入層第k個(gè)節(jié)點(diǎn)和隱含層第i個(gè)節(jié)點(diǎn)之間的權(quán)值,那么有

 

                

   其中有

 

                

 

   這樣對(duì)學(xué)習(xí)規(guī)則理解更為深刻了吧。

 

   有了上述公式,根據(jù)梯度下降法,那么對(duì)于隱含層和輸出層之間的權(quán)值和閥值調(diào)整如下

 

                

 

   而對(duì)于輸入層和隱含層之間的權(quán)值和閥值調(diào)整同樣有

 

                

 

   至此BP神經(jīng)網(wǎng)絡(luò)的原理基本講完。

 

 

5. BP神經(jīng)網(wǎng)絡(luò)的注意點(diǎn)

 

   BP神經(jīng)網(wǎng)絡(luò)一般用于分類或者逼近問(wèn)題。如果用于分類,則激活函數(shù)一般選用Sigmoid函數(shù)或者硬極限函

   數(shù),如果用于函數(shù)逼近,則輸出層節(jié)點(diǎn)用線性函數(shù),即

 

   BP神經(jīng)網(wǎng)絡(luò)在訓(xùn)練數(shù)據(jù)時(shí)可以采用增量學(xué)習(xí)或者批量學(xué)習(xí)。

 

   增量學(xué)習(xí)要求輸入模式要有足夠的隨機(jī)性,對(duì)輸入模式的噪聲比較敏感,即對(duì)于劇烈變化的輸入模式,訓(xùn)

   練效果比較差,適合在線處理。批量學(xué)習(xí)不存在輸入模式次序問(wèn)題,穩(wěn)定性好,但是只適合離線處理。

 

   標(biāo)準(zhǔn)BP神經(jīng)網(wǎng)絡(luò)的缺陷:

 

   (1)容易形成局部極小值而得不到全局最優(yōu)值。

       BP神經(jīng)網(wǎng)絡(luò)中極小值比較多,所以很容易陷入局部極小值,這就要求對(duì)初始權(quán)值和閥值有要求,要使

       得初始權(quán)值和閥值隨機(jī)性足夠好,可以多次隨機(jī)來(lái)實(shí)現(xiàn)。

   (2)訓(xùn)練次數(shù)多使得學(xué)習(xí)效率低,收斂速度慢。

   (3)隱含層的選取缺乏理論的指導(dǎo)。

   (4)訓(xùn)練時(shí)學(xué)習(xí)新樣本有遺忘舊樣本的趨勢(shì)。

   

   BP算法的改進(jìn):

 

   (1)增加動(dòng)量項(xiàng)

       引入動(dòng)量項(xiàng)是為了加速算法收斂,即如下公式

 

       

 

       動(dòng)量因子一般選取

 

   (2)自適應(yīng)調(diào)節(jié)學(xué)習(xí)率

   (3)引入陡度因子

 

   通常BP神經(jīng)網(wǎng)絡(luò)在訓(xùn)練之前會(huì)對(duì)數(shù)據(jù)歸一化處理,即將數(shù)據(jù)映射到更小的區(qū)間內(nèi),比如[0,1]或[-1,1]。

 

 

6. BP神經(jīng)網(wǎng)絡(luò)的C++實(shí)現(xiàn)

 

   BP神經(jīng)網(wǎng)絡(luò)的C++文件如下

 

   

 

BP.h:

[cpp] view plain copy  在CODE上查看代碼片#ifndef _BP_H_  #define _BP_H_     #include <vector>     #define LAYER    3        //三層神經(jīng)網(wǎng)絡(luò)  #define NUM      10       //每層的最多節(jié)點(diǎn)數(shù)     #define A        30.0  #define B        10.0     //A和B是S型函數(shù)的參數(shù)  #define ITERS    1000     //最大訓(xùn)練次數(shù)  #define ETA_W    0.0035   //權(quán)值調(diào)整率  #define ETA_B    0.001    //閥值調(diào)整率  #define ERROR    0.002    //單個(gè)樣本允許的誤差  #define ACCU     0.005    //每次迭代允許的誤差     #define Type double  #define Vector std::vector     struct Data  {      Vector<Type> x;       //輸入數(shù)據(jù)      Vector<Type> y;       //輸出數(shù)據(jù)  };     class BP{     public:         void GetData(const Vector<Data>);      void Train();      Vector<Type> ForeCast(const Vector<Type>);     private:         void InitNetWork();         //初始化網(wǎng)絡(luò)      void GetNums();             //獲取輸入、輸出和隱含層節(jié)點(diǎn)數(shù)      void ForwardTransfer();     //正向傳播子過(guò)程      void ReverseTransfer(int);  //逆向傳播子過(guò)程      void CalcDelta(int);        //計(jì)算w和b的調(diào)整量      void UpdateNetWork();       //更新權(quán)值和閥值      Type GetError(int);         //計(jì)算單個(gè)樣本的誤差      Type GetAccu();             //計(jì)算所有樣本的精度      Type Sigmoid(const Type);   //計(jì)算Sigmoid的值     private:      int in_num;                 //輸入層節(jié)點(diǎn)數(shù)      int ou_num;                 //輸出層節(jié)點(diǎn)數(shù)      int hd_num;                 //隱含層節(jié)點(diǎn)數(shù)         Vector<Data> data;          //輸入輸出數(shù)據(jù)         Type w[LAYER][NUM][NUM];    //BP網(wǎng)絡(luò)的權(quán)值      Type b[LAYER][NUM];         //BP網(wǎng)絡(luò)節(jié)點(diǎn)的閥值             Type x[LAYER][NUM];         //每個(gè)神經(jīng)元的值經(jīng)S型函數(shù)轉(zhuǎn)化后的輸出值,輸入層就為原值      Type d[LAYER][NUM];         //記錄delta學(xué)習(xí)規(guī)則中delta的值  };     #endif  //_BP_H_  BP.cpp:

[cpp] view%20plain copy  #include <string.h>  #include <stdio.h>  #include <math.h>  #include <assert.h>  #include "BP.h"    //獲取訓(xùn)練所有樣本數(shù)據(jù)  void BP::GetData(const Vector<Data> _data)  {      data = _data;  }    //開始進(jìn)行訓(xùn)練  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++)          {              //第一層輸入節(jié)點(diǎn)賦值              for(int i = 0; i < in_num; i++)                  x[0][i] = data.at(cnt).x[i];                while(1)              {                  ForwardTransfer();                       if(GetError(cnt) < ERROR)    //如果誤差比較小,則針對(duì)單個(gè)樣本跳出循環(huán)                      break;                  ReverseTransfer(cnt);                }          }          printf("This is the %d th trainning NetWork !/n", iter);            Type accu = GetAccu();          printf("All Samples Accuracy is %lf/n", accu);          if(accu < ACCU) break;      }      printf("The BP NetWork train End!/n");  }    //根據(jù)訓(xùn)練好的網(wǎng)絡(luò)來(lái)預(yù)測(cè)輸出值  Vector<Type> BP::ForeCast(const Vector<Type> data)  {      int n = data.size();      assert(n == in_num);      for(int i = 0; i < in_num; i++)          x[0][i] = data[i];            ForwardTransfer();      Vector<Type> v;      for(int i = 0; i < ou_num; i++)          v.push_back(x[2][i]);      return v;  }    //獲取網(wǎng)絡(luò)節(jié)點(diǎn)數(shù)  void BP::GetNums()  {      in_num = data[0].x.size();                         //獲取輸入層節(jié)點(diǎn)數(shù)      ou_num = data[0].y.size();                         //獲取輸出層節(jié)點(diǎn)數(shù)      hd_num = (int)sqrt((in_num + ou_num) * 1.0) + 5;   //獲取隱含層節(jié)點(diǎn)數(shù)      if(hd_num > NUM) hd_num = NUM;                     //隱含層數(shù)目不能超過(guò)最大設(shè)置  }    //初始化網(wǎng)絡(luò)  void BP::InitNetWork()  {      memset(w, 0, sizeof(w));      //初始化權(quán)值和閥值為0,也可以初始化隨機(jī)值      memset(b, 0, sizeof(b));  }    //工作信號(hào)正向傳遞子過(guò)程  void BP::ForwardTransfer()  {      //計(jì)算隱含層各個(gè)節(jié)點(diǎn)的輸出值      for(int j = 0; j < hd_num; j++)      {          Type 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);      }        //計(jì)算輸出層各節(jié)點(diǎn)的輸出值      for(int j = 0; j < ou_num; j++)      {          Type 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);      }  }    //計(jì)算單個(gè)樣本的誤差  Type BP::GetError(int cnt)  {      Type ans = 0;      for(int i = 0; i < ou_num; i++)          ans += 0.5 * (x[2][i] - data.at(cnt).y[i]) * (x[2][i] - data.at(cnt).y[i]);      return ans;  }    //誤差信號(hào)反向傳遞子過(guò)程  void BP::ReverseTransfer(int cnt)  {      CalcDelta(cnt);         UpdateNetWork();  }    //計(jì)算所有樣本的精度  Type BP::GetAccu()  {      Type ans = 0;      int num = data.size();      for(int i = 0; i < num; i++)      {          int m = data.at(i).x.size();          for(int j = 0; j < m; j++)              x[0][j] = data.at(i).x[j];          ForwardTransfer();          int n = data.at(i).y.size();          for(int j = 0; j < n; j++)              ans += 0.5 * (x[2][j] - data.at(i).y[j]) * (x[2][j] - data.at(i).y[j]);      }      return ans / num;  }    //計(jì)算調(diào)整量  void BP::CalcDelta(int cnt)  {      //計(jì)算輸出層的delta值      for(int i = 0; i < ou_num; i++)          d[2][i] = (x[2][i] - data.at(cnt).y[i]) * x[2][i] * (A - x[2][i]) / (A * B);      //計(jì)算隱含層的delta值      for(int i = 0; i < hd_num; i++)      {          Type 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);      }  }    //根據(jù)計(jì)算出的調(diào)整量對(duì)BP網(wǎng)絡(luò)進(jìn)行調(diào)整  void BP::UpdateNetWork()  {      //隱含層和輸出層之間權(quán)值和閥值調(diào)整      for(int i = 0; i < hd_num; i++)      {          for(int j = 0; j < ou_num; j++)              w[2][i][j] -= ETA_W * d[2][j] * x[1][i];       }      for(int i = 0; i < ou_num; i++)          b[2][i] -= ETA_B * d[2][i];        //輸入層和隱含層之間權(quán)值和閥值調(diào)整      for(int i = 0; i < in_num; i++)      {          for(int j = 0; j < hd_num; j++)              w[1][i][j] -= ETA_W * d[1][j] * x[0][i];      }      for(int i = 0; i < hd_num; i++)          b[1][i] -= ETA_B * d[1][i];  }    //計(jì)算Sigmoid函數(shù)的值  Type BP::Sigmoid(const Type x)  {      return A / (1 + exp(-x / B));  }  

Test.cpp:

[cpp] view%20plain copy  #include <iostream>  #include <string.h>  #include <stdio.h>     #include "BP.h"     using namespace std;     double sample[41][4]=   {       {0,0,0,0},       {5,1,4,19.020},       {5,3,3,14.150},       {5,5,2,14.360},       {5,3,3,14.150},       {5,3,2,15.390},       {5,3,2,15.390},       {5,5,1,19.680},       {5,1,2,21.060},       {5,3,3,14.150},       {5,5,4,12.680},       {5,5,2,14.360},       {5,1,3,19.610},       {5,3,4,13.650},       {5,5,5,12.430},       {5,1,4,19.020},       {5,1,4,19.020},       {5,3,5,13.390},       {5,5,4,12.680},       {5,1,3,19.610},       {5,3,2,15.390},       {1,3,1,11.110},       {1,5,2,6.521},       {1,1,3,10.190},       {1,3,4,6.043},       {1,5,5,5.242},       {1,5,3,5.724},       {1,1,4,9.766},       {1,3,5,5.870},       {1,5,4,5.406},       {1,1,3,10.190},       {1,1,5,9.545},       {1,3,4,6.043},       {1,5,3,5.724},       {1,1,2,11.250},       {1,3,1,11.110},       {1,3,3,6.380},       {1,5,2,6.521},       {1,1,1,16.000},       {1,3,2,7.219},       {1,5,3,5.724}   };      int main()  {      Vector<Data> data;      for(int i = 0; i < 41; i++)      {          Data t;          for(int j = 0; j < 3; j++)              t.x.push_back(sample[i][j]);          t.y.push_back(sample[i][3]);          data.push_back(t);      }      BP *bp = new BP();      bp->GetData(data);      bp->Train();         while(1)      {          Vector<Type> in;          for(int i = 0; i < 3; i++)          {              Type v;              scanf("%lf", &v);              in.push_back(v);          }          Vector<Type> ou;          ou = bp->ForeCast(in);          printf("%lf/n", ou[0]);      }      return 0;  }   

Makefile:

[cpp] view%20plain copy  派生到我的代碼片Test : BP.h BP.cpp Test.cpp      g++ BP.cpp Test.cpp -o Test     clean:      rm Test  
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 湖州市| 怀柔区| 徐水县| 天峻县| 林甸县| 集贤县| 临沭县| 韶山市| 大方县| 武宁县| 云霄县| 会理县| 施甸县| 全椒县| 眉山市| 银川市| 三河市| 偏关县| 如东县| 吉安市| 宝兴县| 广元市| 黄冈市| 孟津县| 永平县| 驻马店市| 云龙县| 江门市| 丰台区| 宜州市| 新泰市| 区。| 蒲城县| 肥西县| 江安县| 额敏县| 民乐县| 祁连县| 水富县| 闽侯县| 虹口区|