UFLDL教程之一 (Sparse Autoencoder练习)

来源:互联网 发布:linux批量杀进程 编辑:程序博客网 时间:2024/05/23 19:16

反向传播计算可以参考http://tieba.baidu.com/p/3013551686

前言

斯坦福深度学习在线课程是 Andrew Ng 编制的,该教程以深度学习中的重要概念为线索,基本勾勒出了深度学习的框架。为了简明扼要,该教程几乎省略了数学推导和证明过程。我写这个系列不追求概念的讲解,因为教程已经解释的很清楚了,我的目标是把教程所省略的一些关键的数学推导给出来。因为数学原理是深入理解算法模型所绕不过去的,其次,几篇博客也是我的课程笔记,留作以后查阅使用。

综上,如果您已经阅读了对应的教程并理解了主要概念,这一系列能帮您查漏补缺深化理解,否则您会觉得文章的逻辑不连贯。

人工神经网络

人工神经网络的“学习”原理很简单:

每层都有若干个节点,每个节点就好比一个神经元(neuron),它与上一层的每个节点都保持着连接,且它的输入是上一层每个节点输出的线性组合。每个节点的输出是其输入的函数,把这个函数叫激活函数(activation function)。人工神经网络通过“学习”不断优化那些线性组合的参数,它就越有能力完成人类希望它完成的目标。

除了输入层(第1层)以外,第 l +层第i 个节点的输入为:

其中第 l层的节点数。

第 l +层第 i 个节点的输出为:

当 l=1 时:

 

函数  f  就是激活函数。激活函数最常用的有两种:

sigmoid 函数

双曲正切函数

它们的函数曲线类似,都在(-∞,+∞)上单调递增:

sigmoid 函数值域为(0, 1);而双曲正切函数的值域为(-1,1)。

对人工神经网络进行训练,就是为了得到最优的线性组合参数:

其中是网络的总层数。

给定 m 个训练数据:

要用这些数据训练人工神经网络,使它能够对新的输入数据做正确的分类或拟合,首先要保证它在已有的数据上有足够高的正确率。

使用代价函数(Cost Function)来衡量人工神经网络在已有数据上所犯错误的大小:

注意,代价方程有多种形式,只要能反映预测误差即可。

对于单条数据 ,其代价方程为:

可见总代价方程是每条数据代价方程的算术平均。

在优化时,代价方程还会加上一个规则化项,其目的是减小权重的幅度,防止过度拟合:

反向传播算法

可参考 http://tieba.baidu.com/p/3013551686

反向传播算法从输出层开始,反向计算每个节点的残差,并用这些残差计算代价方程对每一个参数的偏导数。

反向传播算法的数学推导过程我在 这篇 文章里已经详细给出,这里在给出一个简洁版本。

对于一个样例 :

将公式向量化:

对于整个样本集:

自编码算法与稀疏性

自编码器要求输出尽可能等于输入,并且它的隐藏层必须满足一定的稀疏性,即隐藏层不能携带太多信息。所以隐藏层对输入进行了压缩,并在输出层中解压缩。整个过程肯定会丢失信息,但训练能够使丢失的信息尽量少。

为了保证隐藏层的稀疏性,自动编码器的代价方程加入了一个稀疏性惩罚项:

其中:

因为代价方程多了一项,所以梯度的表达式也有变化:

稀疏性惩罚项只需要第 1 层参数参与计算,

所以

所以

相当于

变成

可视化自动编码器的训练结果

训练完(稀疏)自编码器,我们还想把这自编码器学到的函数可视化出来,好弄明白它到底学到了什么。

已知:

什么样的输入 可让  得到最大程度的激励?

假设输入有范数约束:

要使 最大,只需要使

最大即可,因为f 是单调递增函数(此处忽略了截距项),令其为表达式(1)。

使(1)取得最大值的  一定满足:

因为超平面的最值一定在闭合区域的边界上取得。

把(1)改写成:

表达式(1)可重写为:

这是两个模为1的向量的内积乘以一个常数,当两个向量重合时它取到最值,即:

最值为:

-----------------------------------------------------------------------------

samplesPatches.m :

for imageNum = 1:10
    [rows,cols] = size(IMAGES(:,:,imageNum));   
    for patchNum = 1:1000
        x_pos = randi([1, rows-patchsize+1]);
        y_pos = randi([1, cols-patchsize+1]);
        patches(:, (imageNum-1)*1000 + patchNum) = reshape(IMAGES( x_pos:x_pos+7,y_pos:y_pos+7, imageNum),64,1);
    end
end


sparseAutoencoderCost.m :


[dims, nums] = size(data);
z2 = W1*data + repmat(b1,1,nums);
a2 = sigmoid(z2);
z3 = W2*a2 + repmat(b2,1,nums);
a3 = sigmoid(z3);

Jcost = (0.5/nums)*sum(sum(a3 - data).^2);
Jweight = lambda/2*(sum(sum(W1.^2))+sum(sum(W2.^2)));
p_real = 1/nums.*sum(a2,2);%;
Jsparse = beta.*sum(sparsityParam.*log(sparsityParam./p_real)+ ...
    (1-sparsityParam).*log((1-sparsityParam)./(1-p_real)));

cost = Jcost + Jweight + Jsparse;

d3 = -(data - a3).*sigmoidInv(z3); %.*(a3.*(1-a3));
sterm =  beta *(-sparsityParam./p_real+(1-sparsityParam)./(1-p_real));%because sparsity regularithm is introduced,so it need be considered when computing the div-
d2 = (W2'*d3 + repmat(sterm,1,nums)).*sigmoidInv(z2);%.*(a2.*(1-a2));

W1grad = W1grad + d2*data';%
W1grad = 1/nums * W1grad + lambda*W1;

W2grad =  W2grad +d3*a2';%
W2grad = 1/nums * W2grad + lambda*W2;

b1grad = b1grad + sum(d2,2);%
b1grad = 1/nums * b1grad;

b2grad = b2grad + sum(d3,2);
b2grad = 1/nums * b2grad;
---------------------或者-------------------

m=size(data,2);  
 
x=data;  
a1=x;  
z2=W1*a1+repmat(b1,1,m);  
a2=sigmoid(z2);  
z3=W2*a2+repmat(b2,1,m);  
a3=sigmoid(z3);  
h=a3;  
y=x;  
squared_error=0.5*sum((h-y).^2,1);  
rho=1/m*sum(a2,2);  
sparsity_penalty= beta*sum(sparsityParam.*log(sparsityParam./rho)+(1-sparsityParam).*log((1-sparsityParam)./(1-rho)));  
cost=1/m*sum(squared_error)+lambda/2*(sum(sum(W1.^2))+sum(sum(W2.^2))) + sparsity_penalty;  
 
 
grad_z3=a3.*(1-a3);  
delta_3=-(y-a3).*grad_z3;  
grad_z2=a2.*(1-a2);  
delta_2=(W2'*delta_3+repmat(beta*(-sparsityParam./rho+(1-sparsityParam)./(1-rho)),1,m)).*grad_z2;  
Delta_W2=delta_3*a2';  
Delta_b2=sum(delta_3,2);  
Delta_W1=delta_2*a1';  
Delta_b1=sum(delta_2,2);  
W1grad=1/m*Delta_W1+lambda*W1;  
W2grad=1/m*Delta_W2+lambda*W2;  
b1grad=1/m*Delta_b1;  
b2grad=1/m*Delta_b2; 


computeNumericalGradient.m :


epsilon = 1e-4;
n = size(theta,1);
E = eye(n);
for i =1:n
    delta = E(:,i) * epsilon;
    numgrad(i) = (J(theta + delta)-J(theta - delta))/(epsilon*2.0);
end



在 MATLAB 命令行界面输入:

执行结果:

训练结果可视化:



0 0
原创粉丝点击