@qiezhian
2014-11-15T08:38:30.000000Z
字数 3681
阅读 6105
research
转自:http://www.itnose.net/detail/6095711.html。
当然对于一个特定的SVM训练器,里面的所有参数不一定全用。比如我用的svm_type为EPS_SVR,那么我要用到的参数主要就是p,c,gama这三个参数。下面是设置参数的代码
新窗口打开复制代码
CvSVMParams param;
param.svm_type = CvSVM::EPS_SVR;
//我的实验是用SVR作回归分析,可能大部分人的实验是用SVM来分类,方法都一样
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);
CvSVMParams param;
param.svm_type = CvSVM::EPS_SVR; //我的实验是用SVR作回归分析,可能大部分人的实验是用SVM来分类,方法都一样
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& varIdx=Mat(),
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);
//对不用的参数step设为0
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);
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);
//对不用的参数step设为0
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);
用上面的代码的就可以自动训练优化出参数了,最后想查看优化后的参数值可以使用CvSVMParams params_re = regressor.get_params()
函数来获得各优化后的参数值。
新窗口打开复制代码
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);