词袋未正确标记响应
Posted
技术标签:
【中文标题】词袋未正确标记响应【英文标题】:Bag of words not correctly labeling responses 【发布时间】:2014-01-12 23:13:57 【问题描述】:我正在尝试在 opencv 中实现 Bag of Words 并附带以下实现。我正在使用Caltech 101 database。但是,由于我是第一次并且不熟悉,因此我计划使用数据库中的两个图像集,椅子图像集和足球图像集。我已经使用 this 为 svm 编码。
一切都很顺利,除了当我调用 classifier.predict(descriptor)
时,我没有按预期获得标签 vale。 无论我的测试图像如何,我总是得到0
而不是“1”。椅子数据集中的图像数量为10
,足球数据集中的图像数量为10
。我将椅子标记为0
,将足球标记为1
。链接代表每个类别的样本,前 10 位是椅子,后 10 位是足球
function hello
clear all; close all; clc;
detector = cv.FeatureDetector('SURF');
extractor = cv.DescriptorExtractor('SURF');
links =
'http://i.imgur.com/48nMezh.jpg'
'http://i.imgur.com/RrZ1i52.jpg'
'http://i.imgur.com/ZI0N3vr.jpg'
'http://i.imgur.com/b6lY0bJ.jpg'
'http://i.imgur.com/Vs4TYPm.jpg'
'http://i.imgur.com/GtcwRWY.jpg'
'http://i.imgur.com/BGW1rqS.jpg'
'http://i.imgur.com/jI9UFn8.jpg'
'http://i.imgur.com/W1afQ2O.jpg'
'http://i.imgur.com/PyX3adM.jpg'
'http://i.imgur.com/U2g4kW5.jpg'
'http://i.imgur.com/M8ZMBJ4.jpg'
'http://i.imgur.com/CinqIWI.jpg'
'http://i.imgur.com/QtgsblB.jpg'
'http://i.imgur.com/SZX13Im.jpg'
'http://i.imgur.com/7zVErXU.jpg'
'http://i.imgur.com/uUMGw9i.jpg'
'http://i.imgur.com/qYSkqEg.jpg'
'http://i.imgur.com/sAj3pib.jpg'
'http://i.imgur.com/DMPsKfo.jpg'
;
N = numel(links);
trainer = cv.BOWKMeansTrainer(100);
train = struct('val',repmat(' ',N,1),'img',cell(N,1), 'pts',cell(N,1), 'feat',cell(N,1));
for i=1:N
train(i).val = linksi;
train(i).img = imread(linksi);
if ndims(train(i).img > 2)
train(i).img = rgb2gray(train(i).img);
end;
train(i).pts = detector.detect(train(i).img);
train(i).feat = extractor.compute(train(i).img,train(i).pts);
end;
for i=1:N
trainer.add(train(i).feat);
end;
dictionary = trainer.cluster();
extractor = cv.BOWImgDescriptorExtractor('SURF','BruteForce');
extractor.setVocabulary(dictionary);
for i=1:N
desc(i,:) = extractor.compute(train(i).img,train(i).pts);
end;
a = zeros(1,10)';
b = ones(1,10)';
labels = [a;b];
classifier = cv.SVM;
classifier.train(desc,labels);
test_im =rgb2gray(imread('D:\ball1.jpg'));
test_pts = detector.detect(test_im);
test_feat = extractor.compute(test_im,test_pts);
val = classifier.predict(test_feat);
disp('Value is: ')
disp(val)
end
这些是我的测试样本:
Soccer Ball
(来源:timeslive.co.za)
Chair
通过这个网站搜索,我认为我的算法还可以,尽管我对此不太有信心。如果有人可以帮助我找到错误,那将是可观的。
按照 Amro 的代码,这是我的结果:
Distribution of classes:
Value Count Percent
1 62 49.21%
2 64 50.79%
Number of training instances = 61
Number of testing instances = 65
Number of keypoints detected = 38845
Codebook size = 100
SVM model parameters:
svm_type: 'C_SVC'
kernel_type: 'RBF'
degree: 0
gamma: 0.5063
coef0: 0
C: 62.5000
nu: 0
p: 0
class_weights: 0
term_crit: [1x1 struct]
Confusion matrix:
ans =
29 1
1 34
Accuracy = 96.92 %
【问题讨论】:
【参考方案1】:我觉得你的逻辑很好。
现在我想如果你想提高分类准确度,你必须调整各种参数。这包括clustering algorithm 参数(例如词汇表大小、集群初始化、终止标准等)、SVM 参数(内核类型、C
系数……)、使用的局部特征算法(SIFT、冲浪,..)。
理想情况下,每当您要执行参数选择时,都应该使用cross-validation。一些方法已经嵌入了这种机制(例如CvSVM::train_auto
),但在大多数情况下,您必须手动执行此操作...
最后,您应该遵循一般机器学习指南;看到整个bias-variance tradeoffdilemma。在线Coursera ML class 在第 6 周详细讨论了这个话题,并解释了如何进行错误分析和使用学习曲线来决定下一步要尝试什么(我们是否需要添加更多实例,增加模型复杂度等等..) .
话虽如此,我编写了自己的代码版本。您可能想将其与您的代码进行比较:
% dataset of images
% I previously saved them as: chair1.jpg, ..., ball1.jpg, ball2.jpg, ...
d = [
dir(fullfile('images','chair*.jpg')) ;
dir(fullfile('images','ball*.jpg'))
];
% local-features algorithm used
detector = cv.FeatureDetector('SURF');
extractor = cv.DescriptorExtractor('SURF');
% extract local features from images
t = struct();
for i=1:numel(d)
% load image as grayscale
img = imread(fullfile('images', d(i).name));
if ~ismatrix(img), img = rgb2gray(img); end
% extract local features
pts = detector.detect(img);
feat = extractor.compute(img, pts);
% store along with class label
t(i).img = img;
t(i).class = find(strncmp(d(i).name,'chair','ball',4));
t(i).pts = pts;
t(i).feat = feat;
end
% split into training/testing sets
% (a better way would be to use cvpartition from Statistics toolbox)
disp('Distribution of classes:')
tabulate([t.class])
tTrain = t([1:7 11:17]);
tTest = t([8:10 18:20]);
fprintf('Number of training instances = %d\n', numel(tTrain));
fprintf('Number of testing instances = %d\n', numel(tTest));
% build visual vocabulary (by clustering training descriptors)
K = 100;
bowTrainer = cv.BOWKMeansTrainer(K, 'Attempts',5, 'Initialization','PP');
clust = bowTrainer.cluster(vertcat(tTrain.feat));
fprintf('Number of keypoints detected = %d\n', numel([tTrain.pts]));
fprintf('Codebook size = %d\n', K);
% compute histograms of visual words for each training image
bowExtractor = cv.BOWImgDescriptorExtractor('SURF', 'BruteForce');
bowExtractor.setVocabulary(clust);
M = zeros(numel(tTrain), K);
for i=1:numel(tTrain)
M(i,:) = bowExtractor.compute(tTrain(i).img, tTrain(i).pts);
end
labels = vertcat(tTrain.class);
% train an SVM model (perform paramter selection using cross-validation)
svm = cv.SVM();
svm.train_auto(M, labels, 'SvmType','C_SVC', 'KernelType','RBF');
disp('SVM model parameters:'); disp(svm.Params)
% evaluate classifier using testing images
actual = vertcat(tTest.class);
pred = zeros(size(actual));
for i=1:numel(tTest)
descs = bowExtractor.compute(tTest(i).img, tTest(i).pts);
pred(i) = svm.predict(descs);
end
% report performance
disp('Confusion matrix:')
confusionmat(actual, pred)
fprintf('Accuracy = %.2f %%\n', 100*nnz(pred==actual)./numel(pred));
这是输出:
Distribution of classes:
Value Count Percent
1 10 50.00%
2 10 50.00%
Number of training instances = 14
Number of testing instances = 6
Number of keypoints detected = 6300
Codebook size = 100
SVM model parameters:
svm_type: 'C_SVC'
kernel_type: 'RBF'
degree: 0
gamma: 0.5063
coef0: 0
C: 312.5000
nu: 0
p: 0
class_weights: []
term_crit: [1x1 struct]
Confusion matrix:
ans =
3 0
1 2
Accuracy = 83.33 %
因此,分类器正确标记了测试集中 6 张图像中的 5 张,这对于开始来说还不错 :) 显然,由于聚类步骤的固有随机性,每次运行代码时都会得到不同的结果。
【讨论】:
奇怪,谢谢...我不知道你是怎么知道这么多的,真的很可观。这真的是题外话,你所有的专业知识都是来自你的大学还是来自工作?或两者。任何你建议在 CS 方面提高自己的东西。 @whoknows:你会惊讶于在 Stack Overflow 上闲逛可以学到很多东西 :) 我对结果感到非常惊讶。 @whoknows:97%的准确率确实是一个不错的结果!我认为是 SVM“自动训练”为您完成了它(即执行交叉验证以选择 SVM 参数).. @whoknows:我还没有研究过这个,但是快速搜索表明 BOW+ORB 组合存在潜在问题(除了你说的 SIFT 或 SURF 之外的任何东西):@ 987654327@, answers.opencv.org/question/24835/… ...【参考方案2】:您用来构建字典的图像数量是多少,即 N 是多少?从您的代码来看,您似乎只使用了 10 张图片(链接中列出的图片)。我希望这个列表在这篇文章中被截断,否则太少了。通常,您需要大约 1000 个或更多图像来构建字典,并且图像不必仅限于您正在分类的这 2 个类。否则,只有 10 个图像和 100 个聚类,您的字典很可能会搞砸。
此外,您可能希望将 SIFT 作为首选,因为它往往比其他描述符表现更好。
最后,您还可以通过检查检测到的关键点进行调试。你可以让 OpenCV 来绘制关键点。有时您的关键点检测器参数设置不正确,导致检测到的关键点太少,进而导致特征向量不佳。
要了解有关 BOW 算法的更多信息,您可以查看这些帖子 here 和 here。第二篇文章有一个免费 pdf 的链接,该链接是 O'Reilley 关于使用 python 进行计算机视觉的书。 BOW 模型(和其他有用的东西)在该书中有更详细的描述。
希望这会有所帮助。
【讨论】:
我的算法好吗。我对用于词袋的一般算法有点模糊。另外我应该使用多少个类,这需要很长时间,所以一个大概的猜测。我应该包括所有的训练样本吗? @whoknows 我添加了指向我过去在 BOW 模型上给出的一些答案的链接。您可能会发现其中的解释有助于理解其工作原理。此外,其中一篇文章包含指向一本有用书籍的链接(带有 Python 代码),其中包含有关如何编写 BOW 模型的详细信息。您可能会发现它们很有用。在单独的说明中,如果您发布的内容正是您正在运行的内容,那么它看起来是错误的。一方面,您需要从 1000 张图像中提取描述符来构建您的字典。字典的大小通常通过交叉验证来决定(即反复试验+绘图结果)以上是关于词袋未正确标记响应的主要内容,如果未能解决你的问题,请参考以下文章