UFLDL-Sparse Autoencoder
稀疏自編碼的作業,在這裏。
1. 實現sampleIMAGES
IMAGES.mat是一個512x512x10的10張已將白化過的圖片。
sampleIMAGES,故名思議,就是採樣IMAGES。
用
imagesc(IMAGES(:,:,4)), colormap gray
可以看到圖像的灰度的樣子,比如第四張圖片:
我們想要採的樣本是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 前向傳播
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 稀疏性保證
接着要計算
它說,這裏取的平均,是在測試集上的平均(averaged over the training set),我覺得很奇怪。
我們知道A_2是一個25x10000的矩陣,那這個m,到底是25還是10000?我怎麼感覺都是25,不是說是隱層的平均輸出麼?
我們想讓
爲了完成上述要求,我們要把
把下面這個東西放進代價函數裏,來實現稀疏性的控制:
文中說,說這裏的S~2~是隱層節點數,也就是25。這裏的
那麼,代碼這麼寫:
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:
其中,
所以,
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,文中說:
這麼寫比較省事。所以:
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,和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的梯度:
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.檢驗梯度
最後,還要保證梯度算的沒錯。。。。
文中提到了這樣的檢測方法:
那麼,我們就要對代價函數做上述的檢測:
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函數的運算。。。。