对于功能这么强的算法,OpenCV中天然也是有集成好了,咱们能够直接调用。OpenCV中的SVM算法是基于LibSVM软件包开发的,LibSVM是台湾大学林智仁(Lin Chih-Jen)等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包。算法
网上讲opencv中SVM使用的文章有不少,但讲SVM参数优化的文章却不多。因此在这里不重点讲怎么使用SVM,而是谈谈怎样经过opencv中自带的库优化SVM中的各参数。
相信用SVM作过实验的人都知道,SVM的各参数对实验结果有很大的影响,好比C,gama,P,coef等等。下面就是CvSVMParams类的原型。数据结构
C++: CvSVMParams::CvSVMParams()机器学习
C++: CvSVMParams::CvSVMParams(int svm_type, 函数
int kernel_type, 学习
)
<1>
svm_type:指定SVM的类型(5种):
- CvSVM::C_SVC : C类支持向量分类机。 n类分组 (n≥2),容许用异常值惩罚因子C进行不彻底分类。
- CvSVM::NU_SVC :
类支持向量分类机。n相似然不彻底分类的分类器。参数为
取代C(其值在区间【0,1】中,nu越大,决策边界越平滑)。
- CvSVM::ONE_CLASS : 单分类器,全部的训练数据提取自同一个类里,而后SVM创建了一个分界线以分割该类在特征空间中所占区域和其它类在特征空间中所占区域。
- CvSVM::EPS_SVR :
类支持向量回归机。训练集中的特征向量和拟合出来的超平面的距离须要小于p。异常值惩罚因子C被采用。
- CvSVM::NU_SVR :
类支持向量回归机。
代替了 p。
<2>kernel_type:SVM的内核类型(4种):
- CvSVM::LINEAR : 线性内核,没有任何向映射至高维空间,线性区分(或回归)在原始特征空间中被完成,这是最快的选择。

.

.
- CvSVM::RBF : 基于径向的函数,对于大多数状况都是一个较好的选择:

.
- CvSVM::SIGMOID : Sigmoid函数内核:

.
<3>
degree:内核函数(POLY)的参数degree。
<4>
gamma:内核函数(POLY/ RBF/ SIGMOID)的参数

。
<5>
coef0:内核函数(POLY/ SIGMOID)的参数coef0。
<6>
Cvalue:SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C。
<7>
nu:SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数

。
<8>
p:SVM类型(EPS_SVR)的参数

。
<9>
class_weights:C_SVC中的可选权重,赋给指定的类,乘以C之后变成

。因此这些权重影响不一样类别的错误分类惩罚项。权重越大,某一类别的误分类数据的惩罚项就越大。
<10>
term_crit:SVM的迭代训练过程的停止条件,解决部分受约束二次最优问题。您能够指定的公差和/或最大迭代次数。
固然对于一个特定的SVM训练器,里面的全部参数不必定全用。好比我用的svm_type为EPS_SVR,那么我要用到的参数主要就是p,c,gama这三个参数。下面是设置参数的代码
- CvSVMParams param;
- param.svm_type = CvSVM::EPS_SVR;
- param.kernel_type = CvSVM::RBF;
- param.C = 1;
- param.p = 5e-3;
- param.gamma = 0.01;
- param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);
设置参数后就能够用CvSVM.train()进行训练了,下面是train的原型
C++: bool CvSVM::train(const Mat& trainData,
const Mat& responses,
const Mat& sampleIdx=Mat(),
CvSVMParams params=CvSVMParams()
我在用train完成训练预测时出现了过拟合的状况,即对于训练集的数据有很好的预测结果,但对不在训练集的测试集预测值都同样(我在网上看到不少网友也遇到这个问题)。因而我开始调整参数,调了半天也没个好结果。
后面我发现其实opencv中SVM类是提供了优化参数值功能的,瞬间感受世界美好了。下面讲讲具体的作法。
要让svm自动优化参数,那么训练时就不能再用train函数了,而应该用train_auto函数。下面是train_auto的函数原型
C++: bool CvSVM::train_auto(const Mat& trainData,
const Mat& responses,
const Mat& varIdx,
const Mat& sampleIdx,
CvSVMParams params,
int k_fold=10,
CvParamGrid Cgrid=CvSVM::get_default_grid(CvSVM::C), CvParamGrid gammaGrid=CvSVM::get_default_grid(CvSVM::GAMMA), CvParamGrid pGrid=CvSVM::get_default_grid(CvSVM::P), CvParamGrid nuGrid=CvSVM::get_default_grid(CvSVM::NU), CvParamGrid coeffGrid=CvSVM::get_default_grid(CvSVM::COEF), CvParamGrid degreeGrid=CvSVM::get_default_grid(CvSVM::DEGREE),
bool balanced=false
)
自动训练函数的参数注释(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能够自动选择最优值,但在代码中也要先赋初始值,要否则编译能经过,但运行时会报错。下面是示例代码
- CvSVMParams param;
- param.svm_type = CvSVM::EPS_SVR;
- param.kernel_type = CvSVM::RBF;
- param.C = 1;
- param.p = 5e-3;
- param.gamma = 0.01;
- param.term_crit = cvTermCriteria(CV_TERMCRIT_EPS, 100, 5e-3);
- CvParamGrid nuGrid = CvParamGrid(1,1,0.0);
- CvParamGrid coeffGrid = CvParamGrid(1,1,0.0);
- CvParamGrid degreeGrid = CvParamGrid(1,1,0.0);
-
- CvSVM regressor;
- regressor.train_auto(PCA_training,tr_label,NULL,NULL,param,
- 10,
- regressor.get_default_grid(CvSVM::C),
- regressor.get_default_grid(CvSVM::GAMMA),
- regressor.get_default_grid(CvSVM::P),
- nuGrid,
- coeffGrid,
- degreeGrid);
用上面的代码的就能够自动训练并优化参数。最后,若想查看优化后的参数值,可使用CvSVM::get_params()函数来得到优化后的CvSVMParams。下面是示例代码:
- CvSVMParams params_re = regressor.get_params();
- regressor.save("training_srv.xml");
- float C = params_re.C;
- float P = params_re.p;
- float gamma = params_re.gamma;
- printf("\nParms: C = %f, P = %f,gamma = %f \n",C,P,gamma);
本文系原创,转载请注明转载自 http://blog.csdn.net/computerme/article/details/38677599