載時自http://blog.csdn.net/u011177305/article/details/46458801?locationNum=1
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
)
自動訓練函數的使用說明:
這個方法根據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。
參考IT修道者博文的文章,使用其如下代碼
- 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();
- 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);
OpenCV Error: Assertion failed (sv_count != 0) in do_train, file /home/.../opencv-2.4.9/modules/ml/src/svm.cpp, line 1346
該問題在stack overflow中有人提出,不過沒有解決方案。
我修改了一下
CvParamGrid CvParamGrid_C(pow(2.0,-5), pow(2.0,15), pow(2.0,2)); CvParamGrid CvParamGrid_gamma(pow(2.0,-15), pow(2.0,3), pow(2.0,2)); if (!CvParamGrid_C.check() || !CvParamGrid_gamma.check()) cout<<"The grid is NOT VALID."<<endl; CvSVMParams paramz; paramz.kernel_type = CvSVM::RBF; paramz.svm_type = CvSVM::C_SVC; paramz.term_crit = cvTermCriteria(CV_TERMCRIT_ITER,100,0.000001); svm.train_auto(trainingData, labels, Mat(), Mat(), paramz,10, CvParamGrid_C, CvParamGrid_gamma, CvSVM::get_default_grid(CvSVM::P), CvSVM::get_default_grid(CvSVM::NU), CvSVM::get_default_grid(CvSVM::COEF), CvSVM::get_default_grid(CvSVM::DEGREE), true); paramz = svm.get_params(); cout<<"gamma:"<<paramz.gamma<<endl; cout<<"C:"<<paramz.C<<endl;
大家不妨嘗試一下。