Self-taught 自我学习器实验报告
1.Self-taught 自我学习实验描述
自我学习是无监督特征学习算法,自我学习意味着算法能够从未标注数据中学习,从而使机器学习算法能够获得更大数量的数据,因而更有可能取得更好的性能。在本实验中,我们将按照自我学习的步骤,使用稀疏自编码器和softmax分类器去构造一个手写数字分类器。
-
实现流程
Step 1 :产生训输入和测试样本集
Step 2 :训练稀疏自编码器
Step 3 :提取特征
Step 4 :训练和测试softMax分类器
Step 5 :对测试样本集进行分类,计算准确度
3.每步关键点及代码、注释
Step 1 :产生输入和测试样本集
利用loadMNISTImages.m和loadMNISTLabels.m从MNIST数据库中加载数据,注意数据文件存放的路径和名字。
Step 2 :训练稀疏自编码器
将没有标签的训练图像作为输入,训练稀疏自编码器,得到对应最优的权值。在该步骤中调用minFunc.m和先前实验得到的sparseAutoencoderCost.m。
具体实现代码如下:
% Find opttheta by running the sparse autoencoder on
% unlabeledTrainingImages
opttheta = theta;
% [cost, grad] = sparseAutoencoderCost(theta, inputSize, hiddenSize, lambda, ...
% sparsityParam, beta, unlabeledData);
% Use minFunc to minimize the function
addpath minFunc/
options.Method = 'lbfgs'; % Here, we use L-BFGS to optimize our cost
% function. Generally, for minFunc to work, you
% need a function pointer with two outputs: the
% function value and the gradient. In our problem,
% sparseAutoencoderCost.m satisfies this.
options.maxIter = 400; % Maximum number of iterations of L-BFGS to run
options.display = 'on';
[opttheta, cost] = minFunc( @(p) sparseAutoencoderCost(p, ...
inputSize, hiddenSize, ...
lambda, sparsityParam, ...
beta, unlabeledData), ...
theta, options);
Step 3 :提取特征
在该步骤中调用feedForwardAutoencoder.m,计算稀疏自编码器的隐藏层单元的输出(激活值),这些输出便是我们从没有标签的训练图像中提取出来的更高阶的特征。
在feedForwardAutoencoder.m中添加如下代码:
% Compute the activation of the hidden layer for the Sparse Autoencoder.
m = size(data,2);
z2 = W1*data+repmat(b1,1,m);
activation = sigmoid(z2);
Step 4 :训练和测试softMax分类器
利用先前实验得到的softmaxCost.m和softmaxTrain.m对步骤3中提取的特征和训练标签集trainLabels进行训练,得到一个多类别的分类器。
具体实现代码如下:
inputSize = hiddenSize;
% C = unique(A) for the array A returns the same values as in A but with
% no repetitions. C will be sorted.
% a = [9 9 9 9 9 9 8 8 8 8 7 7 7 6 6 6 5 5 4 2 1]
% c = unique(a) -> c = [1 2 4 5 6 7 8 9]
numClasses = numel(unique(trainLabels));
lambda1 = 1e-4;
options.maxIter = 100;
softmaxModel = softmaxTrain(inputSize, numClasses, lambda1, ...
trainFeatures, trainLabels, options);
Step 5 :对测试样本集进行分类,计算准确度
调用先前实验得到的softmaxPredict.m对测试样本集进行预测,计算准确度。具体实现代码如下:
[pred] = softmaxPredict(softmaxModel, testFeatures);
-
实验结果及运行环境
我们可以看到隐藏层单元学习提取到了类似图像边缘的高阶特征。
训练准确度:
Test Accuracy:98.247284%
与Lecture Note给出的98.3%基本相符
训练样本耗时:
Elapsed time is 2955.575443 seconds.
约50分钟。
运行环境
处理器: AMD A6-3420M APU with Radeon(tm) HD Graphics 1.50 GHz
RAM:4.00GB(2.24GB可用)
OS:Windows 7,32 bit
Matlab:R2012b(8.0.0.783)
-
附录:稀疏自编码器的部分关键代码与解释
隐藏层单元输出(activation)的表达式如下:
也可以表示为:
矢量化表达式如下
这个步骤称为前向传播forward propagation,更一般的,对神经网络中的l层和l+1层,有:
成本函数由三项构成:
其中
和。
算法通过迭代,尽量使
用反向传播(Backward propagation)算法计算预测误差,需要用到成本函数的梯度,其表达式如下:
算法调用minFunc()更新参数W,b,以便得到更好的预测模型。
实现矢量化的关键是了解各变量的维度大小,各变量维数大小如下:
关键实现代码如下:
function [cost,grad] = sparseAutoencoderCost(theta, visibleSize, hiddenSize, ...
lambda, sparsityParam, beta, data)
%% ---------- YOUR CODE HERE --------------------------------------
[n,m] = size(data); % m is the number of traning set,n is the num of features
% forward algorithm
% B = repmat(A,M,N) -> replicate and tile an array->MxN
% b1 -> b1 row vector 1xm
z2 = W1*data+repmat(b1,1,m);
a2 = sigmoid(z2);
z3 = W2*a2+repmat(b2,1,m);
a3 = sigmoid(z3);
% compute first part of cost
Jcost = 0.5/m*sum(sum((a3-data).^2));
% compute the weight decay
Jweight = 1/2* lambda*sum(sum(W1.^2)) + 1/2*lambda*sum(sum(W2.^2));
% compute the sparse penalty
% sparsityParam(rho): The desired average activation for the hidden units
% rho(rho^) : the actual average activation of hidden unit
rho = 1/m*sum(a2,2);
Jsparse = beta * sum(sparsityParam.*log(sparsityParam./rho)+...
(1-sparsityParam).*log((1-sparsityParam)./(1-rho)));
% the complete cost function
cost = Jcost + Jweight + Jsparse;
% backward propagation
% compute gradient
d3 = -(data-a3).*sigmoidGradient(z3);
% since we introduce the sparsity term--Jsparse in cost function
extra_term = beta*(-sparsityParam./rho+(1-sparsityParam)./(1-rho));
% add the extra term
d2 = (W2'*d3 + repmat(extra_term,1,m)).*sigmoidGradient(z2);
% compute W1grad
W1grad = 1/m*d2*data' + lambda*W1;
% compute W2grad
W2grad = 1/m*d3*a2'+lambda*W2;
% compute b1grad
b1grad = 1/m*sum(d2,2);
% compute b2grad
b2grad = 1/m*sum(d3,2);