[关闭]
@qiezhian 2014-11-15T08:38:30.000000Z 字数 3681 阅读 6105

OpenCv 中SVM类的自动参数优化

research


转自:http://www.itnose.net/detail/6095711.html
当然对于一个特定的SVM训练器,里面的所有参数不一定全用。比如我用的svm_type为EPS_SVR,那么我要用到的参数主要就是p,c,gama这三个参数。下面是设置参数的代码
新窗口打开复制代码

  1. CvSVMParams param;
  2. param.svm_type = CvSVM::EPS_SVR;
  3. //我的实验是用SVR作回归分析,可能大部分人的实验是用SVM来分类,方法都一样
  4. param.kernel_type = CvSVM::RBF;
  5. param.C = 1;
  6. param.p = 5e-3;
  7. param.gamma = 0.01;
  8. param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);
  9. CvSVMParams param;
  10. param.svm_type = CvSVM::EPS_SVR; //我的实验是用SVR作回归分析,可能大部分人的实验是用SVM来分类,方法都一样
  11. param.kernel_type = CvSVM::RBF;
  12. param.C = 1;
  13. param.p = 5e-3;
  14. param.gamma = 0.01;
  15. param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);

设置参数后就可以用CvSVM.train()进行训练了,下面是train的原型

  1. C++: bool CvSVM::train(const Mat& trainData,
  2.       const Mat& responses,
  3. const Mat& varIdx=Mat(),
  4. const Mat& sampleIdx=Mat(),
  5. CvSVMParams params=CvSVMParams()
  6. )

我在用train完成训练预测时出现了过拟合的情况,即对于训练集的数据有很好的预测结果,但对不在训练集的测试集预测值都一样。于是我开始调整参数,调了半天也没个好结果。后面我发现其实opencv中SVM类是提供了优化参数值功能的,瞬间感觉世界美好了。下面讲讲具体的做法。要让svm自动优化参数,那么训练时就不能再用train函数了,而应该用train_auto函数。下面是train_auto的函数原型

  1. C++: bool CvSVM::train_auto(const Mat& trainData,
  2.         const Mat& responses,
  3. const Mat& varIdx,
  4. const Mat& sampleIdx,
  5. CvSVMParams params,
  6. int k_fold=10,
  7. CvParamGrid Cgrid=CvSVM::get_default_grid(CvSVM::C),
  8. CvParamGrid gammaGrid=CvSVM::get_default_grid(CvSVM::GAMMA),
  9. CvParamGrid pGrid=CvSVM::get_default_grid(CvSVM::P),
  10. CvParamGrid nuGrid=CvSVM::get_default_grid(CvSVM::NU),
  11. CvParamGrid coeffGrid=CvSVM::get_default_grid(CvSVM::COEF),
  12. CvParamGrid degreeGrid=CvSVM::get_default_grid(CvSVM::DEGREE),
  13. bool balanced=false
  14. )

自动训练函数的参数注释(13个)
前5个参数参考构造函数的参数注释。
k_fold: 交叉验证参数。训练集被分成k_fold的自子集。其中一个子集是用来测试模型,其他子集则成为训练集。所以,SVM算法复杂度是执行k_fold的次数。
*Grid: (6个)对应的SVM迭代网格参数。
balanced: 如果是true则这是一个2类分类问题。这将会创建更多的平衡交叉验证子集。
自动训练函数的使用说明
这个方法根据CvSVMParams中的最佳参数C, gamma, p, nu, coef0, degree自动训练SVM模型。
参数被认为是最佳的交叉验证,其测试集预估错误最小。
如果没有需要优化的参数,相应的网格步骤应该被设置为小于或等于1的值。例如,为了避免gamma的优化,设置gamma_grid.step = 0,gamma_grid.min_val, gamma_grid.max_val 为任意数值。所以params.gamma 由gamma得出。
最后,如果参数优化是必需的,但是相应的网格却不确定,你可能需要调用函数CvSVM::get_default_grid(),创建一个网格。例如,对于gamma,调用CvSVM::get_default_grid(CvSVM::GAMMA)。
该函数为分类运行 (params.svm_type=CvSVM::C_SVC 或者 params.svm_type=CvSVM::NU_SVC) 和为回归运行 (params.svm_type=CvSVM::EPS_SVR 或者 params.svm_type=CvSVM::NU_SVR)效果一样好。如果params.svm_type=CvSVM::ONE_CLASS,没有优化,并指定执行一般的SVM。
这里需要注意的是,对于需要的优化的参数虽然train_auto可以自动选择最优值,但在代码中也要先赋初始值,要不然编译能通过,但运行时会报错。下面是示例代码
新窗口打开复制代码

  1. CvSVMParams param;
  2. param.svm_type = CvSVM::EPS_SVR;
  3. param.kernel_type = CvSVM::RBF;
  4. param.C = 1; //给参数赋初始值
  5. param.p = 5e-3; //给参数赋初始值
  6. param.gamma = 0.01; //给参数赋初始值
  7. param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);
  8. //对不用的参数step设为0
  9. CvParamGrid nuGrid = CvParamGrid(1,1,0.0);
  10. CvParamGrid coeffGrid = CvParamGrid(1,1,0.0);
  11. CvParamGrid degreeGrid = CvParamGrid(1,1,0.0);
  12. CvSVM regressor;
  13. regressor.train_auto(PCA_training,tr_label,NULL,NULL,param,
  14. 10,
  15. regressor.get_default_grid(CvSVM::C),
  16. regressor.get_default_grid(CvSVM::GAMMA),
  17. regressor.get_default_grid(CvSVM::P),
  18. nuGrid,
  19. coeffGrid,
  20. degreeGrid);
  21. CvSVMParams param;
  22. param.svm_type = CvSVM::EPS_SVR;
  23. param.kernel_type = CvSVM::RBF;
  24. param.C = 1; //给参数赋初始值
  25. param.p = 5e-3; //给参数赋初始值
  26. param.gamma = 0.01; //给参数赋初始值
  27. param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);
  28. //对不用的参数step设为0
  29. CvParamGrid nuGrid = CvParamGrid(1,1,0.0);
  30. CvParamGrid coeffGrid = CvParamGrid(1,1,0.0);
  31. CvParamGrid degreeGrid = CvParamGrid(1,1,0.0);
  32. CvSVM regressor;
  33. regressor.train_auto(PCA_training,tr_label,NULL,NULL,param,
  34. 10,
  35. regressor.get_default_grid(CvSVM::C),
  36. regressor.get_default_grid(CvSVM::GAMMA),
  37. regressor.get_default_grid(CvSVM::P),
  38. nuGrid,
  39. coeffGrid,
  40. degreeGrid);

用上面的代码的就可以自动训练优化出参数了,最后想查看优化后的参数值可以使用CvSVMParams params_re = regressor.get_params()函数来获得各优化后的参数值。
新窗口打开复制代码

  1. CvSVMParams params_re = regressor.get_params();
  2. regressor.save("training_srv.xml");
  3. float C = params_re.C;
  4. float P = params_re.p;
  5. float gamma = params_re.gamma;
  6. printf("\nParms: C = %f, P = %f,gamma = %f \n",C,P,gamma);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注