将 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 输出转换为浮点向量的主要内容,如果未能解决你的问题,请参考以下文章

关于 model.SVs 的 LIBSVM 输出

使用 LibSVM 进行分类

单片机C语言中如何将浮点型变量转换成字符串输出

将浮点向量转换为 16 位 int 而不饱和

SSE中的浮点到uchar转换问题

基于Libsvm的图像分类