目录
1、官网地址:https://www.vlfeat.org/matconvnet/
1、官网地址:https://www.vlfeat.org/matconvnet/
2、配置MatConvNet
PS:这一步完成才能进行下一步
3、提取fc6层特征
oxford5K数据集:http://www.robots.ox.ac.uk/~vgg/data/oxbuildings/
paris6k数据集:http://www.robots.ox.ac.uk/~vgg/data/parisbuildings/
数据集存放地址代码里有体现,可以根据自己的情况修改!
为什么选择fc6层?
答:没有任何原因,哪一层都可以;但是卷积层会比全连接层的效果要好;微调之后的性能也会有所提升!或者进行特征互补!
参考博客:layer选择与fine-tuning性能提升验证
参考论文:Exploiting the complementary strengths of multi-layer CNN features for image retrieval
run matlab/vl_setupnn;
addpath('./data/datasets/paris6k/');
model = 'imagenet-vgg-verydeep-16.mat';
% fc6层
layers = 32;
max_img_dim = 1024;
baseDir = './data/';
net = load(model);
net.layers = {net.layers{1:layers}};
im_folder_oxford = [baseDir,'datasets/paris6k/'];
oxford_gnd = [im_folder_oxford,'gnd_paris6k.mat'];
gnd_oxford = load(oxford_gnd);
% query
Q = [];
% database
X = [];
fprintf('Extracting database features\n');
for i=1:length(gnd_oxford.imlist)
I = imread([im_folder_oxford, gnd_oxford.imlist{i},'.jpg']);
% 缩放
im_ = imresize(single(I),net.meta.normalization.imageSize(1:2));
% 减去均值
im_ = im_ - net.meta.normalization.averageImage;
res = vl_simplenn(net,im_);
feature = res(layers).x;
% 提取卷积层的特征
% x = res(layers).x;
% % 提取的是卷积层特征:原始的是:[14*14*512]
% feature = squeeze(mean(x,[1,2]));
X(i,:) = feature(:);
if mod(i,100) == 0
i
end
end
fprintf('extracting the query image\n');
qimlist = {gnd_oxford.imlist{gnd_oxford.qidx}};
for i=1:length(qimlist)
I = imread([im_folder_oxford, qimlist{i}, '.jpg']);
% 缩放
im_ = imresize(single(I),net.meta.normalization.imageSize(1:2));
% 减去均值
im_ = im_ - net.meta.normalization.averageImage;
res = vl_simplenn(net,im_);
fea = res(layers).x;
% 提取卷积层的特征
% x = res(layers).x;
% fea = squeeze(mean(x,[1,2]));
Q(i,:) = fea(:);
disp(i);
end
save('./data/features/paris6k.mat',"Q","X");
4、计算mAP
官方提供的计算方法:http://www.robots.ox.ac.uk/~vgg/data/oxbuildings/
官方是C++,这里用matlab实现:参考:https://github.com/Relja/netvlad
function [map,aps] = mAP(ranks,gnd,verbose)
% usage; map = mAP(ranks,gnd)
% ranks:1->size(ranks)=db_size
if nargin < 3
verbose = false;
end
map = 0;
nq = numel(gnd);
aps = zeros(nq,1);
for i = 1:nq
qgnd = gnd(i).ok;
if isfield (gnd(i), 'junk')
qgndj = gnd(i).junk;
else
qgndj = [];
end
% positions of positive and junk images
[~, pos] = intersect (ranks (:,i), qgnd);
[~, junk] = intersect (ranks (:,i), qgndj);
pos = sort(pos);
junk = sort(junk);
k = 0;
ij = 1;
if ~isempty (junk)
% decrease positions of positives based on the number of junk images appearing before them
ip = 1;
while ip <= numel (pos)
while ( ij <= length (junk) && pos (ip) > junk (ij) )
k = k + 1;
ij = ij + 1;
end
pos (ip) = pos (ip) - k;
ip = ip + 1;
end
end
ap = score_ap_from_ranks1 (pos, length (qgnd));
if verbose
fprintf ('query no %d -> gnd = ', i);
fprintf ('%d ', qgnd);
fprintf ('\n tp ranks = ');
fprintf ('%d ', pos);
fprintf (' -> ap=%.3f\n', ap);
end
map = map + ap;
aps (i) = ap;
end
map = map / nq;
end
% This function computes the AP for a query
function ap = score_ap_from_ranks1 (ranks, nres)
% number of images ranked by the system
nimgranks = length (ranks);
ranks = ranks - 1;
% accumulate trapezoids in PR-plot
ap = 0;
recall_step = 1 / nres;
for j = 1:nimgranks
rank = ranks(j);
if rank == 0
precision_0 = 1.0;
else
precision_0 = (j - 1) / rank;
end
precision_1 = j / (rank + 1);
ap = ap + (precision_0 + precision_1) * recall_step / 2;
end
end
5、evaluate:
% oxford5k:fc6层特征:0.3265
% load('./data/features/oxford5k.mat');
% paris6k:fc6层特征:
load('./data/features/paris6k.mat');
fprintf(">>Starting retrieval!!!");
% 使用内积
sim = X*Q';
[sim,ranks] = sort(sim,'descend');
map = mAP(ranks,gnd_oxford.gnd);
fprintf("map=%.4f",map);
map=0.4421
注:如有疑问,麻烦指出,谢谢!