说明
SVM(support vector machine,支持向量机)的理论其实是很漂亮的,只是对于初学者而言有点晦涩难懂和繁琐(特别是诸多的公式推导)。因为其经典且应用范围广,其实网上(各编程语言)已经有很多很成熟的包/函数可以直接调用,而且有关SVM的比较细节和系统的理论知识网上也有很多的资料可以参考(在后文的参考资料中我列举了几个)。本文的目标不在于详细地讲解关于SVM的理论知识(实话我现阶段也不是太理解),而是试图梳理必要的知识点、理清楚相关概念之间的逻辑关系、并使用数据集和可被直接调用的SVM工具包来进行分类实践。
本系列博文我规划了至少两篇,后续有更深入的理解了 我再做补充。
Blog
2024.10.6 博文第一次撰写
目录
说明
目录
一、与SVM有关的必要概念
1.1 SVM的最大间隔及其与感知机的对比
1.2 关于SVM(支持向量机)中支持向量的由来
1.3 关于硬间隔、软间隔
1.4 非线性可分与核函数
1.5 关于多类别分类的解决方案
1.6 本章小结
二、基于SVM进行分类实践的处理流程
三、Matlab使用SVM相关工具包/函数的方法
四、基于所生成数据集的二分类实践
4.1 数据生成
4.2 数据训练和分类
4.3 本章小结
五、对Iris数据集的分类实践
六、对glass数据集的分类实践
七、对雷达数据集的分类(实践)
八、总结
九、参考资料
十、数据与代码参考
一、与SVM有关的必要概念
有关线性可分二分类、非线性可分、多类别分类的相关概念我已经在之前关于感知机的博文[1]中有过介绍,这些是很基础且很容易理解的概念,这里不再论述。 SVM是一种在分类和回归分析中分析数据的监督式学习模型与相关的学习算法,你可以将之理解成一套有着自洽的理论体系的工具,我们可以借助它来完成一些分类和回归的任务。本文以及后续博文主要还是以分类,特别是二分类为落脚点来理解它。
本章中,关于SVM我提炼出了几个核心的概念来分别对其进行介绍和解释,相信后文的几个概念弄清楚了,关于SVM的理解也就差不多了。
1.1 SVM的最大间隔及其与感知机的对比
在[1]中,我们讨论了感知机,以及用感知机来解决最基本的线性可分二分类问题,我们给感知机设计的损失函数是误分类点到超平面的总距离,感知机的学习问题本质上就是怎么将该总距离变小直至为0:也即没有误分类的点。只要训练集中全部的点都已经被我们正确分类了,那么迭代(学习)便会停止,我们也就得到了超平面,以二维平面中的分类为例,迭代完成后,我们得到的超平面可能是图中三条直线中的任意一条:
图1.1 感知机训练完成后可能的超平面结果
图中黑色的方块和圆分别代表数据集的两类。感知机的理论只能解决把类分开这个问题,无法解决怎么才能把类分好。上图中不难理解的是,直线2是其中最优的超平面:因为对于直线1和直线3,如果测试集中有一些点稍微更往另一类靠近一些,这两条直线很容易会误分,这说明感知机那套理论学习出来的超平面泛化性(或鲁棒性)不好。
SVM可以更好地解决这个问题:SVM学习出来的超平面是使得训练集两类数据中离超平面最近的数据点到超平面距离和最大的超平面(这句话很拗口,多读几次就明白了)。直白点来说就是:首先训练集中有两个类别,不管用感知机的方法还是SVM的方法,或者是其它什么方法,当我们训练完成后会得到一个超平面,我们分别从这两类数据中找到一个离超平面最近的点,然后分别计算两个点到超平面的距离,并得到距离之和D,如果我们使用的是SVM这套方法,那么SVM得到的超平面下的D,是可以进行分类的所有超平面中最大的!
SVM是利用间隔最大化来求解最优分离超平面(该超平面就处在间隔的正中),其解是唯一的;感知机用的是误分类点到超平面的距离和最小来求解超平面,其解是随机的,且有无穷多个。这便是两者的核心区别。
1.2 关于SVM(支持向量机)中支持向量的由来
为什么会取支持向量机这个名字?理解了其由来,便了解了SVM求解超平面的原理和过程。
首先,我们引入向量:训练集中全部的点,我们都可以用向量来理解/描述它们,一般训练集中数据的典型形式是:
(1-1)
Xi表示数据集中的第i个数据,这个数据由M个属性(特征)组成:--->,这些属性可能有不同的物理意义,比如对于三维空间中的点来说,它们就是坐标值。yi则表示这个数据的所属类别。那么: 我们其实就可以用向量来理解它。
然后,我们来简单推导和理解SVM是如何获得其超平面的:在前面的分析中我们已经给出:SVM是通过找到最大的间隔来得到超平面的,所以得到其超平面是需要通过最大化间隔这个约束条件来获得。后文的一些内容主要参考自[2]。
这里以二维平面来理解SVM的处理原理:在二维平面中,我们以方程式:
(1-2)
来表示我们最终会得到的超平面,将之上下分别移动C来到最大间隔对应两个边界:
(1-3)
(1-4)
不难理解的是,这两个边界超平面必然会经过训练集中的某些点,如下图[2]所示:
图1.2 最大间隔与超平面
其实这些边界点就是所谓的支持向量!进一步地,我们来理解这些点是如何影响超平面的获取的:把式(1-2) 至 (1-4)两边除以c,并用将变量w/c和b/c分别用w’和b’替代,得到:
(1-5)
(1-6)
(1-7)
本质上w’和b’都是代数,我们用w和b来替代意义完全一样,后面的推导将直接使用w和b。如下图[2]所示,便是几个公式、超平面以及最大间隔之间的关系:
图1.3 SVM各概念之间的关系
SVM是要最大化间隔(也就是上图中正负两个超平面之间的间隔),这里两个超平面是平行的,我们将空间中两平行直线之间的距离推广到这里(读者可以这样去理解,也可以去看[2]中更详细的推导),可以得到间隔L为:
(1-8)
那么问题就转换成了在约束条件下L值最大或者w
最小化的问题,我们的约束条件是我们要正确分类训练集中的点:
(1-9)
因为:
(1-10)
将其两边取平方后可以去掉根号更方便计算,那么更规范的SVM优化问题的数学表达式就是:
(1-11)
(1-12)
式中,当样本点处在正负超平面上时,取等号。我们求解上述方程便可以吧 得到超平面了。往下更具体的公式推导需要引入拉格朗日乘子法等方法,通过构造等式求极值来最终获得所需解,不在本文的讨论范围内,读者可以看参考资料[2][3]进行理解。总之,经过一系列的推导和分析后,我们发现其实只有支持向量会影响超平面的获取,训练集中其它的点其实并不起作用!这便是支持向量机的由来!
1.3 关于硬间隔、软间隔
前面两节中我们所讨论的都是指线性可分下的硬间隔:我们基于训练集训练得到的超平面会严格地将训练集分成两类,不允许有误分类的点。硬间隔在训练数据是理想的,没有噪声的情况下是没有啥问题的,但实际应用中,数据是不可能没有噪声的!而且可能存在一些分类标记有误的点,如下图所示:
图1.4 硬间隔与软间隔下的超平面对比
由于异常点(图中红色的方块)的存在,如果我们继续使用前述硬间隔那套方法去求解超平面,那么我们会得到直线2对应的超平面。但是软间隔下,为了使整体的分类效果以及模型的泛化性更优,我们允许存在一些误分类的点,我们得到的超平面是直线1,容易看出,从后续预测的角度来看,直线1的泛化性(鲁棒性)会更优。
那么,我们如何去设置对误分类的容忍度?软间隔下我们如何求解其超平面?这是另外一套与硬间隔下的求解类似但也有诸多不同的处理方法了,更具体的读者可以参看资料[2]。其解决思路是:给每个误分类的点设置一个损失值εi,该值大于等于0,该点离超平面边界的距离越远,值越大:
(1-13)
软间隔下的优化问题表述为(我们也希望损失值越小越好):
(1-14)
(式中C是一个常系数,C≥0,我们可以用来控制对损失值的容忍度:C越大,我们对损失值的容忍度越低,极限情况下C取无穷大时,就是硬间隔了)
subject to:
(1-15)
(1-16)
1.4 非线性可分与核函数
前面讨论的都是线性可分二分类的情况,但实际应用中绝大多数情况下并不是线性可分的。我在博文[1]中给出过简单的示例,典型如下图所示:
图1.5 非线性可分(线性不可分)示意图
此时前面所建立起来的理论和方法将不再适用。非线性可分的情况下,想要建立超平面将数据正确分类,解决的方法是将低维的数据映射到高维去,比如对于上图中的情况,如果我们给数据增加一维(Z方向),想办法将正方形方块对应数据的Z值都设置为0,将圆形对应数据的Z值设置为非0,那么这两类数据我们就可以用前面的方法找到一个超平面将之正确分开。也即:建立非线性学习器分为两步:首先使用一个非线性映射将数据变换到一个可被线性分类的特征空间,然后再在这个特征空间使用线性学习器分类。
不过前述思路下会带来如下问题:我们需要找到一个合适的映射f,在它的作用下将数据映射到更高维度的空间,且不说这个映射关系难不难找,维度更高后计算量、存储量都会显著增加!
核函数的提出则在不增加维度的基础上解决了数据的非线性映射问题!核函数可以提供高维度向量的相似度测量,通过选取合适的核函数,我们可以不用知晓具体的维度转换函数而直接获得数据的高维度差异度,并以此来进行分类判断。关于核函数的理论依据以及相关推导,读者可以参考资料[2][4]。
典型的核函数有:比如高斯核函数(Gaussian Kernel)(又称径向基函数(Radial Basis Function, RBF)):
(1-17)
以及多项式核、Sigmoid核、拉普拉斯核、指数核、傅里叶核等等,这些不同的核函数适用于不同的数据特性和应用场景,具体需要结合实际情况来选择。
1.5 关于多类别分类的解决方案
关于多类别的情况,我在博文[1]中给出过简单的示例,典型如下图所示:
图1.6 多类别示意图
不管是感知机还是SVM它们针对的都是二分类问题!基于SVM解决多分类问题有两种思路:一是梳理出多分类下的优化问题,直接计算出可用于多分类的分类函数,这种思路下计算量大、花费时间长、实现起来比较困难。二是通过组合多个二分类SVM来实现多分类,有如下两种比较经典的方法:
一对一:一对一是指在K类训练样本中构造所有可能的二分类SVM,即每一类样本都与其它类别的样本构成二分类问题,于是我们需要构建个SVM(超平面)。在应用时(测试时),将测试样本送入全部的SVM进行分类,然后基于各个分类结果对所有类别进行投票,得票数最多的类别即为该测试样本的所属类别。
一对多:一对多下,K类训练样本我们会构建K个SVM(超平面),第i个二分类SVM将第i类训练样本的类别标记为+1,而将其余所有训练样本的类别标记为-1。测试样本经过所有二分类SVM进行分类,然后根据预测得到的类别标号判断是否属于第i(i=1,2,…,K)个类别。
我以四分类对上述两种方法做举例说明,我将这四个类别分别编号为A、B、C、D。
一对一下,我们会构建6个SVM对训练集进行训练,每个SVM只负责训练以及区分其中两个类别:
表1.1 一对一方法下的SVM训练情况
SVM编号 | 类别1 | 类别2 |
SVM1 | A | B |
SVM2 | A | C |
SVM3 | A | D |
SVM4 | B | C |
SVM5 | B | D |
SVM6 | C | D |
训练完成后我们会得到6个超平面(分类函数),然后我们用这些结果对测试样本进行测试。我们约定:分类器将该样本分给了哪一类,对应的这一类就加1票,当然,初始情况下大家都是0票。
那么理想情况下,所属A类的测试样本在经过1->3号分类器时,都会被分给A类,A类得3票,后续4-->6号分类器不管结果如何(可能B类会得2票、C类会得1票,或者是其它情况),其它类别的投票都不会超过A类,那么我们可以认为该测试样本属于A类,完成分类,且分类正确。 以此类推,如果各SVM训练得到的超平面泛化性不错,那么绝大多数情况下都会分类正确。
当然,也有不理想的情况:比如我们把测试样本给到各个SVM后,其结果可能是: A、A、D、B、B、C。 A类和B类都是两票,此时我们应该把该测试样本分给谁?这就是分类失败的情况,当然,我们可以设定一个未知类别来装载它。这种情况是存在的,我们需要考虑这种情况,并想办法优化它(当然,没有百分百正确的分类器)。
一对多下,我们会构建4个SVM分类器对训练集进行训练,每个SVM只负责训练以及区分其中一个类别:(表中的类别1)
表1.2 一对多方法下的SVM训练情况
SVM编号 | 类别1 | 类别2 |
SVM1 | A | B、C、D |
SVM2 | B | A、C、D |
SVM3 | C | A、B、D |
SVM4 | D | A、B、C |
训练完成后我们会得到4个超平面(分类函数),然后我们用这些结果对测试样本进行测试。我们约定:分类器将该样本分给了哪一类,对应的这一类就加1票,当然,初始情况下大家都是0票。
那么理想情况下,所属A类的测试样本在经过这4个分类器时,只有第一个分类器会将之分配给类别1也就是A类,其余三个都会分配给类别2,那么我们就认为该测试样本属于A类,完成分类,且分类正确。 以此类推,如果各SVM训练得到的超平面泛化性不错,那么绝大多数情况下都会分类正确。
当然,也有不理想的情况:比如我们把测试样本给到各个SVM后,其结果可能是两个或两个以上的分类器都将之分给了类别1,此时我们应该把该测试样本分给谁?这就是分类失败的情况,当然,我们可以设定一个未知类别来装载它。这种情况是存在的,我们需要考虑这种情况,并想办法优化它(当然,没有百分百正确的分类器)。
1.6 本章小结
本章比较详尽地梳理了有关SVM的几个概念:包括最大间隔、支持向量、硬间隔和软间隔、核函数、多类别分类,这些概念对于理解SVM、使用SVM至关重要。在1.1节中还结合感知机进行了对比以便更深入理解SVM的分类原理。在1.2节中通过回答支持向量的由来,我们一并推导并给出了SVM优化问题的数学表达式,不过关于该优化问题的具体求解不在本文的范围内,第九章中的参考资料可以给读者更多细节和理论上的帮助。
本章的内容可以帮助加深对SVM的理解,也给后文的实践打下了基础!
二、基于SVM进行分类实践的处理流程
基于SVM进行分类应用,其典型的处理流程如下:
图2.1 基于SVM分类实践的典型流程
更具体的关于参数的预设、测试结果的评估在后文结合实践进行介绍。
三、Matlab使用SVM相关工具包/函数的方法
在之前感知机的文章[1]中,关于求超平面的整个代码比较简单,都是自己编写的,但是SVM这里比较复杂,特别是还涉及到核函数。SVM有着广泛的应用,且有比较久远的发展历程,求解的过程也比较标准化,相关的求解其实有比较完善的工具包/函数可以直接调用,后续的实践我直接调用现有的工具包来完成。后文的实践是在Matlab上进行的,本章对可直接调用的工具包/函数进行介绍。
Matlab有其自带的SVM工具包:支持向量机分类 - MATLAB & Simulink - MathWorks 中国,此外也有一些外部的工具包,如比较典型也是大家常用的?LIBSVM: LIBSVM -- A Library for Support Vector Machines (ntu.edu.tw)
考虑到后者的受众更多以及可拓展性更好,本文以及后续博文中我使用LIBSVM进行实践。
LIBSVM是需要下载的,读者可以在其网站LIBSVM -- A Library for Support Vector Machines (ntu.edu.tw)上直接下载。
下载后: 解压 ---> 找到libsvm-3.35下的Matlab文件夹 --->在Matlab界面运行前述文件夹下的make.m函数(此时会生成libsvmread.mexw64、libsvmwrite.mexw64、svmpredict.mexw64、svmtrain.mexw64这几个可以被调用的函数文件) ---> 在Matlab的主页的设置路径里,将libsvm-3.35\matlab这个文件夹放到Matlab的搜索路径即可。 libsvm-3.35是版本号,当然后面可能会有其它更新的版本,不过本文的实践基于该版本。 libsvm-3.35\matlab 文件夹内部的README文档中有关于这个工具包使用的比较详细的说明(包括函数的输入输出、工具包安装等),建议结合实践多看看。
这里结合后续的实践需求,对几个函数的使用以及输入输出做简单说明:
1. model = svmtrain(training_label_vector, training_instance_matrix , [ 'libsvm_options']);
该函数是模型训练函数。输入training_label_vector 是一个N行1列的数组,每行的值对应类别;training_instance_matrix 是一个N行M列的数组,每一行对应训练集中的一个数据,该数据是M维的;[ 'libsvm_options']是一个字符串,用来设置训练参数。 输出model为训练好的模型,官方文档中对其解释为:
这里需要我们设置的参数比较多,省事的话,直接全部默认也行…
2.[predicted_label, accuracy, decision_values/prob_estimates] = svmpredict(testing_label_vector, testing_instance_matrix, model [, 'libsvm_options']);
该函数是模型测试函数。其输入与前面的训练函数类似,只不过对应的将训练集变成了测试集,此外输入中需要我们把训练好的模型送入;在输出部分,predicted_label是一个N行1列的数组,每行对应一个测试数据的预测类别;accuracy是一个包含了准确率(只有它针对分类,我们在解决分类问题时,主要看这个值)、回归的均方误差、回归的相关系数数组;decision_values/prob_estimates与所预设的参数有关:对于n个预测样本、k类的问题,如果指定“-b 1”参数,则其为n * k大小的矩阵,每一行表示这个样本分别属于每一个类别的概率;如果没有指定“-b 1”参数,则为n x k*(k-1)/2的矩阵,每一行表示k(k-1)/2个二分类SVM的预测结果(可以看到,LIBSVM对于多分类问题用的是一对一的分类方法)。
3. [label_vector, instance_matrix] = libsvmread('data.txt');
该函数用于从txt文档中提取可以直接用于训练或者测试的数据集。label_vector, instance_matrix分别对应类别和数据,与前面介绍的一样。它这里txt的数据存储格式是比较特别的,如果有外部的数据想要用这个函数来读取,需要满足它这里特定的格式才行!
4. libsvmwrite('data.txt', label_vector, instance_matrix);
该函数用于将类别和数组写入txt文档中。
关于上面几个函数,读者还可以从参考资料[5]中获得更详细解释。
四、基于所生成数据集的二分类实践
4.1 数据生成
本章的线性可分二分类数据集的生成,沿用了之前感知机的博文[1]中的代码,具体的方法读者看一遍代码就能明白,这里直接给出生成的结果:
图4.1 随机生成的线性可分(二分类)数据集
此次一共随机生成了98组数据(数据已经随机打乱),随后我们选取前floor(98*0.7)的数据进行训练,选取后30%的数据做测试。
4.2 数据训练和分类
本次实践分别选择了线性核函数和高斯核函数做训练,其余参数为默认值。
图4.2 部分代码
‘-t’可以用来选取核函数,后面接0表示线性核,接2表示高斯核。得到的结果如下:
图4.3 两种核函数方法下测试集的分类结果1
不同的颜色对应不同的类别。分类正确率为100%(因为测试数据本身分得比较开,事实上实际应用中100%的分类正确率是很难实现的),结果符合预期:
图4.3 两种核函数方法下测试集的分类结果2
第一个值对应的分类准确率,都为100%
4.3 本章小结
本章使用LIBSVM的函数对随机生成的线性可分(二分类)数据集合进行了模型训练和预测实践,结果符合预期。
五、对Iris数据集的分类实践
见本系列的第二篇博文[6]:SVM及其实践2 --- 对典型数据集的多分类实践-CSDN博客
六、对glass数据集的分类实践
见本系列的第二篇博文[6]:SVM及其实践2 --- 对典型数据集的多分类实践-CSDN博客
七、对雷达数据集的分类(实践)
挖坑待补充
八、总结
本博文(本系列博文)的目的在于捋清楚有关SVM的各个概念及其相互之间的关系,梳理基于SVM的实践流程,此外本系列博文也对多个数据集进行了分类实践。
现如今,人们似乎已经把机器学习就等价于神经网络了,SVM在科研、工程实践中越来越少用到,但SVM是最早的监督学习算法,而且其数学理论完善,具备可解释性(结果可控),SVM是机器学习的基础!通过SVM我们可以更深入地理解有关机器学习的基本概念,为后续更复杂算法的理解和实践打下基础。
九、参考资料
[1] 感知机及其实践-CSDN博客
[2] 【数之道】支持向量机SVM是什么,八分钟直觉理解其本质_哔哩哔哩_bilibili
[3] 看了这篇文章你还不懂SVM你就来打我 - 知乎 (zhihu.com)
[4] Cristianini N, Shawe-Taylor J. An introduction to support vector machines and other kernel-based learning methods[M]. Cambridge university press, 2000.
[5] 在Matlab中使用LIBSVM(函数参数的使用说明)_libsvmread函数-CSDN博客
[6]SVM及其实践2 --- 对典型数据集的多分类实践-CSDN博客
十、数据与代码参考
本文以及后续博文[6]的数据和代码我一并打包在一个文件夹下,并上传至:
SVM及其实践系列博文对应的数据和代码资源-CSDN文库
感兴趣的可以自行下载。