OpenCV SVM总是预测更高级别的标签 [英] OpenCV SVM always predicts higher class label

查看:93
本文介绍了OpenCV SVM总是预测更高级别的标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用OpenCV SVM实现来二进制预测图像功能的重要性.因此,我正在针对正负图像特征对其进行训练,并在{0,1}中寻找分类.

I'm using the OpenCV SVM implementation to binarily predict the importance of an image feature. I'm therefore training it upon positive and negative image features and looking for a classification in {0,1}.

我遇到的问题是,在接受培训之后,SVM总是以更高/更大的班级标签来预测班级.我可以更改训练数据集的标签,但此问题仍然存在.我已经仔细检查了生成的标签和训练cv :: Mat矩阵,但没有发现任何问题.

The problem I'm encountering is that following training, the SVM always predicts the class with the higher/greater class label. I can change the labels for the training data set and this problem persists. I've carefully inspected the generated label and training cv::Mat matrices and haven't found any issues there.

下面是我的SVM类和随附的SVM参数

Below is my SVM class and accompanying SVM parameters

//Populate the SVM parameters
void SVM::setSVMParams()
{
    params.svm_type = cv::SVM::C_SVC;
    params.kernel_type = cv::SVM::RBF;
    params.term_crit = cv::TermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

    params_set = true;
}

//Train the SVM with the given data
void SVM::train(cv::Mat train_data, cv::Mat labels)
{
    //Set the SVM parameters if they haven't been already
    if (!params_set)
    {
        setSVMParams();
    }

    svm.train(train_data, labels, cv::Mat(), cv::Mat(), params);
}

//Based on training, predict the class of the given data
float SVM::predict(cv::Mat sample)
{
    return svm.predict(sample, false);
}

这是负责生成训练数据和相应标签的功能

And here is the function responsible for generating the training data and respective labels

//Creates the appropriate training data and class labels for subsequent SVM training according to supplied D threshold
void Matchings::createSVMTrainingObjects(const float t_D, const float positive_label, const float negative_label, bool print_info)
{
    cv::Mat train_data_l((int)matchings_list.size(), 132, CV_32FC1);
    cv::Mat labels_l((int)matchings_list.size(), 1, CV_32FC1);

    int num_pos = 0;
    int num_neg = 0;

    for (int i = 0; i < matchings_list.size(); i++)
    {
        matching_d entry = matchings_list[i];

        //Important feature, label 1
        if (entry.D > t_D)
        {
            labels_l.at<float>(i) = positive_label;

            num_pos++;
        }
        //Unimportant feature, label -1
        else
        {
            labels_l.at<float>(i) = negative_label;

            num_neg++;
        }

        int j = 0;

        //Copy feature into current row of openCV matrix
        train_data_l.at<float>(i, j++) = entry.feature.x;
        train_data_l.at<float>(i, j++) = entry.feature.y;
        train_data_l.at<float>(i, j++) = entry.feature.scale;
        train_data_l.at<float>(i, j++) = entry.feature.angle;
        for (int k = 0; k < 128; k++)
        {
            train_data_l.at<float>(i, j + k) = entry.feature.vec[k];
        }
    }

    std::cout << "For training: #+ves=" << num_pos << ", #-ves=" << num_neg << std::endl;

    train_data = train_data_l;
    labels = labels_l;
}

最后,这是实际调用SVM预测结果以保留重要图像特征的功能

And finally, here is the function that actually calls upon SVM prediction results for retaining important image features

matchingslist ASIFT::filterFeaturesWithSVM(matchingslist matchings, SVM& svm)
{
    matchingslist new_matchings;

    for (int i = 0; i < (int)matchings.size(); i++)
    {
        cv::Mat first = Utility::keypointToMat(matchings[i].first);
        cv::Mat second = Utility::keypointToMat(matchings[i].second);

        //If both features are of importance, retain them
        if (svm.predict(first) == 1.0f && svm.predict(second) == 1.0f)
        {
            new_matchings.push_back(matchings[i]);
        }
        else
        {
            std::cout << "Feature removed" << std::endl;
        }
    }

    return new_matchings;
}

推荐答案

该方法的一个主要问题是,当您使用RBF时,您没有设置SVM的超参数,因此C=1gamma=1/d(或1/mean ||x||^2),因为这些是大多数SVM实现中的默认值.

One main problem with the approach is that you do not set hyperparemeters of your SVM, while you use RBF, so probably C=1 and gamma=1/d (or 1/mean ||x||^2) as these are default values in most implementations of SVM.

尽管这些对于构建有效模型至关重要.特别是,如果您的C值太低(1可能取决于数据的许多特征),那么SVM只需总是预测其中一个类即可构建一个简单的模型.

While these are critical to build a valid model. In particular, if your C value is too low (1 might be, depends on many features of data) then SVM builds a trivial model simply always predicting one of the classes.

您应该怎么做?您应该检查Cgamma的多个值.这些参数的含义是什么?

What you should do? You should check multiple values of both C and gamma. What are the meanings of these parameters?

  • C(您的1)是错误分类的权重-C越大,SVM将更努力地尝试准确地学习训练数据,可能以过度拟合为代价.
  • gamma(您的默认设置)是RBF内核2倍方差的倒数.换句话说,伽玛值越大,高斯值越小,因此-您的方法在几何意义上更局部".再次-大伽玛可以帮助您最大程度地减少训练误差(偏差),但会导致更高的测试误差(方差).
  • C (your 1) is a weight of missclassification - greater the C, SVM will try harder to learn training data exactly, possibly at the cost of overfitting.
  • gamma (your default) is the inverse of the 2 times variance of your RBF kernel. In other words - greater the gamma, smaller the Gaussians, and thus - your method is more "local" in the geometrical sense. Again - big gamma helps you minimize the training error (bias) but leads to higher testing error (variance).

正确选择方差偏置之间的折衷是机器学习技术的关键要素.如果是RBF SVM,则可以通过上述方法进行控制.和他们一起玩,检查训练集错误和测试集错误,以查看发生了什么.如果您的训练集误差很大,请增加C和/或Gamma.一旦训练集错误成立,请查看测试集-如果太大,请尝试减小值,依此类推.通常通过内部交叉验证以及参数表的网格搜索以自动方式完成.

Correct selection of the tradeoff between variance-bias is crucial element of machine learning techniques. In case of RBF SVM - you can control it through the above. Play around with them, check both training set error and testing set error to see what is happening. If your training set error is big - increase C and/or gamma. Once your training set error is fine, look at the testing set - if it is too big - try to decrese values and so on. It is usually done in automatic manner through some internal cross validation with grid search of the paremeters.

查看有关模型选择超参数优化的材料.

此外,您还可以修复迭代次数

Furthermore you fix number of iterations

params.term_crit = cv::TermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

对于SVM,您永远不要这样做.让它收敛(或至少放置100,000左右),在仅执行100个步骤之后,SVM可能甚至无法收敛(因此导致了微不足道的模型).

while for SVM you should never do that. Let it converge (or at least put something like 100,000), after just 100 steps it might be the case that SVM did not come even close to convergence (thus resulted in trivial model).

这篇关于OpenCV SVM总是预测更高级别的标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆