實驗要求可以參考deeplearning的tutorial,Exercise:Softmax Regression ,softmax迴歸的原理可以參照之前Logistic and Softmax Regression (邏輯迴歸和Softmax迴歸)博文,本實驗實現對手寫數字0-9的識別(也就是分類)。
1. 神經網絡結構:
在之前的博文中談到,softmax迴歸是最神經網絡,只包含輸入成和輸出層,而沒有隱含層。本實驗中的softmax迴歸有28*28個輸入neuron(不包括bias結點),輸入層10個neuron。
2. 數據
實驗中的數據採用的是MNIST手寫數字數據庫(0-9手寫數字),其中訓練數據6萬個,測試數據1萬個,其中每個樣本是大小爲28*28的圖片。(注意,令數據0爲類別10,因爲matlab中起始的index爲1)
下圖是把訓練數據中的前100個手寫數據圖像進行顯示。
3 過程:
之後的過程就是構建softmax迴歸的損失函數(loss function),通過BP算法計算偏導數,梯度檢驗,最後用L-BFGS算法進行優化,學習得到模型的參數。
4. 注意:
1. 在構造loss函數時,我們需要計算,如果該值比較大,指數函數會變得非常大,很有可能出現溢出(overflow)的情況。試驗中,我們對每一個 減去最大的那個,是的最大值爲0,這樣就不會出現溢出的情況了。爲什麼可以這麼做,證明如下。
2. 梯度檢測本身是一個非常耗時的過程,如果在6萬個訓練集上進行這個梯度檢測,那將花去很長的時間。我們可以縮小訓練集的大小,比如說10個,20個,如果在這個小的集上梯度檢測的誤差很小,鎖門我們的BP實現是正確,通過這種方法可以大大縮短梯度檢測時間。
5. 實驗結果:
經過100次迭代之後,得到所需的參數,最後在測試集上顯示92.640%的正確率,這個實驗說明中要求的結果一直,所以代碼應該沒什麼錯誤。
6. 部分代碼
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));
cost = 0;
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.
A = theta*data;
M = bsxfun(@minus, A, max(A,[],1));
M = exp(M);
p = bsxfun(@rdivide,M,sum(M,1));
cost = -1/numCases * groundTruth(:)' * log(p(:)) + lambda /2 * theta(:)'* theta(:);
thetagrad = -1/numCases * (groundTruth - p)*data' + lambda * theta;
% ------------------------------------------------------------------
% Unroll the gradient matrices into a vector for minFunc
grad = [thetagrad(:)];
end