OpenCV 2.4.9 支持向量机(SVM)说明

本文翻译自OpenCV 2.4.9官方文档《opencv2refman.pdf》。

前言

Originally, support vector machines (SVM) was a technique for building an optimal binary (2-class) classifier. Later the technique was extended to regression and clustering problems. SVM is a partial case of kernel-based methods. It maps feature vectors into a higher-dimensional space using a kernel function and builds an optimal linear discriminating function in this space or an optimal hyper-plane that fits into the training data. In case of SVM, the kernel is not defined explicitly. Instead, a distance between any 2 points in the hyper-space needs to be defined. The solution is optimal, which means that the margin between the separating hyper-plane and the nearest feature vectors from both classes (in case of 2-class classifier) is maximal. The feature vectors that are the closest to the hyper-plane are called support vectors, which means that the position of other vectors does not affect the hyper-plane (the decision function). SVM implementation in OpenCV is based on LibSVM.

通常来说,支持向量机(SVM)是一种用来构建一个最优二进制分类器(只分为两类)。后来,这项技术被延伸到回归与集群问题。SVM是以核函数方法为基础的众多方法之一,它通过核函数将特征向量映射到高维空间,并在这个空间创造一个最优线性分类函数,或者创造一个适合所有训练数据的最优超平面。在SVM中,核函数定义的并不明确,除此之外,在超平面上任意两点之间的距离都需要被定义。 解决方法是最优的,意味着分割超平面与两个分类(即二类分类器)上距离最近的特征向量之间的距离是最大的。距离超平面最近的特征向量被称为支持向量,就是说其它向量的位置都不会影响超平面(即决策函数)。 SVM在OpenCV中的实现是基于LibSVM的。

CvParamGrid

CvParamGrid

struct CvParamGrid 该结构体代表了统计模型参数的对数网格范围,它通过更新模型参数来优化统计模型准确度,准确度通过交叉验证的计算进行估计。

  • double CvParamGrid::min_val
    • 统计模型参数的最小值;
  • double CvParamGrid::max_val
    • 统计模型参数的最大值;
  • double CvParamGrid::step
    • 迭代统计模型参数的对数步长;

网格决定了统计模型参数值的迭代序列,如下所示:

其中n是一个最大索引号,满足:

网格已经经过对数化,所以step一定大于1。

CvParamGrid::CvParamGrid

CvParamGrid的构造函数。

  • C++: CvParamGrid::CvParamGrid()
  • C++: CvParamGrid::CvParamGrid( double min_val, double max_val, double log_step )

整个构造函数初始化了对应的数据成员,默认的构造函数创造的虚拟网格如下:

CvParamGrid::CvParamGrid()
{
    min_val = max_val = step = 0;
}

CvParamGrid::check

检测网格的有效性。

  • C++: bool CvParamGrid::check()

如果网格有效的,则返回true;如;如果无效,则返回false。当且仅当下列情况时,网格是有效的:

  • 网格的下边缘边界小于上边缘边界;
  • 网格的下边缘边界是正值;
  • 网格步长大于1;

CvSVMParams

CvSVMParams

struct CvSVMParams SVM训练参数。结构体将被初始化,并传递给CvSVM的训练函数。

CvSVMParams::CvSVMParams

CvSVMParams的构造函数。

  • 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 )

CvSVMParams()的参数

svm_type

SVM公式类型。可能取值如下:

  • CvSVM::C_SVCCC支持向量分类器。可以分为n类 (n ≥ 2),并允许在带有松弛变量 (outliers) 的惩罚乘子C的情况下的不完善分类;
  • CvSVM::NU_SVCν\nu支持向量分类器。可以分为n类 (n ≥ 2),而且可能存在不完善的分类。参数ν\nu替代参数CC使用,且ν\nu值范围在[0, 1]之内,该值越大,决策边缘越光滑;
  • CvSVM::ONE_CLASS:分布估计(单类SVM)。所有的训练数据都是同一类的,SVM构建了边界,将该类与特征空间的其他部分分离;
  • CvSVM::EPS_SVRϵ\epsilon支持向量回归。训练集特征向量与拟合超平面间的距离一定小于pp。该分类器的松弛变量 (outliers) 使用的惩罚因子为CC;
  • CvSVM::NU_SVRν\nu支持向量回归。ν\nu被用来代替pp;

其他具体解释见LibSVM

kernel_type

SVM核函数类型。可能取值如下:

degree

核函数的参数degreedegree,用于多项式核。

gamma

核函数的参数γ\gamma,用于多项式核 / RBF核 / Sigmoid核。

coef0

核函数的参数coef0coef0,用于多项式核 / Sigmoid核。

Cvalue

SVM最优问题的参数CC,用于 C_SVC / EPS_SVR / NU_SVR 分类器。

nu

SVM最优问题的参数ν\nu,用于 NU_SVC / ONE_CLASS / NU_SVR 分类器。

p

SVM最优问题的参数ϵ\epsilon,用于 EPS_SVR 分类器。

class_weights

C_SVC问题中的最优权重,它被分配给特定的分类。这些权重与因子C做乘运算,所以第 i 个分类的的参数C值应该为:

因此,这些权重对其他分类的误分类惩罚有一定影响,权重越大,对应分类的数据误分类的惩罚越大。

term_crit

SVM训练迭代的迭代终止标准,用于解决带有约束条件的二次最优规划问题。你也能明确公差与 / 或迭代最大次数。

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

CvSVM

class CvSVM : public CvStatModel

支持向量机。

注: · (Python) 使用SVM的数字识别例程可以在路径 opencv_source/samples/python2/digits.py 下找到; · (Python) 使用SVM的网格寻找数字识别可以在路径 opencv_source/samples/python2/digits_adjust.py 下找到; · (Python) 使用SVM的视频数字识别例程可以在路径 opencv_source/samples/python2/digits_video.py 下找到;

CvSVM::CvSVM

默认构造函数与训练构造函数。

  • 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() )
  • Python: cv2.SVM( [ trainData, responses [ , varIdx [ , sampleIdx [ , params ]]]] ) →

构造函数与CvStatModel::CvStatModel()有相同的形式。可以在本文档的CvStatModel::train()寻找参数的具体含义。

本文注: 下面从CvStatModel::train()中找到参数列表:

  • C++: bool CvStatModel::train( const Mat& train_data, [int tflag,] …, const Mat& responses, …, [const Mat& var_idx,] …, [const Mat& sample_idx,] … [const Mat& var_type,] …, [const Mat& missing_mask,] … ) = 0

对于其中参数,解释如下:

CvSVM()的参数

通过使用一组输入特征向量并输出相应值(或响应)的方法,训练函数训练了统计模型。输入 / 输出向量(或输入 / 输出值)都以矩阵形式传递。默认情况下,输入特征向量被存入train_data的列中,所有训练向量的组成(即特征)被连续存储。然而当全部输入集的各特定特征值(特征 / 输入变量)的所有值都是连续存储的情况下,一些算法可以处理转置表达式。如果两种布局都支持,训练方法包含的tflag参数起作用,该参数用来明确数据存储方向,具体如下:

  • tflag=CV_ROW_SAMPLE:特征向量按行存储;
  • tflag=CV_COL_SAMPLE:特征向量按列存储;

训练数据train_data必须使用CV_32FC1格式(32位浮点数,单通道)。返回数据responses通常以一维向量(一行或一列)的形式存储,向量中的数据格式为CV_32SC1(仅在分类问题中)或CV_32FC1,返回数据的每个值与训练数据的每个向量一一对应。相反的,某些类似于各种类型的神经网络,返回数据的类型都为向量形式。 对于分类问题,返回值是离散的分类标签;对于回归问题,返回值是被估计函数的值。一些算法只能处理分类问题,一些算法只能处理回归问题,也有一些算法可以处理两种问题。对于后者,输出参数的类型可以通过两种方式传递:一种是单独的参数,另一种是向量var_type的最后一个元素:

  • CV_VAR_CATEGORICAL:输出值为离散类别标签;
  • CV_VAR_ORDERED( =CV_VAR_NUMERICAL):输出值为顺序排列的,即两个不同的值可以以数字形式拿来对比,而且这是一个回归问题;

输入变量的类型可以通过输入参数var_type指定。大多数算法仅仅可以处理连续输入变量。 很多 ML (机器学习)模型可以用一个指定的特征子集与 / 或指定的训练集的样本子集进行训练。为了使其对我们更加简单,训练方法train函数通常包含参数var_idxsample_idx,前者(即var_idx)用来指定该兴趣的变量(特征),后者(即sample_idx)指定感兴趣的样本。两个向量可以使用整数 (CV_32SC1) 向量(基于0的索引列表),也可以使用8位 (CV_8UC1)的活动变量 / 样本。我们也可以传递NULL空指针来代替众多参数,这样的话所有的变量 / 样本都被用来训练。 此外,当已知训练样本的已知特征存在未知值时,一些算法可以处理丢失的量(例如,我们星期一忘记测量病人A的体温)。参数missing_mask是一个与train_data有相同尺寸的8位矩阵,它被用来标记丢失的值(即用非零值进行标记)。 通常,先前的模型统计在运行训练函数之前都被CvStatModel::clear()清除了,然而一些算法可以选择使用新训练数据更新模型统计,而不是重置它。

CvSVM::train

训练一个SVM。

  • 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() )
  • Python: cv2.SVM.train( trainData, responses [ , varIdx [ , sampleIdx [ , params ]]] ) → retval

该函数用来训练一个 SVM 模型,它继承了CvStatModel::train()函数的参数列表,但对下列进行了限制:

  • 数据布局仅仅支持CV_ROW_SAMPLE
  • 输入变量全部为连续值;
  • 输出变量可以是离散的 (param.svm = CvSVM::C_SVC 或 param.svm = CvSVM::NU_SVC),也可以是连续的 (param.svm = CvSVM::EPS_SVR 或 param.svm = CvSVM::NU_SVR),也可以不指定 (param.svm = CvSVM::ONE_CLASS)。
  • 不支持丢失测量值;

所有其他参数都被收集进入CvSVMParams结构体。

CvSVM::train_auto

用最优参数训练SVM。

  • 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 )
  • Python: cv2.SVM.train_auto( trainData, responses, varIdx, sampleIdx, params [ , k_fold [ , Cgrid [ , gammaGrid [ , pGrid [ , nuGrid [ , coeffGrid [ , degreeGrid [ , balanced ]]]]]]]] ) → retval

train_auto()参数

  • k_fold:交叉验证参数。训练集被分成k_fold子集。一个子集被用于测试模型,其余子集组成训练集。所以 SVM 算法总共被执行 k_fold 次;
  • Grid:相关SVM参数的迭代网格;
  • balanced:如果为true,而且问题为二类分类器,那么该函数就创造更平衡的交叉验证子集,子集各分类之间的比例接近在整个训练数据集中比例;

train_auto()函数说明

train_auto()函数通过从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)train_auto()函数可以被用来处理分类问题 (param.svm = CvSVM::C_SVC 或 param.svm = CvSVM::NU_SVC),也可以处理回归问题 (param.svm = CvSVM::EPS_SVR 或 param.svm = CvSVM::NU_SVR)。如果有param.svm_type = CvSVM::ONE_CLASS,则不会生成最优值,且普通带有确定参数的 SVM 将被执行。

CvSVM::predict

预测输入样本的返回值。

  • 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
  • Python: cv2.SVM.predict( sample [ , returnDFVal ] ) → retval
  • Python: cv2.SVM.predict_all( samples [ , results ] ) → results

predict()参数

  • sample:预测的单个输入样本;
  • samples:预测的多输入样本;
  • returnDFVal:指定一个返回值的类型。如果为true,且问题为二类分类器,那么该函数返回决策函数值是有符号的间隔距离;如果为false,那么函数返回一个类标签(分类问题),或者返回估计函数值(回归问题);
  • results:输出对应样本的预测返回值;

如果我们通过了一个样本,那么预测结果就会返回。如果我们想要得到几个样本的返回值,那么我们应该用矩阵results来保存预测结果。 该函数与 TBB 库并行运行。

CvSVM::get_default_grid

生成一个 SVM 参数的网格。

  • C++: CvParamGrid CvSVM::get_default_grid( int param_id )

param_id SVM 参数的 ID,必须从下列表中取值:

  • CvSVM::C
  • CvSVM::GAMMA
  • CvSVM::P
  • CvSVM::NU
  • CvSVM::COEF
  • CvSVM::DEGREE

网格将根据该 ID 参数生成。

该函数根据 SVM 算法的指定参数而生成一个网格,该网格会传递给函数CvSVM::train_auto()

CvSVM::get_params

返回当前 SVM 参数。

  • C++: CvSVMParams CvSVM::get_params() const

在使用函数CvSVM::train_auto()自动训练时,该函数被用来获取最优参数。

CvSVM::get_support_vector

取得若干支持向量与特定的向量。

  • C++: int CvSVM::get_support_vector_count() const
  • C++: const float* CvSVM::get_support_vector( int i ) const
  • Python: cv2.SVM.get_support_vector_count() → retval

i:特定的支持向量的序列;

该方法用来取得一组支持向量。

CvSVM::get_var_count

返回已使用特征的数量(即变量数量);

  • C++: int CvSVM::get_var_count() const
  • Python: cv2.SVM.get_var_count() → retval

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

机器学习笔记(3):多类逻辑回归

仍然是 动手学尝试学习系列的笔记,原文见:多类逻辑回归 — 从0开始 。 这篇的主要目的,是从一堆服饰图片中,通过机器学习识别出每个服饰图片对应的分类是什么(比...

3768
来自专栏杨熹的专栏

凸优化有什么用

本文结构: 凸优化有什么用? 什么是凸优化? ---- 凸优化有什么用? 鉴于本文中公式比较多,先把凸优化的意义写出来吧,就会对它更有兴趣。 我们知道在机器学习...

3718
来自专栏ATYUN订阅号

使用Python进行人脸聚类的详细教程

思考下面这个场景:两名劫匪在抢劫波士顿或纽约等繁华城市的银行。银行的安全摄像头工作正常,捕捉到了抢劫行为,但劫匪戴着头套,没办法看到他们的脸。

1222
来自专栏灯塔大数据

每周学点大数据 | No.16平面图直径

No.16期 平面图直径 小可:好的,关于图的基本内容我听懂了。 Mr. 王:很好,图能够对很多现实问题进行数学抽象,方便通过计算机的手段进行抽象。而平面图指...

3104
来自专栏AI科技大本营的专栏

学习笔记 | Fast.ai深度学习实战课程Lesson2——带你深入了解CNN

Fast.ai 深度学习是我们此前推出的系列课程,共9节课,并且已经进行了汉化。课程主讲人是资深深度学习研究者Jeremy Howard 教授,他本人连续两年在...

5048
来自专栏算法+

shazam音乐检索算法 附完整c代码

https://laplacian.wordpress.com/2009/01/10/how-shazam-works/

1252
来自专栏老秦求学

从Iris数据集开始---机器学习入门

代码多来自《Introduction to Machine Learning with Python》. 该文集主要是自己的一个阅读笔记以及一些小思考,小总结...

55210
来自专栏机器之心

入门 | 无需基础知识,使用JavaScript构建你的第一个神经网络

选自ITNEXT 作者:Daniel Simmons 机器之心编译 参与:程耀彤、李泽南 随着新技术和新工具的出现,构建神经网络已不再是一件需要大量机器学习相关...

3395
来自专栏PaddlePaddle

【序列到序列学习】生成古诗词

生成古诗词 序列到序列学习实现两个甚至是多个不定长模型之间的映射,有着广泛的应用,包括:机器翻译、智能对话与问答、广告创意语料生成、自动编码(如金融画像编码)...

2786
来自专栏云计算教程系列

如何使用TensorFlow构建神经网络来识别手写数字

神经网络被用作深度学习的方法,深度学习是人工智能的许多子领域之一。它们大约在70年前首次提出,试图模拟人类大脑的工作方式,尽管它的形式要简化得多。各个“神经元”...

842

扫码关注云+社区