c++ - OpenCV 3.1.0 : Save and load trained SVMs

标签 c++ svm opencv3.1

目前我正在尝试训练不同的支持 vector 机来识别不同的情绪。因此,例如,为了识别快乐的情绪,我训练了一个支持 vector 机,将快乐的人的图像作为积极因素,将人们表达其他情绪(如愤怒、恐惧、厌恶……)的图像作为消极因素。图像存储在我已划分为训练部分和测试部分的数据库中。

当我训练 SVM 后,我立即使用它们来测试数据库测试图像的准确性,并且效果很好。但我也保存了经过训练的 SVM,因为我想在另一个程序中使用它们,并且不想每次启动另一个程序时都重新训练它们。

因此我在其他程序中加载了 SVM,但结果非常糟糕。准确度接近于零。所以我尝试在训练程序中保存并立即加载 SVM,但这里的准确度现在接近于零。

搜索一段时间后,我发现如果我加载了 SVM 并打印了 SVM 类型、内核类型和支持 vector ,它们与 SVM .xml 文件中的相同。所以我认为问题在于预测没有以正确的方式执行。我也不知道我是否保存我的 SVM 并以适当的方式加载它们。

目前我尝试寻找解决方案但没有成功。我试过的一些链接是:

Train SVM and save it with OpenCV 3.0

How to load previously stored svm classifier?

Load Trained SVM – Emgu CV

opencv 3 (C++) auto trained SVM loading issue

我用来训练 SVM 并立即测试它们而无需再次加载它们的代码是:

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

所以这工作正常,直到我更改代码以先保存 SVM,然后再次加载它们进行预测,如下所示

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

数组 svmSaveNames 包含带有名称的字符串,用于保存不同的 SVM,如 svm_anger.xml、svm_contempt.xml、...

我使用变量 data_file 为每个测试的 SVM 创建一个 .txt 文件。所以首先我训练和测试 SVM 来识别例如情绪愤怒,并且在测试这个 SVM 时我使用所有的测试图像。所以所有这些图像的预测(1 = 正/-1 = 负)被写入一个文本文件。

参数startTest和stopTest用于验证正例图像,预测给值为1,是否在需要识别为正例的图像范围内。在数据库的测试图中,我按照情绪对所有图像进行了排序,所以先是愤怒然后是蔑视,...

二维矩阵 testing_mat 包含来自所有提供给 SVM 以预测情绪的测试图像的数据。

所以我的问题是,在我加载 SVM 后,它们没有给我正确的预测。

最佳答案

找了一段时间发现如果用线性核完全没有问题。然后我可以保存和加载 SVM,预测是正确的。所以我开始寻找它适用于线性内核而不适用于其他内核的原因。

根据问题 #5054,答案是 OpenCV 3.1 中存在错误在 Github 上。我尝试了建议的解决方案,但仍然没有用。最终我下载了 OpenCV 2.4,现在一切正常。

关于c++ - OpenCV 3.1.0 : Save and load trained SVMs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37108811/

相关文章:

c++ - Direct2D CreateTextLayout() - 如何获取插入符坐标

machine-learning - 只考虑 a-zA-Z 和数字进行训练和测试有意义吗?

android - Android 中的 Facemark 或 Kazemi

c++ - opencv 3.1 的静态库在哪里

c++ - 概念包含适用于函数,但不适用于结构

c++ - 在 googlemocks EXPECT_CALL 中匹配 std::wstring

c++ - RedisClient 通过 EVAL 命令使用 Lua 脚本

machine-learning - SVM 模型将概率得分大于 0.1(默认阈值 0.5)的实例预测为正例

java - 有谁知道如何向 org.w3c.dom.Element 添加值以实例化 MiningSchema 和 SupportVectorMachineModel ?

c++ - 使用 C++ REST SDK 将图像从 OpenCV 3 发送到 Cognitive Face API