最近在学习UFLDL Tutorial,这是一套关于无监督学习的教程。在此感觉Andrew Ng做的真的是非常认真。下面把我的代码贴出来,方便大家学习调试。所有代码已经过matlab调试通过。
Building Deep Networks for Classification练习
这一章是用fine-tune的多层网络进行mnist数字的识别。特征提取层使用unlabeld数据训练多层的sparse autoencoder,分类层使用labeled数据训练softmax regression分类器,最后再用labeled数据对整个网络进行fine-tune。本章需要用到前面几章的一些.m文件。因此需要先做前面章节的练习。
本章识别mnist的网络结构图如下
流程
(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);
运行结果
这个表是我在debug的过程中得到的,由表中可看到经过fine-tune的结果要好很多。
小结
本章的练习花了好几天的时间,最主要在Softmax对前面求导花了很长时间。推算也比较复杂。这一章做的效率不高,但做完后就会有一种豁然开朗的感觉。建议各位自行推导这些公式。