CvSVM 回归只预测整数

Posted

技术标签:

【中文标题】CvSVM 回归只预测整数【英文标题】:CvSVM regression only predicts integers 【发布时间】:2014-09-08 23:18:57 【问题描述】:

我正在尝试使用 this 手动标记的数据库来熟悉 CvSVM,该数据库包含 590 张图像,从 0-5 分级(0 表示模糊,5 表示完美)。如果等级 =3,我将其标记为 1(清晰)。

对于功能,我只是使用五种不同的通用指标进行模糊评估。每个都通过它们在训练数据中的均值和标准差进行标准化。同样的训练均值和标准差也用于标准化测试数据。

出于某种原因,我的 SVM 只能预测整数。我已经检查了 int casts 和其他愚蠢的错误,但无法弄清楚。我意识到我的特征可能不是很健壮,因为不同图像之间存在很大差异(标准化不是很有帮助,因为标准化测试特征的范围最终大于训练特征的范围),但仍然我觉得我应该得到一些小数预测,即使它们不准确。

培训:

// data format is [ img1 grade feature1 feature2 ... feature5, img2... ]
void train_svm(CvSVM& svm, const Mat& data)

    CvSVMParams params;
    params.svm_type         = CvSVM::EPS_SVR;
    params.kernel_type      = CvSVM::RBF;
    params.term_crit        = cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, (int)1e8, FLT_EPSILON);

    CvParamGrid Cgrid(.01, 100, exp(1));
    CvParamGrid gammaGrid(.01, 10, exp(.05));
    CvParamGrid pGrid(.01, 1.8, exp(.01));

    params.C        = Cgrid.min_val;
    params.gamma    = gammaGrid.min_val;
    params.p        = pGrid.min_val;

    // split features from grades
    Mat features  = data.colRange(2, data.cols);
    Mat grades    = data.colRange(1, 2);

    try
    
        svm.train_auto(features, grades, Mat(), Mat(), params, 10,
                       Cgrid,
                       gammaGrid,
                       pGrid,
                       CvSVM::get_default_grid(CvSVM::NU),
                       CvSVM::get_default_grid(CvSVM::COEF),
                       CvSVM::get_default_grid(CvSVM::DEGREE),
                       false);
    
    catch (Exception e)
    
        params = svm.get_params();
        qDebug() << params.C << params.gamma << params.p;
    
    params = svm.get_params();

    svm.train(features, grades, Mat(), Mat(), params);

测试:

void test_svm(const CvSVM& svm, const Mat& data)

    Mat features = data.colRange(2, data.cols);
    Mat grades   = data.colRange(1, 2);

    int num_test = features.rows;
    assert(features.rows == grades.rows);

    Mat results(num_test, 1, CV_32FC1);

    svm.predict(features, results);
    qDebug() << "Act\t\tPred";
    for (int i = 0; i < num_test; i++)
    
        float actual = grades.at<float>(i, 0);
        float predicted = results.at<float>(i, 0);
        qDebug() << actual << "\t" << predicted;
    

预测总是 0 或 1。没有小数。

谁能弄清楚我做错了什么?

【问题讨论】:

【参考方案1】:

我认为您将分类 (n>=2) 与回归 (n=2) 混合在一起。基本的 SVM 计算单个超平面来分隔 2 个类。有 2 种概括:要么计算所有类之间的多个超平面(n>2 分类),要么如果你有一个超平面,你可以确定一个新点与该超平面的距离。

但假设您在类 1 和 3 之间有一个超平面,并且有一个点落在边界上。您不能只预测第 2 类,因为它位于第 1 类和第 3 类的边界上。

【讨论】:

好的,假设我通过将所有标签 =3 设置为 1 将标签映射到 n=2 空间。我现在是否能够确定一个新点与 -1 和 1 之间的超平面的距离有多近? @mavirick:是的,就是这样。实际上,您只有两个类,blurry=0 和 sharp=1,并且您想在两者之间进行回归。 如果我这样做,映射到 blurry=0 和 sharp=1,我仍然只能得到整数作为输出——现在只有 0 或 1。 那是因为您需要将returnDFVal参数设置为true,而predict的向量变体缺少该参数。【参考方案2】:

像往常一样,答案很简单,我很尴尬。

问题是我一次性将所有测试特征传递给 CvSVM,它对每个样本进行严格分类——因此是整数。来自 CvSVM 文档:

C++: float CvSVM::predict(const CvMat* samples, CvMat* results) const

但是,当单独测试样本时,可以选择将结果作为距边距的距离,即我正在寻找的浮点数:

C++: float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const

正如文档清楚地解释的那样:

returnDFVal – 指定返回值的类型。如果为 true 并且问题是 2 类分类,则该方法返回决策函数值,即到边缘的有符号距离,否则该函数返回类标签(分类)或估计的函数值(回归)。

使用 returnDFVal=true 单独预测测试样本解决了我的问题。

【讨论】:

以上是关于CvSVM 回归只预测整数的主要内容,如果未能解决你的问题,请参考以下文章

回归预测基于matlab麻雀搜索算法优化SVM回归预测含Matlab源码 1625期

predict_proba() 预测单个值时的逻辑回归

回归预测基于matlab麻雀搜索算法优化CNN回归预测含Matlab源码 JQ002期

线性回归案例:波士顿房价预测

回归预测基于matlab麻雀算法优化相关向量机RVM回归预测含Matlab源码 J001期

OPencv SVM 预测概率