CvSVM回归只能预测整数

CvSVM regression only predicts integers

本文关键字:整数 回归 CvSVM      更新时间:2023-10-16

我试图通过使用这个手工标记的590张图像数据库来熟悉CvSVM,这些图像从0-5分级(0是模糊的,5是完美的)。如果一个等级是<3,我标记为0(模糊),如果>=3,我标记为1(清晰)。

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

由于某种原因,我的SVM只能预测整数。我检查了int类型转换和其他愚蠢的错误,但无法找出它。我意识到我的特征可能不是很健壮,因为不同图像之间有太多的差异(标准化不是很有帮助,因为标准化测试特征的范围最终比训练特征的范围更大),但我仍然觉得我应该得到一些十进制的预测,即使它们是不准确的。

培训:

// 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() << "ActttPred";
    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。没有小数。

有谁能指出我做错了什么吗?

我认为你把分类(n>=2)和回归(n=2)混在一起了。基本支持向量机计算一个超平面来分离两个类。有两种推广:要么你计算所有类之间的多个超平面(n>2分类),要么如果你有一个超平面,你可以确定一个新点离那个超平面有多近。

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

和往常一样,答案如此简单,我感到很尴尬。

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

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

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

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

文档清楚地解释:

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

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