前言
練習內容:Exercise:Softmax Regression。完成MNIST手寫數字數據庫中手寫數字的識別,即:用6萬個已標注數據(即:6萬張28*28的圖像塊(patches)),作訓練數據集,然后利用其訓練softmax分類器,再用1萬個已標注數據(即:1萬張28*28的圖像塊(patches))作為測試數據集,用前面訓練好的softmax分類器對測試數據集進行分類,並計算分類的正確率。
注意:本實驗中,只用原始數據本身作訓練集,而並不是從原始數據中提取特征作訓練集。
理論知識:Softmax回歸和Deep learning:十三(Softmax Regression),看softmax回歸之前,最好看一下線性回歸和邏輯回歸。
優秀的編程技巧:
1. labels(labels==0) = 10; % 把標簽0變為標簽10,故labels的值是[1,10],而原來是[0,9]
優點:這種寫法不需要用if語句去檢查labels中的每個值,而直接把labels中的0替換為10,效率很高,減少運行時間。
2. acc = mean(labels(:) == pred(:));%計算正確率
優點:讓人眼前一亮的正確率計算方式,表達式labels(:) == pred(:)得到一個矩陣A,如元素labels(i)與pred(i)對應相等,剛A(i)為1,否則為0。然后再計算A的的平均值就得到了正確率。大牛的編程技巧太棒了,記得有一種說法:一個程序員的優秀程度,主要是看其代碼的簡潔程度。這種實現方式不僅表達簡單,而且運行效率高。
3.
% 為加快梯度檢查的效率,從而方便調試,可在調試時可減少輸入數據大小。下面隨機產生合成的數據集用於調試。
DEBUG = true; % Set DEBUG to true when debugging.
if DEBUG
inputSize = 8;
inputData = randn(8, 100);
labels = randi(10, 100, 1);
end
優點:這種寫法、思想不錯,方便調試。
4.防止溢出的技巧:
M = bsxfun(@minus,theta*data,max(theta*data, [], 1));% max(theta*data, [], 1)返回theta*data每一列的最大值,返回值為行向量 % theta*data的每個元素值都減去其對應列的最大值,即:把每一列的最大值都置為0了 % 這一步的目的是防止下一步計算指數函數時溢出
這種方法在以后的很多地方都可以看到,這里Ng特別介紹且用到了這一技巧。
一些matlab函數:
sparse函數
功能:Create sparse matrix-創建稀疏矩陣
用法1:S=sparse(X)——將矩陣X轉化為稀疏矩陣的形式,即矩陣X中任何零元素去除,非零元素及其下標(索引)組成矩陣S。 如果X本身是稀疏的,sparse(X)返回S。
例如:
A=
0 2 0
4 0 6
7 0 0
B=sparse(A)=
(2,1) 4
(3,1) 7
(1,2) 2
(2,3) 6
用法2:S = sparse(i,j,s,m,n,nzmax)——由i,j,s三個向量創建一個m*n的稀疏矩陣(上面的B矩陣形式),並且最多含有nzmax個元素。
例如:
B=sparse([1,2,3],[1,2,3],[0,1,2],4,4,4)
B =
(2,2) 1
(3,3) 2
其中i=[1,2,3],稀疏矩陣的行位置;j=[1,2,3],稀疏矩陣的列位置;s=[0,1,2],稀疏矩陣元素值。 其位置為一一對應。
m=4(>=max(i)),n=4(>=max(j)) (注:m和n的值可以在滿足條件的范圍內任意選取),用於限定稀疏的大小。
nzmax=4(>=max(i or j)),稀疏矩陣最多可以有nzmax個元素。
一些簡寫的情況:
S = sparse(i,j,s,m,n)——nzmax = length(S) ;
S = sparse(i,j,s)——使m = max(i) 和 n = max(j),在S中零元素被移除前計算最大值,[i j s]中其中一行可能為[m n 0];
S = sparse(m,n)——sparse([],[],[],m,n,0)的縮寫,生成一個m*n的所有元素都是0的稀疏矩陣。
應用舉例:
S = sparse(1:n,1:n,1) 生成一個n*n的單位稀疏矩陣,和S = sparse(eye(n,n))有相同的結果,但是如果它的元素大部分是零元素的情況下也會暫時性的生成n*n的全矩陣。 book.iLoveMatlab.cn
B = sparse(10000,10000,pi) 可能不是非常有用的,但是它是能運行和允許的,它生成一個10000*10000的僅僅包含一個非零原色的矩陣,不要用full(B),因為這需要800兆儲存單元。
full函數
功能:把稀疏矩陣轉為全矩陣
A=full(X)——把稀疏矩陣X轉換為全矩陣存儲形式A。
matlab sparse matrix和full matrix
其實這只是matlab中存儲稀疏矩陣的兩種方法。
MATLAB函數sparse簡介
函數功能:
這個函數與稀疏矩陣有關。
先說MATLAB中兩個概念:full storage organization(對應於full matrix)和sparse storage organization(對應於sparse matrix)。
而要說明這兩個概念,需要介紹稀疏矩陣的概念。
一般意義上的稀疏矩陣,就是看起來很松散的,也就是說,在這個矩陣中,絕大多數元素是零。例如:
0, 0, 0, 0;
0, 0, 1, 0;
0, 0, 0, 0;
0, 1, 0, 2;
計算機存儲稀疏矩陣可以有兩種思路:
1.按照存儲一個普通矩陣一樣存儲一個稀疏矩陣,比如上面這個稀疏矩陣中總共十六個元素(三個非零元素),把這些元素全部放入存儲空間中。這種存儲方式,在matlab就叫做full storage organization。
2.只存儲非零元素,那么怎么存儲呢?
(4,2) 1
(2,3) 1
(4,4) 2
看出來了吧, 只存儲非零元素在稀疏矩陣中的位置和值。比如,上面所舉的這個例子,值為2的項在第4行第4列,那么我們就只需要存儲這一非零項在稀疏矩陣中的“坐標”(4,4)和這一非零項的值2。在MATLAB中,這種存儲方式就叫做sparse storage organization。雖然,這樣要多存儲一組坐標,但如果稀疏矩陣中非零元素非常少,以這種存儲方式存儲稀疏矩陣反而節省了內存空間。
為什么matlab中會同時存在這兩種存儲方式呢?
第一種方式, 更加直觀,進行矩陣運算時(比如稀疏矩陣的乘法),算法簡單易實現。
而第二種方式,雖然有時可以節省存儲數據時占用的存儲空間,但進行運算時需要專門的算法實現(使用C語言編寫過稀疏矩陣乘法的同學應該能體會到)。
sparse函數的功能就是把以第一種存儲形式存儲的稀疏矩陣轉換成第二種形式存儲(其實這個函數更重要的功能是構建稀疏矩陣,這里不再討論)。對應的函數為full,即把以第二種方式存儲的稀疏矩陣轉換成第一種方式存儲。
在MATLAB中,存儲一個稀疏矩陣有兩種方法。
語法格式:
S = sparse(A)
S = sparse(i,j,s,m,n,nzmax)
S = sparse(i,j,s,m,n)
S = sparse(i,j,s)
S = sparse(m,n)
各種語法格式詳見MATLAB幫助文檔。
相關函數:full、issparse
程序示例
>> A = [0, 0, 0, 0;
0, 0, 1, 0;
0, 0, 0, 0;
0, 1, 0, 2];
>> sparse(A)
ans =
(4,2) 1
(2,3) 1
(4,4) 2
當然sparse函數還可以通過一定規則構造稀疏矩陣,這里就不多說了。
max函數
當A是一個列向量時候,返回一個最大值,在此不在贅述。
當Amxn是一個矩陣的時候,有以下幾種情況:
① C = max(max(A)),返回矩陣最大值
② D = max(A,[],1),返回每一行的最大值,即mx1的行向量
③ E = max(A,[],2),返回每一列的最大值,即1xm的列向量
④ F = max(A,8),當元素小於8,用8填充
⑤ [U V] = max(A),返回行列最大元素的行號與列號
注意以下幾個表達式:
H = max(A)
I = max(A(:))
J = max(A(:,:))
編程實驗如下:
A = fix (rand (5,3)*50)%
B = A;%矩陣備份一次
C = max(max(A))%矩陣最值
D = max(A,[],1)%每一列的最值,得到行向量
E = max(A,[],2)%每一行的最值,得到列向量
F = max(A,8)%小於8的數替換成8
[U V] = max(A)%U為列極值,V為行號
H = max(A)%功能同D
I = max(A(:))%功能同C
J = max(A(:,:))%功能同D
softmax回歸基本知識
代價函數為:
代價函數梯度為:
實驗步驟
1.初始化參數,加載訓練數據集。注意:MNIST手寫數字數據集所有圖片的每個像素灰度值都已經被歸一化到了[0,1]之間,所以將來如果是用自己的訓練樣本,不要忘記歸一化像素值。
2.矢量化編程實現softmax回歸的代價函數及其梯度,即softmaxCost.m文件。
3.利用computeNumericalGradient函數檢查上一步中的梯度計算是否正確,該函數見Deep Learning一:Sparse Autoencoder練習(斯坦福大學UFLDL深度學習教程)。
4.用用L-BFGS算法訓練softmax回歸模型,得到模型softmaxModel,見softmaxTrain.m中的softmaxTrain函數
5.加載測試數據集,用上一步訓練得到模型softmaxModel來對測試數據進行分類,得到分類結果(見softmaxPredict.m),然后計算正確率。
運行結果
Accuracy: 92.640%
Elapsed time is 15.591119 seconds.
注意:別忘記了Andrew Ng的提醒,他們自己的准確率有92.6%。如果你得到的准確率小於91%,請檢查你的代碼、訓練數據集及其權重是否正確;如果你的准確率非常高,達到99%至100%時,你可能把測試數據集作為了訓練數據集。
問題
1.在softmaxExercise.m中有如下一句代碼:
images = loadMNISTImages('train-images.idx3-ubyte');
labels = loadMNISTLabels('train-labels.idx1-ubyte');
labels(labels==0) = 10; % 把標簽0變為標簽10,故labels的值是[1,10],而原來是[0,9] ?為什么非要這樣?
為什么非要把原來的標簽0變為標簽10呢?搞不懂!
在Exercise:Softmax Regression中是這樣解釋的:The images are pre-processed to scale the pixel values to the range [0,1], and the label 0 is remapped to 10 for convenience of implementation, so that the labels take values in . 也就是說,它是為了實現的方便才把標簽0變為10,但是究竟是為了在哪的實現方便?沒看出來!
代碼
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));%產生一個100*100的矩陣,它的第labels(i)行第i列的元素值為1,其余全為0,其中i為1到numCases,即:1到100 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. M = bsxfun(@minus,theta*data,max(theta*data, [], 1));% max(theta*data, [], 1)返回theta*data每一列的最大值,返回值為行向量 % theta*data的每個元素值都減去其對應列的最大值,即:把每一列的最大值都置為0了 % 這一步的目的是防止下一步計算指數函數時溢出 M = exp(M); p = bsxfun(@rdivide, M, sum(M)); cost = -1/numCases * groundTruth(:)' * log(p(:)) + lambda/2 * sum(theta(:) .^ 2); thetagrad = -1/numCases * (groundTruth - p) * data' + lambda * theta; % ------------------------------------------------------------------ % Unroll the gradient matrices into a vector for minFunc grad = [thetagrad(:)]; end
softmaxPredict.m
1 function [pred] = softmaxPredict(softmaxModel, data) 2 3 % softmaxModel - model trained using softmaxTrain 4 % data - the N x M input matrix, where each column data(:, i) corresponds to 5 % a single test set 6 % 7 % Your code should produce the prediction matrix 8 % pred, where pred(i) is argmax_c P(y(c) | x(i)). 9 10 % Unroll the parameters from theta 11 theta = softmaxModel.optTheta; % this provides a numClasses x inputSize matrix 12 pred = zeros(1, size(data, 2)); 13 14 %% ---------- YOUR CODE HERE -------------------------------------- 15 % Instructions: Compute pred using theta assuming that the labels start 16 % from 1. 17 18 [nop, pred] = max(theta * data); 19 % pred= max(peed_temp); 20 21 22 23 24 25 % --------------------------------------------------------------------- 26 27 end
——
——