OpenCV - 集成样本支持向量机

3
我一直在尝试使用OpenCV实现样本SVM集合。它的一般想法是,在训练时给定K个样本(例如汽车图像),可以训练K个SVM,其中每个SVM使用一个正样本和K-1个负样本进行训练。然后在测试时,集合将会触发K次,得分最高的将是最好的预测。
为了实现这一点,我正在使用OpenCV SVM实现(使用当前GIT master - 在撰写本文时为3.0),以及C++接口。作为特征,我正在使用HOGs,并且响应大小约为7000。因此,每个图像都有一个7000D的特征向量。
我面临的问题是,各种SVM无法正确训练。实际上,它们根本没有训练!事实上,训练非常快速,并且总是返回每个SVM的1个支持向量,alpha=1.0。我不确定这是否是由于我只有一个正样本与许多(>900)负样本,还是我的代码中存在错误。但是,经过多次检查,我无法发现任何明显的错误。
这是我设置问题的方式(假设我们已经获得了整个数据集的HOG响应,并将它们放入一个std :: vector>训练数据中)。请注意,EnsambleSVMElement是一个结构体,保存着SVM和一堆其他信息。
简而言之:我设置了一个训练矩阵,其中每行包含特定样本的HOG响应。然后我分别开始训练每个SVM。对于每个训练迭代,我创建一个标签向量,其中每个条目都设置为-1(负样本),除了与我正在训练的当前SVM相关联的条目,该条目设置为1(因此如果我正在训练条目100,则唯一的正标签将在labels [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 has 1 support vectors"。

为了完整起见,以下是我的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);

将C值从0.1变化到1.0并不会影响结果。设置样本权重也不会影响结果,具体请参见这里。仅供参考,以下是我设置的样本权重(对负数进行大幅惩罚):

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

我的代码或问题陈述中明显存在问题。有人能够发现吗?

谢谢!

2个回答

3

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


嗨Raul,感谢您的回复。最终我使用Matlab进行训练,然后编写我的评估代码。我记得我尝试了几个C值(我迭代了几个值,范围从0.1到1000),但我从未得到任何有意义的结果。 至于实际训练,我现在正在进行负面挖掘,但这也是在Matlab中完成的。 - Fabrizio

0
我认为你这里有一个小错误:第二行,我认为应该是


*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());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接