筆記 - 機器學習 神經網路 - 進階學習

[筆記] 機器學習 神經網路 - 進階學習

代價函數與反向傳播算法 ( Backpropagation )

符號定義 :

  • L : 神經網路中擁有的層數
  • sₗ : 第 l 層中的單元個數
  • K : 輸出的單元 ( 分類 ) 個數

神經網路的代價函數

  • 神經網路中的代價函數

    • 過往的正規化就是計算輸出層中的每個單元
    • 而在神經網路則是機算整個網路中的所有單元
    • 此 i ( 後者 ) 並非訓練資料的 i ( 前者 )

反向傳播算法 ( Backpropagation )

  • 是一種訓練神經網路的常見方法,與梯度下降結合使用,目的是找到一組能最大限度地減小誤差的權重

  • 演算法 :

假設有訓練資料 {(x⁽¹⁾, y⁽¹⁾) ... (x⁽ᵐ⁾, y⁽ᵐ⁾)}

設定 Δᵢⱼ⁽ˡ⁾ := 0 ( for all l, i, j )

For i = 1 to m :

  1. 設定 a⁽¹⁾ := x⁽ⁱ⁾
  2. 計算 a⁽ˡ⁾ ( for l = 2, 3, ..., L )
  3. 使用 y⁽ⁱ⁾ 計算 δ⁽ᴸ⁾ = a⁽ᴸ⁾ - y⁽ⁱ⁾,L 代表 output layer
  4. 使用 δ⁽ˡ⁾ = ((Θ⁽ˡ⁾)ᵀδ⁽ˡ⁺¹⁾) .* a⁽ˡ⁾ .* (1 - a⁽ˡ⁾) 計算 δ⁽ᴸ⁻¹⁾, δ⁽ᴸ⁻²⁾, ..., δ⁽²⁾

    • 激勵函數的導函數 : g'(z⁽ˡ⁾) = a⁽ˡ⁾ .* (1 - a⁽ˡ⁾)
  5. Δᵢⱼ⁽ˡ⁾ := Δᵢⱼ⁽ˡ⁾ + aⱼ⁽ˡ⁾δᵢ⁽ˡ⁺¹⁾,向量化 : Δ⁽ˡ⁾ := Δ⁽ˡ⁾ + δ⁽ˡ⁺¹⁾(a⁽ˡ⁾)ᵀ

    • Dᵢⱼ⁽ˡ⁾ := (1 / m)(Δᵢⱼ⁽ˡ⁾ + λΘᵢⱼ⁽ˡ⁾),if j ≠ 0
    • Dᵢⱼ⁽ˡ⁾ := (1 / m) Δᵢⱼ⁽ˡ⁾,if j = 0
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
function [J grad] = nnCostFunction(nn_params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda)

Theta1 = reshape(nn_params(1:hidden_layer_size * (input_layer_size + 1)), hidden_layer_size, (input_layer_size + 1));

Theta2 = reshape(nn_params((1 + (hidden_layer_size * (input_layer_size + 1))):end), num_labels, (hidden_layer_size + 1));

m = size(X, 1);
J = 0;
Theta1_grad = zeros(size(Theta1));
Theta2_grad = zeros(size(Theta2));

% 前向傳播算法

a1 = [ones(m, 1) X];

z2 = a1 * Theta1';
a2 = sigmoid(z2);
a2 = [ones(size(a2, 1), 1) a2];

z3 = a2 * Theta2';
a3 = sigmoid(z3);
h = a3;

yVec = zeros(m, num_labels);

for i = 1:m

yVec(i, y(i)) = 1;

endfor

J = 1 / m * sum(sum(-1 * yVec .* log(h) - (1 - yVec) .* log(1 - h)));

regularator = (lambda / (2 * m)) * (sum(sum(Theta1(:, 2:end) .^ 2)) + sum(sum(Theta2(:, 2:end) .^ 2)));

J = J + regularator;

% 反向傳播算法

for t = 1:m

% 設定 a1 為 X
a1 = [1; X(t,:)'];

% 計算 aL ( L = 1, 2, ..., L )
z2 = Theta1 * a1;
a2 = [1; sigmoid(z2)];

z3 = Theta2 * a2;
a3 = sigmoid(z3);

% 計算 deltaL
yy = ([1:num_labels] == y(t))';
delta3 = a3 - yy;

% 計算 delta ( L - 1, L - 2, ..., 2 )
delta2 = (Theta2' * delta3) .* [1; sigmoidGradient(z2)];
delta2 = delta2(2:end); % 不計算 bias unit

% 計算 big delta
Theta1_grad = Theta1_grad + delta2 * a1';
Theta2_grad = Theta2_grad + delta3 * a2';

endfor

Theta1_grad = (1/m) * Theta1_grad + (lambda/m) * [zeros(size(Theta1, 1), 1) Theta1(:,2:end)];
Theta2_grad = (1/m) * Theta2_grad + (lambda/m) * [zeros(size(Theta2, 1), 1) Theta2(:,2:end)];

% 展開
grad = [Theta1_grad(:) ; Theta2_grad(:)];

end
  • 在 Octave 上的前向傳播與反向傳播
1
2
3
4
5
6
7
function g = sigmoidGradient(z)

g = zeros(size(z));

g = sigmoid(z) .* (1 - sigmoid(z));

end
  • 在 Octave 上的激勵函數的導函數

  • δⱼ⁽ˡ⁾ 就是 aⱼ⁽ˡ⁾ 的偏差,也是代價函數的導數

  • δ₁⁽⁴⁾ = a₁⁽⁴⁾ - y⁽ⁱ⁾
  • δ₂⁽³⁾ = Θ₁₂⁽³⁾ * δ₁⁽⁴⁾
  • δ₂⁽²⁾ = Θ₁₂⁽²⁾ * δ₁⁽³⁾ + Θ₂₂⁽²⁾ * δ₂⁽³⁾

實作反向傳播算法

矩陣展開成向量與還原

  • fminunc() 的高級優化算法中,通常都需要傳入向量,這時我們就需要將矩陣展開成向量
1
2
thetaVector = [Theta1(:); Theta2(:); Theta3(:);]
deltaVector = [D1(:); D2(:); D3(:)]
  • 假設有 Θ⁽¹⁾、Θ⁽²⁾、Θ⁽³⁾,D⁽¹⁾、D⁽²⁾、D⁽³⁾,展開成向量
1
2
3
Theta1 = reshape(thetaVector(1:110), 10, 11)
Theta2 = reshape(thetaVector(111:220), 10, 11)
Theta3 = reshape(thetaVector(221:231), 1, 11)
  • 假設 Θ⁽¹⁾ 為 10 11 矩陣、Θ⁽²⁾ 為 10 11 矩陣、Θ⁽³⁾ 為 1 * 11 矩陣,將他們還原
應用
1
2
3
創建初始化的 Θ⁽¹⁾、Θ⁽²⁾、Θ⁽³⁾
展開成向量 initialTheta
fminunc(@costFunction, initialTheta, options)
  • 使用 fminunc()
1
2
3
4
5
6
7
function [jval, gradientVec] = costFunction(thetaVec)

還原 thetaVec 成 Θ⁽¹⁾、Θ⁽²⁾、Θ⁽³⁾
使用梯度下降或反向傳播算法算出 D⁽¹⁾、D⁽²⁾、D⁽³⁾ 和 J(Θ)
展開 D⁽¹⁾、D⁽²⁾、D⁽³⁾ 成向量 gradientVec

end
  • costFunction() 寫法

梯度驗證 ( Gradient Checking )

  • 通常使用反向傳播算法可能會出現許多 BUG,梯度驗證可以確保我們的反向傳播算法是如預期地工作的
  • 算式 :

  • 有多個 Θ 矩陣時 :

  • 通常 ϵ 設定為 10⁻⁴,如果太小會導致數值問題
1
2
3
4
5
6
7
8
9
10
11
12
13
epsilon = 1e-4;

for i = 1:n,

thetaPlus = theta;
thetaPlus(i) += epsilon;

thetaMinus = theta;
thetaMinus(i) -= epsilon;

gradApprox(i) = (J(thetaPlus) - J(thetaMinus))/(2*epsilon)

end;
  • 在 Octave 上的梯度驗證
  • 驗證 gradApprox ≈ deltaVector,確定反向傳播算法沒有錯誤後,就必須把梯度驗證關掉了,因為梯度驗證會導致程式執行非常的慢

隨機初始化 ( Random Initialization )

  • 在神經網路中,將 Θ 的所有權重初始化為 0 是不適合的
  • 這樣會因為對稱而造成所有節點更新為相同的值
  • 所以我們需要使用下面方法來隨機初始化 ( 打破對稱 Symmetry breaking ) Θ 的權重 :

  • 將每個 Θᵢⱼ⁽ˡ⁾ 初始化為 [−ϵ, ϵ] 之間的隨機值,此 ϵ 並非梯度驗證的 ϵ
1
2
3
4
5
%If the dimensions of Theta1 is 10x11, Theta2 is 10x11 and Theta3 is 1x11.

Theta1 = rand(10, 11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta2 = rand(10, 11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta3 = rand(1, 11) * (2 * INIT_EPSILON) - INIT_EPSILON;
  • 在 Octave 上的隨機初始化概念
1
2
3
4
5
6
7
8
function W = randInitializeWeights(L_in, L_out)

W = zeros(L_out, 1 + L_in);

epsilon_init = 0.12;
W = rand(L_out, 1 + L_in) * 2 * epsilon_init - epsilon_init;

end
  • 在 Octave 上的隨機初始化

總結

  1. 神經網路的布局

    • input 單元數 = 特徵數 ( x )
    • output 單元數 = 類別數 ( y )
    • hidden 單元數通常越多越好,但計算的成本通常會隨之增加,必須取得平衡
    • 潛規則 :

      • 至少有一層 hidden layer
      • 有兩層以上的 hidden layer,則建議每層單元數都相同
  2. 訓練神經網路

    1. 隨機初始化權重 ( Θ )
    2. 實現向前傳播取得 hΘ(x⁽ⁱ⁾)
    3. 實現代價函數
    4. 實現反向傳播算法以計算導數

      1
      2
      3
      4
      5
      6
      for i = 1:m,

      使用 (x⁽ⁱ⁾, y⁽ⁱ⁾) 執行向前傳播與反向傳播
      取得 a⁽ˡ⁾ 與 delta d⁽ˡ⁾ ( l = 2, ..., L )

      end;
    5. 使用梯度驗證確認反向傳播算法是否正確,確認後關閉

    6. 使用梯度下降或其他最優化功能計算代價函數最小值,並獲得 Θ 的權重
tags: 筆記 機器學習 神經網路
Author: Kenny Li
Link: https://kennyliblog.nctu.me/2019/08/05/Machine-learning-neural-network-advanced/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.