OpenCV-示例SVM的集合



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

为了实现这一点,我使用OpenCVSVM实现(在编写本文时使用当前的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不会影响结果。也没有为样本设置权重,如本文所述。仅供参考,这就是我设置权重的方式(负的话会受到很大的惩罚):

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

在我的代码中,或者在我对问题的表述中,显然存在一些错误。有人能发现吗?

谢谢!

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

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

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

最新更新