CvSVM回归仅预测整数

时间:2014-07-17 22:21:36

标签: c++ opencv svm libsvm

我试图通过使用this手工标记的590张图像数据库来熟悉CvSVM,这些图像从0-5开始分级(0是模糊的,5是完美的)。如果等级<3,则将其标记为0(模糊),如果&gt; = 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.无小数。

任何人都可以弄清楚我做错了什么吗?

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

问题在于我将所有测试功能一次性传递给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单独预测测试样本解决了我的问题。