At the moment I am trying to train different SVMs for the recognition of different emotions. So for example to recognize the emotion happy I train a SVM with images of happy people as positives and images where people express other emotions such as anger, fear, disgust, ... as negatives. The images are stored in a database that I have partitioned in a training section and testing section.
When I have trained the SVMs, I immediatly use them to test the accuracy on the test images of the database and this works fine. But I also save the trained SVMs because I would like to use them in another programm and don't want to retrain them every time I start the other program.
Thus I loaded the SVMs in the other program but the results were very bad. The accuracy was near zero percent. So I tried to save and immedialty load the SVMs in the training program but also here the accuracy was now near zero percent.
After searching for a while I found out that if I have loaded the SVMs and I print the SVM type, kernel type and supportvectors that they are the same as in the SVM .xml file. So I think that the problem is that the prediction is not executed in the right way. I also don't know if I save my SVMs and load them in the appropriate way.
At the moment I have tried searching for a solution but without any success. Some of the links that I have tried are:
Train SVM and save it with OpenCV 3.0
How to load previously stored svm classifier?
opencv 3 (C++) auto trained SVM loading issue
The code that I use to train the SVMs and to test them immediately without loading them again is:
trainData = ml::TrainData::create(training_mat, ROW_SAMPLE, label_mat);
svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::RBF);
svm->trainAuto(trainData);
svm->save(svmSaveNames[i]);
// Test SVMs
data_file.open(filenameLabelsTestingImages[i]);
data_file << "Number\n";
startTest = stopTest;
stopTest = startTest + emotionCountersTesting[i];
int numberRightClassified = 0;
int numberClassified = 0;
for (int j = 0; j < numberOfTestImg; j++)
{
cv::Mat testing_one_image_mat(1, numberOfFeatures, CV_32F);
for (int k = 0; k < numberOfFeatures; k++)
{
testing_one_image_mat.at<float>(0, k) = testing_mat.at<float>(j, k);
}
int value_svm = svmNew->predict(testing_one_image_mat);
if (value_svm == 1)
{
if (j >= startTest && j < stopTest)
{
numberRightClassified++;
}
numberClassified++;
}
data_file << value_svm << endl;
}
data_file.close();
So this works fine until I change the code to save the SVMs first and then load them again for prediction as follow
trainData = ml::TrainData::create(training_mat, ROW_SAMPLE, label_mat);
svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::RBF);
svm->trainAuto(trainData);
svm->save(svmSaveNames[i]);
Ptr<SVM> svmNew = SVM::create();
svmNew = SVM::load<SVM>(svmSaveNames[i]);
//cout << "The type is " << svmNew->getType() << endl;
//cout << "The kernel type is " << svmNew->getKernelType() << endl;
//cout << "The support vectors are " << svmNew->getSupportVectors() << endl;
// Test SVMs
data_file.open(filenameLabelsTestingImages[i]);
data_file << "Number\n";
startTest = stopTest;
stopTest = startTest + emotionCountersTesting[i];
int numberRightClassified = 0;
int numberClassified = 0;
for (int j = 0; j < numberOfTestImg; j++)
{
cv::Mat testing_one_image_mat(1, numberOfFeatures, CV_32F);
for (int k = 0; k < numberOfFeatures; k++)
{
testing_one_image_mat.at<float>(0, k) = testing_mat.at<float>(j, k);
}
//int value_svm = svm -> predict(testing_one_image_mat);
int value_svm = svmNew->predict(testing_one_image_mat);
if (value_svm == 1)
{
if (j >= startTest && j < stopTest)
{
numberRightClassified++;
}
numberClassified++;
}
data_file << value_svm << endl;
}
data_file.close();
The array svmSaveNames contains strings with names for saving the different SVMs like svm_anger.xml, svm_contempt.xml, ...
I use the variable data_file to create a .txt file for every SVM that is tested. So first I train and test the SVM to recognize for example the emotion anger and while testing this SVM I use all the test images. So the prediction of all those images (1 = positive / -1 = negative) is written to a textfile.
The parameters startTest and stopTest are used to verify if the positive images, prediction gives value 1, is in the range of the images that are needed to be recognized as positive. In the testing map of the database I ordered all the images by there emotion so first anger then contempt,...
The 2D matrix testing_mat contains the data from all the test images that is given to the SVM to predict the emotion.
So my problem is that after I have loaded the SVMs they don't give me the right prediction.
After searching for a while I found out that if I use a linear kernel there is no problem at all. So then I can save and load the SVM and the prediction is correct. So I started to search for a reason why it works for the linear kernel and not for the other kernels.
The answer is that there is a bug in OpenCV 3.1 according to issue #5054 on Github. I tried the proposed solution but it still didn't work. Eventually I donwloaded OpenCV 2.4 and now everything works well.
来源:https://stackoverflow.com/questions/37108811/opencv-3-1-0-save-and-load-trained-svms