【caffe-matlab】权重以及特征图的可视化

前言

移植了各种caffe,是时候进行下一步操作了,先拿可视化下手吧。大部分内容可能跟网上的方法不一样,大家看完我的博客最好去网上看看大牛们的博客,万一被我误导了,就罪过了o(╯□╰)o,开更.............

环境:微软caffe+wind7+matlab2013a

参考:http://caffe.berkeleyvision.org/tutorial/interfaces.html

             http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb

一、模型读取

读取bvlc_reference_caffenet 的模型结构以及训练好的参数,注意此处的模型结构为deploy,而非train时候的。

addpath('..') %加入+caffe路径
caffe.set_mode_cpu();%设置CPU模式
model = '../../models/bvlc_reference_caffenet/deploy.prototxt';%模型
weights = '../../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel';%参数
net=caffe.Net(model,'test');%测试
net.copy_from(weights); %得到训练好的权重参数
net %显示net的结构
然后我们就可以看到模型的结构了:

net = Net with properties:layer_vec: [1x24 caffe.Layer]blob_vec: [1x15 caffe.Blob]inputs: {'data'}outputs: {'prob'}name2layer_index: [24x1 containers.Map]name2blob_index: [15x1 containers.Map]layer_names: {24x1 cell}blob_names: {15x1 cell}
这里额外提一下,net 通过"." 能显示的东西,除了上面输出的这些properties外,还有Net.m中定义的函数
function self = Net(varargin)
function layer = layers(self, layer_name)
function blob = blobs(self, blob_name)
function blob = params(self, layer_name, blob_index)
function forward_prefilled(self)
function backward_prefilled(self)
function res = forward(self, input_data)
function res = backward(self, output_diff)
function copy_from(self, weights_file)
function reshape(self)
function save(self, weights_file)
我们在matlab中进行操作的基础也就是这些函数,当然还有其它的,以后慢慢接触吧。

二、输入数据整理

嗯,还是拿这只猫开刀,这只猫一般藏在E:\CaffeDev\caffe-master\examples\images\cat.jpg,没找到的话直接右键保存下方图片

先说一下过程:

①先把均值读进来

d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat');
mean_data = d.mean_data;
②读取图片

im = imread('../../examples/images/cat.jpg');%读取图片
IMAGE_DIM = 256;%图像将要resize的大小,建议resize为图像最小的那个维度
CROPPED_DIM = 227;%待会需要把一张图片crops成十块,最终softmax求出每一块可能的标签

设置在输入网络之前需要将图片resize的大小,一般我们会取图片长宽最小的那个,其次需要设置的是输入网络的图片的大小,注意与deploy.prototxt的输入一致,比如

name: "CaffeNet"
layer {name: "data"type: "Input"top: "data"input_param { shape: { dim: 10 dim: 3 dim: 227 dim: 227 } }
}
这里关注一下input_param,代表一次输入十张图片,每张图片三通道,每张图片大小是227*227。此外注意一下,在opencv中,彩色图像按照BGR存储,而matlab中读取的顺序一般是RGB。所以对这只猫需要进行如下处理:

im_data = im(:, :, [3, 2, 1]);  %matlab按照RGB读取图片,opencv是BGR,所以需要转换顺序为opencv处理格式
im_data = permute(im_data, [2, 1, 3]);  % 原始图像m*n*channels,现在permute为n*m*channels大小
im_data = single(im_data);  % 强制转换数据为single类型
im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear');  % 线性插值resize图像
注意一下你在训练的train.prototxt中的预处理部分
 transform_param {mirror: truecrop_size: 227mean_file: "data/ilsvrc12/imagenet_mean.binaryproto"}
这里最后一行代表进行了零均值处理,关于这一部分参数,可以看我前面用classification,exe手写识别时候提到的那个博客,介绍了如何看这一部分进行了怎样的预处理。

先零均值化一下,然后按照deploy和train的prototxt,将这只猫crop(分成)十块,采用的是classification.demo的分割方法,分别取猫的上下左右四个角以及中心的大小为deploy中提到的227*227大小。这是五个,然后再对图片翻转180°;合起来就是代表这只猫的十张图片:

im_data = im_data - mean_data;  % 零均值
crops_data = zeros(CROPPED_DIM, CROPPED_DIM, 3, 10, 'single');%注意此处是因为prototxt的输入大小为宽*高*通道数*10
indices = [0 IMAGE_DIM-CROPPED_DIM] + 1;%获得十块每一块大小与原始图像大小差距,便于crops
%下面就是如何将一张图片crops成十块
n = 1;
%此处两个for循环并非是1:indices,而是第一次取indices(1),然后是indices(2),每一层循环两次
%分别读取图片四个角大小为CROPPED_DIM*CROPPED_DIM的图片
for i = indicesfor j = indicescrops_data(:, :, :, n) = im_data(i:i+CROPPED_DIM-1, j:j+CROPPED_DIM-1, :);%产生四个角的cropdata,1 2 3 4crops_data(:, :, :, n+5) = crops_data(end:-1:1, :, :, n);%翻转180°来一次,产生四个角的翻转cropdata,6 7 8 9n = n + 1;end
end
center = floor(indices(2) / 2) + 1;
%以中心为crop_data左上角顶点,读取CROPPED_DIM*CROPPED_DIM的块
crops_data(:,:,:,5) = ...im_data(center:center+CROPPED_DIM-1,center:center+CROPPED_DIM-1,:);
%与for循环里面一样,翻转180°,绕左边界翻转
crops_data(:,:,:,10) = crops_data(end:-1:1, :, :, 5);
可视化看看长啥样:

clear
clc
close all
%caffenet的解读:http://www.2cto.com/kf/201606/515700.html
%% 设置网络
addpath('..') %加入+caffe路径
caffe.set_mode_cpu();%设置CPU模式
model = '../../models/bvlc_reference_caffenet/deploy.prototxt';%模型
weights = '../../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel';%参数
net=caffe.Net(model,'test');%测试
net.copy_from(weights); %得到训练好的权重参数
net %显示net的结构%% 预处理
d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat');
mean_data = d.mean_data;%读取均值
im = imread('../../examples/images/cat.jpg');%读取图片
IMAGE_DIM = 256;%图像将要resize的大小,建议resize为图像最小的那个维度
CROPPED_DIM = 227;%最终需要把一张图片crops成十块,最终求出每一块可能的标签
im_data=im;
im_data = im(:, :, [3, 2, 1]);  %matlab按照RGB读取图片,opencv是BGR,所以需要转换顺序为opencv处理格式
im_data = permute(im_data, [2, 1, 3]);  % 原始图像m*n*channels,现在permute为n*m*channels大小
im_data = single(im_data);  % 强制转换数据为single类型
im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear');  % 线性插值resize图像
% im_data = im_data - mean_data;  % 零均值
crops_data = zeros(CROPPED_DIM, CROPPED_DIM, 3, 10, 'single');%注意此处是因为prototxt的输入大小为宽*高*通道数*10
indices = [0 IMAGE_DIM-CROPPED_DIM] + 1;%获得十块每一块大小与原始图像大小差距,便于crops
%下面就是如何将一张图片crops成十块
n = 1;
%此处两个for循环并非是1:indices,而是第一次取indices(1),然后是indices(2),每一层循环两次
%分别读取图片四个角大小为CROPPED_DIM*CROPPED_DIM的图片
for i = indicesfor j = indicescrops_data(:, :, :, n) = im_data(i:i+CROPPED_DIM-1, j:j+CROPPED_DIM-1, :);%产生四个角的cropdata,1 2 3 4crops_data(:, :, :, n+5) = crops_data(end:-1:1, :, :, n);%翻转180°来一次,产生四个角的翻转cropdata,6 7 8 9n = n + 1;end
end
center = floor(indices(2) / 2) + 1;
%以中心为crop_data左上角顶点,读取CROPPED_DIM*CROPPED_DIM的块
crops_data(:,:,:,5) = ...im_data(center:center+CROPPED_DIM-1,center:center+CROPPED_DIM-1,:);
%与for循环里面一样,翻转180°,绕左边界翻转
crops_data(:,:,:,10) = crops_data(end:-1:1, :, :, 5);cat_map=zeros(CROPPED_DIM*2,CROPPED_DIM*5,3);%两行五列展示
cat_num=0;
for i=0:1for j=0:4cat_num=cat_num+1cat_map(CROPPED_DIM*i+1:(i+1)*CROPPED_DIM,CROPPED_DIM*j+1:(j+1)*CROPPED_DIM,:)=crops_data(:,:,:,cat_num);end
end
imshow(uint8(cat_map))

看着比较怪的原因在于,中间经过了matlab处理方式到opencv处理方式的转变,但是我们依旧用matlab输出了。

三、前向计算

res=net.forward({crops_data});
prob=res{1};
prob1 = mean(prob, 2);
[~, maxlabel] = max(prob1);
这一步完毕以后,整个网络就会充满参数了,权重,特征图均生成完毕,接下来可视化它们。

四、特征图可视化

4.1、特征图提取方法

说一下步骤,首先利用net 中的blob_name函数取出与deploy.prototxt对应的 top 名字,显示一下看看

names=net.blob_namesnames = 'data''conv1''pool1''norm1''conv2''pool2''norm2''conv3''conv4''conv5''pool5''fc6''fc7''fc8''prob'

然后利用blob调用get_data()函数获取我们需要的特征图的值。注意,每一层的特征图是四维,看看前三层的特征图大小:

size(featuremap{1})=227   227     3    10
size(featuremap{2})= 55    55    96    10
size(featuremap{3})=  27    27    96    10
结合deploy中每一层的卷积核大小以及步长,利用 (当前层特征图大小 - 卷积核大小) / 步长+1=下一层特征图大小,可以推导出每一个featuremap 的前两维,第三个维度代表的是卷积核个数,featuremap {2}到featuremap {3}是池化了。第四个维度代表最开始输入了十张图

4.2 部分可视化方法:

这一部分针对指定的第crop_num张图像在第map_num层进行可视化。注意,这一部分的可视化包含池化层等。

function [  ] = feature_partvisual( net,mapnum,crop_num )
names=net.blob_names;
featuremap=net.blobs(names{mapnum}).get_data();%获取指定层的特征图
[m_size,n_size,num,crop]=size(featuremap);%获取特征图大小,长*宽*卷积核个数*通道数
row=ceil(sqrt(num));%行数
col=row;%列数
feature_map=zeros(n_size*col,m_size*row);%特征图的宽实际是matlab读取图像的高
cout_map=1;
for i=0:row-1for j=0:col-1if cout_map<=numfeature_map(j*n_size+1:(j+1)*n_size,i*m_size+1:(i+1)*m_size)=(mapminmax(featuremap(:,:,cout_map,crop_num),0,1)*255)';
cout_map=cout_map+1;endend
end
imshow(uint8(feature_map))
str=strcat('feature map num:',num2str(cout_map-1));
title(str)
end
调用方法:

mapnum=1;%第几层的feature☆☆☆☆☆☆☆☆
crop_num=1;%第几个crop的特征图☆☆☆☆☆☆☆☆
feature_partvisual( net,mapnum,crop_num )


中间有个处理细节是归一化然后乘以255,是避免featuremap的数值过小,或者有负数,导致特征图一片漆黑;在下面的权重可视化方法采取的是另一种处理。

读者可以更改"☆"标志的行中的数值去提取不同crop图像的不同层特征图。

第一层特征图:


第二层featuremap:


4.3、全部可视化

这一部分可视化每一张输入图片在指定卷积层的特征图,按照每一行为存储图片的特征图为图例。

function [  ] = feature_fullvisual( net,mapnum )
names=net.blob_names;
featuremap=net.blobs(names{mapnum}).get_data();%获取指定层的特征图
[m_size,n_size,num,crop]=size(featuremap)%获取特征图大小,长*宽*卷积核个数*图片个数
row=crop;%行数
col=num;%列数
feature_map=zeros(n_size*colm_size*row);
for i=0:row-1for j=0:col-1feature_map(j*n_size+1:(j+1)*n_size,i*m_size+1:(i+1)*m_size)=(mapminmax(featuremap(:,:,j+1,i+1),0,1)*255)';
end
end
figure
imshow(uint8(feature_map))
str=strcat('feature map num:',num2str(row*col));
title(str)
end
调用方法

mapnum=2;%第几层的feature☆☆☆☆☆☆☆☆
feature_fullvisual( net,mapnum )
第一层:


第二层:基本看不清楚了,十张输入图片,每一张都有96个特征图,不好显示


五、卷积核可视化

【注】卷积核可视化中,采用的像素放大方法与特征图的不一样。特征图中采用归一化mapminmax到(0,1)范围,然后乘以255,;在下面卷积核的可视化中采用(x-最小值)/最大值*255的方法去放大像素。读者可根据自己喜好决定。

5.1、权重提取方法

先建议读者去看看多通道卷积的概念:http://blog.csdn.net/u014114990/article/details/51125776,不看也行,注意这句话,每一个通道的卷积核是不一样的,同一个卷积核只在同一个特征图中共享,应该理解的没错吧o(╯□╰)o。

通过net 的layer_names 函数能够获取deploy.txt 对应的name 的名称,每一个name的blob对应两个值,分别是权重和偏置,提取方法如下:

【注】貌似仅仅卷积核能够获取到权重,池化层倒是没有权重,全连接部分也是有权重的,但是没什么意义

layers=net.layer_names;
convlayer=[];
for i=1:length(layers)if strcmp(layers{i}(1:3),'con')%仅仅卷积核能获取到权重convlayer=[convlayer;layers{i}];end
end
w=cell(1,length(convlayer));%存储权重
b=cell(1,length(convlayer));%存储偏置
for i=1:length(convlayer)w{i}=net.layers(convlayer(i,:)).params(1).get_data();b{i}=net.layers(convlayer(i,:)).params(2).get_data();
end
提取完毕以后观察一下每一层的权重维度,发现也是四维,显示一下前三个卷积核的维度:

size(w{1})= 11    11     3    96
size(w{2})= 5     5    48   256
size(w{3})= 3     3   256   384

前两个维度不说了,卷积核的大小,第三个维度代表卷积核的左边,也就是上一层的特征图的个数(对应前面说的每一个通道对应不同卷积核),第四个维度代表每一个通道对应的卷积核个数(也就是卷积核右边下一层的特征图的个数)。

【注】稍微说一下为什么`conv1`的输出大小是96, 而到了`conv2`的输入时大小为48呢?因为`conv2`有个参数叫`group`, 相当于两两合一起了, 你看`conv3`肯定就没有设置`group', 所以输入才是和`conv2`的输出大小一样都是256

5.2、部分可视化方法

那么我们可视化也是可选的,需要选择哪一个特征图对应的卷积核,可视化方法如下:

function [  ] = weight_partvisual( net,layer_num ,channels_num )
layers=net.layer_names;
convlayer=[];
for i=1:length(layers)if strcmp(layers{i}(1:3),'con')convlayer=[convlayer;layers{i}];end
end
w=net.layers(convlayer(layer_num,:)).params(1).get_data();
b=net.layers(convlayer(layer_num,:)).params(2).get_data();
minval=min(min(min(min(w))));
maxval=max(max(max(max(w))));
w=(w-minval)/maxval*255;weight=w(:,:,channels_num,:);%四维,核长*核宽*核左边输入*核右边输出(核个数)
[kernel_r,kernel_c,input_num,kernel_num]=size(w);
map_row=ceil(sqrt(kernel_num));%行数
map_col=map_row;%列数
weight_map=zeros(kernel_r*map_row,kernel_c*map_col);
kernelcout_map=1;
for i=0:map_row-1for j=0:map_col-1if kernelcout_map<=kernel_numweight_map(i*kernel_r+1+i:(i+1)*kernel_r+i,j*kernel_c+1+j:(j+1)*kernel_c+j)=weight(:,:,:,kernelcout_map);kernelcout_map=kernelcout_map+1;endend
end
figure
imshow(uint8(weight_map))
str1=strcat('weight num:',num2str(kernelcout_map-1));
title(str1)end

 
 

调用方法

layer_num=1;%想看哪一个卷积核对应的权重☆☆☆☆☆☆☆☆☆☆
channels_num=1;%想看第几个通道对应的卷积核
weight_partvisual( net,layer_num ,channels_num )

看看效果:

第一个卷积层的第一个通道对应的卷积核:


第二个卷积层的第一个通道对应的卷积核:


2017.3.4更新日志:

谢谢 TensorSense指出的代码错误,上面说过避免像素值过小的计算方法是通过减去最最小值除以最大值以后乘以255,但是代码却写成了

w=w-min(min(min(min(w))));
w=w/max(max(max(max(w))))*255;
在此做一下更正,应该是
minval=min(min(min(min(w))));
maxval=max(max(max(max(w))));
w=(w-minval)/maxval*255;

当然也可以用全部可视化中提到的MATLAB自带函数mapminmanx函数进行归一化。


5.3、全部可视化

将指定卷积层对应的每一个特征图的全部卷积核画出

function [  ] = weight_fullvisual( net,layer_num  )
layers=net.layer_names;
convlayer=[];
for i=1:length(layers)if strcmp(layers{i}(1:3),'con')convlayer=[convlayer;layers{i}];end
endweight=net.layers(convlayer(layer_num,:)).params(1).get_data();%四维,核长*核宽*核左边输入*核右边输出(核个数)
b=net.layers(convlayer(layer_num,:)).params(2).get_data();
minval=min(min(min(min(w))));
maxval=max(max(max(max(w))));
w=(w-minval)/maxval*255;[kernel_r,kernel_c,input_num,kernel_num]=size(weight);
map_row=input_num;%行数
map_col=kernel_num;%列数
weight_map=zeros(kernel_r*map_row,kernel_c*map_col);
for i=0:map_row-1for j=0:map_col-1weight_map(i*kernel_r+1+i:(i+1)*kernel_r+i,j*kernel_c+1+j:(j+1)*kernel_c+j)=weight(:,:,i+1,j+1);end
end
figure
imshow(uint8(weight_map))
str1=strcat('weight num:',num2str(map_row*map_col));
title(str1)end


第一层:


第二层:


附上所有代码:

主函数

<pre name="code" class="cpp">clear
clc
close all
%caffenet的解读:http://www.2cto.com/kf/201606/515700.html
%% 设置网络
addpath('..') %加入+caffe路径
caffe.set_mode_cpu();%设置CPU模式
model = '../../models/bvlc_reference_caffenet/deploy.prototxt';%模型
weights = '../../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel';%参数
net=caffe.Net(model,'test');%测试
net.copy_from(weights); %得到训练好的权重参数
net %显示net的结构%% 预处理
d = load('../+caffe/imagenet/ilsvrc_2012_mean.mat');
mean_data = d.mean_data;%读取均值
im = imread('../../examples/images/cat.jpg');%读取图片
IMAGE_DIM = 256;%图像将要resize的大小,建议resize为图像最小的那个维度
CROPPED_DIM = 227;%最终需要把一张图片crops成十块,最终求出每一块可能的标签
im_data=im;
im_data = im(:, :, [3, 2, 1]);  %matlab按照RGB读取图片,opencv是BGR,所以需要转换顺序为opencv处理格式
im_data = permute(im_data, [2, 1, 3]);  % 原始图像m*n*channels,现在permute为n*m*channels大小
im_data = single(im_data);  % 强制转换数据为single类型
im_data = imresize(im_data, [IMAGE_DIM IMAGE_DIM], 'bilinear');  % 线性插值resize图像
% im_data = im_data - mean_data;  % 零均值
crops_data = zeros(CROPPED_DIM, CROPPED_DIM, 3, 10, 'single');%注意此处是因为prototxt的输入大小为宽*高*通道数*10
indices = [0 IMAGE_DIM-CROPPED_DIM] + 1;%获得十块每一块大小与原始图像大小差距,便于crops
%下面就是如何将一张图片crops成十块
n = 1;
%此处两个for循环并非是1:indices,而是第一次取indices(1),然后是indices(2),每一层循环两次
%分别读取图片四个角大小为CROPPED_DIM*CROPPED_DIM的图片
for i = indicesfor j = indicescrops_data(:, :, :, n) = im_data(i:i+CROPPED_DIM-1, j:j+CROPPED_DIM-1, :);%产生四个角的cropdata,1 2 3 4crops_data(:, :, :, n+5) = crops_data(end:-1:1, :, :, n);%翻转180°来一次,产生四个角的翻转cropdata,6 7 8 9n = n + 1;end
end
center = floor(indices(2) / 2) + 1;
%以中心为crop_data左上角顶点,读取CROPPED_DIM*CROPPED_DIM的块
crops_data(:,:,:,5) = ...im_data(center:center+CROPPED_DIM-1,center:center+CROPPED_DIM-1,:);
%与for循环里面一样,翻转180°,绕左边界翻转
crops_data(:,:,:,10) = crops_data(end:-1:1, :, :, 5);%% 展示被crop的图需要im_data = im_data - mean_data注释
cat_map=zeros(CROPPED_DIM*2,CROPPED_DIM*5,3);%两行五列展示
cat_num=0;
for i=0:1for j=0:4cat_num=cat_num+1cat_map(CROPPED_DIM*i+1:(i+1)*CROPPED_DIM,CROPPED_DIM*j+1:(j+1)*CROPPED_DIM,:)=crops_data(:,:,:,cat_num);end
end
figure
imshow(uint8(cat_map))
%% 前向计算
res=net.forward({crops_data});
prob=res{1};
prob1 = mean(prob, 2);
[~, maxlabel] = max(prob1);
%% 观察网络结构,获取特征图
%注意blob_names和layer_names的区别
%获取特征图,特征图就是prototxt的每一层top名字
mapnum=2;%第几层的feature☆☆☆☆☆☆☆☆
crop_num=1;%第几个crop的特征图☆☆☆☆☆☆☆☆
feature_partvisual( net,mapnum,crop_num )
feature_fullvisual( net,mapnum )%% 观察网络结构,获取权重
%看多通道卷积解释http://blog.csdn.net/u014114990/article/details/51125776
%中间group过一次,96分两两group变成48,第56行
%获取权重,每一层的layer_names存储了权重和偏置,第一个参数是权重,第二个参数是偏置
layer_num=2;%想看哪一层的权重☆☆☆☆☆☆☆☆☆☆
channels_num=1;%想看第几个通道对应的卷积核
weight_partvisual( net,layer_num ,channels_num )
weight_fullvisual( net,layer_num  )

 部分特征图可视化: 

function [  ] = feature_partvisual( net,mapnum,crop_num )
names=net.blob_names;
featuremap=net.blobs(names{mapnum}).get_data();%获取指定层的特征图
[m_size,n_size,num,crop]=size(featuremap);%获取特征图大小,长*宽*卷积核个数*通道数
row=ceil(sqrt(num));%行数
col=row;%列数
feature_map=zeros(m_size*row,n_size*col);
cout_map=1;
for i=0:row-1for j=0:col-1if cout_map<=numfeature_map(i*m_size+1:(i+1)*m_size,j*n_size+1:(j+1)*n_size)=(mapminmax(featuremap(:,:,cout_map,crop_num),0,1)*255)';cout_map=cout_map+1;endend
end
figure;imshow(uint8(feature_map))
str=strcat('feature map num:',num2str(cout_map-1));
title(str)
end
全部特征图可视化:

function [  ] = feature_fullvisual( net,mapnum )
names=net.blob_names;
featuremap=net.blobs(names{mapnum}).get_data();%获取指定层的特征图
[m_size,n_size,num,crop]=size(featuremap)%获取特征图大小,长*宽*卷积核个数*图片个数
row=crop;%行数
col=num;%列数
feature_map=zeros(m_size*row,n_size*col);
for i=0:row-1for j=0:col-1feature_map(i*m_size+1:(i+1)*m_size,j*n_size+1:(j+1)*n_size)=(mapminmax(featuremap(:,:,j+1,i+1),0,1)*255)';end
end
figure
imshow(uint8(feature_map))
str=strcat('feature map num:',num2str(row*col));
title(str)
end
部分卷积核可视化:

function [  ] = weight_visual( net,layer_num ,channels_num )
layers=net.layer_names;
convlayer=[];
for i=1:length(layers)if strcmp(layers{i}(1:3),'con')convlayer=[convlayer;layers{i}];end
end
w=net.layers(convlayer(layer_num,:)).params(1).get_data();
b=net.layers(convlayer(layer_num,:)).params(2).get_data();
minval=min(min(min(min(w))));
maxval=max(max(max(max(w))));
w=(w-minval)/maxval*255;
[kernel_r,kernel_c,input_num,kernel_num]=size(w);
map_row=ceil(sqrt(kernel_num));%行数
map_col=map_row;%列数
weight_map=zeros(kernel_r*map_row,kernel_c*map_col);
kernelcout_map=1;
for i=0:map_row-1for j=0:map_col-1if kernelcout_map<=kernel_numweight_map(i*kernel_r+1+i:(i+1)*kernel_r+i,j*kernel_c+1+j:(j+1)*kernel_c+j)=weight(:,:,:,kernelcout_map);kernelcout_map=kernelcout_map+1;endend
end
figure
imshow(uint8(weight_map))
str1=strcat('weight num:',num2str(kernelcout_map-1));
title(str1)end
全部卷积核可视化:

function [  ] = weight_fullvisual( net,layer_num  )
layers=net.layer_names;
convlayer=[];
for i=1:length(layers)if strcmp(layers{i}(1:3),'con')convlayer=[convlayer;layers{i}];end
endweight=net.layers(convlayer(layer_num,:)).params(1).get_data();%四维,核长*核宽*核左边输入*核右边输出(核个数)
b=net.layers(convlayer(layer_num,:)).params(2).get_data();
minval=min(min(min(min(weight))));
maxval=max(max(max(max(weight))));
weight=(weight-minval)/maxval*255;[kernel_r,kernel_c,input_num,kernel_num]=size(weight);
map_row=input_num;%行数
map_col=kernel_num;%列数
weight_map=zeros(kernel_r*map_row,kernel_c*map_col);
for i=0:map_row-1for j=0:map_col-1weight_map(i*kernel_r+1+i:(i+1)*kernel_r+i,j*kernel_c+1+j:(j+1)*kernel_c+j)=weight(:,:,i+1,j+1);end
end
figure
imshow(uint8(weight_map))
str1=strcat('weight num:',num2str(map_row*map_col));
title(str1)end


六、全连接探讨

这里初步探索一下CaffeNet 的最后一个池化层pool5到第一个全连接层fc6的连接,我最开始的理解是直接把pool层所有的单元拉成一个列向量,不过分析以后,感觉应该是类似BP,pool5先被拉成一个一维向量,然后利用权重连接到fc6层的所有单元上,类似二部图的连接方法。

实验过程如下:

①首先提取出pool5的特征图大小

K>> A=net.blobs('pool5').get_data();
K>> size(A)ans =6     6   256    10

可以发现对于每一个输入图片(总共十张)都有256个6*6大小的特征图。预先计算一下256*6*6=9216

②然后提取出fc6的特征图大小

K>> B=net.blobs('fc6').get_data();
K>> size(B)ans =4096          10
然后发现pool5到fc6的连接并不是简单的拉成一维向量,而是利用了一个9216*4096的权重去将pool5的特征映射到fc6的单元中

③验证一下是否如所想的映射方法, 只需要看看pool5到fc6的权重大小即可

K>> C=net.layers('fc6').params(1).get_data();
K>> size(C)ans =9216        4096
发现果真如此,所以池化层到全连接层的确是用了一次映射而非简单的拉成向量

最后贴三个关于softmax分类器的地址:

http://blog.csdn.net/hlx371240/article/details/40201499

https://wugh.github.io/posts/2016/02/cs224d-notes2-softmax-classification-and-window-classification/?utm_source=tuicool&utm_medium=referral

http://deeplearning.stanford.edu/wiki/index.php/Exercise:Softmax_Regression
【特别提示】记得搜一些大牛的代码看看,我自己理解可能部分有问题哦~~~~如果读者发现错误,谢谢指正


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【caffe-matlab】使用matlab训练caffe及绘制loss

前言 此博客主要介绍如何利用matlab一步一步训练caffe模型&#xff0c;类似使用caffe.exe 的train命令。 国际惯例&#xff0c;参考博客&#xff1a; http://caffe.berkeleyvision.org/tutorial/interfaces.html http://www.cnblogs.com/denny402/p/5110204.html 抱怨一…

【caffe-matlab】目标检测R-FCN算法于Windows下配置

前言 首先谢谢好友推荐的这篇论文及代码&#xff0c;前面学习的caffe可能比较浅显&#xff0c;想要深入caffe就可以从这个代码下手了&#xff0c;配置方法还是挺简单的&#xff0c;但是可能会出现部分问题。在作者的论文中有github的地址。注意&#xff0c;本文只介绍如何配置…

【写作】Texlive和Texmaker学习

前言 最近要看一些论文做一下笔记&#xff0c;所以准备使用一下比较流行的Texlive和Texmaker写一下。其实CSDN的Markdown也是不错滴。 首先国际惯例&#xff0c;贴几个地址&#xff1a; Texlive镜像下载地址&#xff1a;http://mirror.lzu.edu.cn/CTAN/systems/texlive/Imag…

《Neural Networks for Machine Learning》学习一

前言 最近报了一下Hinton大牛的coursera的神经网络课程&#xff0c;奈何比较懒&#xff0c;一直没看&#xff0c;还是写个博客督促自己比较好 贴一下课程地址&#xff1a;https://www.coursera.org/learn/neural-networks/home/week/1 第一讲主题是为何需要机器学习&#xf…

《Neural Networks for Machine Learning》学习二

前言 课程地址&#xff1a;https://www.coursera.org/learn/neural-networks/home/week/1‘’ 【Lecture 2】百度云下载地址&#xff1a;链接&#xff1a;http://pan.baidu.com/s/1nvMynhR 密码&#xff1a;ru3y 神经网络架构概览 前馈神经网络(Feed-Forward neural network)…

入门 | 初学者必读:解读14个深度学习关键词

作者&#xff1a;Matthew Mayo 机器之心编译 参与&#xff1a;Xuwen Wang、Chen Chen 微信公众号&#xff1a;&#xff08;almosthuman2014&#xff09;授权转载&#xff0c;禁止二次转载&#xff0c;点此为原文链接 本文介绍了包括 LSTM、ANNS、生物神经元、反向传播、多元感知…

深度 | 一篇文章带你进入无监督学习:从基本概念到四种实现模型(附论文)

作者&#xff1a;Eugenio Culurciello 机器之心编译 参与&#xff1a;李亚洲、武竞 微信公众号&#xff1a;&#xff08;almosthuman2014&#xff09;授权转载&#xff0c;禁止二次转载&#xff0c;点此为原文链接 这是今年 6 月份普渡大学副教授 Eugenio Culurciello 写的一篇…

【caffe-Windows】微软官方caffe之 Python接口配置及图片生成实例

前言 发现许多代码还是用python写的&#xff0c;所以还是配置一下接口吧&#xff0c;虽然博主不会Python&#xff0c;咳咳。在这里使用的python安装包是anaconda2&#xff0c;注意使用Python2.7版本的那个安装包。 官网地址&#xff1a;https://www.continuum.io/downloads …

判别模型的玻尔兹曼机论文源码解读

前言 三号要去参加CAD/CG会议&#xff0c;投了一篇关于使用生成模型和判别模型的RBM做运动捕捉数据风格识别的论文。这段时间一直搞卷积RBM了&#xff0c;差点把原来的实验内容都忘记了&#xff0c;这里复习一下判别式玻尔兹曼机的训练流程。 国际惯例&#xff0c;贴几个链接…

Jacobian矩阵和Hessian矩阵

原文转自&#xff1a;http://jacoxu.com/?p146 1. Jacobian 在向量分析中, 雅可比矩阵是一阶偏导数以一定方式排列成的矩阵, 其行列式称为雅可比行列式. 还有, 在代数几何中, 代数曲线的雅可比量表示雅可比簇&#xff1a;伴随该曲线的一个代数群, 曲线可以嵌入其中. 它们全部都…

为什么梯度下降法对于非线性可分数据有效

前言 晚上逛微博看到的&#xff0c;顺便拿过来翻译一下&#xff0c;做做笔记 国际惯例&#xff0c;来个原文链接&#xff1a; 原文地址&#xff1a;Why is gradient descent robust to non-linearly separable data? PDF拷贝&#xff1a;http://download.csdn.net/detail/…

卷积RBM源码解读

前言 卷积RBM相对RBM来说具有很多优势&#xff0c;详细的我也不说了&#xff0c;看文章就行。主要还是为了加深自己对细节部分的理解吧。 国际惯例&#xff0c;贴几个链接 卷积RBM的创始人Honglak Lee&#xff1a;http://web.eecs.umich.edu/~honglak/hl_publications.html#…

c语言:递归法求n的阶乘|练习题

一、题目 输入一个数n&#xff0c;用递归法求n的阶乘 二、思路分析 1、因为n!(n-1)!*n,所以&#xff0c;可以选择用递归法 三、代码截图【带注释】 四、源代码【带注释】 #include <stdio.h> //思路&#xff1a; //因为n!(n-1)!*n,所以&#xff0c;可以选择用递归法 int…

【caffe-Windows】cifar实例编译之model的生成

参考&#xff1a;<span style"font-family: Arial, Helvetica, sans-serif;">http://blog.csdn.net/chengzhongxuyou/article/details/50715455</span> 准备工作 按照之前的教程&#xff0c;成功生成过caffe&#xff0c;并且编译整个caffe.sln项目工程&a…

机器学习性能改善备忘单:32个帮你做出更好预测模型的技巧和窍门

文章来源&#xff1a;大数据文摘 作者 | Jason Brownlee 选文 | Aileen 翻译 | 姜范波 校对 | 寒小阳 机器学习最有价值(实际应用最广)的部分是预测性建模。也就是在历史数据上进行训练&#xff0c;在新数据上做出预测。 而预测性建模的首要问题是&#xff1a; 如何才能得…

【caffe-Windows】新层添加——LSTM

前言 原始的【caffe-Windows】是没有LSTM层的&#xff0c;维护以后的caffe的windows版本也懒得配置了&#xff0c;因为大部分文章的代码还是基于老版caffe。其实大部分的添加层方法都可以参考本博客&#xff0c;仅限Windows。 需要的文件有&#xff1a; 1. 原始的caffe-Wind…

【caffe-Windows】关于LSTM的使用-coco数据集

前言 建议大家使用Linux&#xff0c;因为Linux下的配置就没这么麻烦&#xff0c;各种make就行啦。Linux用户请绕道&#xff0c;因为此博客只针对Windows&#xff0c;可能比Linux麻烦很多倍。 在caffe-Windows新增LSTM层以后&#xff0c;相信很多人和我一样很好奇如何使用这一…

【caffe-Windows】关于LSTM的简单小例子

前言 这里主要是看到了一个简单的LSTM例子&#xff0c;比上一个coco简单很多&#xff0c;所以在这里记录一下&#xff0c;便于后续的分析&#xff0c;参考博客在上一篇文章的末尾提到过&#xff1a;Recurrent neural nets with Caffe 需要说明的是这个例子也并非原原本本的使…

概率有向图模型

1. 前言 主要参考书籍《深度学习导论及案例分析》、维基百科“贝叶斯网络”、老笨妞的博客、PRML中文翻译&#xff0c;重点还是概念的掌握和几个小理论的推导&#xff0c;比较枯燥。加入了自己的一些简单理解。 个人感觉概率有向图模型最大的意义在于&#xff1a;一个特定的有…

概率无向图模型

1. 前言 前面看了概率有向图模型&#xff0c;必然对无向图模型也要研究一下。而且这个概率无向图模型对学习RBM有很大的帮助&#xff0c;它关系到能量函数的来源&#xff0c;所以还是看看吧。参考资料依旧是概率有向图模型中参考的三个资料。 有向图将一组变量上的联合概率分…