【问题标题】:OpenCV SVM always predicts higher class labelOpenCV SVM 总是预测更高的类别标签
【发布时间】:2016-02-18 17:36:29
【问题描述】:

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

我遇到的问题是,在训练之后,SVM 总是预测具有更高/更大类标签的类。我可以更改训练数据集的标签,但这个问题仍然存在。我仔细检查了生成的标签和训练 cv::Mat 矩阵,没有发现任何问题。

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

//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);
}

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

//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 预测结果以保留重要图像特征的函数

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;
}

【问题讨论】:

  • 您应该展示您的问题的最小工作示例。您正在使用的代码,示例数据。没有它,没有人能帮上忙——只能猜测。
  • 谢谢,是的,我应该做的。我已经用代码示例更新了这个问题,以了解我如何与 SVM 交互

标签: c++ opencv machine-learning svm


【解决方案1】:

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

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

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

  • C(你的 1)是错误分类的权重 - 大于 C,SVM 将更加努力地准确学习训练数据,可能以过度拟合为代价。
  • gamma(您的默认值)是您的 RBF 内核的 2 倍方差的倒数。换句话说 - 伽玛越大,高斯越小,因此 - 您的方法在几何意义上更“局部”。同样 - 大 gamma 可以帮助您最大限度地减少训练误差(偏差),但会导致更高的测试误差(方差)。

正确选择方差-偏差之间的权衡是机器学习技术的关键要素。在 RBF SVM 的情况下 - 您可以通过上述方式对其进行控制。和他们一起玩,检查训练集错误和测试集错误,看看发生了什么。如果您的训练集误差很大 - 增加 C 和/或 gamma。一旦您的训练集错误正常,请查看测试集 - 如果它太大 - 尝试减少值等等。它通常通过一些内部交叉验证和参数的网格搜索以自动方式完成。

查看关于模型选择超参数优化的材料。

此外,您还可以确定迭代次数

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

对于 SVM,您永远不应该这样做。让它收敛(或至少放 100,000 之类的东西),仅仅 100 步之后,可能会出现 SVM 甚至没有接近收敛的情况(因此导致了平凡的模型)。

【讨论】:

  • 谢谢,这肯定有帮助,我将尝试更改 C 和 gamma(我不确定它们默认设置为什么)
  • 我认为终止条件参数中的值与 C 或 gamma 没有任何关系,100 对应于最大迭代次数,1e-6 对应于所需的精度。见这里 - docs.opencv.org/2.4/modules/core/doc/…
  • 再次感谢您的回答,它非常有帮助且很有见地。我只是有另一个后续问题..我不完全确定您对训练集错误的意思。您的意思是使用相同的数据集进行训练和测试吗?
  • 是的,训练集误差是在用于训练的相同数据上测量的误差。如果这里的错误很高 - 那么你肯定 underfit;当它很小时——那么重要的是不要过度拟合(测试/有效数据的高错误)
猜你喜欢
  • 2016-04-16
  • 2016-01-30
  • 2013-05-22
  • 2014-07-09
  • 1970-01-01
  • 2015-10-01
  • 2019-09-09
  • 2021-07-03
  • 2020-08-03
相关资源
最近更新 更多