前面的矩阵乘法卷积流程:
图像-->扩充边界(padarray)-->图像数据重排(im2col)-->矩阵相乘-->图像数据重排(reshape)-->图像
哪么反向卷积应该是:
图像<--缩减边界()<--图像数据重排(col2im)<--矩阵转置相乘<--图像数据重排(reshape)<--图像
转置应该是作用图像上,所以也就是:
图像-->转置-->图像数据重排(reshape)-->矩阵相乘-->图像数据重排(col2im)-->缩减边界-->图像
matlab中的col2im好象只能作用在一行,网上也找不到使用方法,
这里先用《Python中如何实现im2col和col2im函数(sliding类型)》的col2im改编到matlab中使用
%对于col2im的实现,我们沿着列块矩阵逐行计算,将得到的行展成子矩阵,
%然后将子矩阵放置在最终结果对应的位置(每次当前值进行相加),
%同时记录每个位置的值放置的次数。最后,将当前位置的值除以放置的次数,
%即可得到结果(原始矩阵)。
function result = Python_col2im(mtx, image_size, block_size)
%p, q = block_size
p=block_size(2);q=block_size(1);
sx = image_size(2) - p + 1;
sy = image_size(1) - q + 1;
result = zeros(image_size);
weight = zeros(image_size); % # weight记录每个单元格的数字重复加了多少遍
col = 1;
%# 沿着行移动,所以先保持列(i)不动,沿着行(j)走
%for i in range(sy):
for i=1:sy
%for j in range(sx):
for j=1:sx
tmp2=reshape(mtx(:,col),p,q);
result( i:i + q-1, j:j + p-1) = result( i:i + q-1, j:j + p-1) + tmp2;
%weight[j:j + p, i:i + q] += np.ones(block_size)
weight(i:i + q-1,j:j + p-1)=weight(i:i + q-1,j:j + p-1) +ones(block_size);
col =col +1;
end
end
%col
result = result ./ weight;
这个col2im 只是实现了步长为1,还要有一个2倍上采样:
% 2倍上采样(加空行 空列)
function Y = up2(X)
[h,w,d]=size(X);
newX=zeros(h,2*w,d);
%加宽
y1=zeros(h,1,d);%加列用
p=1;
for j=1:w
newX(:,p+1,:)=X(:,j,:);%后1
newX(:,p,:)=y1(:,:,:);%前0
p=p+2;
end
clear X;
Y=zeros(2*h,2*w,d);
%加宽
y1=zeros(1,2*w,d);%加行用
p=1;
for j=1:h
Y(p+1,:,:)=newX(j,:,:);%后1
Y(p,:,:)=y1(:,:,:);%前0
p=p+2;
end
流程就成这样了:
图像-->转置-->2倍上采样-->图像数据重排(reshape)-->矩阵相乘-->图像数据重排(col2im)-->缩减边界-->图像
然后到13层取核来和vl_nnconvt比较结果:
load m13.mat;%让程序运行到13层,保存,这里取出
clear convfea;
clear net;
% 1。是上采样2倍 放大2倍(加空行 空列)
u1=(imlow);% 图像
u1=u1'; %转置
u1=up2(u1);%2倍上采样
%2。图像数据重排(reshape)
[h,w,c]=size(u1);
u1=reshape(u1,1,h*w);%一行
%3.核排成一列
weight0=weight(:,:,2,1);%取其中一个核,和后面的vl_nnconvt 要同一个
[wh,ww,wc]=size(weight0);
weight0=reshape(weight0,wh*ww,1);%一列
%4。矩阵相乘
u2=weight0*u1;
%5。图像数据重排(col2im)
u3 = Python_col2im(u2, [w+2,h+2], [3,3]);
% %缩减边界
u3=u3(2:end-1,2:end-1);
ups1=u3+bias(2);%偏置
%与vl_nnconvt来比较
ups2 = vl_nnconvt(imlow, weight(:,:,2,1), bias(2),'upsample', upsample ,'crop', crop,'numGroups',numGroups) ;%
ups1 = vl_nnrelu(ups1, 0.2);%激励函数
ups2 = vl_nnrelu(ups2, 0.2);
k=10;%这个只是让效果更明显
u1_2=uint8((ups1-ups2)*255*k);%ups2-ups1;
u2_1=uint8((ups2-ups1)*255*k);%ups1-ups2;
figure;%显示
subplot(2,2,1);imshow(uint8((ups1*255))*k);title('1');
subplot(2,2,2);imshow(uint8(ups2*255)*k);title('2');
%然后显示两者相减
subplot(2,2,3);imshow(u1_2);title('1-2');
subplot(2,2,4);imshow(u2_1);title('2-1');
% imwrite(u1_2, ['1-2.jpg']);
% imwrite(u2_1, ['2-1.jpg']);
效果:
不对呀,我们的图像很暗,如果乘上9 (行数),ups1=ups1*9;好象就差不多了,
在Python_col2im 函数中有个平均除法,把它去掉:
%对于col2im的实现,我们沿着列块矩阵逐行计算,将得到的行展成子矩阵,
%然后将子矩阵放置在最终结果对应的位置(每次当前值进行相加),
%同时记录每个位置的值放置的次数。最后,将当前位置的值除以放置的次数,
%即可得到结果(原始矩阵)。
function result = Python_col2im(mtx, image_size, block_size)
%p, q = block_size
p=block_size(2);q=block_size(1);
sx = image_size(2) - p + 1;
sy = image_size(1) - q + 1;
result = zeros(image_size);
% weight = zeros(image_size); % # weight记录每个单元格的数字重复加了多少遍
col = 1;
%# 沿着行移动,所以先保持列(i)不动,沿着行(j)走
%for i in range(sy):
for i=1:sy
%for j in range(sx):
for j=1:sx
tmp2=reshape(mtx(:,col),p,q);
result( i:i + q-1, j:j + p-1) = result( i:i + q-1, j:j + p-1) + tmp2;
%weight[j:j + p, i:i + q] += np.ones(block_size)
% weight(i:i + q-1,j:j + p-1)=weight(i:i + q-1,j:j + p-1) +ones(block_size);
col =col +1;
end
end
%col
% result = result ./ weight;
再来看效果:
好象差不多了,再看一下数据:
从这里可以看到除了左上角,其它的地方已经完全一样了
这个单通道单核应该可以用了,但是在2倍残差放大中还是不能用,因为按照反向要得到输入图,就要
用64个方程求解,才得输入图,不象正向,只是简单的加法。
还得再找一个。
先这样吧。