多層神經網絡
對於多層神經網絡的訓練,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')
輸出結果下圖所示,交叉熵代價函數能更快地速度降低訓練誤差。