您的位置:首页 > 运维架构

Opencv中SVM的使用问题

2015-04-16 21:18 316 查看
CvSVM svm;// = CvSVM();//新建一个SVM      
CvSVMParams param;//这里是参数  
CvTermCriteria criteria;      
criteria = cvTermCriteria( CV_TERMCRIT_EPS, 1000, FLT_EPSILON );      
param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria );      
/*     
    SVM种类:CvSVM::C_SVC     
    Kernel的种类:CvSVM::RBF     
    degree:10.0(此次不使用)     
    gamma:8.0     
    coef0:1.0(此次不使用)     
    C:10.0     
    nu:0.5(此次不使用)     
    p:0.1(此次不使用)     
    然后对训练数据正规化处理,并放在CvMat型的数组里。     
                                                        */         
    //☆☆☆☆☆☆☆☆☆(5)SVM学习☆☆☆☆☆☆☆☆☆☆☆☆           
    svm.train( data_mat, res_mat, NULL, NULL, param );//训练啦      
    //☆☆利用训练数据和确定的学习参数,进行SVM学习☆☆☆☆       
    svm.save( "SVM_DATA.xml" );


1.首先声明一个CvSVM类

2.OpenCV学习–cvTermCriteria介绍

<pre name="code" class="cpp">CvTermCriteria
迭代算法的终止准则
#define CV_TERMCRIT_ITER    1
#define CV_TERMCRIT_NUMBER  CV_TERMCRIT_ITER
#define CV_TERMCRIT_EPS     2

typedef struct CvTermCriteria
 {
  int    type;  /* CV_TERMCRIT_ITER 和CV_TERMCRIT_EPS二值之一,或者二者的组合 */
  int    max_iter; /* 最大迭代次数 */
  double epsilon; /* 结果的精确性 */
 }
 CvTermCriteria;
/* 构造函数 */
inline  CvTermCriteria  cvTermCriteria( int type, int max_iter, double epsilon );
/* 在满足max_iter和epsilon的条件下检查终止准则并将其转换使得type=CV_TERMCRIT_ITER+CV_TERMCRIT_EPS */
CvTermCriteria cvCheckTermCriteria( CvTermCriteria criteria,
                                    double default_eps,
                                    int default_max_iters );



3.Opencv中的CvSVMParams介绍

C++: CvSVMParams:: CvSVMParams (int svm_type ,

int kernel_type ,

double degree ,

double gamma ,

double coef0 ,

double Cvalue ,

double nu ,

double p ,

CvMat* class_weights ,

CvTermCriteria term_crit

)







4.样本train

设置参数后就可以用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
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);


======================================================

用OpenCV使用SVM算法的大概流程是

1)设置训练样本集

需要两组数据,一组是数据的类别,一组是数据的向量信息。

2)设置SVM参数

利用CvSVMParams类实现类中的成员变量svm_type表示SVM类型:

CvSVM::C_SVC C-SVC

CvSVM::NU_SVC v-SVC

CvSVM::ONE_CLASS 一类SVM

CvSVM::EPS_SVR e-SVR

CvSVM::NU_SVR v-SVR

成员变量kernel_type表示核函数的类型:

CvSVM::LINEAR 线性:u‘v

CvSVM::POLY 多项式:(r*u'v + coef0)^degree

CvSVM::RBF RBF函数:exp(-r|u-v|^2)

CvSVM::SIGMOID sigmoid函数:tanh(r*u'v + coef0)

成员变量degree针对多项式核函数degree的设置

gamma针对多项式/rbf/sigmoid核函数的设置

coef0针对多项式/sigmoid核函数的设置

Cvalue为损失函数

在C-SVC、e-SVR、v-SVR中有效,nu设置v-SVC、一类SVM和v-SVR参数

p为设置e-SVR中损失函数的值

class_weightsC_SVC的权重

term_crit为SVM训练过程的终止条件。

其中默认值degree = 0,gamma = 1,coef0 = 0,Cvalue = 1,nu = 0,p = 0,class_weights = 0

3)训练SVM

调用CvSVM::train函数建立SVM模型,第一个参数为训练数据,第二个参数为分类结果,最后一个参数即CvSVMParams

4)用这个SVM进行分类

调用函数CvSVM::predict实现分类

CvSVM::predict用来预测一个新样本的响应值,在分类器问题中,这个函数返回类别编号,在回归问题中,返回函数值。

另外:

对输入图片进行行人检测时由于图片的大小不一样,所以要用到多尺度检测。这里是用hog类的方法detectMultiScale。参数解释如下:

HOGDescriptor::detectMultiScale(const
GpuMat& img,
vector<Rect>& found_locations,
doublehit_threshold=0,
Size win_stride=Size(),
Size padding=Size(),
double scale0=1.05,
int group_threshold=2)

myHOG.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);//对图片进行多尺度行人检测
该函数表示对输入的图片img进行多尺度行人检测 img为输入待检测的图片;found_locations为检测到目标区域列表;参数3为程序内部计算为行人目标的阈值,也就是检测到的特征到SVM分类超平面的距离;参数4为滑动窗口每次移动的距离。它必须是块移动的整数倍;参数5为图像扩充的大小;参数6为比例系数,即滑动窗口每次增加的比例;参数7为组阈值,即校正系数,当一个目标被多个窗口检测出来时,该参数此时就起了调节作用,为0时表示不起调节作用。

5)获得支持向量

除了分类,也可以得到SVM的支持向量,调用函数CvSVM::get_support_vector_count获得支持向量的个数,

CvSVM::get_support_vector获得对应的索引编号的支持向量。
6)获取决策函数中的alpha向量
CvSVM::get_alpha_vector()

7)获取偏移量

CvSVM::get_rho

——结论——

▪决策函数为【rho-w*x】,大于0表示正样本,小于0表示负样本

其中w=alpha*sv;

alpha中存放每个支持向量的权重,sv表示每个支持向量

w为加权后的支持向量
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: