UFLDL作业记录

UFLDL-Sparse Autoencoder

稀疏自编码的作业,在这里

1. 实现sampleIMAGES

IMAGES.mat是一个512x512x10的10张已将白化过的图片。
sampleIMAGES,故名思议,就是采样IMAGES。

imagesc(IMAGES(:,:,4)), colormap gray

可以看到图像的灰度的样子,比如第四张图片:

pic_4

我们想要采的样本是10000个8x8的样本,因为sampleIMAGES里已经这么初始化了。

patchsize = 8;  % we'll use 8x8 patches 
numpatches = 10000; 
patches = zeros(patchsize*patchsize, numpatches);

patches被初始化程成了一个64x10000的矩阵。


Idea很简单:
随机从10张图片里选一张,随机从x坐标里选8个像素,随机从y坐标里选8个像素。

其实我们只要定下10000个随机的点,作为8x8的样本的左上角就可以了。
设,左上角的点的坐标是(a,b,c),显然(a+8-1,b+8-1,c)要不大于(512,512,10)

先选x坐标的值:

  a = randi(512-8+1,1,10000);

在选y坐标的值:

  b = randi(512-8+1,1,10000);

最后选图片到底是第几张:

  c = randi(10,1,10000);

于是,10000张8x8的图像,其实就是:

d = IMAGES(a:a+8-1,b:b+8-1,c)

所以patches就是:

 for i = 1:10000
     pathces(:,i) = reshape(d(:,:,i),1,64);
 end

综合起来,就是:

tic
image_size = size(IMAGES);
a = randi(image_size(1) - patchsize + 1, 1, numpatches);
b = randi(image_size(2) - patchsize + 1, 1, numpatches);
c = randi(image_size(3), 1, numpatches);
d = IMAGES(a:a+8-1, b:b+8-1, c)
for num = 1 : numpatches
   patches(:,num)=reshape(d(:,:,num),1,patchsize*patchsize);
end
toc

2. 构建Sparse autoencoder objective

可以看到,train.m里,已经设定了hiddenSize = 25,所以这个网络结构其实是:64x25x64,隐层有25个单元。

先按正常的神经网络的训练顺序来

2.1 前向传播

Θ 已经在initializeParameters里定义好了,所以 W~1~(25x64),W~2~(64x25)和b~1~(25x1),b~2~(64x1) 已经有了,可以直接开始算前向传播:

  B_1 = repmat(b_1,1,10000);%截距
  Z_2 = (W_1*patches) + B_1;%输入
  A_2 = sigmoid(Z_2);%隐层输出
  B_2 = repmat(b_2,1,10000);%截距
  Z_3 = (W_2*A_2) + B_2;%输入
  A_3 = sigmoid(Z_3);%结果

2.2 稀疏性保证

接着要计算 ρ^ ,号称是隐层的平均输出,文中给的公式是:
ρ^j=1mmi=1[a(2)j(x(i))]
它说,这里取的平均,是在测试集上的平均(averaged over the training set),我觉得很奇怪。

我们知道A_2是一个25x10000的矩阵,那这个m,到底是25还是10000?我怎么感觉都是25,不是说是隐层的平均输出么?

我们想让 ρ^ 尽量的小,最好是某个挺小的值 ρ ,这个 ρ 也叫稀疏性参数

为了完成上述要求,我们要把 ρ^ ρ 的相对熵算一下:
KL(ρ||ρ^j)=ρlogρρ^j+(1ρ)log1ρ1ρ^j
把下面这个东西放进代价函数里,来实现稀疏性的控制:
s2j=1KL(ρ||ρ^j)
文中说,说这里的S~2~是隐层节点数,也就是25。这里的 ρ 又是个标量,显然上面的那个 ρ^ 里的m是10000了。

那么,代码这么写:

  mean_A_2 = sum(A_2,2)./10000;
  rho = sparsityParam
  KL = sum(rho.*log(rho./mean_A_2)+(1-rho).*log((1-v)/(1.-mean_A_2));

2.3 代价函数

代价函数J:
Jsparse(W,b)=J(W,b)+βs2j=1KL(ρ||ρ^j)
其中, J(W,b) ,按照反向传播来算是:

J(W,b)=[1mmi=1(12hW,b(x(i))y(i)2)]+λ2nl1l=1sli=1sl+1j=1(W(l)ji)2

所以,

  J=(1/2*10000)*sum(sum((A_3-patches).^2))+lambda/2*(sum(sum(W_1.^2))+sum(sum(W_2.^2)))+beta*KL;

2.4梯度下降

  daoshu_Z_3 = sigmoid(A_3).*(1-sigmoid(A_3);
  delta_3 = -(patches-A_3).*daoshu_Z_3;

对于delta_2,文中说:
δ(2)i=((s2j=1W(2)jiδ(3)j)+β(ρρ^i+1ρ1ρ^i))f(z(2)i)
这么写比较省事。所以:

  sparity_penalty = (-rho./mean_A_2+(1-rho)./(1-mean_A_2));
  daoshu_Z_2 = sigmoid(A_2).*(1-sigmoid(A_2);
  delta_2=(W_2'*delta_3+repmat(beta*sparity_penalty,1,mm)).*daoshu_Z_2;

则,W偏导,b偏导为:
W(l)J(W,b;x,y)=δ(l+1)(a(l))T

b(l)J(W,b;x,y)=δ(l+1)

所以W,和b的偏导代码是:

 W1_pd = delta_2 * pathces';
 W2_pd = delta_3 * A_2';
 b1_pd = sum(delta_2,2);
 b2_pd = sum(delta_3,2);

W,b的梯度:

ΔW(l):=ΔW(l)+W(l)J(W,b;x,y)

Δb(l):=Δb(l)+b(l)J(W,b;x,y)

 W1grad = W1grad + W1_pd;
 W2grad = W2grad + W2_pd;
 b1grad = b1grad + b1_pd;
 b2grad = b2grad + b2_pd;

最终更新权重:

  b1grad=b1grad/10000;
  b2grad=b2grad/10000;
  W1grad=W1grad/10000+lambda*W_1;
  W2grad=W2grad/10000+lambda*W_2;

至此,代价函数就写完了。

3.检验梯度

最后,还要保证梯度算的没错。。。。
文中提到了这样的检测方法:
g(θ)J(θ+EPSILON)J(θEPSILON)2×EPSILON.
那么,我们就要对代价函数做上述的检测:

eps = 1e-4;  
m = size(theta,1);  
for i=1:m  
    theta_p = theta;  
    theta_p(i,:) = theta_p(i,:) + eps;  
    theta_m = theta;  
    theta_m(i,:) = theta_m(i,:) - eps;  
    numgrad(i,:) = (J(theta_p) - J(theta_m))/(eps*2.0);  
end 

其实有向量化的方法:

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

m一大,eye就超出了matlab的限制了,所以,我用的上一个。
这一步句,巨慢无比,因为要进行mx2次的J函数的运算。。。。

4.结果

result

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值