SVM训练二分类,从Matlab libsvm 到 OpenCV3.0 ml::SVM

最近用Matlab libsvm实现了一个二分类的项目,需要将代码迁移到VS,参考了网上的一些博客后,成功实现了完美迁移,以下捋一捋迁移的经验。

1.SVM原理  https://blog.csdn.net/c406495762/article/details/78072313

2.Matlab使用libsvm需要先进行配置,因为需要进行参数优化,故需要下载台湾大学林智仁(Lin Chih-Jen)教授github上的libsvm包,链接https://github.com/faruto/Libsvm-FarutoUltimate-Version

Matlab libsvm配置博文 https://my.oschina.net/u/4476995/blog/3191329

之后便可使用Matlab libsvm了

% 参数c和参数g寻优
[bestacc,bestc,bestg] = SVMcgForClass(train_label,train,-10,10,-10,10,2,0.2,0.2,0.5);
% 使用寻优得到的参数进行训练
cmd = ['-c ',num2str(bestc),' -g ',num2str(bestg)];
model=svmtrain(train_label,train,cmd);
% 预测
[predict_label, accuracy, dec_values]=svmpredict(test_label,test,model);

SVMcgForClass使用的是网格参数寻优,(-10,10,-10,10,0.2,0.2)表示参数c的网格变化范围为(2^-10, 2^-9.8,...,2^9.8, 2^10),参数 g的网格变化范围同c一样,2表示寻优时按照2折交叉验证,最后一个0.5参数为matlab作图时使用,坐标范围70:0.5:100

svmtrain中带入bestc和bestg进行训练。

svmpredict预测得到预测标签predict_label, 准确度accuracy, dec_value个人人为是预测的每类的得分(虽然有些奇怪)

如果需要savemodel或者loadmodel,参考博文 https://blog.csdn.net/weixin_42296976/article/details/86103729?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

% savemodel('modelname.model', model)
% model = loadmodel('modelname.model', N);

3.VS上使用SVM, 除了手撕SVM源码以外,就是调用Opencv内的ml.cpp,注意此时命名空间为using namespace cv::ml

Ptr<SVM> svm = SVM::create();
// trainDataMat 格式为CV_32F, trainLabelMat 格式为CV_32S
// ROW_SAMPLE表示对于输入矩阵按行训练
Ptr<TrainData> trainDataSet = TrainData::create(trainDataMat, ROW_SAMPLE, trainLabelMat);
void svm_train(Ptr<SVM>& svm, Ptr<TrainData>& trainDataSet)
{
	svm->setType(SVM::Types::C_SVC);		    // C类支持向量分类机
	svm->setKernel(SVM::KernelTypes::RBF);		    // RBF核函数
	svm->setC(0.757858283255200);				
	svm->setGamma(0.00170029406893774);	
    	
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5000, 1e-5));	// 迭代训练过程的中止条件	

        // 对于需要优化的参数, 需要设置网格
	ParamGrid Cgrid = SVM::getDefaultGrid(SVM::ParamTypes::C);
	ParamGrid gammaGrid = SVM::getDefaultGrid(SVM::ParamTypes::GAMMA);
	ParamGrid pGrid = SVM::getDefaultGrid(SVM::ParamTypes::P);
	ParamGrid nuGrid = SVM::getDefaultGrid(SVM::ParamTypes::NU);
	ParamGrid coeffGrid = SVM::getDefaultGrid(SVM::ParamTypes::COEF);
	ParamGrid degreeGrid = SVM::getDefaultGrid(SVM::ParamTypes::DEGREE);
        // 对于不需要优化的参数, 步长设置为0即可
        pGrid.logStep = 0.0;
	nuGrid.logStep = 0.0;
	coeffGrid.logStep = 0.0;
	degreeGrid.logStep = 0.0;

	svm->trainAuto(trainDataSet, 2, Cgrid, gammaGrid, pGrid, nuGrid, coeffGrid, degreeGrid, true);
	//svm->train(trainDataSet);
}

二分类需要的参数有 SVM类型 C_SVC, 核函数RBF较优,同时需要对它们设置初值。训练终止条件为迭代5000次或者误差小于1e-5。对于需要优化的参数,需要设置网格,对于不需要优化的参数,步长设置为0。这里网格为minval:step:maxval

需要参数优化时,使用trainAuto函数进行循环,2表示2折交叉验证,末尾参数设置为true时表示如果是二分类,将创建更多的类平衡交叉验证子集。

经过使用trainAuto进行参数c和参数g优化后,对比发现训练得到的结果不如Matlab SVMcgForClass 网格寻优得到的结果,所以我直接将Matlab寻优得到参数c和参数g写在setC()和setGamma()里面,使用trian函数进行训练,得到的结果于Matlab得到的结果一致。

预测函数大有意思,可解释为如下:

/*
svm->predict(InputArray samples, OutputArray results = noArray(), int flags = 0)
如果只有samples一个参数, 此时只能对测试矩阵的每行依次预测, 返回值为标签分类的一个float值
如果还有results参数, 此时可对整个测试矩阵进行预测, 不会返回值, 结果会保存在Mat result中, 为标签分类的值
如果还有flags()参数, Mat result中保存的结果为预测的得分, 而不是标签, 类似于matlab中的dec_values
*/
float val = svm->predict(testDataMat.row(i));
svm->predict(testDataMat, result);
svm->predict(testDataMat, Score, StatModel::Flags::RAW_OUTPUT);

保存模型函数和加载模型函数就没有多大意思了,如下:

// 注意保存模型与加载模型的写法不同
Ptr<SVM> svm = SVM::create();
svm->save("modelName.xml");
svm = SVM::load("modelName.xml");

完工~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值