【原】Coursera—Andrew Ng機器學習—編程作業 Programming Exercise 3—多分類邏輯回歸和神經網絡


作業說明

Exercise 3,Week 4,使用Octave實現圖片中手寫數字 0-9 的識別,采用兩種方式(1)多分類邏輯回歸(2)多分類神經網絡。對比結果

(1)多分類邏輯回歸實現 lrCostFunction 計算代價和梯度。實現 OneVsAll 使用 fmincg 函數進行訓練。使用 OneVsAll 里訓練好的 theta 對 X 的數據類型進行預測,得到平均准確率。

(2)多分類神經網絡:兩層 theta 權重值在 ex3weights 里已提供。參數不需要調,只需要在 predict 里進行矩陣計算,即可得到分類結果。

數據集 :ex3data1.mat 。手寫數字圖片數據,5000個樣例每張圖片20px * 20px,也就是一共400個特征。數據集X維度為5000 * 400

     ex3weights.mat。神經網絡每一層的權重。

 

文件清單

ex3.m - Octave/MATLAB script that steps you through part 1
ex3 nn.m - Octave/MATLAB script that steps you through part 2
ex3data1.mat - Training set of hand-written digits
ex3weights.mat - Initial weights for the neural network exercise
submit.m - Submission script that sends your solutions to our servers
displayData.m - Function to help visualize the dataset
fmincg.m - Function minimization routine (similar to fminunc)
sigmoid.m - Sigmoid function
[*] lrCostFunction.m - Logistic regression cost function
[*] oneVsAll.m - Train a one-vs-all multi-class classi er
[*] predictOneVsAll.m - Predict using a one-vs-all multi-class classi er
[*] predict.m - Neural network prediction function

  * 為必須要完成的

結論

因為Octave里數組下標從1開始。所以這里將分類結果0用10替代。預測結果中的1-10代表圖片數字為1,2,3,4,5,6,7,8,9,0

矩陣運算 tricky 的地方在於維度對應,哪里需要轉置很關鍵。

多分類邏輯回歸模型

一、在數據集X里隨機選擇100個數字,繪制

displayData.m:

function [h, display_array] = displayData(X, example_width)
%DISPLAYDATA Display 2D data in a nice grid
%   [h, display_array] = DISPLAYDATA(X, example_width) displays 2D data
%   stored in X in a nice grid. It returns the figure handle h and the 
%   displayed array if requested.

% Set example_width automatically if not passed in
if ~exist('example_width', 'var') || isempty(example_width) 
    example_width = round(sqrt(size(X, 2)));
end

% Gray Image
colormap(gray);

% Compute rows, cols
[m n] = size(X);
example_height = (n / example_width);

% Compute number of items to display
display_rows = floor(sqrt(m));
display_cols = ceil(m / display_rows);

% Between images padding
pad = 1;

% Setup blank display
display_array = - ones(pad + display_rows * (example_height + pad), ...
                       pad + display_cols * (example_width + pad));

% Copy each example into a patch on the display array
curr_ex = 1;
for j = 1:display_rows
    for i = 1:display_cols
        if curr_ex > m, 
            break; 
        end
        % Copy the patch
        
        % Get the max value of the patch
        max_val = max(abs(X(curr_ex, :)));
        display_array(pad + (j - 1) * (example_height + pad) + (1:example_height), ...
                      pad + (i - 1) * (example_width + pad) + (1:example_width)) = ...
                        reshape(X(curr_ex, :), example_height, example_width) / max_val;
        curr_ex = curr_ex + 1;
    end
    if curr_ex > m, 
        break; 
    end
end

% Display Image
h = imagesc(display_array, [-1 1]);

% Do not show axis
axis image off

drawnow;

end

ex3.m里的調用

load('ex3data1.mat'); % training data stored in arrays X, y
m = size(X, 1);

% Randomly select 100 data points to display
rand_indices = randperm(m);
sel = X(rand_indices(1:100), :);

displayData(sel);

運行效果如下:

 

二、代價函數

注意:θ0不參與正則化。

正則化邏輯回歸的代價函數如下,分為三項:

梯度下降算法如下:

 

 

lrCostFunction.m:

function [J, grad] = lrCostFunction(theta, X, y, lambda)

m = length(y); % number of training examples

temp = theta; temp(1) = 0;   % because we don't add anything for j = 0  

% 第一項
part1 = -y' * log(sigmoid(X * theta));
% 第二項
part2 = (1 - y)' * log(1 - sigmoid(X * theta));

% 正則項
regTerm = lambda / 2 / m * temp' * temp;
J = 1 / m * (part1 - part2) + regTerm; 

% 梯度
grad = 1 / m * X' *((sigmoid(X * theta) - y)) + lambda / m * temp;

grad = grad(:);

end

正則化之后的代價函數同時返回代價 J 和 grad 梯度。這里和上個星期實現的二分類邏輯回歸代碼是一樣的。

 三、訓練oneVsAll多分類模型

week2邏輯回歸分類的目標是區分兩種類型。寫好代價函數之后,調用一次 fminunc 函數,得到 theta、就可以畫出 boundary。

但是多分類中需要訓練 K 個分類器,所以多了一個 oneVsAll.m。其實就是循環 K 次,得到一個 theta矩陣(row 為 K,column為特征值個數)。

function [all_theta] = oneVsAll(X, y, num_labels, lambda)

% Some useful variables
m = size(X, 1);
n = size(X, 2);

% You need to return the following variables correctly 
all_theta = zeros(num_labels, n + 1);

% Add ones to the X data matrix
X = [ones(m, 1) X];

initial_theta = zeros(n + 1, 1);

options = optimset('GradObj', 'on', 'MaxIter', 50);

% Run fmincg to obtain the optimal theta
% This function will return theta and the cost 
for i = 1 : num_labels,
  [theta] = ...
    fmincg(@(t)(lrCostFunction(t, X, (y == i), lambda)), ...
         initial_theta, options);
  all_theta(i,:) = theta';
end;
end

多分類使用的 Octave 函數是 fmincg 不是 fminunc,fmincg更適合參數多的情況。

注意這里用到了 y == i,這個操作將 y 中每個數據和 i 進行比較。得到的矩陣(這里是向量)相同的為1,不同的為0。

ex3.m 里的調用

lambda = 0.1;
[all_theta] = oneVsAll(X, y, num_labels, lambda);

四、使用OneVsAll分類器進行預測

predictOneVsAll.m

function p = predictOneVsAll(all_theta, X)

m = size(X, 1);
num_labels = size(all_theta, 1);

% You need to return the following variables correctly 
p = zeros(size(X, 1), 1);

% Add ones to the X data matrix
X = [ones(m, 1) X];  
   
temp = X * all_theta';
[x, p] = max(temp,[],2);

end

將 X 與 theta 相乘得到預測結果,得到一個 5000*10 的矩陣,每行對應一個分類結果(只有一個1,其余為0)。

題目要求返回的矩陣 p 是一個 5000*1 的矩陣。每行是 1-K 的數字。使用 max 函數,得到兩個返回值。第一個 x 是一個全1的向量,沒用。第二個是 1 所在的 index,也就是對應的類別。

ex3.m 中的調用:

pred = predictOneVsAll(all_theta, X);
fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100);

三層神經網絡

這里g(z) 使用 sigmoid 函數。

神經網絡中,從上到下的每個原點是 feature 特征 x0, x1, x2...,不是實例。計算過程其實就是 feature 一層一層映射的過程。一層轉換之后,feature可能變多、也可能變少。下一層 i+1層 feature 的個數是通過權重矩陣里當前 θ(i) 的 row 行數來控制。

兩層權重 θ 已經在 ex3weights.mat 里給出。從a1映射到a2權重矩陣 θ1為 25 * 401,從a2映射到a3權重矩陣 θ2為10 * 26。因為最后有10個分類。(這意味着運算的時候要注意轉置)

一、使用OneVsAll分類器進行預測

權重已經在文件中給出了,只需要矩陣相乘,預測就好了

predict.m :

function p = predict(Theta1, Theta2, X) %PREDICT Predict the label of an input given a trained neural network % p = PREDICT(Theta1, Theta2, X) outputs the predicted label ofxgiven the % trained weights of a neural network (Theta1, Theta2) % Useful values m = size(X, 1); num_labels = size(Theta2, 1); % You need to return the following variables correctly p = zeros(size(X, 1), 1); % ====================== YOUR CODE HERE ====================== % Instructions: Complete the following code to make predictions using % your learned neural network. You should set p to a % vector containing labels between 1 to num_labels. % % Hint: The max function might come in useful. In particular, the max % function can also return the index of the max element, for more % information see 'help max'. If your examples are in rows, then, you % can use max(A, [], 2) to obtain the max for each row. %0 % Add ones to thexdata matrix a1 = [ones(m, 1) X]; %5000x401 a2 = sigmoid(a1 * Theta1'); %5000x401乘以401x25得到5000x25。即把401個feature映射到25  a2 = [ones(m, 1) a2]; %5000x26 a3 = sigmoid(a2 * Theta2'); %5000x26乘以26x10得到5000x10。即把26個feature映射到10  [x,p] = max(a3,[],2);  %和上面邏輯回歸多分類一樣,最后使用 max 函數獲得分類結果。 % ========================================================================= end

二、預測結果

em3_nn.m 里的調用

%% Setup the parameters you will use for this exercise input_layer_size = 400; % 20x20 Input Images of Digits hidden_layer_size = 25; % 25 hidden units num_labels = 10; % 10 labels, from 1 to 10 % (note that we have mapped "0" to label 10) load('ex3weights.mat'); pred = predict(Theta1, Theta2, X); fprintf('\nTraining Set Accuracy: %f\n', mean(double(pred == y)) * 100); % To give you an idea of the network's output, you can also run % through the examples one at the a time to see what it is predicting. % Randomly permute examples    隨機獲取數字,顯示預測結果 rp = randperm(m); for i = 1:m % Display fprintf('\nDisplaying Example Image\n'); displayData(X(rp(i), :)); pred = predict(Theta1, Theta2, X(rp(i),:)); fprintf('\nNeural Network Prediction: %d (digit %d)\n', pred, mod(pred, 10)); % Pause with quit option s = input('Paused - press enter to continue, q to exit:','s'); if s == 'q' break end end

 

運行結果:

准確率 Training Set Accuracy: 97.520000

 

這里我比較疑惑的一點是。代碼中沒對 0 進行特殊處理,為什么能預測成10。后來一想 整個計算過程都是權重矩陣控制的,給的 weights 文件里已經是調整好的結果了,0 就是會被分類成10。

所以神經網絡最主要的還是調參啊,調 θ 矩陣。

三、關於矩陣相乘

矩陣這里轉置總是出問題。仔細思考一下

 

(1)假設只有一個實例 x,而且它像圖中一樣是一個列向量。那根據神經網絡的公式,最相符的應該是  θ(i) * x。最后的得到的是 K 維列向量。

(2)但實際情況中,訓練數據通常一行一個實例。如果嚴格按圖和公式去計算,(θ(i) * XT)T 就需要將 X 先轉置過來,最后再轉置回去。應該是下面的代碼,但是明顯能看出比上面的方法麻煩:

a1 = [ones(1, m); X'];      %401x5000
a2 = sigmoid(Theta1 * a1);  %25x401 乘以 401x5000   得到25x5000

a2 = [ones(1, m); a2];      %26x5000
a3 = sigmoid(Theta2 * a2);  %10x26 乘以 26x5000    得到10x5000

a3 = a3'; % 5000x10

(3)所以用 X * θ(i)替換 (θ(i) * XT)T

a1 = [ones(m, 1) X];    %5000x401
a2 = sigmoid(a1 * Theta1');  %5000x401乘以401x25得到5000x25。即把401個feature映射到25

a2 = [ones(m, 1) a2];    %5000x26
a3 = sigmoid(a2 * Theta2');  %5000x26乘以26x10得到5000x10。即把26個feature映射到10

 

完整代碼

https://github.com/madoubao/coursera_machine_learning/tree/master/homework/machine-learning-ex3/ex3

 


免責聲明!

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



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