(转载请注明出处:http://blog.csdn.net/zhazhiqiang/ 未经允许请勿用于商业用途)
一、理论
参考网友的博客:
总结:
1、SVM是一个分类器(Classifier) ,也可以做回归 (Regression) 。
2、SVM的主要思想可以概括为两点:
(1)它是针对线性可分情况进行分析,对于线性不可分的情况,通过使用非线性映射算法将低维输入空间线性不可分的样本转化为高维特征空间使其线性可分,从而 使得高维特征空间采用线性算法对样本的非线性特征进行线性分析成为可能;
(2)它基于结构风险最小化理论之上在特征空间中建构最优分割超平面,使得学习器得到全局最优化,并且在整个样本空间的期望风险以某个概率满足一定上界。
3、最优超平面:使得每一类数据与超平面距离最近的向量与超平面之间的距离最大的这样的平面。
4、支持向量:那些在间隔区边缘的训练样本点。
5、核函数:SVM的关键在于核函数。简单说就是将低维空间线性不可分的样本转化为高维空间线性可分的。低维空间向量集通常难于划分,解决的方法是将它们映射到高维空间。但这个办法带来的困难就是计算复杂度的增加,而核函数正好巧妙地解决了这个问题。也就是说,只要选用适当的核函数,就可以得到高维空间的分类函数。在SVM理论中,采用不同的核函数将导致不同的SVM算法。在确定了核函数之后,由于确定核函数的已知数据也存在一定的误差,考虑到推广性问题,因此引入了松弛系数以及惩罚系数两个参变量来加以校正。在确定了核函数基础上,再经过大量对比实验等将这两个系数取定,该项研究就基本完成,适合相关学科或业务内应用,且有一定能力的推广性。当然误差是绝对的,不同学科、不同专业的要求不一。
<5-1>径向基(RBF)核函数(高斯核函数) 的说明
这个核函数可以将原始空间映射到无穷维空间。对于参数σ,如果选的很大,高次特征上的权重实际上衰减得非常快,所以实际上(数值上近似一下)相当于一个低维的子空间;反过来,如果选得很小,则可以将任意的数据映射为线性可分——当然,这并不一定是好事,因为随之而来的可能是非常严重的过拟合问题。不过,总的来说,通过调控参数
<5-2>径向基(RBF)核函数的参数选取
径向基(RBF)核函数主要确定惩罚因子C和参数σ。其中C控制着使间隔margin最大且错误率最小的折中,就是在确定的特征空间中调节学习机器的置信范围和经验风险的比例;而σ2是RBF核函数参数,主要影响样本数据在高维特征空间中分布的复杂程度。因此分类器的好坏取决于参数C、σ的确定。参数选择的好坏直接影响到分类器性能的好坏,但这方面目前缺乏理论指导,没有合适的方法,传统的参数选取都是通过反复的试验,人工选取令人满意的解。这种方法需要人的经验指导,并且需要付出较高的时间代价。常用的参数选择方法有: I、网格法【OpenCV中SVM用到】
选取U个C和V个σ2,就会有 II、双线性法
利用RBF核SVM的性能,首先对线性SVM求解最佳参数,使之为参数的线性SVM推广识别率最高,称为
的 III、梯度下降搜索法 设泛化误差为
核函数为
其中 IV、遗传算法 基本步骤为: a t=0 b 随机选择初始种群P(t) c 计算个体适应度函数值F(t) d 若种群中最优个体所对应的适应度函数值足够大或者算法已经连续运行多代,且个体的最佳适应度无明显改进则转到第h步 e t=t+1 f 应用选择算子法从P(t-1)中选择P(t) g 对P(t)进行交叉、变异操作,转到第c步 h 给出最佳的核函数参合和惩罚因子C,并用其训练数据集以获得全局最优分类面。 遗传算法的缺点是收敛很慢,容易受局部极小值干扰。 <5-3>验证核函数性能的方法(3种)(衡量泛化能力) I、单一验证估计 将大数量的样本分为两部分:训练样本和测试样本,此时测试集的错误率为:
式中,p为样本数, II、K折交叉验证【OpenCV中SVM用到】
K折交叉验证是一种迭代方式,一共迭代K次,每次将所有训练样本分为K份相等的子集样本,训练样本是选择其中K-1份样本,测试样本是剩余的一个样本。通过K次迭代后,可以利用平均值来评估期望泛化误差,根据期望泛化误差选择一组性能最佳的参数。K折交叉验证由K折交叉验证误差决定,K折交叉验证误差是算法错误率的估计,其计算方式为:假设 III、留一法 留一法是K折交叉验证的特例,其基本思想是当可用样本数为N时,训练集由其中N-1个样本构成,测试样本为剩余的一个样本,经N次重复,使所有的样本都参加过测试。通过理论证明,这种估计是无偏估计。因此,从实现原理来说,留一法的效果是最佳的;但是,在参数固定的情况下,确定其错误率对样本要训练N-1次,运算量很大。为了解决留一法计算量大的缺陷,目前该方法确定核函数及其参数的常用方法是估计经验风险的上界,只要上界小,分类器的推广能力就强。
二、OpenCV中SVM的参数和函数说明
1、训练参数结构体 CvSVMParams(可参考【OpenCV2.4】SVM的参数和函数介绍)
(1)注意:该结构必须被初始化后,传给CvSVM
(2)构造函数的原型:
C++: CvSVMParams::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 ) (3)注释A. 默认的构造函数初始化有以下值:
CvSVMParams::CvSVMParams() : svm_type(CvSVM::C_SVC), kernel_type(CvSVM::RBF), degree(0), gamma(1), coef0(0), C(1), nu(0), p(0), class_weights(0) { term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON ); } <1>svm_type:指定SVM的类型(5种):
<2>kernel_type:SVM的内核类型(4种):
![]()
![]()
![]()
![]() <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的迭代训练过程的中止条件,解决部分受约束二次最优问题。您可以指定的公差和/或最大迭代次数。
2、支持向量机CvSVM类(8个函数)
(1)构造函数
<1>构造函数的原型
C++: CvSVM::CvSVM() C++: CvSVM::CvSVM(const Mat& trainData, const Mat& responses, const Mat& varIdx=Mat(), const Mat& sampleIdx=Mat(), CvSVMParams params=CvSVMParams() ) C++: CvSVM::CvSVM(const CvMat* trainData, const CvMat* responses, const CvMat* varIdx=0, const CvMat* sampleIdx=0, CvSVMParams params=CvSVMParams() )
<1>作用:训练一个SVM
<2>训练函数的原型
C++: bool CvSVM::train(const Mat& trainData, const Mat& responses, const Mat& varIdx=Mat(), const Mat& sampleIdx=Mat(), CvSVMParams params=CvSVMParams() ) C++: bool CvSVM::train(const CvMat* trainData, const CvMat* responses, const CvMat* varIdx=0, const CvMat* sampleIdx=0, CvSVMParams params=CvSVMParams() ) 和构造函数的参数是一样的,请参考构造函数的参数注释。
(3)自动训练函数
<1>作用:根据可选参数训练一个SVM。
<2>自动训练函数原型
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 ) C++: bool CvSVM::train_auto(const CvMat* trainData, const CvMat* responses, const CvMat* varIdx, const CvMat* sampleIdx, CvSVMParams params, int kfold=10, CvParamGrid Cgrid=get_default_grid(CvSVM::C), CvParamGrid gammaGrid=get_default_grid(CvSVM::GAMMA), CvParamGrid pGrid=get_default_grid(CvSVM::P), CvParamGrid nuGrid=get_default_grid(CvSVM::NU), CvParamGrid coeffGrid=get_default_grid(CvSVM::COEF), CvParamGrid degreeGrid=get_default_grid(CvSVM::DEGREE), bool balanced=false )
<4>自动训练函数的使用说明
<5>网格搜索法+K交叉验证
上述使用说明是OpenCV使用文档中的,这里再加其他一些补充:
B、优化参数的方式一般是用网格搜索法取值,然后对这组参数进行K交叉验证,计算精确值(交叉验证的准确率等于能够被正确分类的数量百分比),寻求最优参数。
(4)预测函数
<1>作用:对输入样本做预测响应。
<2>预测函数的函数原型
C++: float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const C++: float CvSVM::predict(const CvMat* sample, bool returnDFVal=false ) const C++: float CvSVM::predict(const CvMat* samples, CvMat* results) const <3>预测函数的参数注释
<4>预测函数的使用说明
<1>作用: 生成一个SVM网格参数。
<2>函数原型
C++: CvParamGrid CvSVM::get_default_grid(int param_id)
<3>函数的参数注释
<4>函数的使用说明
该函数生成一个指定的SVM网格参数,主要用于传递给自动训练函数CvSVM::train_auto()。
(6)获取当前SVM参数的函数
<1>作用:获取当前SVM参数
<2>函数原型:
C++: CvSVMParams CvSVM::get_params() const
<3>函数的使用说明
这个函数主要是在使用CvSVM::train_auto()时去获得最佳参数。
(7)获取支持向量及其数量的函数
<1>作用:获取支持向量及其数量
<2>函数原型:
C++: int CvSVM::get_support_vector_count() const //获取支持向量的数量 C++: const float* CvSVM::get_support_vector(int i) const //获取支持向量 参数:i – 指定支持向量的索引。
(8)获取所用特征的数量的函数 <1>作用:获取所用特征的数量 <2>函数原型: 三、OpenCV的简单的程序例子
上述讲述了处理一个线性可分情况的例子,包含了SVM使用的几个步骤:
(1)准备训练样本及其类别标签(trainingDataMat,labelsMat)
(2)设置训练参数(CvSVMParams)
(3)对SVM进行训练(CvSVM::train)
(4)对新的输入样本进行预测(CvSVM::predict)
(5)获取支持向量(CvSVM::get_support_vector_count,CvSVM::get_support_vector )
上述讲述了处理一个线性不可分情况的例子,着重讲述了惩罚因子C的作用:
换而言之,C越大,优化时越关注错分问题;C越小,越关注能否产生一个较大间隔的超平面。
3、多分类的简单例子(可参考利用SVM解决2维空间向量的3级分类问题)
上述讲述了一个三分类的例子,核函数用了RBF,并用到了其参数gamma,以及惩罚因子C,训练与预测和二分类一样,只要对样本赋予第三类的类别标签。
4、文字识别的简单例子(可参考SVM对文字识别的简单使用和使用OPENCV训练手写数字识别分类器)
训练与预测的使用方法和上述一样,主要看下对图像数据的处理(简单的特征提取)。
5、HOG+SVM的例子(可参考OpenCV中的HOG+SVM物体分类和利用HOG+SVM训练自己的XML文件)
训练与预测的使用方法还是和上述一样,主要看下Hog特征的使用(HOGDescriptor::compute)。
四、SVM处理流程总结:
1、收集数据,相关性分析(比如p卡方检验),特征选择(比如主成份分析PCA)。
2、归一化数据:就是根据实际要求,将数据的取值范围转化为统一的区间如[a,b],a,b为整数。(参考缩放训练和测试数据时的常见错误[附录B])
3、分训练集和测试集:利用抽样技术将数据集分为训练集和测试集。抽样技术有分层抽样,简单抽样(等概率抽样)。一般训练集数量大于测试集数量,就是要保证足够的训练样例。
4、将数据转化为软件(接口)所支持的格式。
5、选择核函数,可以优先考虑RBF。
6、使用交叉验证(cross-validation)寻找最佳参数C和Υ:对训练集利用交叉验证法选择最好的参数C和r(西格玛)(RBF核函数中的参数gama)。可以通过网格法寻找出最优的参数,注意一次交叉验证得到一个参数对所对应的模型精度,网格法目的就是找到使得模型精度达到对高的参数对(这里的参数对可能不止两个,有可能也有其他的),可以使用一些启发式的搜索来降低复杂度,虽然这个方法笨了点,但是它能得到很稳定的搜索结果。需要提到的这里在对训练集进行分割的时候涉及到抽样,一个较好的方法就是分层抽样。从这步可以看出其实
Cross-Validation是一种评估算法的方法。
a. 训练的目的得到参数和支持向量(存储在xml文件中),得到参数就能得到支持向量,带进算式计算SVM分类的准确度,以准确度最高的一组参数作为最终的结果,没有绝对线性可分的,都有一个误差,参数就是把那个误差降到最低。 b. 这里的准确性是指将训练集的每个样本的向量与支持向量做运算,将运算结果与标记值比较,判断是否属于这个类,统计这个类的正确的样本数,最高的那一组参数准确性最高。 c. 最终训练得到分类器。SVM只能分两类,所以这里的分类器是两个类组成一个分类器,如果有K类,就有k(k-1)/2个分类器。
7、使用最佳参数C和Υ来训练整个训练集:用6中得到的参数对在整个训练集合上进行训练,从而得出模型。
8、测试:利用测试集测试模型,得到精度。这个精度可以认为是模型最终的精度。当然有人会担心3步中抽样会有一定的误差,导致8得到的精度不一定是最好的,因此可以重复3-8得到多个模型的精度,然后选择最好的一个精度最为模型的精度(或者求所有精度的均值做为模型精度)。(需要多次选择训练集和测试集,然后每一次得到一个精度的模型,选择最好的一个精度作为模型,也就是我们项目里面要多次训练的原因)。
9. 识别分类:两个类超平面的形成,意味着目标函数的形成,然后代入待识别样本,识别时对应的组代入对应的参数,得出结果进行投票,判定属于那个类。
|
|