PCANet代码分析


这段时间的工作内容从模式识别转了图像low-level处理,方法也换了,从神经网络换了词典学习,甚至到了spatial domain处理.这一换虽然是折腾,但词典学习完全颠覆了我对深度学习和神经网络的理解,我也产生了我的第一个想法,也算有收获.不过上周一查新,有篇PCANet和我的想法很像,这文章很新,预发了15年12月的TIP,仔细一看又是Yi Ma大神的挂名.PCANet自称deep learning new baseline,简单还准确率高.看完文章,我甚至觉得这想法就不应该让我想出来,就应该让Yi Ma的团队想出来去做,他们的实验做的太好了,又会写.不过既然是大牛挖的坑就跳吧,目测能改进(人家本来就自称baseline..).总觉得我能不能毕业就靠这篇文章了.

Two stage PCA

Stage 1


重点就是这两步PCA,计算PCA然后对图像片计算PCA系数.
训练样本1000张32*32*3的图片.第一步取40个PCA向量,第二步取8个PCA向量.

1
V{stage} = PCA_FilterBank(OutImg, PCANet.PatchSize(stage), PCANet.NumFilters(stage));

比如对于stage 1, 上面的输入OutImg是1000个32*32*3的图像片.
PCA需要在小片上计算,一个小片5*5*3=75维.所以所有小片组成的样本的协方差矩阵75*75,PCA特征向量算出来也应该是75*75.

1
2
3
4
5
6
%PCA_FilterBank.m
Rx = zeros(NumChls\*PatchSize^2,NumChls\*PatchSize^2); % sum covariance
for i = RandIdx %1:ImgZ
im = im2col_mean_removal(InImg{i},[PatchSize PatchSize]); % collect all the patches of the ith image in a matrix, and perform patch mean removal
Rx = Rx + im\*im'; % sum of all the input images' covariance matrix
end

里面有个有用的函数,im2col_mean_removal,找到一张大图里所有的小片并且去均值,这里的返回应该是75*784,75是一个小片的维度,784=(32-5+1)^2.
Stage 1里得到75x40的PCA基.然后是投影.
具体做法,对一张32x32x3的大图先补0变成36x36x3,目的是使计算投影后的结果和原图一样大(只不过变成了32x32x1).

1
2
3
4
5
%PCA_output.m
for j = 1:NumFilters
cnt = cnt + 1;
OutImg{cnt} = reshape(V(:,j)'*im,ImgX,ImgY); % convolution output
end

这个循环对一张大图,计算了40个PCA的投影.V(:,j)是一个PCA基,im的维度是75x1024,是36x36的图像上所有的5x5x3片,V(:,j)’*im算出了这1024个片(位置)在这个基向量上的投影.

1
OutImgIdx = kron(InImgIdx,ones(NumFilters,1));

这样一张32x32x3的大图变成了40张32x32的图.OutImgIdx用来记录这个对应关系(从1变40的关系).

Stage 2

经过第一步,1000张32x32x3变成了40000张32x32x1,作为新的输入.Stage 2的PCA取前8个,并且由于现在不是3通道了,所以PCA基算出是25x8.
Stage 2计算出的投影就是在做feature extraction.
这一步虽然有40000张输入,但应该对应到最初的input layer上去,也就是一次计算40张32x32,这40张对应着一张32x32x3.8个PCA基,所以用PCA_output的输出是320个32x32,都对应与最初的一张输入图像.

特征计算

一张图输入经过stage 1的40个基变为40张特征图, 每张特征图经过stage 2的8个基变为8张图片.
这8张图片,首先经过Heaviside step变成01图,然后从每个像素位置看,都是一个8位二进制数,这样8张又成了一张,每个像素位置处是一个范围在\([0, 2^8-1]\)的数.于是输出层的图像数又和stage 1的输出一样了.
1->40->320->40.


对输出层的每一张图,把它分成B个blocks,每个blocks里做bins为2^8-1的histogram,然后把这B个blocks的histogram连成一个向量输出.这张图与这个式子对应.


Blocks之间可以重合.
比如block大小8,重合50%,步长就是4.32x32的图里共有ceil((32-8+1)/4)^2=49个8x8的block.
1
stride = round((1-PCANet.BlkOverLapRatio)*PCANet.HistBlockSize); 
blkwise_fea = sparse(histc(im2col_general(T,PCANet.HistBlockSize,...
  stride),(0:2^PCANet.NumFilters(end)-1)'));

上面两行做了histogram统计,得到49个256x1的统计向量.这一步再用[4 2 1]的spatial pyramid pooling,变成21x256.40张图连成一个21x256x40的向量,这就是一张图的最终特征了.