1. 程式人生 > >one-vs-all案例

one-vs-all案例

使用one-vs-all初始手寫字母識別

資料特點

  • 每一個圖片都是20 x 20的畫素矩陣,但是在輸入的樣本中是一個1 x 400的向量,標籤y在{0, 1, 2, ..., 9}之間取值
  • 共有5000個訓練樣本

視覺化資料

  • 從5000個樣本中隨機的挑選出100個訓練樣本進行視覺化
  • 得到的100個樣本中,每一個樣本都是一個向量,要想對其視覺化,需要將其從向量還原為原始的矩陣
  • 首先確定矩陣的高和寬(單位是畫素pixel)
  • 建立一個displayArray矩陣,用來儲存100個樣本轉換為矩陣的畫素資料,形象地講,就是將100個圖片放到一個大的面板上,這樣才能做到視覺化資料
  • 初始完畢displayArray矩陣之後,使用matlib中的imagesc函式將其顯示出來
  • 程式碼如下:
  • myDisplayData.m
function [h, displayArray] = myDisplayData(X)

% 獲取一張圖片的高和寬
exampleHeight = round(sqrt(size(X(1, :), 2)));
exampleWidth = round(size(X(1, :), 2) / exampleHeight);

% 計算整個面板的高和寬(但是是圖片的個數)
[m, n] = size(X);
displayRows = round(sqrt(m));
displayCols = round(m / displayRows);

% 先創建出displayRows * exampleHeight, displayCols * exampleWidth的面板
displayArray = ones(displayRows * exampleHeight, displayCols * exampleWidth);

% 將圖片放到面板對應的位置上
% 下面的式子就和數學有一些關係,如何確定現在填充的矩陣在displayArray中的位置
currExample = 1;
for i = 1:displayRows
    for j = 1:displayCols
        displayArray(...
                     (i - 1) * exampleWidth + 1:exampleWidth + (i - 1) * exampleWidth, ...
                     (j - 1) * exampleHeight + 1:exampleHeight + (j - 1) * exampleHeight ...
                     ) = ...
                                                 reshape(X(currExample, :), ...
                                                 exampleHeight, exampleWidth);
        currExample = currExample + 1;
    end
end

colormap(gray);
h = imagesc(display_array);
axis image off;
end

資料預處理

  • 為X新增bias(偏移量): X = [ones(m, 1), X]; % m表示樣本的數量
  • m: 訓練樣本的數量
  • n: 特徵的數量,不包括bias(偏移)特徵
  • y: 標籤,{0, 1, 2, ..., 9}
  • numLabel: y可以取的值的個數,這裡為10

確定假設函式

  • 由題目可知,這是一個典型的Multi-Class Logistic Regression問題,因此使用邏輯迴歸模型
  • 模型函式: \[h(\theta)=g(\theta^{T}x)={{1}\over{1+e^{-\theta^{T}x}}}\]
  • 因為這個一個10分類的問題,所以需要擬合出10個假設函式才行,也就是要最小化出10個\(\theta\)
    向量,我們呼叫oneVsAll函式返回的引數應該是一個矩陣,每一個行向量是一個類別的假設函式的引數

計算損失函式(cost function)和梯度

  • 損失函式公式: \[J(\theta)={{1}\over{m}}\sum_{i=1}^m(-y^{(i)}log(h_{\theta}(x^{(i)})) - (1-y^{(i)})log(1-h_{\theta}(x^{(i)})))+{{\lambda}\over{2m}}\sum_{j=1}^m{\theta_{j}^2}\]其中\(\theta\), \(y^{(i)}\), \(x^{(i)}\)為向量或者矩陣,後一項是對非偏差項的正則化
  • 梯度公式: j >= 1 \[{{\partial}\over{\partial}\theta_{j}}J(\theta)={{1}\over{m}}\sum_{i=1}^m{(h_{\theta}(x^{(i)})-y^{(i)})x^{(i)}} + {{\lambda}\over{m}}\theta_{j}\] j = 0 \[{{\partial}\over{\partial}\theta_{0}}J(\theta)={{1}\over{m}}\sum_{i=1}^m{(h_{\theta}(x^{(i)})-y^{(i)})x^{(i)}}\]
  • 注意,上面的\(h_{\theta}(x^{(i)})\)是sigmoid函式,自己在實現的時候總是將其寫成線性迴歸函式

在oneVsAll.m檔案中實現\(minimize_{\theta}J(\theta)\)

  • 每一個類都進行梯度下降,計算出這一類的引數,也就是寫一個迴圈,在每一個迴圈中都有可以得到最終的這個類別對應的引數,迴圈的次數為numLabels
  • 核心程式碼

    for index = 1:numLabels 
      initialTheta = zeros(n + 1, 1);
      options = optimset('GradObj', 'on', 'MaxIter', 50);
      % fmincg會自動選擇最優的學習率alpha
      allTheta(index, :) = fmincg(@(t)(lrCostFunction(t, X, (y == index), lambda)), ...
                              initialTheta, options);
    end

預測

  • 輸入的一個樣本,需要為其新增bias值,在將樣本分別輸入到10個假設函式中,計算出最大的值,那個值對應的就是類別。
  • 核心程式碼
tmp = zeros(m, num_labels);
for i = 1:num_labels
    tmp(:, i) = sigmoid(X * allTheta(i, :)');
end
[val, p] = max(tmp, [], 2);