SVM:从理论到OpenCV实践
(转载请注明出处:http://blog.csdn.net/zhazhiqiang/ 未经允许请勿用于商业用途)
常用的核函数有以下4种:⑴线性核函数⑵多项式核函数⑶径向基(RBF)核函数(高斯核函数)⑷Sigmoid核函数(二层神经网络核函数)
<5-1>径向基(RBF)核函数(高斯核函数) 的说明
这个核函数可以将原始空间映射到无穷维空间。对于参数σ,如果选的很大,高次特征上的权重实际上衰减得非常快,所以实际上(数值上近似一下)相当于一个低维的子空间;反过来,如果选得很小,则可以将任意的数据映射为线性可分——当然,这并不一定是好事,因为随之而来的可能是非常严重的过拟合问题。不过,总的来说,通过调控参数,高斯核实际上具有相当高的灵活性,也是使用最广泛的核函数之一。
径向基(RBF)核函数主要确定惩罚因子C和参数σ。其中C控制着使间隔margin最大且错误率最小的折中,就是在确定的特征空间中调节学习机器的置信范围和经验风险的比例;而σ2是RBF核函数参数,主要影响样本数据在高维特征空间中分布的复杂程度。因此分类器的好坏取决于参数C、σ的确定。参数选择的好坏直接影响到分类器性能的好坏,但这方面目前缺乏理论指导,没有合适的方法,传统的参数选取都是通过反复的试验,人工选取令人满意的解。这种方法需要人的经验指导,并且需要付出较高的时间代价。常用的参数选择方法有:
I、网格法【OpenCV中SVM用到】
选取U个C和V个σ2,就会有的组合状态,每种组合状态对应一种SVM分类器,通过测试对比,找出推广识别率最高的C和σ2组合。一般取U=V=15,C取值分别为,取值分别为共255个C、σ2组合。网格法实质上是一种穷举法,随着排列组合的可能情况越多,其运算量将急剧增加。
II、双线性法
利用RBF核SVM的性能,首先对线性SVM求解最佳参数,使之为参数的线性SVM推广识别率最高,称为;然后固定,对满足
的,训练SVM,根据对其推广识别率的估算,得到最优参数。虽然这种方法对σ2有非常明确的公式,但首先要求解C,而很难确定最优的C。
III、梯度下降搜索法
设泛化误差为
核函数为,是待定的核参数,基本过程为:
a 将θ置一个初始值
b 用一个标准的SVM解法(如SMO),求出SVM的解——Lagrange乘子
c
d 跳转到b直至T最小
其中是足够小且最终收敛到零的数列。步骤c是一个标准的梯度下降算法。由分类函数公式可以求解,的求解较麻烦,需要通过求解一个二次规划问题得到。
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折交叉验证误差是算法错误率的估计,其计算方式为:假设为错分类的样本个数,经过K次迭代后,得到,那么算法的错误率可以近似为错误分类数和总样本点数之比。该方法具有操作简单的优点,成为目前应用最广泛的方法,但是这种方法容易受样本划分方式的影响。
III、留一法
留一法是K折交叉验证的特例,其基本思想是当可用样本数为N时,训练集由其中N-1个样本构成,测试样本为剩余的一个样本,经N次重复,使所有的样本都参加过测试。通过理论证明,这种估计是无偏估计。因此,从实现原理来说,留一法的效果是最佳的;但是,在参数固定的情况下,确定其错误率对样本要训练N-1次,运算量很大。为了解决留一法计算量大的缺陷,目前该方法确定核函数及其参数的常用方法是估计经验风险的上界,只要上界小,分类器的推广能力就强。
(1)注意:该结构必须被初始化后,传给CvSVM
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)注释
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 );
}
B. 构造函数的参数(一共10个):
- 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::POLY : 多项式内核:
- CvSVM::RBF : 基于径向的函数,对于大多数情况都是一个较好的选择:
- CvSVM::SIGMOID : Sigmoid函数内核:
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()
)
<2>构造函数的参数注释(5个)
- trainData: 训练数据,必须是CV_32FC1 (32位浮点类型,单通道)。数据必须是CV_ROW_SAMPLE的,即特征向量以行来存储。
- responses: 响应数据,通常是1D向量存储在CV_32SC1 (仅仅用在分类问题上)或者CV_32FC1格式。
- varIdx: 指定感兴趣的特征。可以是整数(32sC1)向量,例如以0为开始的索引,或者8位(8uC1)的使用的特征或者样本的掩码。用户也可以传入NULL指针,用来表示训练中使用所有变量/样本。
- sampleIdx: 指定感兴趣的样本。描述同上。
- params: 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>训练函数的参数注释(5个)
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
)
<3>自动训练函数的参数注释(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。
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>预测函数的参数注释
- sample: 需要预测的输入样本。
- samples: 需要预测的输入样本们。
- returnDFVal: 指定返回值类型。如果值是true,则是一个2类分类问题,该方法返回的决策函数值是边缘的符号距离。
- results: 相应的样本输出预测的响应。
- 这个函数用来预测一个新样本的响应数据(response)。
- 在分类问题中,这个函数返回类别编号;在回归问题中,返回函数值。
- 输入的样本必须与传给trainData的训练样本同样大小。
- 如果训练中使用了varIdx参数,一定记住在predict函数中使用跟训练特征一致的特征。
- 后缀const是说预测不会影响模型的内部状态,所以这个函数可以很安全地从不同的线程调用。
(5)生成SVM网格参数的函数
C++: CvParamGrid CvSVM::get_default_grid(int param_id)
- param_id: SVM参数的IDs必须是下列中的一个:(网格参数将根据这个ID生成 )
- CvSVM::C
- CvSVM::GAMMA
- CvSVM::P
- CvSVM::NU
- CvSVM::COEF
- CvSVM::DEGREE
C++: CvSVMParams CvSVM::get_params() const
这个函数主要是在使用CvSVM::train_auto()时去获得最佳参数。
C++: int CvSVM::get_support_vector_count() const //获取支持向量的数量
C++: const float* CvSVM::get_support_vector(int i) const //获取支持向量
参数:i – 指定支持向量的索引。
(8)获取所用特征的数量的函数
<1>作用:获取所用特征的数量
<2>函数原型:
C++: int CvSVM::get_var_count() const
- C比较大时:分类错误率较小,但是间隔也较小。 在这种情形下, 错分类对模型函数产生较大的影响,既然优化的目的是为了最小化这个模型函数,那么错分类的情形必然会受到抑制。
- C比较小时:间隔较大,但是分类错误率也较大。 在这种情形下,模型函数中错分类之和这一项对优化过程的影响变小,优化过程将更加关注于寻找到一个能产生较大间隔的超平面。
由于样本非线性可分, 自然就有一些被错分类的样本。
四、SVM处理流程总结:
a. 训练的目的得到参数和支持向量(存储在xml文件中),得到参数就能得到支持向量,带进算式计算SVM分类的准确度,以准确度最高的一组参数作为最终的结果,没有绝对线性可分的,都有一个误差,参数就是把那个误差降到最低。
b. 这里的准确性是指将训练集的每个样本的向量与支持向量做运算,将运算结果与标记值比较,判断是否属于这个类,统计这个类的正确的样本数,最高的那一组参数准确性最高。
c. 最终训练得到分类器。SVM只能分两类,所以这里的分类器是两个类组成一个分类器,如果有K类,就有k(k-1)/2个分类器。
SVM:从理论到OpenCV实践的更多相关文章
- HOG:从理论到OpenCV实践
(转载请注明出处:http://blog.csdn.net/zhazhiqiang/ 未经允许请勿用于商业用途) 一.理论 1.HOG特征描述子的定义: locally normalised ...
- RHCS集群理论暨最佳实践
RHCS集群理论暨 最佳实践 什么是集群? 集群是一组(>2)相互独立的,通过高速网络互联的计算机组成的集合.群集一般可以分为科学集群,负载均衡集群,高可用性集群三大类. 科学集 ...
- Hu矩SVM训练及检测-----OpenCV
关键词:Hu矩,SVM,OpenCV 在图像中进行目标物识别,涉及到特定区域内是否存在目标物,SVM可在样本量较少情况下对正负样本(图片中前景背景)做出良好区分,图片基本特征包括诸如HOG.LBP.H ...
- 支持向量机(SVM)理论总结系列.线性可分(附带R程序案例:用体重和心脏重量来预测一只猫的性别)
附注:不要问我为什么写这么快,是16年写的. 1.名词解释 支持向量机中的机:在机器学习领域,常把一些算法看做一个机器,如分类机(也叫作分类器) 2.问题描述 空间中有很多已知类别的点,现在想用一个面 ...
- 【opencv实践】边缘检测
边缘检测: 一.canny算子 Canny边缘检测根据对信噪比与定位乘积进行测度,得到最优化逼近算子,也就是Canny算子.类似与 LoG 边缘检测方法,也属于先平滑后求导数的方法. 二.canny算 ...
- 【原创 Hadoop&Spark 动手实践 3】Hadoop2.7.3 MapReduce理论与动手实践
开始聊MapReduce,MapReduce是Hadoop的计算框架,我学Hadoop是从Hive开始入手,再到hdfs,当我学习hdfs时候,就感觉到hdfs和mapreduce关系的紧密.这个可能 ...
- OpenCV实践之路——人脸检测(C++/Python) 【转】
转自:http://blog.csdn.net/xingchenbingbuyu/article/details/51105159 版权声明:本文为博主原创文章,转载请联系作者取得授权. 本文由@星沉 ...
- OpenCV实践之路——Python的安装和使用
本文由@星沉阁冰不语出品,转载请注明作者和出处. 文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/50936076 微博:http ...
- opencv实践::对象提取与测量
问题描述 照片是来自太空望远镜的星云图像,科学家想知道它的面 积与周长. 解决思路 方法一: 通过二值分割+图像形态学+轮廓提取 #include <opencv2/opencv.hpp> ...
随机推荐
- P1082 找朋友
描述 童年的我们,对各种事物充满了好奇与向往.这天,小朋友们对数字产生了兴趣,并且想和数字交朋友.可是,怎么分配这些数字才能使得每个小朋友都唯一地找到一个数字朋友呢?C小朋友说:咱们按自己名字的字典序 ...
- Python中itertools模块
itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用. ch ...
- AE CreateFeatureClass 创建shp. 删除shp. 向shp中添加要素
/// <summary> /// 创建多边形shp /// </summary> /// <param name="pPolygon">< ...
- NSDictionary 遍历
NSDictionary *dic1=[NSDictionary dictionaryWithObjectsAndKeys: @"1",@"a", ...
- 控制CPU占用率曲线
编程之美的第一个问题,我的机器是双核的,用文中的代码,得到的曲线波动比较大额,受其他进程的影响比较大.文中提到10ms接近windows的调度时间片,如果选得太小,会造成线程被频繁唤醒和挂起,造成内核 ...
- Servlet编写登录界面
package com.mhb; import java.io.IOException;import java.io.PrintWriter; import javax.servlet.Servlet ...
- 解决Cygwin中vim的backspace不能正常使用(转)
转载于:http://blog.chinaunix.net/uid-20614631-id-1914849.html 亲测可用 先把Cygwin下载下来,想在linux下编程的话一定要安装vim,g ...
- hadoop-0.23.9安装以及第一个mapreduce测试程序
hadoop是一个能够对大量数据进行分布式处理的软件框架.它实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS.HDFS有着高容错性的特点,并且设计 ...
- 富有魅力的git stash
git stash 会把当前的改动暂时搁置起来, 也就是所谓的git 暂存区. 你可以执行 git stash list 来查看你所有暂存的东东. 也可以 git stash apple ** 来拿下 ...
- Android-Universal-Image-Loader
基本以后都不用了,所以自己就不总结了 http://www.cnblogs.com/kissazi2/p/3886563.html http://www.cnblogs.com/kissazi2/p/ ...