OpenCV支持向量机(SVM)介绍

支持向量机(SVM)介绍

目标

本文档尝试解答如下问题:

什么是支持向量机(SVM)?

支持向量机 (SVM) 是一个类分类器,正式的定义是一个能够将不同类样本在样本空间分隔的超平面。 换句话说,给定一些标记(label)好的训练样本 (监督式学习), SVM算法输出一个最优化的分隔超平面。

如何来界定一个超平面是不是最优的呢? 考虑如下问题:

假设给定一些分属于两类的2维点,这些点可以通过直线分割, 我们要找到一条最优的分割线.

Note

在这个示例中,我们考虑卡迪尔平面内的点与线,而不是高维的向量与超平面。 这一简化是为了让我们以更加直觉的方式建立起对SVM概念的理解, 但是其基本的原理同样适用于更高维的样本分类情形。

在上面的图中, 你可以直觉的观察到有多种可能的直线可以将样本分开。 那是不是某条直线比其他的更加合适呢? 我们可以凭直觉来定义一条评价直线好坏的标准:

距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性较差。 因此我们的目标是找到一条直线,离所有点的距离最远。

由此, SVM算法的实质是找出一个能够将某个值最大化的超平面,这个值就是超平面离所有训练样本的最小距离。这个最小距离用SVM术语来说叫做 间隔(margin) 。 概括一下,最优分割超平面 最大化 训练数据的间隔。

如何计算最优超平面?

下面的公式定义了超平面的表达式:

 叫做 权重向量 ,  叫做 偏置(bias) 。

See also

关于超平面的更加详细的说明可以参考T. Hastie, R. Tibshirani 和 J. H. Friedman的书籍 Elements of Statistical Learning , section 4.5 (Seperating Hyperplanes)。

最优超平面可以有无数种表达方式,即通过任意的缩放  和  。 习惯上我们使用以下方式来表达最优超平面

式中  表示离超平面最近的那些点。 这些点被称为 支持向量**。 该超平面也称为 **canonical 超平面.

通过几何学的知识,我们知道点  到超平面  的距离为:

特别的,对于 canonical 超平面, 表达式中的分子为1,因此支持向量到canonical 超平面的距离是

刚才我们介绍了间隔(margin),这里表示为 , 它的取值是最近距离的2倍:

最后最大化  转化为在附加限制条件下最小化函数  。 限制条件隐含超平面将所有训练样本  正确分类的条件,

式中  表示样本的类别标记。

这是一个拉格朗日优化问题,可以通过拉格朗日乘数法得到最优超平面的权重向量  和偏置  。

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>

using namespace cv;

int main()
{
    // Data for visual representation
    int width = 512, height = 512;
    Mat image = Mat::zeros(height, width, CV_8UC3);

    // Set up training data
    float labels[4] = {1.0, -1.0, -1.0, -1.0};
    Mat labelsMat(3, 1, CV_32FC1, labels);

    float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
    Mat trainingDataMat(3, 2, CV_32FC1, trainingData);

    // Set up SVM‘s parameters
    CvSVMParams params;
    params.svm_type    = CvSVM::C_SVC;
    params.kernel_type = CvSVM::LINEAR;
    params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

    // Train the SVM
    CvSVM SVM;
    SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);

    Vec3b green(0,255,0), blue (255,0,0);
    // Show the decision regions given by the SVM
    for (int i = 0; i < image.rows; ++i)
        for (int j = 0; j < image.cols; ++j)
        {
            Mat sampleMat = (Mat_<float>(1,2) << i,j);
            float response = SVM.predict(sampleMat);

            if (response == 1)
                image.at<Vec3b>(j, i)  = green;
            else if (response == -1)
                 image.at<Vec3b>(j, i)  = blue;
        }

    // Show the training data
    int thickness = -1;
    int lineType = 8;
    circle( image, Point(501,  10), 5, Scalar(  0,   0,   0), thickness, lineType);
    circle( image, Point(255,  10), 5, Scalar(255, 255, 255), thickness, lineType);
    circle( image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
    circle( image, Point( 10, 501), 5, Scalar(255, 255, 255), thickness, lineType);

    // Show support vectors
    thickness = 2;
    lineType  = 8;
    int c     = SVM.get_support_vector_count();

    for (int i = 0; i < c; ++i)
    {
        const float* v = SVM.get_support_vector(i);
        circle( image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(128, 128, 128), thickness, lineType);
    }

    imwrite("result.png", image);        // save the image 

    imshow("SVM Simple Example", image); // show it to the user
    waitKey(0);

}

解释

  1. 建立训练样本

本例中的训练样本由分属于两个类别的2维点组成, 其中一类包含一个样本点,另一类包含三个点。

float labels[4] = {1.0, -1.0, -1.0, -1.0};
float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}};

函数 CvSVM::train 要求训练数据储存于float类型的 Mat 结构中, 因此我们定义了以下矩阵:

Mat trainingDataMat(3, 2, CV_32FC1, trainingData);
Mat labelsMat      (3, 1, CV_32FC1, labels);
  1. 设置SVM参数

    此教程中,我们以可线性分割的分属两类的训练样本简单讲解了SVM的基本原理。 然而,SVM的实际应用情形可能复杂得多 (比如非线性分割数据问题,SVM核函数的选择问题等等)。 总而言之,我们需要在训练之前对SVM做一些参数设定。 这些参数保存在类 CvSVMParams 中。

    CvSVMParams params;
    params.svm_type    = CvSVM::C_SVC;
    params.kernel_type = CvSVM::LINEAR;
    params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
    
    • SVM类型. 这里我们选择了 CvSVM::C_SVC 类型,该类型可以用于n-类分类问题 (n  2)。 这个参数定义在 CvSVMParams.svm_type 属性中.

      Note

      CvSVM::C_SVC 类型的重要特征是它可以处理非完美分类的问题 (及训练数据不可以完全的线性分割)。在本例中这一特征的意义并不大,因为我们的数据是可以线性分割的,我们这里选择它是因为它是最常被使用的SVM类型。

    • SVM 核类型. 我们没有讨论核函数,因为对于本例的样本,核函数的讨论没有必要。然而,有必要简单说一下核函数背后的主要思想, 核函数的目的是为了将训练样本映射到更有利于可线性分割的样本集。 映射的结果是增加了样本向量的维度,这一过程通过核函数完成。 此处我们选择的核函数类型是 CvSVM::LINEAR 表示不需要进行映射。 该参数由 CvSVMParams.kernel_type 属性定义。
    • 算法终止条件. SVM训练的过程就是一个通过 迭代 方式解决约束条件下的二次优化问题,这里我们指定一个最大迭代次数和容许误差,以允许算法在适当的条件下停止计算。 该参数定义在 cvTermCriteria 结构中。
  2. 训练支持向量机

    调用函数 CvSVM::train 来建立SVM模型。

    CvSVM SVM;
    SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
    
  3. SVM区域分割

函数 CvSVM::predict 通过重建训练完毕的支持向量机来将输入的样本分类。 本例中我们通过该函数给向量空间着色, 及将图像中的每个像素当作卡迪尔平面上的一点,每一点的着色取决于SVM对该点的分类类别:绿色表示标记为1的点,蓝色表示标记为-1的点。

Vec3b green(0,255,0), blue (255,0,0);

for (int i = 0; i < image.rows; ++i)
    for (int j = 0; j < image.cols; ++j)
    {
    Mat sampleMat = (Mat_<float>(1,2) << i,j);
    float response = SVM.predict(sampleMat);

    if (response == 1)
       image.at<Vec3b>(j, i)  = green;
    else
    if (response == -1)
       image.at<Vec3b>(j, i)  = blue;
    }
  1. 支持向量

    这里用了几个函数来获取支持向量的信息。 函数 CvSVM::get_support_vector_count 输出支持向量的数量,函数 CvSVM::get_support_vector 根据输入支持向量的索引来获取指定位置的支持向量。 通过这一方法我们找到训练样本的支持向量并突出显示它们。

    int c     = SVM.get_support_vector_count();
    
    for (int i = 0; i < c; ++i)
    {
    const float* v = SVM.get_support_vector(i); // get and then highlight with grayscale
    circle(   image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(128, 128, 128), thickness, lineType);
    }
    

结果

  • 程序创建了一张图像,在其中显示了训练样本,其中一个类显示为白色圆圈,另一个类显示为黑色圆圈。
  • 训练得到SVM,并将图像的每一个像素分类。 分类的结果将图像分为蓝绿两部分,中间线就是最优分割超平面。
  • 最后支持向量通过灰色边框加重显示。

翻译者

[email protected] OpenCV中文网站 <[email protected]>

from: http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms

时间: 2024-10-06 21:19:46

OpenCV支持向量机(SVM)介绍的相关文章

opencv 支持向量机SVM分类器

支持向量机SVM是从线性可分情况下的最优分类面提出的.所谓最优分类,就是要求分类线不但能够将两类无错误的分开,而且两类之间的分类间隔最大,前者是保证经验风险最小(为0),而通过后面的讨论我们看到,使分类间隔最大实际上就是使得推广性中的置信范围最小.推广到高维空间,最优分类线就成为最优分类面. 支持向量机是利用分类间隔的思想进行训练的,它依赖于对数据的预处理,即,在更高维的空间表达原始模式.通过适当的到一个足够高维的非线性映射,分别属于两类的原始数据就能够被一个超平面来分隔.如下图所示: 空心点和

OpenCV 2.4+ C++ SVM介绍

转自:http://www.cnblogs.com/justany/archive/2012/11/23/2784125.html opencv中svm的使用方法 分类器 分类器是一种计算机程序. 他的设计目标是在通过学习后,可自动将数据分到已知类别. 平面线性分类器 一个简单的分类问题,如图有一些圆圈和一些正方形,如何找一条最优的直线将他们分开? 我们可以找到很多种方法画出这条直线,但怎样的直线才是最优的呢? 距离样本太近的直线不是最优的,因为这样的直线对噪声敏感度高,泛化性较差. 因此我们的

opencv使用svm

作者 群号 C语言交流中心 240137450  微信 15013593099 OpenCV开发SVM算法是基于LibSVM软件包开发的,LibSVM是台湾大学林智仁(LinChih-Jen)等开发设计的一个简单.易于使用和快速有效的SVM模式识别与回归的软件包.用OpenCV使用SVM算法的大概流程是 1)设置训练样本集 需要两组数据,一组是数据的类别,一组是数据的向量信息. 2)设置SVM参数 利用CvSVMParams类实现类内的成员变量svm_type表示SVM类型: CvSVM::C_

支持向量机(SVM)(二)-- 拉格朗日对偶(Lagrange duality)

简介: 1.在之前我们把要寻找最优的分割超平面的问题转化为带有一系列不等式约束的优化问题.这个最优化问题被称作原问题.我们不会直接解它,而是把它转化为对偶问题进行解决. 2.为了使问题变得易于处理,我们的方法是把目标函数和约束全部融入一个新的函数,为了使问题变得易于处理,我们的方法是把目标函数和约束全部融入一个新的函数,即拉格朗日函数,再通过这个函数来寻找最优点.即拉格朗日函数,再通过这个函数来寻找最优点. 3.约束条件可以分成不等式约束条件和等式约束条件,只有等式约束条件的问题我们在高等数学课

机器学习与数据挖掘-支持向量机(SVM)(一)

最近在看斯坦福大学的机器学习的公开课,学习了支持向量机,再结合网上各位大神的学习经验总结了自己的一些关于支持向量机知识. 一.什么是支持向量机(SVM)? 1.支持向量机(Support Vector Machine,常简称为SVM)是一种监督式学习的方法,可广泛地应用于统计分类以及回归分析.支持向量机属于一般化线性分类器,这族分类器的特点是他们能够同时最小化经验误差与最大化几何边缘区,因此支持向量机也被称为最大边缘区分类器. 2.支持向量机将向量映射到一个更高维的空间里,在这个空间里建立有一个

opencv的svm学习_1

概述 本篇是对opencv的svm学习笔记,基于对opencv官方svm教程的修改和记录.opencv的svm教程如下: 官网原版:http://docs.opencv.org/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html#introductiontosvms 汉语翻译版:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/ml/introductio

【转载】支持向量机SVM(一)

支持向量机SVM(一) [转载请注明出处]http://www.cnblogs.com/jerrylead 1 简介 支持向量机基本上是最好的有监督学习算法了.最开始接触SVM是去年暑假的时候,老师要求交<统计学习理论>的报告,那时去网上下了一份入门教程,里面讲的很通俗,当时只是大致了解了一些相关概念.这次斯坦福提供的学习材料,让我重新学习了一些SVM知识.我看很多正统的讲法都是从VC 维理论和结构风险最小原理出发,然后引出SVM什么的,还有些资料上来就讲分类超平面什么的.这份材料从前几节讲的

关于支持向量机(SVM)一些不得不说的话

做为一种监督学习模型,支持向量机(Supprot Vector Machine)在机器学习领域内很重要.首先,SVM用来干什么?一句话将,就是分类(Classification).比较简单的分类,比如线性分类.Logistic 回归等等,得到的分类结果未必是最优的.而SVM则旨在找到一个最优的分类器.从这个目的出发,SVM提出了Soft Margin,Support Vector等等看似很直观的概念. 对支持向量机的介绍,往往从线性模型开始讲起.如果想对这个部分有一个了解,有两个英文的资料绝对值

数据挖掘入门系列教程(八点五)之SVM介绍以及从零开始推导公式

目录 SVM介绍 线性分类 间隔 最大间隔分类器 拉格朗日乘子法(Lagrange multipliers) 拉格朗日乘子法推导 KKT条件(Karush-Kuhn-Tucker Conditions) 拉格朗日乘子法对偶问题 Slater 条件 最大间隔分类器与拉格朗日乘子法 核技巧 核函数 软间隔 软间隔支持向量机推导 SMO算法 SMO变量的选择方法 总结 参考 还是老规矩,这一篇博客是对SVM进行介绍,下一篇博客就是使用SVM进行具体的使用. SVM介绍 首先介绍SVM是什么,SVM(s