OpenCV - an ensemble of exemplary SVMs

I am trying to implement a sample SVM ensemble using OpenCV. The general idea outside of it is that given K training examples (e.g. car images) it is possible to train K SVMs where each SVM is trained using one positive pattern and negative negative K-1 results. During testing, the ensemble will shoot K times, with the best result being the best forecast.

To implement this, I am using the OpenCV SVM implementation (using the current GIT master - 3.0 at the time of writing) and a C ++ interface. I use HOG as functions, and the response size is ~ 7000. Therefore, each image has a 7000D function vector.

The problem I am facing is that the various SVMs are not being trained properly. In fact, they don't exercise at all! Training is actually very fast and always returns 1 support vector per SVM, with alpha = 1.0. I'm not sure if this is because I have one positive versus many (> 900) negatives, or if this is just a bug in my code. However, after looking at it a few times, I don't see any obvious errors.

This is how I set up my problem (assuming we got HOG responses for the whole dataset and put them in std :: vector> trainingData). Note that EnsambleSVMElement is the Struct that holds the SVM, and a lot of other information.

In short: I am setting up a training matrix where each row contains a HOG response for a specific sample. Then I start training each SVM separately. For each iteration of training, I create a vector of labels, where each entry is -1 (negative sample), except that the entry is associated with the current SVM that I am training, which is set to 1 (so if I participate in the entry 100 , only the positive mark will be on labels [100]).

Learning code

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 always prints "SVM_i has 1 support vectors".

For completeness, these are my SVM options:

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

      

Changing the C value between 0.1 and 1.0 does not affect the results. There is also no setting for sample weights, as read here . Just for reference, this is how I adjust the weight (big penalty for negatives):

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

      

There is clearly something wrong in my code, or in my problem statement. Can anyone spot this?

Thank!

+3


source to share


2 answers


Have you made any progress? I assume your C parameter is too low, try larger values ​​(10, 100, 1000). Another important aspect is that in Exemplar SVM, the learning phase is not so easy. The author alternates between the training phase and a hard negative mining step to make the training phase more effective. If you need more information than the Exemplar-SVM article, you can see Malisiewicz's abstracts: http://people.csail.mit.edu/tomasz/papers/malisiewicz_thesis.pdf



+3


source


I think you have a small mistake: second line, I think it should be



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

      

0


source







All Articles