UFLDL学习笔记(5)

最近在学习UFLDL Tutorial,这是一套关于无监督学习的教程。在此感觉Andrew Ng做的真的是非常认真。下面把我的代码贴出来,方便大家学习调试。所有代码已经过matlab调试通过。


Building Deep Networks for Classification练习

这一章是用fine-tune的多层网络进行mnist数字的识别。特征提取层使用unlabeld数据训练多层的sparse autoencoder,分类层使用labeled数据训练softmax regression分类器,最后再用labeled数据对整个网络进行fine-tune。本章需要用到前面几章的一些.m文件。因此需要先做前面章节的练习。

本章识别mnist的网络结构图如下

UFLDL学习笔记(5)

流程

(1)逐层训练Sparse Autoencoder权重(先W1,再W2)

(2)以Sparse Autoencoder的输出训练Softmax分类器权重(W3)

(3)用labeled的数据fine-tune所有权重。

优点

(1)物理意义更明显,逐层抽取特征。

(2)与普通ANN相比,避免陷入局部最优。

其它

(1)若labeled数据多则fine-tune有效。

(2)层间的非线性映射函数是为了增加非线性表征力,若层间是线性映射则无论多少层都是线性的。


代码编写

好了,下面贴出我的matlab代码。一共有3个.m文件需要自己编写。

一、stackedAEExercise.m 主函数

Step 0. 参数设置。无需编写

Step 1. 读取mnist数据。无需编写。

Step 2. 训练第一层Sparse Autoencoer权重。代码:

% 参考前面章节给出的代码
addpath minFunc/
sae1options.Method = ‘lbfgs‘; 
sae1options.maxIter = 100;	  % 迭代次数,调试时可设为较小值
sae1options.display = ‘on‘;
[sae1OptTheta,cost] = minFunc( @(p) sparseAutoencoderCost(p, ...
                                   inputSize, hiddenSizeL1, ...
                                   lambda, sparsityParam, ...
                                   beta, trainData), ...
                              sae1Theta, sae1options);
Step 3. 训练第二层Sparse Autoencoder权重。代码:

% 参考前面章节给出的代码
ftoptions.Method = ‘lbfgs‘; 
ftoptions.maxIter = 100;	  % 迭代次数,调试时可设为较小值
ftoptions.display = ‘on‘;
[sae2OptTheta,cost] = minFunc( @(p) sparseAutoencoderCost(p, ...
                                   hiddenSizeL1, hiddenSizeL2, ...
                                   lambda, sparsityParam, ...
                                   beta, sae1Features), ...
                              sae2Theta, ftoptions);
Step 4. 训练Softmax分类器权重。代码:

smOptions.maxIter = 100; %Softmax训练迭代次数
sampleN = size(sae2Features,2);  %[输入维数,样本数]
[softmaxModel] = softmaxTrain(hiddenSizeL2, numClasses, lambda, sae2Features, trainLabels, smOptions);  %训练Softmax分类器
saeSoftmaxOptTheta = reshape(softmaxModel.optTheta,hiddenSizeL2*numClasses,1);
Step 5. Finetune softmax model。代码:

% 参考前面章节给出的代码
ftoptions.Method = ‘lbfgs‘; 
ftoptions.maxIter = 100;	  % 迭代次数,调试时可设为较小值
ftoptions.display = ‘on‘;
[stackedAEOptTheta,cost] = minFunc( @(p) stackedAECost(p, ...
                                   inputSize, ...
                                        hiddenSizeL2, numClasses, netconfig, ...
                                        lambda, trainData, trainLabels), ...
                              stackedAETheta, ftoptions);


二、stackedAEPredict.m 根据模型预测结果。代码:

W1 = stack{1}.w;
b1 = stack{1}.b;
W2 = stack{2}.w;
b2 = stack{2}.b;

sampleN = size(data,2);
h1 = sigmoid(W1*data + repmat(b1,1,sampleN));
h2 = sigmoid(W2*h1 + repmat(b2,1,sampleN));
y = softmaxTheta*h2;
[tmp,pred] = max(y);

三、stackedAECost.m 计算整个模型的误差和所有权重梯度。用于fine-tune。这个.m文件花了我很长很长时间。。原本想尽量用矩阵形式去掉for,但是最后还是保留了两个,为了结构清晰。我的建议是,求导仔细,大胆编程。代码:

% ----------初始化值-------------------
format long
sampleN = size(data,2);
outputSize = size(groundTruth,1);

W1 = stack{1}.w;
b1 = stack{1}.b;
W2 = stack{2}.w;
b2 = stack{2}.b;
W3 = softmaxTheta;

N2 = size(W2,2);    %第一隐层节点数
N3 = size(W3,2);    %第二隐层节点数

A1 = data;
A2 = sigmoid(W1*A1+repmat(b1,1,sampleN));
A3 = sigmoid(W2*A2+repmat(b2,1,sampleN));
A4 = exp(W3*A3) ./ repmat(sum(exp(W3*A3)),outputSize,1);

P = A4;             %输出值
X = A1;             %输入值
Y = groundTruth;    %label值

% -----------损失函数--------------------
cost = -1/sampleN * sum(sum(Y.*log(P)));            %损失函数

% -----------softmax层权值梯度-----------
softmaxThetaGrad = -1/sampleN * (Y-P)*A3‘;  %softmax层权值梯度

% -----------第二隐层权值梯度-------------
% 完全按照求导公式来,弄了很久
dEdA3 = zeros(N3,sampleN);
sumK = zeros(N3,sampleN);
for k = 1:outputSize
    sumL = zeros(N3,sampleN);
    for l = 1:outputSize
        sumL = sumL + (W3(l,:)-W3(k,:))‘ * exp((W3(l,:)-W3(k,:))*A3);
    end
    sumK = sumK + repmat(Y(k,:),N3,1) .* repmat(A4(k,:),N3,1) .* sumL;
end
dEdA3 = sumK;

dEdO3 = dEdA3.*A3.*(1-A3);
stackgrad{2}.w = 1/sampleN * dEdO3*A2‘;
stackgrad{2}.b = 1/sampleN * sum(dEdO3,2);

% -----------第一隐层权值梯度-------------
dEdO2 = W2‘*dEdO3.*A2.*(1-A2);
stackgrad{1}.w = 1/sampleN * dEdO2*X‘;
stackgrad{1}.b = 1/sampleN * sum(dEdO2,2);

运行结果

UFLDL学习笔记(5)
这个表是我在debug的过程中得到的,由表中可看到经过fine-tune的结果要好很多。

小结

本章的练习花了好几天的时间,最主要在Softmax对前面求导花了很长时间。推算也比较复杂。这一章做的效率不高,但做完后就会有一种豁然开朗的感觉。建议各位自行推导这些公式。





UFLDL学习笔记(5)

上一篇:连载:面向对象葵花宝典:思想、技巧与实践(8) - “接口” 详解


下一篇:嵌入式中通讯协议的设计