Machine Learning-支持向量机(SVM-Support Vector Machines)

点击量:1108

好久没有更新文章了,距离上一篇文章已经快大半个月了。主要是最近这段时间太忙了,在两个项目之间来回切换,再加上好多同事要离职,组里有点动荡。其实在5月5号那天我就一口气提前把整个course都学完了,主要是每个周末都要空出来完成作业好烦(虽然不做作业我也没啥好干的),那还不如一下子全部做完吧。全部学下来感觉最难的两部分内容就是神经网络和支持向量机了,我这里说的难,指的是真正理解这两个算法,知道他们的工作原理,甚至是理解他们背后的数学原理。如果你仅仅为了完成课后的assignment,那这两部分的内容其实也是很easy的。课程中一涉及到算法背后的原理,感觉Andrew Ng讲得不够清楚,他只会告诉你用什么样的公式去计算,但不会告诉你为什么要用这个公式,以及这个公式是怎么来的。当然,我这么说并不是质疑Andrew Ng讲得不好,而是这门课设计的初衷就是为了让更多人的学会机器学习,而不管你有没有数学背景,所以Andrew Ng一直在说don’t worry about the math,don’t worry about the math…哈哈
本来这篇文章是要写Week6的内容的,但是我看了一下week6主要讲得是如何测试一个机器学习系统的性能,以及如何调整参数以达到良好的学习效果。我个人觉得,这部分内容适合在整个系列的结尾统一来讲。因此呢,本文就暂时跳过week6而主要总结下Week7的内容,介绍机器学习里一个非常重要的算法:支持向量机(SVM-Support Vector Machines)。

什么是支持向量机(Support Vector Machines)?
一个思维正常的人,第一眼看到这个概念,不管是英文还是中文,都很难理解这个概念。支持?向量?机器?一个支持向量的机器?什么跟什么啊,这么一想根本就是驴唇不对马嘴啊。其实,支持向量机是机器学习领域里一个十分重要的分类学习算法,没错,他是一个分类算法,本质上是个分类器。至于为什么要用这几个单词来命名这个算法,我们会在大致介绍完这个算法后给出。

先从简单的分类器说起
回顾我们之前在逻辑回归里讲到的使用sigmoid函数做的一个线性分类器,最终我们会找到一个decision boundary把两类数据分开,大致的结果如下:
decision_boundary_linear
这里的decision boundary(也就是图中分割的直线)的数学表达式就是 (x_{1}+x_{2}=3)。OK,那我们传统的算法是如何得到这条直线的呢?很简单,先得到cost function,然后使用梯度下降算法不断优化参数,最后得到最优解。从函数图像的角度来看就是:随机选取一条直线对数据进行分割,然后不断调整直线的位置以达到最佳分割点。 这是之前的套路,那有没有更好的算法来分离数据呢?我们先来看一张图:

large_margin_classifier

如果让你画一条直线来分割上图中的实心圆和空心圆,你凭着直觉肯定能找到一个非常接近最优解的直线。虽然你靠的只是一种“直觉”,但这背后却有着一套严谨的数学理论,这就是支持向量机算法的主要内容。换句话说,支持向量机的目的就是:寻找到这样一个超平面,使得它到两边最近样本点的间距(margin)都最大!所以支持向量机又被称为Large margin classifier(最大间距分类器)。仔细观察一下你就会发现,这个分类算法很神奇,最终这条直线/超平面的位置是由距离它最近的几个点决定的(上图就是一个实心圆和两个空心圆),跟其他样本点根本没有关系。也就是说这条直线/超平面是由这几个样本点支撑(Support)起来的,而每一个样本点都是一个多维向量(Vector),再加上这个算法本质上是个分类器(Classification Machine),所以它才叫Support Vector Machines!!!这里不得不吐槽下学术界有些新技术的命名,有点阳春白雪的味道,专门去一些让人看不懂的专有名词。哈哈。OK,看到这里,你对SVM肯定有了一个非常直观的理解了,当然这是不够滴,下面我们具体介绍下这个算法。

支持向量机的数学表达
正如上一节所说,支持向量机最直观的理解就是“寻找到这样一个超平面,使得它到两边最近样本点的间距(margin)都最大”,那么如何把这句话转换成严谨的数学语言呢?
主要分为两步:

  • 1.对于任意一条给定的直线,找到所有距离这条直线最近的样本点(可能有一个,可能多个)
  • 具体地:
    1.首先我们定义直线:
    $$y(x) = w^{T}x + b$$

    2.任一样本点x到该直线的距离为:
    $$\frac{1}{\left | w \right |}(w^{T}x + b)$$
    其中,||w||是w的范数,几何意义上表示一个向量的长度。如果不能一下子理解对这个公式,可以回忆一下初中数学知识,对照来看。平面上一个点(a,b)到直线$$Ax+By+C=0$$的距离为:
    $$d=\frac{\left | Aa+Bb+C \right |}{\sqrt{A^{2} + B^{2}}}$$
    这时你就发现:
    $$\left | w \right | = \sqrt{A^{2} + B^{2}}$$
    这也是为什么后面求目标函数时要使用范数的平方,是为了抵消开根号,方便求导。

    3.根据上述对最大间距的描述,我们有公式:
    $$\underset{w,b}{\max}\left { \frac{1}{\left | w \right |} \underset{n}{min} \left [ y_{i} (w^{T}x + b)\right ]\right }$$
    这个数学表达式精准地描述了上述对支持向量机的理解:先找出所有可能的直线/平面,满足条件就是样本点到该直线的距离最小。这个集合里的每一个元素至少包含两个信息:1.距离其最近的支撑点,2.支撑点到直线/平面的距离。然后再在这个集合中找出间距最大的那一个,就是我们要求的最优解了。但是为什么这个公式多乘以了一个y呢?这是因为直线两侧的点到直线的距离是有正负的,所以点到直线距离的公式是要加上绝对值的。所以这里我们使用(y=\left { 1,-1 \right })来表示两种不同的类别,这样一来(y_{i} * (w^{T}x + b))肯定就是正数了。

    4.这个公式还是有点复杂,我们来做个简单的等价变化。首先对于(\underset{n}{min} \left [ y_{i} (w^{T}x + b)\right ])而言,表示的是点到直线的最小值。假设存在一个这样的最小值:margin,那么该公式就可以转化为:$$y_{i} (w^{T}x + b) >= margin$$
    从而3中的公式就可以等价地转化为:
    $$\max\left {margin*\frac{1}{\left | w \right |}\right }, \ s.t. \ y_{i} (w^{T}x + b) >= margin$$

    而我们求目标函数时一般倾向于求其最小值,所以上面的公式可以等价地转化为:

    $$min\left {margin*{\left | w \right |}\right }, \ s.t. \ y_{i} (w^{T}x + b) >= margin$$

    正如我们上面提到的,这个范数||w||其实是个平方根,处理平方根不利于后面的求导,因此我们可以使用范数的平方,得到:

    $$min\left { margin\frac{1}{2}\left | w \right | ^{2}\right }, \ s.t. \ y_{i} (w^{T}x + b) >= margin$$

    为了后面的方便我们可以把margin设定为一个固定常数【1】。为什么呢?因为margin=1对最终的分类结果影响不大(不是没有影响)。具体地,我们设定最终得到的能完美分隔的直线到最近的点的距离为margin’。如果margin’ > margin,那么就说明我们把所有样本点都考虑进去了,因为条件放宽了(简单点就是:a>2 是 a>1的子集)。如果margin’ < margin,那么在margin’和margin之间的点没有被考虑到。比如margin’=0.5,margin=1。由于我们的约束条件是:(y_{i} (w^{T}x + b) >= 1),而实际上可能的最佳间隔是0.5,那么0.5到1之间的点就没有被考虑到,所以会影响结果。但是!如果我们把假设值设得很小,比如margin = 1,那么即使最后实际的最佳margin比1还小,这样的误差对最终结果的影响也是很小很小的,因为越靠近直线的点越难分隔,1已经足够小了,所以设为1对最终的分类结果影响不大。
    最终我们会得到如下公式:
    $$min\left {\frac{1}{2}*\left | w \right |^{2}\right }, \ s.t. \ y_{i} (w^{T}x + b) >= 1,i=1,…,n$$
    (其中:s.t. 是subject to的缩写,表示在某种约束条件下)
    以上就是支持向量机(Support Vector Machines)最需要理解清楚的部分了。

    OK,写了那么多,终于把那个“直觉”抽象成一个严谨的数学表达式了,那么该如何求解这个数学问题呢?我们知道目标函数是二次的,而约束条件是线性的,所以这是一个凸二次规划问题(convex quadratic programming)。他的求解步骤如下:
    a).先使用拉格朗日乘子法(lagrange multiplier)得到与这个问题等价的“对偶问题”(dual problem)。具体地,
    先给每条约束添加拉格朗日乘子α>=0,得到拉格朗日函数:
    $$L = \frac{1}{2}\left | w \right |^{2} – \sum_{n=1}^{N}a_{n}*\left { y_{n}\left ( w^{T}x^{n} +b \right ) – 1 \right }$$
    这样就把三个变量w,b,α整合进了一个函数,然后求得该函数的极值,此时我们可以使得函数L对w和b的偏导数为零就可以得到:
    $$w=\sum_{n=1}^{N}a_{n}y_{n}x_{n}$$
    $$0=\sum_{n=1}^{N}a_{n}y_{n}$$

    再把这两个公式代入到上文的拉格朗日函数,我们就可以得到凸二次规划的对偶问题,形式如下:
    $$\underset{all \ a_{n}}{\max}L(a) = \sum_{n=1}^{N}a_{n} – \frac{1}{2}\sum_{n=1}^{N}\sum_{M=1}^{N}a_{n}a_{m}y_{n}y_{m}x_{n}^{T}x_{m}\ \ s.t. \ a_{n}\geq 0,\forall n,\sum_{n=1}^{N}a_{n}y_{n}=0$$

    b).接下来如何求得对偶问题的极值呢?我们通过高效的SMO(Sequential minimal optimization)算法来最终求得拉格朗日乘子α的值。得到α就可以计算出w和b,代入到$$y(x) = w^{T}x + b$$就会得到最终的分类函数:
    $$f(x)=\left ( \sum_{i=1}^{n}a_{i}y_{i}x_{i} \right )^{T}x+b$$
    $$=\sum_{i=1}^{n}a_{i}y_{i} \left \langle x_{i},x \right \rangle + b$$
    值得注意的是,拉格朗日乘子α对于非支撑向量而言都是0。也就是说最终的分类函数只跟那几个支撑向量有关。
    上面两步计算推导涉及到很多数学知识,比如对偶问题,拉格朗日乘子,SMO算法,KTT条件等等,这些知识已经远远超过了本文的范畴,本文不作讨论。因为对于大部分只想了解SVM原理,搞一些应用的人来说,根本没必要这么深入下去。过于专注于这么细枝末节的东西,反而会让降低你对SVM在整体上的理解。总之,我们需要知道的是在训练完成后,大部分的训练样本是不需要保留的,最终的模型仅与支撑向量有关

    核函数
    在这之前我们都假设样本空间是线性可分的,然而在很多现实任务中,原始样本可能并不存在一个能正确分类的线性超平面。那怎么办呢?对于这样的问题,我们可以将样本从原始空间映射到一个更高维的特征空间,使得样本在这个特征空间内线性可分,然后再运用SVM求解。举个直观的例子:
    feature_map_kernel
    上图左边表示,样本点在二维平面是不能被线性分隔的,但是一旦把它映射到三维空间就可以很容易被一个超平面线性分隔了。(至于为什么会这样,如何证明我就orz了…)具体地,
    我们用(\varnothing \left ( x \right ))表示将x映射后的特征向量,映射后的SVM求解过程和映射前完全一样,只要把所有跟x有关的变量都换成(\varnothing \left ( x \right ))即可。这样就得到映射后的对偶问题:

    $$\sum_{i=1}^{N}\sum_{j=1}^{N}\alpha {i}\alpha _{j}y _{i}y _{j}\varnothing \left ( x{i} \right )^{T}\varnothing \left ( x_{j} \right )-\sum_{i=1}^{N}\alpha_{i} \s.t.\0\leq \alpha {i}\leq C\\sum{i=1}^{N} y_{i}\alpha _{i}=0$$

    这时我们会发现上面的式子需要计算映射后的两个向量的内积:$$\varnothing \left ( x_{i} \right )^{T}\varnothing \left ( x_{j} \right )$$
    因为映射后特征维度可能会很高,甚至是无穷维度的,直接计算映射后的两个向量的内积通常是很复杂很困难的。那怎么办呢?这个时候就有人提出:能不能找到这样一种函数,使得它满足:
    $$\kappa \left ( x_{1},x_{2} \right ) = \left \langle x_{1},x_{2} \right \rangle$$
    也就是说x1和x2在特征空间的内积等于他们在原始样本空间中通过函数k(.,.)计算的结果,这样一来就大大降低了计算的工作量。这个函数k(.,.)被称为核函数,而这种方法被称为“核技巧”(kernel trick)。其实,之所以提出这个方法是因为恰巧对偶问题公式、分类函数中都有两个向量的内积形式,研究者们通过内积联想有一种函数(核函数)能够对运算进行转换,于是核函数和SVM的结合就这样的诞生了。在实际工作中,我们通常不知道映射的形式是什么,而是直接通过核函数来计算内积进行映射,所以“核函数选择”对支持向量机来说至关重要。那么有哪些常用的核函数呢?

  • a).线性核,其实就是没有映射$$\kappa \left ( x_{1},x_{2} \right ) = \left \langle x_{1},x_{2} \right \rangle$$
  • 至于那些函数能作为核函数,请参考周志华《机器学习》6.3章节核函数部分。

    松弛变量(slack variable)
    我们之前介绍的方法是每一个样本点都要满足约束条件(这就是hard margin),这就会导致一个问题:如果几个关键的支撑向量偏离正常样本点太多就会影响最终的分类结果。比如可能会导致有些近似线性可分的问题变成线性不可分(有一/几个样本点直接跑到对面样本里去了),还有可能导致最终的分类margin变小。比如下图:
    Optimal-Hyper-Plane-2
    图中用黑圈圈起来的那个蓝点是一个异常点(outlier),很明显它是偏离大多数样本空间的,正是因为它的异常导致了最终的分割线变成了虚线而非最优的实线。那么该如何解决呢?很简单,我们要舍弃那些异常点,换句话说就是允许一部分样本点不满足约束条件(这就是soft margin):
    $$ y_{i} (w^{T}x + b) >= 1,i=1,…,n$$
    因此,我们引入松弛变量
    $$\xi {i} \geq 0$$
    得到一个新的约束条件:
    $$ y
    {i} (w^{T}x + b) >= 1 – \xi {i},i=1,…,n$$
    怎么来理解这个变量的引入呢?当我们确定一条直线/平面时,可能有些点到这条直线的距离不满足约束条件(小于1),但是这条直线对其他最近点的margin却是最大的,所以我们保留这个最大值!
    最终我们会得到这样的目标函数:
    $$ \min \frac{1}{2}\left | w \right |^{2} + C\sum
    {i=1}^{n}\xi {i}\ s.t. \ y{i} (w^{T}x + b) >= 1 – \xi _{i},i=1,…,n \\xi _{i}\geq 0,i=1,…,n$$
    具体的推导和计算不再叙述了,这里重点理解一个参数大C(因为调用某些SVM库时会提供这个参数),如果C无穷大的话,那么要使得上述函数取得最小值,则必须使得(\xi =0),也就是说满足原来的约束条件,也就是hard margin。如果C是一个有限值,那么就允许部分样本点不满足约束条件,也就是soft margin。



    课后编程作业已经上传至本人GitHub,如有需要可以参考,但请遵守课堂准则,不要抄袭。

    参考文章:
    1.周志华《机器学习》清华大学出版社
    2.支持向量机通俗导论(理解SVM的三层境界)
    3.支持向量机: Maximum Margin Classifier -pluskid
    4.支持向量机(SVM)是什么意思? – 回答作者: 靠靠靠谱
    5.机器学习有很多关于核函数的说法,核函数的定义和作用是什么?回答作者: 魏晋

    Machine Learning-支持向量机(SVM-Support Vector Machines)》上有2条评论

    1. Pingback引用通告: 核技巧(The Kernel Trick) | Eric Fan

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注