将 LibSVM 输出转换为浮点向量
Posted
技术标签:
【中文标题】将 LibSVM 输出转换为浮点向量【英文标题】:Convert LibSVM output to vector of floats 【发布时间】:2013-10-06 00:33:33 【问题描述】:我需要形成HOGDescriptor::setSVMDetector()
输入。
我使用 openCV 计算描述符,然后使用 libSVM 获取模型文件。 要形成输入,我知道我需要获取支持向量的值并使用 alpha 对它们进行元素 mul(然后在末尾添加 -rho),但是 我不知道从哪里获得这些 alpha。
我有一个 SV 列表,例如:
1 1:-0.0434783 2:0.153846 3:0.194444 4:-0.353712 5:-0.45054
1 1:-0.2173916 2:-0.38461 3:0.222262 4:-0.676686 5:-0.78062
但是从哪里获得 alphas?
【问题讨论】:
【参考方案1】:好的,现在事情似乎很清楚了。 在我的例子中,Alpha 是第一列。 由于在我的测试模型中它们都等于 -1 或 1(不知道为什么),我认为这些是标签。
无论如何,这是我的解析器(但您只需要在文件中保留 SV):
std::ifstream ifs("cars_model.model");
const int nsv = 90;
const int nfeatures = 144;
float rho = 12.5459;
char ts[4000] = ""; // !
std::vector<float> res(nfeatures,0);
std::vector<float> alphas;
Mat_<float> temp(nsv, nfeatures);
int c = 0;
std::cout << "Loading model file...\n";
for (int i=0; i<nsv; i++)
float al = 0;
ifs >> al;
alphas.push_back(al);
for (int j=0; j<nfeatures; j++)
float ind, s;
char junk;
ifs >> ind >> junk >> s;
temp.at<float>(c, j) = s;
//std::cout << f << ' ' << s << '\n';
c++;
ifs.close();
std::cout << "Computing primal form...\n";
for (int i=0; i<nsv; i++)
float alpha = alphas[i];
for (int j=0; j<nfeatures; j++)
res[j] += (temp.at<float>(i,j) * alpha);
//res.push_back(-rho);
std::ofstream ofs("primal.txt");
for (int i=0; i<res.size(); i++)
ofs << res[i] << ' ';
ofs.close();
你知道,它有效。您可以将 rho 设置为检测器的阈值。
【讨论】:
【参考方案2】:但是为什么要“手动”分类呢? OpenCv has a classification routine 调用 predict
,它使用找到的 SVs' 和 alphas'
float response = SVM.predict(sampleMat);
如果你真的想自己做,你不仅需要 SV 和 alpha,还需要一个用于训练和计算的核函数
SUM alpha_i K( support_vector_i , data_point ) - rho
我不确定是否可以在不扩展 SVM 类的情况下“手动”提取 alpha,正如在 sources 中看到的那样 - alpha 存储在 CvSVMDecisionFunc
结构中:
struct CvSVMDecisionFunc
double rho;
int sv_count;
double* alpha;
int* sv_index;
;
而对这个结构的唯一引用是在protected
部分:
protected:
(...)
CvSVMDecisionFunc* decision_func;
从svm.cpp
的源代码我们可以发现,它只能通过save
例程公开访问。所以一些“hack”是保存模型并从那里提取 alpha(它将位于“决策函数”部分,以人类可读的格式编写)。
最简单的提取技术似乎扩展CvSVM
类并包含类似方法
public:
CvSVMDecisionFunc* get_decision_function() return decision_func;
更新
经过澄清,OP 实际上是在尝试在 opencv 中使用外部训练模型 - 最简单的方法是将由其他方法(libsvm、linearsvm 等)创建的 libsvm 模型转换为 opencv 兼容格式并使用read
加载它方法
void CvSVM::read( CvFileStorage* fs, CvFileNode* svm_node )
see source for more details.
【讨论】:
据我了解,您可以使用 .predict(),但您必须为它提供一个已经计算的 HOG,以获得与您训练 CvSVM 的完全相同大小的图像,这很不方便。如果您想使用扫描给定图像并返回一个点数组的例程,并在其中找到答案,您应该使用 .detectMultiScale()。 我不太明白你的评论。 SVM 将总是要求与训练中使用的输入大小完全相同。不管你是提取 alpha 还是使用 predict 方法,它的工作方式都是一样的。 好吧,首先,我决定不使用openCV进行训练,因为我查了很多资料,有人说最好使用svmlight或libsvm,所以我不能使用CvSVMDecisionFunc。我要谈论的第二件事是,detectMultiScale() 获取任意大小的图像,并为您完成所有工作,在图像的每个点计算 HOG,并返回匹配点。我说的对吗? 因此您可以简单地将使用 libsvm 或 svmlight 训练的 SVM 模型转换为 opencv 可以使用read
方法读取的格式。虽然有人可以说,它的训练过程有些故障(?)分类过程是正确实现的,所以只需从外部源加载模型并使用 CvSVM 对象作为你的 detectMultiScale() 的检测器。
哦,谢谢,我不知道 .read()。顺便说一句,我现在弄清楚了一些事情,所以我将发布我的解析器代码,并尝试您的方法,然后比较结果。以上是关于将 LibSVM 输出转换为浮点向量的主要内容,如果未能解决你的问题,请参考以下文章