一、 引言
最近在机器学习课上,学到的《机器学习实战》第六章的支持向量机,这部分内容非常多,不仅要会编程和测试,还要理解它的数学基础,这里对这部分的学习进行一些总结。
二、 SVM的数学原理
从一个简单的二分问题开始说吧:
我们要把这两类不同的点区分开,那么在这个二维平面上就是找条直线,尽量使得这些点更好的分隔开,那么这条直线可以表示为AX+BY+C=0.
在数据集中自然是多种属性的,这时候就可以看成是n维空间,这个时候要区分这些数据,我们的目标是需要找到一个n-1维的超平面,这个超平面可以将数据分成两类,, 可以表示为W1X1+W2X2+…+WnXn+b=0(等价于 )每部分数据属于一个类别,这样的超平面其实有很多,我们需要找到一个最好的,我们希望这个超平面到每边最近数据点的距离是最大的,称为最大间隔超平面,如何找到最好的分割面呢?就是找W的系数,即权值。
还是以二维平面为例,假设距离区分直线的两条直线分别为d1和d2,支持向量机找最优权值的策略即使,先到最边上的点,再找到这两个距离之和D=d1+d2,然后求解D的最大值.
分界面是二维的,那么分界面可以表示为W1X1+W2X2+b=0,上分界线可以表示成W1X1+W2X2+b=1,下分界线可以表示成W1X1+W2X2+b=0-1;那么D就等于两直线的距离,由初等数学中两直线距离公式可知,
,这里的W=(w1,w2),是一个向量,|W|为向量的距离,那么
,下分界线同理,所以
,要使得D最大(期望训练数据中的每个点到超平面的距离最大),即
。
为了方便后续的计算,我们可以引入其对偶问题,这样优化问题变成了,约束条件为
或者
分界面以上的点有 ,我们可以假设它的标签y为1,所以分界面以下的点有
,我们可以假设它的标签y为-1。 这样的话对于上下两条分界线外的点,约束条件乘以他们的标签,我们可以修改约束条件为
,也等价于
,又因为求解
,不如求解等效的
,
所以最终的优化问题变成了 和约束条件
,这么转换的原因是为了在形式上满足KKT条件和拉格朗日乘子法,方便我们接下来求解优化问题中的W和b.
而上下边界上的点就是支持向量,这些点很关键,这也是”支持向量机“命名的由来。
概括来说SVM的核心思想就是找到不同类别之间的分界面,使得两类样本尽量落在面的两边,而且离分界面尽量远。
这里再介绍一下KKT条件和拉格朗日乘子法。
通常情况下我们要求解的最优化问题可以分为三类情况:
<1>无约束的优化问题
Min(f(x))或Max(f(x))
<2>有等式约束的优化问题
Min(f(x))或Max(f(x))
<3>有不等式约束的优化问题
Min(f(x))或Max(f(x))
对于第一类问题的求解,在高数上我们已经学习过,就是先求f(x)的导数,然后令其为零,可以求得候选最优值,再在这些值中进行验证,如果是凸函数,就可以保证最优解。
对于第二类问题,一般使用的是拉格朗日乘子法,就是把目标函数和约束条件乘以一个系数写成一个式子,这个式子称为拉格朗日函数,系数称为拉格朗日乘子。即 a是横向量,h(x)是列向量。
再通过拉格朗日函数对各个变量Xi 求偏导,令其为零,求得候选值得集合,再通过验证得到最优值。
对于第三类优化问题,一般使用的方法KKT条件,同样地,我们把所有的等式、不等式约束与f(x)写为一个式子,也叫拉格朗日函数,系数也称拉格朗日乘子,即
通过一些条件,可以求出最优值的必要条件,这个条件称为KKT条件。
这些条件表示为:
<1>L(a,b,x)对x求导为零;
<2>g(x)=0;
<3>
因为约束条件h(x)<=0,如果要满足这个等式,必须有a=0或者h(x)=0,这个是SVM很多性质的来源,如支持向量的概念。
再回到我们上面提到的SVM分类器,从我们分析的结果 ,
。满足使用拉格朗日乘子法的条件。
1. 求一个最优化问题
2. 存在不等式约束
3. 目标函数是凸函数
这个也是满足的。
所以引入拉格朗日乘子法,优化的目标改变为:
接下来求偏导,令其等于零:
这时候再带回L中,把w和b消掉
求解最开始的函数的最小值等价到现在就是求解W的最大值。现在的问题变成了:
其中是KKT条件中的要求。
我们可以发现点w是一个异常点,,这在数据中是非常常见的,属性上与其附近的点很相近,但标签却截然不同,为了解决这个这个问题,我们引入了松弛变量
修改之后的约束条件为 并且
运用拉格朗日乘子法之后的公式就变成了:
我们在优化的时候,尽可能使得松弛变量之和最小,常数C是决定松弛变量之和对优化问题的影响程度,越大表明影响越严重,C是一个大于零的值。
现在把所有问题综合起来:
,看起来相当复杂是吧,不用担心,但是该怎么求还是求。
然后对 w,b,分别求导数
因为 ,所以
,即
,又因为之前就得到
,所以
将上述条件代入目标函数中消掉w,b,r,最终得到:
发现 也一起消掉了,并且目标函数也变成了没加松弛变量之前的一样,但是相比之前添加了新的条件
最终的优化问题就变成了
接下来就是要去找最优解了。
这里就用的到SMO算法了。
1996年,John Platt发布了一个称为SMO的强大算法,用于训练SVM。SMO表示序列最小优化(Sequential Minimal Optimization)。SMO是将大优化问题分解为多个小优化问题来求解,小优化问题一般很容易求解,并且对他们进行顺序求解的结果与将他们作为整体来求得结果是完全一样的,而且这样求解的时间会短很多。
SMO方法:
概要:SMO方法的中心思想是每次取一对αi和αj,调整这两个值。增大其中一个,同时减小另外一个, αi和αj是具有一定函数关系的,所以说只有一个参数而已,得到了这些 ,就很容易计算出权重向量w了,并得到相应的超平面。
算法过程:
1.初始化α为0;
2.在每次迭代中(小于等于最大迭代数),找到第一个不满足KKT条件的训练数据,对应的αi,在其它不满足KKT条件的训练数据中,找到误差最大的x,对应的index的αj,αi和αj组成了一对,根据约束条件调αi, αj。
不满足KKT条件的公式
算法过程的数学表达:
最后来提一下核函数的概念。
再回到我们上面提到构造,都是基于数据完全线性可分,支持向量机(SVM)是一个二分类器,是一个线性的分类器
我们在之前所述是在线性问题的基础上构造的,那如果是非线性问题呢,比如说之前提到的分界线,如果变成是一个曲线呢,怎么得到这个曲线方程呢,在多维空间中就很更麻烦。但是数学家们提供了解决方法,非线性问题映射到高纬度后,会变成一个线性问题了。
比如:二维下的一个点<x1,x2><x1,x2>, 可以映射到一个5维空间,这个空间的5个维度分别是:x1,x2,x1x2,x12,x22x1,x2,x1x2,x12,x22。
映射到高维度,有两个问题:一个是如何映射?另外一个问题是计算变得更复杂了。
我们可以使用核函数(Kernel function)来解决这个问题
从上述算法过程的数学表达我们不难看出,关于向量X的计算,总是在计算两个向量的內积K(x1,x2)= <x1,x2>,所以在高纬空间里,公式的变化只有计算低维空间下的內积<x1,x2>变成了计算高纬空间下的內积<x1’,x2’>,核函数提供的方法就是通过原始空间的向量值计算高纬空间的內积,而不去管这个映射的方式。
核函数有很多种,一般使用的是高斯核(径向基函数(radial basisfunction))
可以通过调节σ来匹配维度的大小,σ越大,维度越低。
三、 程序调试
1.打开testSet.txt文件,得到每行的类标签和整个数据矩阵,类标签中的-1改用0代替,为了方便后续的处理
2.简化版的SMO
伪代码大致如下:(不同层次的循环用颜色匹配)
创建一个alpha向量并将其初始化为0向量,当迭代次数小于最大迭代次数(外循环),对数据集中每个数据向量(内循环),
如果该数据向量可以被优化:随机选择另外一个数据向量,同时优化这个向量
如果两个向量都不能被优化,退出内循环
如果所有向量都未被优化,增加迭代数,进入下次循环。
2.1 、检查alpha[j]是否改变,退出for循环,alpha[i]和alpha[j]进行同样大小的改变,一个增加,一个减小,进行优化之后设置常数项b.
2.2、观察alpha矩阵,去除掉其中的零元素
![](https://i-blog.csdnimg.cn/blog_migrate/99144370437177bb15dde7e9cd41b8bc.png)
2.3、查看那些数据点是支持向量,非零的alpha值是支持向量
3.完整的Platt SMO算法加速优化(这里引用了一个博主的文章,他对这块的解释很有逻辑性,感兴趣可以移步欣赏,并且附有有详细的代码。【机器学习实战-python3】支持向量机(Support Vecrtor Machines SVM))
简化版SMO对于小规模数据集可用,但对于大规模数据,运行速度会变慢。
完整的SMO算法通过一个外循环来选择alpha值,选择过程在两种方式之间交替:
1-在所有数据集上进行单遍扫描; 2-在非边界(不等于边界0/C的值)alpha中实现单遍扫描。实现非边界值的扫描时,需要建立alpha列表,然后对表进行遍历,跳过那些已知不会改变的alpha值。
选择第一个alpha后,通过内循环来选择第二个alpha,优化过程中选择最大步长的方式获取第二个alpha。
完整的Platt SMO算法包括以下三个部分,对应的程序大家可以到《机器学习实战》第六章找到。
<1>用于清理代码的数据结构和3个用对E缓存的辅助函数。
<2>优化过程:(选择第二个alpha)与之前简化版SMO差别不大,不过添加了自己的数据结构,在oS中传递,使用selectJ代替selectJrand来选择则第二个alpha,alpha改变时更新Ecache值
<3>外循环(包含了kernel函数-高斯核)
经过迭代得到权值W。
3.对数据进行分类的验证(对第一个数据点分类,得到的值如果大于零,则属于1类,如果小于零则属于-1类,并通过命令得到其原始的标签验证分类结果的正确性)再对第二个、第三个数据点进行验证。
4.观察k1=1.3测试错误率,训练错误率,支持向量个数。
5.手写识别问题
流程
(1)收集数据:提供原始数据的文本文件
(2)准备数据:基于手写二值图像构造向量
(3)分析数据:对图像向量进行目测
(4)训练算法:采用两种不同的核函数,并对径向基核函数采用不同设置来运行SMO算法
(5)测试算法:编写测试函数来测试不同核函数并计算error rate
导入数据进行测试:kTup=('rbf', 10)
有50个支持向量,测试数据错误率为1.6%
四、总结
算法的实现来源于数学,数学是一个非常强大的工具,深刻了解到数学上的逻辑性,会帮助我们理解程序每一个步骤,在编程时更加的有效率。
这次只是实现了一些对简单问题的分类,接下来有时间的话,想去寻找一些有意思的一些数据集,希望在上面运用支持向量机的方法,再对比一些其他的分类方法,看看支持向量机的优势与不足。
非常感谢阅读!如有不足之处,请留下您的评价和问题。
参考文献
【1】 深入理解拉格朗日乘子法(LagrangeMultiplier) 和KKT条件
https://blog.csdn.net/xianlingmao/article/details/7919597
【2】 解密SVM系列(三):SMO算法原理与实战求解
https://blog.csdn.net/on2way/article/details/47730367
【3】 机器学习实战 - 读书笔记(06) – SVM支持向量机
https://www.cnblogs.com/steven-yang/p/5658362.html
【4】 《机器学习实战》-PeterHarrington
【5】 《统计学习方法》-李航