1. 程式人生 > >BP神經網路原理與matlab實現

BP神經網路原理與matlab實現

個人部落格文章連結: http://www.huqj.top/article?id=166

BP神經網路,即“反向傳播”神經網路,是一種被廣泛運用的人工神經網路,它的思想就是通過反向傳播不斷調整模型權重,最終使得模型輸出與預期輸出的誤差控制在一個小範圍內。其中反向傳播的演算法(BP演算法)是核心。

    一、模型架構

    一個普通的神經網路模型大致如下圖:

    image.png

    其中第一層稱為“輸入層”,最後一層稱為“輸出層”,其他層都是“隱含層”,每一層由若干個神經元(也就是圖中的小圓圈)組成,輸入層的神經元數目就是訓練資料每個X的維度值,或者說是特徵數目,輸出層的神經元數目就是資料集的因變數維度。隱含層的數目和每層的神經元個數是隨意的,一般根據模型需要調節。相鄰層之間通過權重相連,每一層的每個神經元都與下一層的每個神經元相連。

    BP神經網路訓練的計算過程分為兩種:前向傳播反向傳播

    前向傳播就是從資料資料前向計算出最終結果的過程,這也是模型訓練好之後應用的方式。反向傳播是一種引數調節方法,它從前向傳播計算出的最終結果與實際資料相比計算誤差,並根據數學公式逆向推導各個神經元和權重的誤差,然後更新權重,重複前向傳播的過程。在前向傳播的過程中,除了第一層,每個神經元都接受上一層的輸入,然後使用一個 激勵函式 輸出值到下一層。

    二、數學原理以下公式都為矩陣表示形式

    BP神經網路,本質上也是一個引數調優的模型,其中引數就是各個權重。

    使用 a 表示每個神經元的輸出, z 表示每個神經元的輸入, W 表示權重, g(z) 表示神經元的激勵函式,則前向傳播的計算公式如下:

    a(1) = Xi        

    i 表示是第i組訓練資料

    z(2) = W(1) * a(1)  Add(a0 = 1)        

    W 是一個 Sl+1 * (Sl  + 1) 的矩陣, Sk 表示是第 層神經元的數目,這裡添加了一個值為1的偏置單元

    a(2) = g(z(2))

    g是激勵函式,在分類問題中,通常使用sigmoid函式

    以此類推,即可完成前向傳播的過程,直到計算到輸出層。

 

    而對於反向傳播(BP)的過程,實際就是求代價函式偏導數的過程,神經網路模型的代價函式如下:

    image.png

    為了計算這個代價函式的偏導數,我們定義了兩個矩陣變數:δ 和 Δ,分別是二維和三維矩陣,δ 用來儲存每個神經元的偏差,Δ 用來儲存每個權重的偏差。

    反向傳播的計算公式如下:

    δ(end) = a(end) - yi

    輸出層的偏差就是預測值與實際值的插值, i 表示是第 i  組訓練資料

    δ(j) = (W(j))T * δ(j+1) * g'(z(j))

    即上一層的誤差是由下一層的誤差和兩層之間的連線權重,以及該層神經元的激勵函式導數值決定的。對於激勵函式為sigmoid函式的模型而言,可以通過導數計算得到如下公式:

    δ(j) = (W(j))T * δ(j+1) * a(j) * (1 - a(j))

    這樣依次從後往前計算,就可以得到所有神經元的δ值。

    對於Δ值的計算,有如下公式:

    Δ(j) = Δ(j) + δ(j+i) * (a(j))T

    注意 Δ 是累加值,累加的是每組訓練資料。當累加完所有訓練資料之後,就可以計算出代價函式的導數了:

    D = Δ / m + lambda * W / m

    可以從數學上證明,此時D就是代價函式的導數(加上了正則化引數),然後要做的就是應用梯度下降法調整權重W,再重複此過程。

    三、matlab實現

    有了上面的數學原理和公式推導,我們可以使用Matlab很快的實現一個BP神經網路模型:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

%% 主函式

function [W, delta, iterNum] = BPNN(size_, alpha, lambda, threshold, maxIter, X, y)

    %BP神經網路實現

    %引數含義:

    %size - 一維陣列,表示神經網路架構(不包含偏置單元)

    %alpha - 學習率α

    %lambda - 正則化引數

    %threshold - 誤差閾值

    %maxIter - 最大迭代次數

    %X,y - 訓練資料

     

    %判斷引數合法性

    if size(X, 2) ~= size_(1) || size(y, 2) ~= size_(end) || size(y, 1) ~= size(X, 1)

       fprintf('訓練資料集與模型結構不符\n'); 

    end

 

    %初始化一些引數

    layerNum = length(size_);

    maxUnitNum = max(size_);

    m = size(X, 1);

    iterNum = 0;

     

    %每個神經元的輸出

    a = zeros(layerNum, maxUnitNum);

    %每個神經元的誤差

    d = zeros(layerNum, maxUnitNum);

    %初始隨機權重

    W = rand(layerNum - 1, maxUnitNum + 1, maxUnitNum + 1);

     

    %迭代訓練

    while iterNum < maxIter

       iterNum = iterNum + 1;

       D = zeros(layerNum - 1, maxUnitNum + 1, maxUnitNum + 1);

       delta = 0;

       for i = 1 : m

           %前向傳播

           [out, a] = forwardPropagation(size_, W, X(i, :), a);

           d(end, 1 : length(out)) = out - y(i, :);

           delta = delta + sum(abs(out - y(i, :)));

           %反向傳播

           [d, D] = backPropagation(size_, W, d, D, a);

       end

       delta = delta / m;

       if delta <= threshold

           fprintf('誤差小於閾值,訓練結束');

           break;

       end

       %調整權重

       W = adjustWeight(size_, W, D, alpha, lambda, m);

    end

 

end

 

%% 一次前向傳播

function [out, a] = forwardPropagation(size_, W, x, a)

    out = x;

    a(1, 1 : size_(1)) = x;

    for i = 1 : length(size_) - 1

        out = reshape(W(i, 2 : size_(i + 1) + 1, 1 : size_(i) + 1), size_(i + 1), size_(i) + 1) * [1, out]';

        out = sigmoid(out');

        a(i + 1, 1 : size_(i + 1)) = out;

    end

end

 

%% 一次反向傳播

function [d, D] = backPropagation(size_, W, d, D, a)

    for i = length(size_) - 1 : -1 : 1

        %調節每個神經元的誤差值

        d(i, 1 : size_(i)) = d(i + 1, 1 : size_(i + 1)) * ...

            reshape(W(i, 2 : size_(i + 1) + 1, 2 : size_(i) + 1), size_(i + 1), size_(i))...

            .* (a(i, 1 : size_(i)) .* (1 - a(i, 1 : size_(i))));

        % 累加調節每個權重的誤差

        D(i, 2 : size_(i + 1) + 1, 1 : size_(i) + 1) = D(i, 2 : size_(i + 1) + 1, 1 : size_(i) + 1) + ...

            reshape(([1; a(i, 1 : size_(i))'] * d(i + 1, 1 : size_(i + 1)))', 1, size_(i + 1), size_(i) + 1);

    end

end

 

%% 調整權重

function W = adjustWeight(size_, W, D, alpha, lambda, m)

    D = D / m;

    for i2 = 1 : length(size_) - 1

        %非常數項係數加上正則化引數

        D(i2, 2 : size_(i2 + 1) + 1, 2 : size_(i2) + 1) = D(i2, 2 : size_(i2 + 1) + 1, 2 : size_(i2) + 1) + ...

           lambda * W(i2, 2 : size_(i2 + 1) + 1, 2 : size_(i2) + 1) / m;

       %梯度下降調整權重

       W(i2, 1 : size_(i2 + 1) + 1, 1 : size_(i2) + 1) = W(i2, 1 : size_(i2 + 1) + 1, 1 : size_(i2) + 1) -...

           alpha * D(i2, 1 : size_(i2 + 1) + 1, 1 : size_(i2) + 1);

    end

end

    使用這個函式進行一次神經網路訓練實驗的測試程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

% 測試BP神經網路函式

 

%% 讀取資料

clc;

clear;

data = load('machine-learning-ex2\ex2\ex2data2.txt');

 

%% 初始化引數

m = size(data, 1);

X = data(:,[1, 2]);

y = data(:, 3);

size_ = [2, 4, 1];

lambda = 0;

alpha = 2;

threshold = 0.1;

 

%% 畫出點集

hold on

LogisticPlotData([ones(m, 1), X], y);

 

%% 開始訓練

[W, delta, times] = BPNN(size_, alpha, lambda, threshold, 2000, X, y);

 

%% 測試準確度

[~, precious] = BPNNPredict(size_, W, X, y)

 

%% 畫出決策邊界

u = min(X(:, 1)) - 0.5: 0.1: max(X(:, 1)) + 0.5;

v = min(X(:, 2)) - 0.5: 0.1: max(X(:, 2)) + 0.5;

 

z = zeros(length(u), length(v));

 

for i = 1 : length(u)

   for j = 1 : length(v)

      [z(i, j), precious] = BPNNPredict(size_, W, [u(i), v(j)], 0); 

   end

end

z = z';

contour(u, v, z, [0.5, 0.5], 'LineWidth', 2);

hold off;

    這是一個分類問題,可以使用邏輯迴歸的方法實現,可以參考部落格:http://www.huqj.top/article?id=165  ,這裡使用BP神經網路實現,最終決策邊界如下。

    image.png

    在訓練集上的準確度可以達到87%.BP神經網路相對於邏輯迴歸的優勢就在於它不需要手動選擇模型,而是通過訓練可以自動選擇一個合適的模型來模擬。