支持向量机(SVM)非线性数据切割
支持向量机(SVM)非线性数据切割
1.目标
本指导中你将学到:
l 当不可能线性切割训练数据时,如何定义SVM最优化问题。
l 在这样的问题上。如何配置CvSVMParams中的參数满足你的SVM;
2.动机
为什么我们有兴趣扩展SVM最优化问题来处理非线性切割训练数据?SVM在计算机视觉应用中须要一个比线性分类器更加强有力的工具。
原因在于,其实,在这样的问题上训练数据差点儿不能被一个超平面切割开。考虑一个这样的任务。比如,面部识别。
这样的情况下,训练数据由图像上的一组面部数据和非面部(不论什么除面部以外的其它东西)数据组成。这些训练数据很复杂,以至于能够对每个样本找到一种表述(特征向量),能把整个数据线性的从非面部中切割出来。
3.最优化问题扩展
记住,通过SVM我们得到一个切割超平面。
那么,由于如今训练数据是非线性可分的了。我们必须承认原来找到的超平面将不能正确分类当中的一些样本。
误分类是优化问题中须要考虑的一个新的变化。新的模型既要满足找超平面的老问题。给出最大边缘,而且还要做新工作,正确地生成新的训练数据,而使其不出现太多分类错误。我们先从寻找超平面这个优化问题的构想出发,由超平面给出最大边缘(边缘的概念在上篇中有解释):
有非常多种方法能够改动这个模型。所以它把误分类考虑在内了。
比方,你能够考虑最小化同一个量加上一个常数乘以训练数据误分类的错误数量,比如:
然而。这个并非最好的解决方式,在其它原因中(amongsome other reasons),我们对距离期望决策区域距离非常小的误分类样本和没有误分类的样本不作区分。因此,更好的解决方式将把误分类样本离他们的正确决策区域的距离考虑在内,比如:
对于每个训练数据样本,要定义一个新的參数ξi。每个此參数都包括了训练样本到他们的正确决策区域的距离。下图显示了两类非线性可分类的训练数据,一个分类超平面和误分类样本到正确决定区域的距离。
注意:图中值仅仅显示了误分类样本的距离。其它样本的距离为0。由于他们已经在正确的区域了。
图中红色和蓝色的线是每个决策区域的边界。每个ξi是从误分类点到期望区域的边界,明确这一点非常重要。最后。优化问题的新公式为:
怎么选择常数C呢?非常明显这个问题依赖于训练数据是怎么分布的。虽然没有统一的答案,考虑一下规则会非常有帮助:
l C的值越大,误分类的数量会越少,但边缘也会越小。这样的情况。是把误分类错误看的非常重,对误分类要求严格。
然而,优化的目标是最小化自变量,少量误分类错误是同意的。
l C值越小,边缘越大。误分类错误越大。这样的情况下最小化没有过多考虑求和项。因此其焦点在于寻找具有更大边缘的超平面。
4.代码
你可能也在OpenCV源码库中的此路径sample/cpp/tutorial_code/gpu/non_linear_svm/non_linear_svms目录中找到了源码,以及那些视频文件,也能够在此下载。
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp> #define NTRAINING_SAMPLES 100 // Number of training samples per class
#define FRAC_LINEAR_SEP 0.9f // Fraction of samples which compose the linear separable part using namespace cv;
using namespace std; int main()
{
// Data for visual representation
const int WIDTH = 512, HEIGHT = 512;
Mat I = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); //--------------------- 1. Set up training data randomly ---------------------------------------
Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);
Mat labels (2*NTRAINING_SAMPLES, 1, CV_32FC1); RNG rng(100); // Random value generation class // Set up the linearly separable part of the training data
int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES); // Generate random points for the class 1
Mat trainClass = trainData.rowRange(0, nLinearSamples);
// The x coordinate of the points is in [0, 0.4)
Mat c = trainClass.colRange(0, 1);
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));
// The y coordinate of the points is in [0, 1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); // Generate random points for the class 2
trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
// The x coordinate of the points is in [0.6, 1]
c = trainClass.colRange(0 , 1);
rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));
// The y coordinate of the points is in [0, 1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); //------------------ Set up the non-linearly separable part of the training data --------------- // Generate random points for the classes 1 and 2
trainClass = trainData.rowRange( nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
// The x coordinate of the points is in [0.4, 0.6)
c = trainClass.colRange(0,1);
rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
// The y coordinate of the points is in [0, 1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT)); //------------------------- Set up the labels for the classes ---------------------------------
labels.rowRange( 0, NTRAINING_SAMPLES).setTo(1); // Class 1
labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2); // Class 2 //------------------------ 2. Set up the support vector machines parameters --------------------
CvSVMParams params;
params.svm_type = SVM::C_SVC;
params.C = 0.1;
params.kernel_type = SVM::LINEAR;
params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6); //------------------------ 3. Train the svm ----------------------------------------------------
cout << "Starting training process" << endl;
CvSVM svm;
svm.train(trainData, labels, Mat(), Mat(), params);
cout << "Finished training process" << endl; //------------------------ 4. Show the decision regions ----------------------------------------
Vec3b green(0,100,0), blue (100,0,0);
for (int i = 0; i < I.rows; ++i)
for (int j = 0; j < I.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << i, j);
float response = svm.predict(sampleMat); if (response == 1) I.at<Vec3b>(j, i) = green;
else if (response == 2) I.at<Vec3b>(j, i) = blue;
} //----------------------- 5. Show the training data --------------------------------------------
int thick = -1;
int lineType = 8;
float px, py;
// Class 1
for (int i = 0; i < NTRAINING_SAMPLES; ++i)
{
px = trainData.at<float>(i,0);
py = trainData.at<float>(i,1);
circle(I, Point( (int) px, (int) py ), 3, Scalar(0, 255, 0), thick, lineType);
}
// Class 2
for (int i = NTRAINING_SAMPLES; i <2*NTRAINING_SAMPLES; ++i)
{
px = trainData.at<float>(i,0);
py = trainData.at<float>(i,1);
circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick, lineType);
} //------------------------- 6. Show support vectors --------------------------------------------
thick = 2;
lineType = 8;
int x = svm.get_support_vector_count(); for (int i = 0; i < x; ++i)
{
const float* v = svm.get_support_vector(i);
circle( I, Point( (int) v[0], (int) v[1]), 6, Scalar(128, 128, 128), thick, lineType);
} imwrite("result.png", I); // save the Image
imshow("SVM for Non-Linear Training Data", I); // show it to the user
waitKey(0);
}
译者注:因为凝视直接加入在代码中会导致排版问题。偷懒把凝视堆在此下了:
//训练数据矩阵。行数200。列2
//标记矩阵。行200,列1
//生成线性可切割的训练数据
//生成第1类的随机点
//取子矩阵。0~nLinearSamples行
//取上面子矩阵的子矩阵,第0列
//随机填充该列,其值范围从1到0.4 * WIDTH
//取子矩阵的第1列
//随机填充该列。其值范围从1到HIGHT
//此例中矩阵的第0列和第1列分别当做点的x,y坐标
//生成第2类的随机点
//取子矩阵。留出一个切割带直到最后
//取第0列
//随机填充该列,其值范围从0.6 * WIDTH到WIDTH
//取第1列
//随机填充该列。其值范围从1到HIGHT
//随机生成非线性可切割的训练数据
//取子矩阵。中间切割带部分
//取第0列
//随机填充,其值范围就是中间带的x坐标
//取第1列
//随机填充,值就为整个HIGHT范围
//Class 1//设置标识,1为第一类
// Class 2//标识2为第二类
//通过上一篇能够了解到,此參数是跟维度有关的。高维又是须要映射,这里LINEAR指不映射
//遍历整副图片,预測每一个像素点所属的类别。并作对应着色
5.代码解析
(1)创建训练数据
此处训练数据由一组标记了的二维点组成,共两类。
为了让这个练习更加有吸引力,训练数据通过均匀分布概率密度方程(a uniform probability density functions (PDFs))随机生成。我们已经把训练数据的生成分成了两个主要部分。第一部分,我们生成线性可分的两类数据。
// Generate random points for the class 1
Mat trainClass = trainData.rowRange(0,nLinearSamples);
// The x coordinate of the points is in [0,0.4)
Mat c = trainClass.colRange(0, 1);
rng.fill(c, RNG::UNIFORM, Scalar(1),Scalar(0.4 * WIDTH));
// The y coordinate of the points is in [0,1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1),Scalar(HEIGHT));
// Generate random points for the class 2
trainClass =trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
// The x coordinate of the points is in[0.6, 1]
c = trainClass.colRange(0 , 1);
rng.fill(c, RNG::UNIFORM,Scalar(0.6*WIDTH), Scalar(WIDTH));
// The y coordinate of the points is in [0,1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1),Scalar(HEIGHT));
第二部分,我们为两类创建非线性可分的数据和重叠的数据。
// Generate random points for the classes 1and 2
trainClass = trainData.rowRange( nLinearSamples,2*NTRAINING_SAMPLES-nLinearSamples);
// The x coordinate of the points is in[0.4, 0.6)
c = trainClass.colRange(0,1);
rng.fill(c, RNG::UNIFORM,Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
// The y coordinate of the points is in [0,1)
c = trainClass.colRange(1,2);
rng.fill(c, RNG::UNIFORM, Scalar(1),Scalar(HEIGHT));
译者注:
void RNG::fill(InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false )
这个函数是对矩阵mat填充随机数,随机数的产生方式有參数2来决定,假设为參数2的类型为RNG::UNIFORM。则表示产生均一分布的随机数,假设为RNG::NORMAL则表示产生高斯分布的随机数。相应的參数3和參数4为上面两种随机数产生模型的參数。比方说假设随机数产生模型为均匀分布。则參数a表示均匀分布的下限,參数b表示上限。
假设随机数产生模型为高斯模型,则參数a表示均值。參数b表示方程。
參数5仅仅有当随机数产生方式为均匀分布时才有效,表示的是是否产生的数据要布满整个范围(没用过,所以也没细致去研究)。
另外。须要注意的是用来保存随机数的矩阵mat能够是多维的,也能够是多通道的,眼下最多仅仅能支持4个通道。
(2)创建SVM參数
可參见上一篇中关于CvSVMParams的解说。
CvSVMParams params;
params.svm_type = SVM::C_SVC;
params.C = 0.1;
params.kernel_type = SVM::LINEAR;
params.term_crit = TermCriteria(CV_TERMCRIT_ITER, (int)1e7,1e-6);
这里跟我们前一篇的配置仅有两处不同:
l CvSVM::C_SVC:我们这里选择了一个非常小的数值。目的是,在优化中不正确误分类错位做过多惩处。这么做到原因是我们希望获得最接近直观预期的解决方式。然而,我们推荐通过调整获得一个更能反映问题的參数。
注意:这里在两类之间重叠的点非常少,给FRAC_LINEAR_SEP一个更小的值。点的密度将添加。并且參数CvSVM::C_SVC的影响更深。
l Termination Criteria of thealgorithm,算法终止标准:为了通过非线性可分离的训练数据正确地解决这个问题,最大迭代次数必须添加非常多。特别的。我们对这一參数值添加了5个数量级。
(3)训练SVM
我们调用方法CvSVM::train来建立SVM模型。注意训练过程可能会花非常长时间。执行改程序是要有耐心。
CvSVM svm;
svm.train(trainData, labels, Mat(), Mat(),params);
(4)显示决策区域
方法CvSVM::predict通过已训练的SVM来分类输入样本。在此例中,我们用这种方法根据SVM的预測来着色相关区域。也就是说,遍历一个图像。把它的像素当成笛卡尔平面的点。每个点根据SVM预測的类来着色;深绿色的是标记为1的类,深蓝色是标记为2的类。
Vec3b green(0,100,0), blue (100,0,0);
for (int i = 0; i < I.rows; ++i)
for (int j = 0; j < I.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1,2) << i, j);
float response = svm.predict(sampleMat);
if (response == 1) I.at<Vec3b>(j, i) = green;
else if (response == 2) I.at<Vec3b>(j, i) = blue;
}
(5)显示训练数据
方法circle用来显示训练数据的样本点。标记为1的类的样本显示为亮绿色,标记为2的类的样本点显示为亮蓝色。
int thick = -1;
int lineType = 8;
float px, py;
// Class 1
for (int i = 0; i < NTRAINING_SAMPLES;++i)
{
px = trainData.at<float>(i,0);
py = trainData.at<float>(i,1);
circle(I, Point( (int) px, (int)py ), 3, Scalar(0, 255, 0), thick, lineType);
}
// Class 2
for (int i = NTRAINING_SAMPLES; i<2*NTRAINING_SAMPLES; ++i)
{
px = trainData.at<float>(i,0);
py = trainData.at<float>(i,1);
circle(I, Point( (int) px, (int) py ), 3, Scalar(255, 0, 0), thick,lineType);
}
(6)支持向量机
这里我么用来非常多方法来获取支持向量的信息。
方法CvSVM::get_support_vector_count输出该问题中支持向量的总数,方法CvSVM::get_support_vector能够依据索引获取到每个支持向量。我们用这些方法找到是支持向量的训练样本,并显示为高亮。
thick = 2;
lineType = 8;
int x = svm.get_support_vector_count();
for (int i = 0; i < x; ++i)
{
const float* v = svm.get_support_vector(i);
circle( I, Point( (int) v[0], (int) v[1]), 6,Scalar(128, 128, 128), thick, lineType);
}
6结果
l 代码打开了一个图像,显示两类的训练数据。当中一类显示为亮绿色,还有一类显示为亮蓝色。
l 训练SVM。并用它来分类图像上全部的像素点。图像被分成蓝绿两块区域。
两个区域的边界就是切割超平面。由于训练数据是非线性可切割的,可以看到,一些样本被误分类了。一些绿色的点在蓝色区域中,另一些蓝色的点在绿色区域中。
l 最后,被灰色的圈包围的训练样本的点是支持向量。
原文:http://docs.opencv.org/doc/tutorials/ml/non_linear_svms/non_linear_svms.html#nonlinearsvms
支持向量机(SVM)非线性数据切割的更多相关文章
- 吴裕雄 python 机器学习——支持向量机SVM非线性分类SVC模型
import numpy as np import matplotlib.pyplot as plt from sklearn import datasets, linear_model,svm fr ...
- 大数据-10-Spark入门之支持向量机SVM分类器
简介 支持向量机SVM是一种二分类模型.它的基本模型是定义在特征空间上的间隔最大的线性分类器.支持向量机学习方法包含3种模型:线性可分支持向量机.线性支持向量机及非线性支持向量机.当训练数据线性可分时 ...
- OpenCV支持向量机SVM对线性不可分数据的处理
支持向量机对线性不可分数据的处理 目标 本文档尝试解答如下问题: 在训练数据线性不可分时,如何定义此情形下支持向量机的最优化问题. 如何设置 CvSVMParams 中的参数来解决此类问题. 动机 为 ...
- 非线性支持向量机SVM
非线性支持向量机SVM 对于线性不可分的数据集, 我们引入了核(参考:核方法·核技巧·核函数) 线性支持向量机的算法如下: 将线性支持向量机转换成非线性支持向量机只需要将变为核函数即可: 非线性支持向 ...
- 机器学习:Python中如何使用支持向量机(SVM)算法
(简单介绍一下支持向量机,详细介绍尤其是算法过程可以查阅其他资) 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别.分类(异 ...
- 以图像分割为例浅谈支持向量机(SVM)
1. 什么是支持向量机? 在机器学习中,分类问题是一种非常常见也非常重要的问题.常见的分类方法有决策树.聚类方法.贝叶斯分类等等.举一个常见的分类的例子.如下图1所示,在平面直角坐标系中,有一些点 ...
- 机器学习之支持向量机—SVM原理代码实现
支持向量机—SVM原理代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9596898.html 1. 解决 ...
- 复习支持向量机(SVM)没空看书时,掌握下面的知识就够了
支持向量机(support vector machines, SVM)是一种二类分类模型.它的基本模型是定义在特征空间上的间隔最大的线性分类器:支持向量机还包括核技巧,这使它成为实质上的非线性分类器. ...
- 一步步教你轻松学支持向量机SVM算法之理论篇1
一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
随机推荐
- UINavigationController 操作记录
//设置字体大小 颜色 { UIColor *color = [UIColor brownColor]; UIFont * font = [UIFont systemFontOfSize:20]; N ...
- 【剑指offer 面试题16】反转链表
思路: 用三个指针preNode.curNode.nextNode完成. #include <iostream> using namespace std; struct ListNode ...
- 《Python 学习手册4th》 第十七章 作用域
''' 时间: 9月5日 - 9月30日 要求: 1. 书本内容总结归纳,整理在博客园笔记上传 2. 完成所有课后习题 注:“#” 后加的是备注内容 (每天看42页内容,可以保证月底看完此书) “重点 ...
- python测试基于websocket协议的即时通讯接口
随着html5的广泛应用,基于websocket协议的即时通讯有了越来越多的使用场景,本文使用python中的websocket-client模块来做相关的接口测试 import webclient ...
- oracle文件管理OMF
OMF是为了简化对数据文件的管理,靠参数DB_CREATE_FILE_DEST实现: 如果定义了DB_CREATE_FILE_DEST,则创建表空间就不需要制定数据文件位置.文件名称,数据文件会按照固 ...
- codevs3044 线段树+扫描线
3044 矩形面积求并 http://hzwer.com/879.html 扫描线 // #pragma comment(linker, "/STACK:1024000000,1024000 ...
- oc_转_NSInteger 和 NSNumber
Objective-C 支持的类型有两种:基本类型和类. 基本类型,如同 C 语言中的 int 类型一样,拿来就可以直接用.而类在使用时,必须先创建一个对象,再为对象分配空间,接着做初始化和赋值.类的 ...
- [Hive - LanguageManual] Hive Default Authorization - Legacy Mode
Disclaimer Prerequisites Users, Groups, and Roles Names of Users and Roles Creating/Dropping/Using R ...
- 软件开发杂谈之从需求到上线---valen
背景 IT已经成为当代企业必不可少的竞争手段,从无到有到标配,可以说以后不懂IT的就是文盲这句一点也不过,而软件开发是个复杂工程,零零碎碎各种理论工具和技巧,一言难尽. 本文意在言简意赅,简述软件开发 ...
- 有关OOM KILLER的一些理解
Linux下有一种OOM KILLER 的机制,它会在系统内存耗尽的情况下,启用自己算法有选择性的kill 掉一些进程. 一.为什么会有OOM killer 当我们使用应用时,需要申请内存,即进行ma ...