学习Opencv2.4.9(四)---SVM支持向量机

作者:咕唧咕唧liukun321

来自:http://blog.csdn.net/liukun321

  • 先来看一下什么是SVM(支持向量机)

SVM是一种训练机器学习的算法,可以用于解决分类和回归问题,同时还使用了一种称之为kernel trick(支持向量机的核函数)的技术进行数据的转换,然后再根据这些转换信息,在可能的输出之中找到一个最优的边界(超平面)。简单来说,就是做一些非常复杂的数据转换工作,然后根据预定义的标签或者输出进而计算出如何分离用户的数据。

支持向量机方法是建立在统计学习理论的VC 维理论和结构风险最小原理基础上的,根据有限的样本信息在模型的复杂性(即对特定训练样本的学习精度,Accuracy)和学习能力(即无错误地识别任意样本的能力)之间寻求最佳折衷,以期获得最好的推广能力(或称泛化能力)。

  • 支持向量机较其他传统机器学习算法的优点:

1、小样本,并不是说样本的绝对数量少(实际上,对任何算法来说,更多的样本几乎总是能带来更好的效果),而是说与问题的复杂度比起来,SVM算法要求的样本数是相对比较少的。SVM解决问题的时候,和样本的维数是无关的(甚至样本是上万维的都可以,这使得SVM很适合用来解决文本分类的问题,当然,有这样的能力也因为引入了核函数)。

2、结构风险最小。(对问题真实模型的逼近与问题真实解之间的误差,就叫做风险,更严格的说,误差的累积叫做风险)。

3、非线性,是指SVM擅长应付样本数据线性不可分的情况,主要通过松弛变量(也有人叫惩罚变量)和核函数技术来实现,这一部分是SVM的精髓。(关于文本分类这个问题究竟是不是线性可分的,尚没有定论,因此不能简单的认为它是线性可分的而作简化处理,在水落石出之前,只好先当它是线性不可分的反正线性可分也不过是线性不可分的一种特例而已,我们向来不怕方法过于通用)。

  • SVM的强大离不开一个很重要的东西--核函数:

1、为何需要核函数?

很多情况下低维空间向量集是难于划分的,解决办法是将它们映射到高维空间。但这个办法带来的艰苦就是策画错杂度的增长,而核函数正好奇妙地解决了这个问题。也就是说,只要选用恰当的核函数,就可以获得高维空间的分类函数(超平面)。在SVM理论中,采取不合的核函数将导致不合的SVM算法。在断定了核函数之后,因为断定核函数的已知数据也存在必然的误差,推敲到推广性题目,是以引入了败坏系数以及处罚系数两个参变量来加以校订。

其实核函数的本质作用可以简练概括为:将低维空间的线性不可分类问题,借助核函数转化为高维空间的线性可分,进而可以在高维空间找到分类的最优边界(超平面)。(下图引自July‘s 支持向量机通俗导论(理解SVM的三层境界))。若要要分类下图红色和蓝色样本点:

              

二维线性不可分                                                                                                                三维线性可分

2、核函数的分类

(1)线性核函数

(2)多项式核函数

(3)径向基(RBF)核函数(高斯核函数)

(4)Sigmoid核函数(二层神经收集核函数)

3、Opencv中的核函数定义:

CvSVM::LINEAR : 线性内核,没有任何向映射至高维空间,线性区分(或回归)在原始特点空间中被完成,这是最快的选择。

.

CvSVM::POLY : 多项式内核:

.

CvSVM::RBF : 基于径向的函数,对于大多半景象都是一个较好的选择:

.

CvSVM::SIGMOID : Sigmoid函数内核:

.

  • Opencv中SVM参数设置:

Opencv中SVM参数设置使用CvSVMParams方法定义如下:

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
)

CvSVMParams方法如果不传自定义参数会按如下代码进行默认初始化:

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 );
}

kernel_type:SVM的内核类型(4种):

上面已经介绍过了就不再多说了。

svm_type:指定SVM的类型(5种):

1、CvSVM::C_SVC : C类支撑向量分类机。 n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。

2、CvSVM::NU_SVC : 类支撑向量分类机。n类似然不完全分类的分类器。参数为庖代C(其值在区间【0,1】中,nu越大,决定计划鸿沟越腻滑)。

3、CvSVM::ONE_CLASS : 单分类器,所有的练习数据提取自同一个类里,然后SVM建树了一个分界线以分别该类在特点空间中所占区域和其它类在特点空间中所占区域。

4、CvSVM::EPS_SVR : 类支撑向量回归机。练习集中的特点向量和拟合出来的超平面的间隔须要小于p。异常值处罚因子C被采取。

5、CvSVM::NU_SVR : 类支撑向量回归机。 庖代了 p。

degree:内核函数(POLY)的参数degree。

gamma:内核函数(POLY/ RBF/ SIGMOID)的参数

coef0:内核函数(POLY/ SIGMOID)的参数coef0。

Cvalue:SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C。

nu:SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数

p:SVM类型(EPS_SVR)的参数

class_weights:C_SVC中的可选权重,赋给指定的类,乘以C今后变成 。所以这些权重影响不合类此外错误分类处罚项。权重越大,某一类此外误分类数据的处罚项就越大。

term_crit:SVM的迭代练习过程的中断前提,解决项目组受束缚二次最优题目。您可以指定的公差和/或最大迭代次数。

  • Opencv中SVM训练函数:
CvSVM::train(const CvMat* trainData,
const CvMat* responses,
const CvMat* varIdx=0,
const CvMat* sampleIdx=0,
CvSVMParams params=CvSVMParams()
)

1、trainData: 练习数据,必须是CV_32FC1 (32位浮点类型,单通道)。数据必须是CV_ROW_SAMPLE的,即特点向量以行来存储。

2、responses: 响应数据,凡是是1D向量存储在CV_32SC1 (仅仅用在分类题目上)或者CV_32FC1格局。

3、varIdx: 指定感爱好的特点。可所以整数(32sC1)向量,例如以0为开端的索引,或者8位(8uC1)的应用的特点或者样本的掩码。用户也可以传入NULL指针,用来默示练习中应用所有变量/样本。

4、sampleIdx: 指定感爱好的样本。描述同上。

5、params: SVM参数。

  • Opencv中的SVM识别(预言)函数:

Opencv的预言函数所有重载如下:

float CvSVM::predict(const Mat& sample, bool returnDFVal=false ) const
float CvSVM::predict(const CvMat* sample, bool returnDFVal=false ) const
float CvSVM::predict(const CvMat* samples, CvMat* results) const

    1、sample: 须要猜测的输入样本。

2、samples: 须要猜测的输入样本们。

3、returnDFVal: 指定返回值类型。若是值是true,则是一个2类分类题目,该办法返回的决定计划函数值是边沿的符号间隔。

4、results: 响应的样本输出猜测的响应。

这个函数用来猜测一个新样本的响应数据(response)。

在分类题目中,这个函数返回类别编号;在回归题目中,返回函数值。

输入的样本必须与传给trainData的练习样本同样大小。

若是练习中应用了varIdx参数,必然记住在predict函数中应用跟练习特点一致的特点。

  • Opencv中SVM分类问题代码流程:

(1)获得练习样本及制作其类别标签(trainingDataMat,labelsMat

(2)设置练习参数(CvSVMParams)

(3)对SVM进行训练(CvSVM::train)

(4)对新的输入样本进行猜测(CvSVM::predict),并输出结果类型(对应标签)

(5)获取支撑向量(CvSVM::get_support_vector_count,CvSVM::get_support_vector )

  • SVM多类分类问题的几种方法:

目前,构造SVM多类分类器的方法主要有两类:一类是直接法,直接在目标函数上进行修改,将多个分类面的参数求解合并到一个最优化问题中,通过求解该最优化问题“一次性”实现多类分类。这种方法看似简单,但其计算复杂度比较高,实现起来比较困难,只适合用于小型问题中;另一类是间接法,主要是通过组合多个二分类器来实现多分类器的构造,常见的方法有one-against-oneone-against-all两种。

1、一对多法(one-versus-rest,简称OVRSVMs)。训练时依次把某个类别的样本归为一类,其他剩余的样本归为另一类,这样k个类别的样本就构造出了k个SVM。分类时将未知样本分类为具有最大分类函数值的那类。

假如我有四类要划分(也就是4个Label),他们是A、B、C、D。于是我在抽取训练集的时候,分别抽取A所对应的向量作为正集,B,C,D所对应的向量作为负集;B所对应的向量作为正集,A,C,D所对应的向量作为负集;C所对应的向量作为正集,A,B,D所对应的向量作为负集;D所对应的向量作为正集,A,B,C所对应的向量作为负集,这四个训练集分别进行训练,然后的得到四个训练结果文件,在测试的时候,把对应的测试向量分别利用这四个训练结果文件进行测试,最后每个测试都有一个结果f1(x),f2(x),f3(x),f4(x).于是最终的结果便是这四个值中最大的一个。

PS:这种方法有种缺陷,因为训练集是1:M,这种情况下存在偏差.因而不是很实用.

2、一对一法(one-versus-one,简称OVOSVMs或者pairwise)。其做法是在任意两类样本之间设计一个SVM,因此k个类别的样本就需要设计k(k-1)/2个SVM。当对一个未知样本进行分类时,最后得票最多的类别即为该未知样本的类别。Libsvm中的多类分类就是根据这个方法实现的。

还是假设有四类A,B,C,D四类。在训练的时候我选择A,B;A,C; A,D; B,C;B,D;C,D所对应的向量作为训练集,然后得到六个训练结果,在测试的时候,把对应的向量分别对六个结果进行测试,然后采取投票形式,最后得到一组结果。

3、层次支持向量机(H-SVMs)。层次分类法首先将所有类别分成两个子类,再将子类进一步划分成两个次级子类,如此循环,直到得到一个单独的类别为止。

4、DAG-SVMS是由Platt提出的决策导向的循环图DDAG导出的,是针对“一对一”SVMS存在误分、拒分现象提出的。

这里仅仅是对几种多分类方法的简要说明,如果直接调用Opencv的predict方法,并不需要关心多分类算法的具体实现,来看看下面的例子:

  • Opencv中SVM多类分类问题编程实例:
#include <cv.h>
#include <highgui.h>
#include <ml.h>
#include <cxcore.h>

#include <iostream>
using namespace std;

int main()
{
 // step 1:
//训练数据的分类标记,即4类
 float labels[16] = {1.0, 1.0,1.0,1.0,2.0,2.0,2.0,2.0,3.0,3.0,3.0,3.0,4.0,4.0,4.0,4.0};
 CvMat labelsMat = cvMat(16, 1, CV_32FC1, labels);
 //训练数据矩阵
 float trainingData[16][2] = { {0, 0}, {4, 1}, {4, 5}, {-1, 6},{3,11},{-2,10},{4,30},{0,25},{10,13},{15,12},{25,40},{11,35},{8,1},{9,6},{15,5},{20,-1} };
 CvMat trainingDataMat = cvMat(16, 2, CV_32FC1, trainingData);

 // step 2:
 //训练参数设定
 CvSVMParams params;
 params.svm_type = CvSVM::C_SVC;                 //SVM类型
 params.kernel_type = CvSVM::LINEAR;             //核函数的类型

 //SVM训练过程的终止条件, max_iter:最大迭代次数  epsilon:结果的精确性
 params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, FLT_EPSILON );

 // step 3:
 //启动训练过程
 CvSVM SVM;
 SVM.train( &trainingDataMat, &labelsMat, NULL,NULL, params);

 // step 4:
 //使用训练所得模型对新样本进行分类测试
 for (int i=-5; i<15; i++)
 {
      for (int j=-5; j<15; j++)
      {
           float a[] = {i,j};
           CvMat sampleMat;
           cvInitMatHeader(&sampleMat,1,2,CV_32FC1,a);
           cvmSet(&sampleMat,0,0,i);                                        // Set M(i,j)
           cvmSet(&sampleMat,0,1,j);                                        // Set M(i,j)
           float response = SVM.predict(&sampleMat);
           cout<<response<<" ";
      }
      cout<<endl;
 }

 // step 5:
 //获取支持向量
 int c = SVM.get_support_vector_count();
 cout<<endl;
 for (int i=0; i<c; i++)
 {
      const float* v = SVM.get_support_vector(i);
      cout<<*v<<" ";
 }
 cout<<endl;

 system("pause");
 return 0;
}

运行结果:

PS: 统计学习泛化误差界的概念,就是指真实风险应该由两部分内容刻画,一是经验风险,代表了分类器在给定样本上的误差;二是置信风险,代表了我们在多大程度上可以信任分类器在未知文本上分类的结果。很显然,第二部分是没有办法精确计算的,因此只能给出一个估计的区间,也使得整个误差只能计算上界,而无法计算准确的值(所以叫做泛化误差界,而不叫泛化误差)。

置信风险与两个量有关,一是样本数量,显然给定的样本数量越大,我们的学习结果越有可能正确,此时置信风险越小;二是分类函数的VC维,显然VC维越大,推广能力越差,置信风险会变大。
泛化误差界的公式为:R(w)≤Remp(w)+Ф(n/h)
公式中R(w)就是真实风险,Remp(w)就是经验风险,Ф(n/h)就是置信风险。统计学习的目标从经验风险最小化变为了寻求经验风险与置信风险的和最小,即结构风险最小。
SVM正是这样一种努力最小化结构风险的算法。

时间: 2024-12-27 22:42:45

学习Opencv2.4.9(四)---SVM支持向量机的相关文章

机器学习算法与Python实践之(四)支持向量机(SVM)实现

机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 [email protected] http://blog.csdn.net/zouxy09 机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学习算法.恰好遇见这本同样定位的书籍,所以就参考这本书的过程来学习了. 在这一节我们主要是

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ml(SVM支持向量机一)

本系列学习笔记参考自OpenCV2.4.10之opencv\sources\samples\cpp\tutorial_code和http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html SVM为支持向量机.它是一个分类器.简单说,SVM是通过我们一组训练样本来对平面进行一个最优的分割. introduction_to_svm.cpp(SVM支持向量机) demo源码和注释如下: #include "stdafx.h" //预

SVM -支持向量机原理详解与实践之二

SVM -支持向量机原理详解与实践之二 SVM原理分析 以下内容接上篇. 拉格朗日对偶性(Largrange duality)深入分析 前面提到了支持向量机的凸优化问题中拉格朗日对偶性的重要性. 因为通过应用拉格朗日对偶性我们可以寻找到最优超平面的二次最优化, 所以以下可以将寻找最优超平面二次最优化(原问题),总结为以下几个步骤: 在原始权重空间的带约束的优化问题.(注意带约束) 对优化问题建立拉格朗日函数 推导出机器的最优化条件 最后就是在对偶空间解决带拉格朗日乘子的优化问题. 注:以上这个四

SVM -支持向量机原理详解与实践之三

SVM -支持向量机原理详解与实践之三 什么是核 什么是核,核其实就是一种特殊的函数,更确切的说是核技巧(Kernel trick),清楚的明白这一点很重要. 为什么说是核技巧呢?回顾到我们的对偶问题:     映射到特征空间后约束条件不变,则为:     在原始特征空间中主要是求,也就是和的内积(Inner Product),也称数量积(Scalar Product)或是点积(Dot Product),映射到特征空间后就变成了求,也就是和的映射到特征空间之后的内积,就如我前面所提到的在原始空间

6-11 SVM支持向量机2

SVM支持向量机的核:线性核.进行预测的时候我们需要把正负样本的数据装载在一起,同时我们label标签也要把正负样本的数据全部打上一个label. 第四步,开始训练和预测.ml(machine learning(机器学习模块)). 原文地址:https://www.cnblogs.com/ZHONGZHENHUA/p/9785154.html

SVM -支持向量机原理详解与实践之四

SVM -支持向量机原理详解与实践之四 SVM原理分析 SMO算法分析 SMO即Sequential minmal optimization, 是最快的二次规划的优化算法,特使对线性SVM和稀疏数据性能更优.在正式介绍SMO算法之前,首先要了解坐标上升法. 坐标上升法(Coordinate ascent) 坐标上升法(Coordinate Ascent)简单点说就是它每次通过更新函数中的一维,通过多次的迭代以达到优化函数的目的. 坐标上升法原理讲解 为了更加通用的表示算法的求解过程,我们将算法表

学习php的第四天

今天是学习php的第四天.由于花了一天的时间来装一个系统,而我对这个也并不是很了解,所以就不再赘述.只学习了如何设置链接. 首先是几个定义..表示当前所在目录,src图片地址.加载超链接 <a href=...>.text-decoration意为链接装饰,用于去除下划线. 下面是代码.我用昨天的导航条为基础,给每个标题都设置了链接.代码如下. <html> <head> <title></title> <style> div{hei

20145320《Java程序设计》第3周学习总结(第四章)

20145320<Java程序设计>第3周学习总结(第四章) 教材学习内容总结 对象(Object):存在的具体实体,具有明确的状态和行为 类(Class):具有相同属性和行为的一组对象的集合,用于组合各个对象所共有操作和属性的一种机制 从类看对象:类定义可以视为一个具有类似特性与共同行为的对象的模板,可用来产生对象 从对象看类:类的产生,是从少数实例,推广到大量相似实例的抽象化过程(abstraction) 类是对象的设计图,对象是类的实例,生成对象要先定义类 4.1 类与对象 定义类使用c

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意