UFLDL深度學習筆記 (二)SoftMax 迴歸(矩陣化推導)

UFLDL深度學習筆記 (二)Softmax 迴歸

本文爲學習「UFLDL Softmax迴歸」的筆記與代碼實現,文中略過了對代價函數求偏導的過程,本篇筆記主要補充求偏導步驟的詳細推導。php

1. 詳細推導softmax代價函數的梯度

經典的logistics迴歸是二分類問題,輸入向量$ x^{(i)}\in\Re^{n+1}$ 輸出0,1判斷\(y^{(i)}\in{\{0,1\}}\),Softmax迴歸模型是一種多分類算法模型,如圖所示,輸出包含k個類型,\(y^{(i)}\in{\{0,1,…,k\}}\)html

在經典的多分類問題MNIST數字識別任務中包含0-9十個手寫數字。softmax的思路是將輸入值直接判決爲k個類別的機率,這裏就須要一個判決函數,softmax採用指數形式。求和的倒數是爲了歸一化機率。git

\[h_\theta(x^{(i)})=\begin{bmatrix}p(y^{(i)}=1|x^{(i)};\theta)\\ p(y^{(i)}=2|x^{(i)};\theta)\\\vdots\\ p(y^{(i)}=k|x^{(i)};\theta)\\\end{bmatrix}=\frac{1}{\sum_{j=1}^k e^{\theta_j^T \cdot x^{(i)}}}\begin{bmatrix} e^{\theta_1^T \cdot x^{(i)}} \\ e^{\theta_2^T \cdot x^{(i)}}\\\vdots\\ e^{\theta_k^T \cdot x^{(i)}}\\\end{bmatrix}\]github

爲了矩陣運算方便,將權重參數記做矩陣形式 \[\theta = \begin{bmatrix} \theta_1^T \\ \theta_2^T\\\vdots\\ \theta_k^T\\\end{bmatrix}_{k\times(n+1)}\]算法

包含權重懲罰項的softmax的代價函數爲數據庫

\[J(\theta)=-\frac 1 m \left [\sum_{i=1}^m\sum_{j=1}^k 1\{y^{(i)}=j\}\cdot log(p(y^{(i)}=j|x^{(i)};\theta)) \right] +\frac \lambda 2 \sum_{i=1}^k\sum_{j=0}^n\theta_{ij}^2 \]ide

原文Softmax迴歸略過了求偏導的過程,下文對其作分步推導\(\theta_j\)是行向量,表示每一個輸入x與第j個輸出分類鏈接的權重, 將對數內除法拆分爲減法可得:函數

\[ J(\theta)=-\frac 1 m \left [\sum_{i=1}^m\sum_{j=1}^k 1\{y^{(i)}=j\}\cdot ({\theta_j^T x^{(i)}}-log(\sum_{l=1}^ke^{\theta_l^T \cdot x^{(i)}})) \right] +\frac \lambda 2 \sum_{i=1}^k\sum_{j=0}^n\theta_{ij}^2 \]工具

\(\theta_j\)求偏導,可得:學習

\[\begin{align} \frac {\nabla J(\theta)} {\nabla \theta_j} &= -\frac 1 m\sum_{i=1}^m \left [ \frac {\nabla\sum_{j=1}^k 1\{y^{(i)}=j\}\theta_j^T x^{(i)}} {\nabla \theta_j} - \frac {\nabla \sum_{j=1}^k 1\{y^{(i)}=j\}log(\sum_{l=1}^ke^{\theta_l^T \cdot x^{(i)}}))} {\nabla \theta_j} \right] +\lambda\theta_j \\ &= -\frac 1 m\sum_{i=1}^m \left [ 1\{y^{(i)}=j\} x^{(i)} - \frac {\nabla\sum_{j=1}^k 1\{y^{(i)}=j\}\sum_{l=1}^ke^{\theta_l^T \cdot x^{(i)}}} {\sum_{l=1}^ke^{\theta_l^T \cdot x^{(i)}}\nabla \theta_j} \right] +\lambda\theta_j \\ &= -\frac 1 m\sum_{i=1}^m \left [ 1\{y^{(i)}=j\} x^{(i)} - \frac {x^{(i)}e^{\theta_j^T \cdot x^{(i)}}} {\sum_{l=1}^ke^{\theta_l^T \cdot x^{(i)}}} \right] +\lambda\theta_j \\ &= -\frac 1 m\sum_{i=1}^m x^{(i)}\left [ 1\{y^{(i)}=j\} - p(y^{(i)}=j|x^{(i)};\theta) \right] +\lambda\theta_j \end{align}\]

這樣咱們獲得了代價函數對參數權重的梯度,相似前篇稀疏自編碼的作法,須要作如下步驟:

  • 結合梯度降低法,使用訓練數據求出參數權重\(\theta\)的最優解;
  • 用訓練過的權重對測試數據作前向傳播,每一個測試數據獲得\(k\)個軟判決輸出值,分別表示判決爲\(1…k\)分類的機率;
  • 選取\(k\)箇中的最大值即爲對測試數據的分類結果;
  • 與測試數據集的真實輸出對比統計得到預測準確率。

2. 偏導的矩陣化表示

當真正編寫代碼時會發現上述梯度公式是對行向量\(\theta\)的,UFLDL沒有給出矩陣公式,矩陣表達又該是怎樣呢?請看下文推導。

基本符號表達式這樣的:

輸入數據:\(X_{(n+1) \times m}\)

機率矩陣:\(norm(exp(\theta_{k\times (n+1)} \times X_{(n+1) \times m}) )= P_{k\times m}\)

1函數表示第i個輸入的輸出值是否爲分類j,遍歷全部輸入、輸出獲得矩陣 $ G_{k \times m}$,稱爲groundTruth.

偏導第j行的向量爲輸入數據每一行(共n+1行)與\(G_{k \times m} P_{k \times m}\)的每一行的點積,加上\(\lambda\theta_j\) 自己:

\[\begin{align} \frac {\nabla J(\theta)} {\nabla \theta_j} &=-\frac 1 m X_{(n+1) \times m} \bullet(g_{m\times1}-p_{m\times1}) +\lambda\theta_j \end{align}\]

再進一步寫成矩陣形式:

\[ \begin{align} \frac {\nabla J(\theta)} {\nabla \theta} &=-\frac 1 m (G_{k \times m}-P_{k\times m}) *X_{(n+1) \times m}^T +\lambda\theta \end{align} \]

好了,矩陣化完成,能夠痛快地寫代碼了!

3. matlab代碼實現

這裏只給出實現過程當中遇到問題的代碼片斷,完整代碼見https://github.com/codgeek/deeplearning,編寫過前一節稀疏自編碼 的小夥伴應該對總體結構比較熟悉了,softmaxCost.m實現給定參數權重時的代價值與梯度的矩陣計算,softmaxExercise.m結合梯度降低調用代價、梯度計算,完整實現上述四個步驟。

對1函數的計算有一些語法技巧,示例代碼給出的full/sparse有些抽象,我用最基本的的==返回矩陣邏輯結果這個特性來計算,

首先把校驗標籤複製k份得到\(k\times m\)的矩陣:labels = repmat(labels, numClasses, 1);

而後製造出每一行等於行號的矩陣:k = repmat((1:numClasses)',1,numCases);

因此1函數對應的矩陣$ G_{k \times m}$爲groundTruth = double((k == labels));

上一節已經給出了完整的矩陣化公式,也是理論轉換爲代碼實現的難點所在,softmaxCost.m詳細代碼以下,

function [cost, grad] = softmaxCost(theta, numClasses, inputSize, lambda, data, labels, ~)
% numClasses - the number of classes 
% inputSize - the size N of the input vector
% lambda - weight decay parameter
% data - the N x M input matrix, where each column data(:, i) corresponds to
%        a single test set
% labels - an M x 1 matrix containing the labels corresponding for the input data
%

% Unroll the parameters from theta
theta = reshape(theta, numClasses, inputSize);

numCases = size(data, 2);
% groundTruth = full(sparse(labels, 1:numCases, 1));
% 
labels = repmat(labels, numClasses, 1);
k = repmat((1:numClasses)',1,numCases);% numClasses×numCases. 
groundTruth = double((k == labels));% % groundTruth algrithum is the same as (k===label)
thetagrad = zeros(numClasses, inputSize);

%% ---------- YOUR CODE HERE --------------------------------------
%  Instructions: Compute the cost and gradient for softmax regression.
%                You need to compute thetagrad and cost.
%                The groundTruth matrix might come in handy.
cost = 0;
z = theta*data;
z = z - max(max(z)); % avoid overflow while keep p unchanged.
z = exp(z); % matrix product: numClasses×numCases
p = z./repmat(sum(z,1),numClasses,1); % normalize the probbility aganist numClasses. numClasses×numCases
cost = -mean(sum(groundTruth.*log(p), 1)) + sum(sum(theta.*theta)).*(lambda/2);

thetagrad = -(groundTruth - p)*(data')./numCases + theta.*lambda; % numClasses×inputSize

% Unroll the gradient matrices into a vector for minFunc
grad = thetagrad(:);
end

另一部分須要稍動腦筋的是預測判斷。怎樣寫的簡捷高效呢?請看下文.

function [pred] = softmaxPredict(softmaxModel, data)
theta = softmaxModel.optTheta;  % this provides a numClasses x inputSize matrix
pred = zeros(1, size(data, 2));

inputSize = softmaxModel.inputSize;
numClasses=  softmaxModel.numClasses;

%% ---------- YOUR CODE HERE --------------------------------------
z=exp(theta*data);
[~, pred] = max(z);
end

關鍵在於使用matlab的max函數第二個返回值,它就是每列最大值的行號。

4. 圖示與結果

數據集來自Yann Lecun的筆跡數據庫,咱們先瞜一眼原始MMIST數據集的筆跡。

handwritting

設定與練習說明相同的參數,運行完整代碼https://github.com/codgeek/deeplearning 能夠看到預測準確率達到92.6%。達到了練習的標準結果。

result

小結一下,看到梯度、矩陣化推導過程不難發現,通常都是先從對矩陣單個元素的偏導開始,給出表達式,而後把每一個元素列舉成行成列,根據行、列計算的關係,往矩陣乘法的「乘加」模式上套用,最終給出很是精簡的矩陣化公式,矩陣只是一個規範化工具,難以直接在矩陣的抽象層次上推導,也很容易把一些在矩陣上不成立的直覺公式用上去而出錯,因此現階段仍是一個從抽象到具體再到抽象的過程。

相關文章
相關標籤/搜索