【问题标题】:OpenCV - Ensemble of exemplar SVMsOpenCV - 示例 SVM 的集合
【发布时间】:2014-10-19 22:18:40
【问题描述】:

我一直在尝试使用 OpenCV 实现 ensemble of exemplar SVM。除此之外的一般想法是,给定 K 个训练样本(例如汽车图像),可以训练 K 个 SVM,其中每个 SVM 使用一个正样本和 K-1 个负样本进行训练。然后在测试时,集成将触发 K 次,最高分是最好的预测。

为了实现这一点,我正在使用 OpenCV SVM 实现(在撰写本文时使用当前的 GIT master - 3.0)和 C++ 接口。作为功​​能,我使用的是 HOG,响应大小约为 7000。因此,每张图像都有一个 7000D 的特征向量。

我面临的问题是各种 SVM 没有正确训练。实际上,他们根本不训练!训练实际上执行得非常快,每个 SVM 总是返回 1 个支持向量,alpha=1.0。我不确定这是否是因为我有一个单一的正面与许多(> 900)个负面,或者它只是我的代码中的一个错误。但是,看了几遍后,我没有发现任何明显的错误。

这就是我设置问题的方式(假设我们得到了整个数据集的 HOG 响应并将它们放在 std::vector > trainingData 中)。请注意,EnsambleSVMElement 是一个包含 SVM 和一堆其他信息的结构。

简而言之:我设置了一个训练矩阵,其中每一行包含特定样本的 HOG 响应。然后我开始分别训练每个 SVM。对于每次训练迭代,我创建一个标签向量,其中每个条目设置为 -1(负样本),除了与我正在训练的当前 SVM 相关联的条目设置为 1(因此,如果我正在训练条目 100,则只有正标签会在标签[100])。

训练代码

int ensambles = trainingData.size();

if(ensambles>1)
{
    //get params to normalise the data in [0-1]
    std::vector<float> mins(trainingData.size());
    std::vector<float> maxes(trainingData.size());

    for(int i=0; i<trainingData.size(); ++i)
    {
        mins[i] =   *std::min_element(trainingData[i].begin(), trainingData[i].end());
        maxes[i] =  *std::max_element(trainingData[i].begin(), trainingData[i].end());
    }

    float min_val = *std::min_element(mins.begin(), mins.end());
    float max_val = *std::min_element(maxes.begin(), maxes.end());
    int featurevector_size = trainingData[0].size();

    if(featurevector_size>0)
    {
        //set-up training data. i-th row contains HOG response for sample i
        cv::Mat trainingDataMat(ensambles, featurevector_size, CV_32FC1); 
        for(int i=0; i<trainingDataMat.rows; ++i)
            for(int j=0; j<trainingDataMat.cols; ++j)
                trainingDataMat.at<float>(i, j) = (trainingData.at(i).at(j)-min_val)/(max_val-min_val); //make sure data are normalised in [0-1] - libSVM constraint

        for(int i=0; i<ensambles; ++i)
        {
            std::vector<int> labels(ensambles, -1);
            labels[i] = 1; //one positive only, and is the current sample
            cv::Mat labelsMat(ensambles, 1, CV_32SC1, &labels[0]);
            cv::Ptr<cv::ml::SVM> this_svm = cv::ml::StatModel::train<SVM>(trainingDataMat, ROW_SAMPLE, labelsMat, svmparams);
            ensamble_svm.push_back(EnsambleSVMElement(this_svm));   
            Mat sv = ensamble_svm[i].svm->getSupportVectors();
            std::cout << "SVM_" << i << " has " << ensamble_svm[i].svm->getSupportVectors().rows << " support vectors." << std::endl;
        }
    }
    else
        std::cout <<"You passed empty feature vectors!" << std::endl;
}
else
    std::cout <<"I need at least 2  SVMs to create an ensamble!" << std::endl;

cout 总是打印“SVM_i 有 1 个支持向量”。

为了完整起见,这些是我的 SVM 参数:

cv::ml::SVM::Params params;
params.svmType    = cv::ml::SVM::C_SVC;
params.C           = 0.1;
params.kernelType = cv::ml::SVM::LINEAR;
params.termCrit   = cv::TermCriteria(cv::TermCriteria::MAX_ITER, (int)1e4, 1e-6);

在 0.1 和 1.0 之间变化 C 不会影响结果。也没有为样本设置权重,如here 所示。仅供参考,这是我设置权重的方式(对负数的惩罚很大):

cv::Mat1f class_weights(1,2); 
class_weights(0,0) = 0.01; 
class_weights(0,1) = 0.99; 
params.classWeights = class_weights;

在我的代码中或在我对问题的表述中显然有问题。有人能看出来吗?

谢谢!

【问题讨论】:

    标签: c++ opencv svm


    【解决方案1】:

    你有进步吗? 我的猜测是你的 C 参数太低,尝试更大的值(10、100、1000)。 另一个重要方面是,在 Exemplar SVM 框架中,训练阶段并非如此简单。作者在训练步骤和硬负挖掘步骤之间交替进行,以使训练阶段更有效。 如果您需要比 Exemplar-SVM 文章中报告的更多详细信息,可以查看 Malisiewicz 博士论文:http://people.csail.mit.edu/tomasz/papers/malisiewicz_thesis.pdf

    【讨论】:

    • 您好,劳尔,感谢您的回复。最后,我最终使用 Matlab 进行培训,然后编写了我的评估代码。我记得我尝试了几个 C 值(我迭代了几个从 0.1 到 1000 的值),但我从来没有得到任何有意义的东西。至于实际训练,我现在是做负挖掘,不过还是在Matlab里做的。
    【解决方案2】:

    我觉得你这里有个小错误:第二行,我觉得应该是

    *std::max_element(...), not *std::min_element(...)
    
     float min_val = *std::min_element(mins.begin(), mins.end());
     float max_val = *std::min_element(maxes.begin(), maxes.end());
    

    【讨论】:

      猜你喜欢
      • 2016-01-21
      • 2014-04-23
      • 2015-08-14
      • 1970-01-01
      • 2015-05-04
      • 2015-07-25
      • 2015-06-14
      • 2013-05-22
      • 2016-10-29
      相关资源
      最近更新 更多