OpenCV SVM总是预测更高的类别标签

我使用OpenCV的SVM实现来二元预测图像特征的重要性。因此,我在正负图像特征上进行训练,并希望得到{0,1}的分类结果。

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

以下是我的SVM类及其相关的SVM参数

//填充SVM参数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;}//使用给定数据训练SVMvoid SVM::train(cv::Mat train_data, cv::Mat labels){    //如果SVM参数尚未设置,则设置    if (!params_set)    {        setSVMParams();    }    svm.train(train_data, labels, cv::Mat(), cv::Mat(), params);}//根据训练结果,预测给定数据的类别float SVM::predict(cv::Mat sample){    return svm.predict(sample, false);}

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

//根据提供的D阈值创建适当的训练数据和类别标签,用于后续的SVM训练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];        //重要特征,标签1        if (entry.D > t_D)        {            labels_l.at<float>(i) = positive_label;            num_pos++;        }        //不重要特征,标签-1        else        {            labels_l.at<float>(i) = negative_label;            num_neg++;        }        int j = 0;        //将特征复制到OpenCV矩阵的当前行        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 << "用于训练:正样本数=" << num_pos << ", 负样本数=" << 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 (svm.predict(first) == 1.0f && svm.predict(second) == 1.0f)        {            new_matchings.push_back(matchings[i]);        }        else        {            std::cout << "特征已移除" << std::endl;        }    }    return new_matchings;}

回答:

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

这些参数对于构建有效模型至关重要。特别是,如果您的C值过低(1可能就是,具体取决于数据的许多特征),那么SVM将构建一个简单的模型,简单地总是预测一个类别

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

  • C(您的1)是分类错误的权重 – C值越大,SVM将更努力地精确学习训练数据,可能导致过拟合。
  • gamma(您的默认值)是RBF核的2倍方差的倒数。换句话说 – gamma值越大,高斯分布越小,因此 – 您的算法在几何意义上更“局部”。同样 – 大的gamma有助于最小化训练误差(偏差),但会导致更高的测试误差(方差)。

正确选择方差-偏差之间的权衡是机器学习技术的关键元素。对于RBF SVM – 您可以通过上述参数来控制。尝试不同的参数,检查训练集误差和测试集误差以了解情况。如果您的训练集误差很大 – 增加C和/或gamma。一旦您的训练集误差合适,再看测试集 – 如果误差太大 – 尝试降低值,以此类推。这通常通过内部交叉验证和参数的网格搜索来自动完成。

查看有关模型选择超参数优化的资料。

此外,您固定了迭代次数

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

而对于SVM,您永远不应该这样做。让它收敛(至少设置为10,000步),仅100步后,SVM可能尚未接近收敛(因此导致了简单模型)。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注