2015-11-17 41 views
2

我正在使用OpenCV SVM实现来双向预测图像特征的重要性。因此,我正在对正面和负面图像特征进行培训,并在{0,1}中寻找分类。OpenCV SVM总是预测更高级别的标签

我遇到的问题是,在训练之后,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; 
} 
+0

您应该为您的问题提供最少的工作示例。您正在使用的代码,示例数据。没有它,没有人可以帮助 - 只有猜测。 – lejlot

+0

谢谢,是的,我应该做的..我已经更新了代码示例的问题,以了解我如何与SVM交互 –

回答

5

该方法的一个主要问题是,在使用RBF时,您没有设置SVM的hyperparemeters,所以可能是C=1gamma=1/d(或1/mean ||x||^2),因为它们在大多数SVM实现中都是默认值。

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

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

  • C(您1)是missclassification的重量 - 越大C,SVM会更加努力学习如何正确地训练数据,可能在过度拟合的成本。
  • gamma(您的默认值)是您的RBF内核的2倍方差的倒数。换句话说 - 更大的伽马值,更小的高斯,因此 - 你的方法在几何意义上更“局部”。再次 - 大伽玛可以帮助您最小化训练误差(偏差),但会导致更高的测试误差(差异)。

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

查看材料机型选择 and 超参数优化

而且你解决迭代

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

的数量,同时对SVM你永远不应该这样做。让它收敛(或者至少可以放100000),经过100步之后,SVM甚至不会收敛(因此导致了平凡的模型)。

+0

谢谢,这肯定有帮助,我将尝试更改C和伽马(我不确定是什么它们默认设置为) –

+0

我认为终止标准参数中的值与C或gamma没有任何关系,100对应于最大迭代次数,1e-6对应于所需的精度。看到这里 - http://docs.opencv.org/2.4/modules/core/doc/old_basic_structures.html#cvtermcriteria –

+0

你是对的,我更新了答案。 – lejlot