【MATLAB深度學習】多層神經網絡


多層神經網絡

  對於多層神經網絡的訓練,delta規則是無效的,因為應用delta規則訓練必須要誤差,但在隱含層中沒有定義。輸出節點的誤差是指標准輸出和神經網絡輸出之間的差別,但訓練數據不提供隱藏層的標准輸出。

  真正的難題在於怎么定義隱藏節點的誤差,於是有了反向傳播算法。反向傳播算法的重要性在於,它提供了一種用於確定隱含節點誤差的系統方法。在該算法中,輸出誤差從輸出層逐層后移,直到與輸入層相鄰的隱含層。

1.反向傳播算法

  在反向傳播算法中,隱含節點誤差的計算方式是求取delta的反向加權和,節點的delta是誤差與激活函數導數之積。該過程從輸出層開始,並重復於所有隱含層。

  MATLAB代碼實現:

  輸入數據為 { [(0,0,1),0],[(0,1,1),1],[(1,0,1),1],[(1,1,1),0] },網絡結構為三個輸入節點,四個節點組成的隱含層,一個輸出節點。Sigmoid函數為激活函數,采用SGD實現反向傳播算法。

function [W1, W2] = BackpropXOR(W1, W2, X, D)
% 以神經網絡的權重和訓練數據作為輸入,返回調整后的權重
% 其中W1和W2為相應層的權重矩陣;X和D分別是訓練數據的輸入和標准輸入
  alpha = 0.9;
  
  N = 4;  
  for k = 1:N
    x = X(k, :)';
    d = D(k);
    
    v1 = W1*x;
    y1 = Sigmoid(v1);    
    v  = W2*y1;
    y  = Sigmoid(v);
    
    e     = d - y;
    delta = y.*(1-y).*e;

    e1     = W2'*delta;    % 反向傳播
    delta1 = y1.*(1-y1).*e1; 
    
    dW1 = alpha*delta1*x';
    W1  = W1 + dW1;
    
    dW2 = alpha*delta*y1';    
    W2  = W2 + dW2;
  end
end

  Sigmoid函數定義如下:

function y = Sigmoid(x)
  y = 1 ./ (1 + exp(-x));
end

  驗證函數效果程序:

clear all
           
X = [ 0 0 1;
      0 1 1;
      1 0 1;
      1 1 1;
    ];

D = [ 0
      1
      1
      0
    ];
      
W1 = 2*rand(4, 3) - 1;
W2 = 2*rand(1, 4) - 1;

for epoch = 1:10000           % train
  [W1 W2] = BackpropXOR(W1, W2, X, D);
end

N = 4;                        % inference
for k = 1:N
  x  = X(k, :)';
  v1 = W1*x;
  y1 = Sigmoid(v1);
  v  = W2*y1;
  y  = Sigmoid(v)
end

  輸出結果為:0.0077,0.9887,0.9885,0.0134。解決了異或問題。

2.動量

  動量m是一個添加到delta規則中用於調整權重的項。使用動量項推動權重在一定程度上向某個特定方向調整,而不是產生立即性改變。它的行為類似於物理學中的動量,能夠阻礙物體本身對外力的反應。

 

   是上一次的動量,是一個小於1的常數。動量隨時間變化方式如下:

  在過程的每一步,都向動量加上上一步的權重更新,如等。由於小於1,所以越早的權重更新對動量的影響越小。雖然影響力隨着時間的推移而減弱,但是更早的權重更新仍然存在於動量之中。因此,權重不僅受某個特定權重更新值的影響。故而,學習的穩定性得到提高。此外,動量隨着權重更新而逐漸增大。因而權重更新量也隨之越來越大。因此,學習的效率也提高了。

   應用了動量的反向傳播算法:

function [W1, W2] = BackpropMmt(W1, W2, X, D)
  alpha = 0.9;
  beta  = 0.9;

  mmt1 = zeros(size(W1));
  mmt2 = zeros(size(W2));
  
  N = 4;  
  for k = 1:N
    x = X(k, :)';
    d = D(k);
    
    v1 = W1*x;
    y1 = Sigmoid(v1);    
    v  = W2*y1;
    y  = Sigmoid(v);
    
    e     = d - y;
    delta = y.*(1-y).*e;

    e1     = W2'*delta;
    delta1 = y1.*(1-y1).*e1; 
    
    % 動量
    dW1  = alpha*delta1*x';
    mmt1 = dW1 + beta*mmt1;
    W1   = W1 + mmt1;
    
    dW2  = alpha*delta*y1';
    mmt2 = dW2 + beta*mmt2;    
    W2   = W2 + mmt2;
  end
end

  測試代碼:

clear all
           
X = [ 0 0 1;
      0 1 1;
      1 0 1;
      1 1 1;
    ];

D = [ 0
      1
      1
      0
    ];
      
W1 = 2*rand(4, 3) - 1;
W2 = 2*rand(1, 4) - 1;

for epoch = 1:10000           % train
  [W1 W2] = BackpropMmt(W1, W2, X, D);
end

N = 4;                        % inference
for k = 1:N
  x  = X(k, :)';
  v1 = W1*x;
  y1 = Sigmoid(v1);
  v  = W2*y1;
  y  = Sigmoid(v)
end

  測試結果為 0.0030,0.9947,0.9909,0.0160。

3.代價函數與學習規則

  神經網絡誤差的度量就是代價函數。神經網絡的誤差越大,代價函數的值就越高。

 

  交叉熵函數對誤差更敏感,通常認為交叉熵函數導出的學習規則能夠得到更好的性能。正則化的本質是將權重疊加到代價函數中

  交叉函數示例程序:網絡結構和輸入數據更上面一樣

 

function [W1, W2] = BackpropCE(W1, W2, X, D)
  alpha = 0.9;
  
  N = 4;  
  for k = 1:N
    x = X(k, :)';        % x = a column vector
    d = D(k);
    
    v1 = W1*x;
    y1 = Sigmoid(v1);    
    v  = W2*y1;
    y  = Sigmoid(v);
    
    e     = d - y;
    delta = e;

    e1     = W2'*delta;
    delta1 = y1.*(1-y1).*e1; 
    
    dW1 = alpha*delta1*x';
    W1 = W1 + dW1;
    
    dW2 = alpha*delta*y1';    
    W2 = W2 + dW2;
  end
end

 

  其差別在於delta的計算上。以下是測試代碼:

clear all
           
X = [ 0 0 1;
      0 1 1;
      1 0 1;
      1 1 1;
    ];

D = [ 0
      1
      1
      0
    ];
      
W1 = 2*rand(4, 3) - 1;
W2 = 2*rand(1, 4) - 1;

for epoch = 1:10000                    % train
  [W1 W2] = BackpropCE(W1, W2, X, D);
end

N = 4;                                 % inference
for k = 1:N
  x  = X(k, :)';
  v1 = W1*x;
  y1 = Sigmoid(v1);
  v  = W2*y1;
  y  = Sigmoid(v)
end

  輸出結果為 4.0043e-05,0.9997,0.9999,3.9127e-04。

 

4.代價函數比較

  比較兩種代價函數的誤差均值,代碼如下:

clear all
           
X = [ 0 0 1;
      0 1 1;
      1 0 1;
      1 1 1;
    ];

D = [ 0
      0
      1
      1
    ];


E1 = zeros(1000, 1);
E2 = zeros(1000, 1);

W11 = 2*rand(4, 3) - 1;      % Cross entropy       
W12 = 2*rand(1, 4) - 1;      % 
W21 = W11;                   % Sum of squared error
W22 = W12;                   %

for epoch = 1:1000
  [W11 W12] = BackpropCE(W11, W12, X, D);
  [W21 W22] = BackpropXOR(W21, W22, X, D);

  es1 = 0;
  es2 = 0;
  N   = 4;
  for k = 1:N
    x = X(k, :)';
    d = D(k);

    v1  = W11*x;
    y1  = Sigmoid(v1);
    v   = W12*y1;
    y   = Sigmoid(v);
    es1 = es1 + (d - y)^2;
    
    v1  = W21*x;
    y1  = Sigmoid(v1);
    v   = W22*y1;
    y   = Sigmoid(v);
    es2 = es2 + (d - y)^2;
  end
  E1(epoch) = es1 / N;
  E2(epoch) = es2 / N;
end

plot(E1, 'r')
hold on
plot(E2, 'b:')
xlabel('Epoch')
ylabel('Average of Training error')
legend('Cross Entropy', 'Sum of Squared Error')

  輸出結果下圖所示,交叉熵代價函數能更快地速度降低訓練誤差。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM