机器学习(四):支持向量机

作者: fromeast | 来源:发表于2019-07-10 20:43 被阅读4次

    一、基本原理

    给定训练样本集D=\left\{\left(\boldsymbol{x}_{1}, y_{1}\right),\left(\boldsymbol{x}_{2}, y_{2}\right), \ldots,\left(\boldsymbol{x}_{m}, y_{m}\right)\right\}, y_{i} \in\{-1,+1\},学习的目标即是找到一个划分超平面,这个超平面可以通过线性方程 \boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}+b=0 来描述。
    对于样本点\left(\boldsymbol{x}_{i}, y_{i}\right) \in D,若y_{i}=+1,则\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_{i}+b>0;若y_{i}=-1,则\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_{i}+b<0,令\left\{\begin{array}{ll}{\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_{i}+b \geqslant+1,} & {y_{i}=+1} \\ {\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}_{i}+b \leqslant-1,} & {y_{i}=-1}\end{array}\right.y_{i}\left(\boldsymbol{w}^{\mathbf{T}} \boldsymbol{x}_{i}+b\right) \geqslant 1
    样本空间中,任一点x到超平面的距离为r=\frac{\left|\boldsymbol{w}^{\mathrm{T}} \boldsymbol{x}+b\right|}{\|\boldsymbol{w}\|},距离超平面最近的几个样本点被称为支持向量(support vector),使上述不等式成立,因此两类支持向量的间隔(margin)\gamma=\frac{2}{\|\boldsymbol{w}\|}

    划分超平面、支持向量与间隔
    支持向量机的目的是找到能够正确划分训练数据集的最大间隔的划分超平面,即 可重写做 这是一个凸二次规划问题(convex quadratic programming),最大间隔划分超平面存在唯一性。
    为了更好求解上述最优化问题,考虑其对偶问题,首先构造拉格朗日函数: 其中,,令

    带入原方程,则得到对偶问题
    求出后,即可求得模型为
    上述过程需要满足KKT条件,即由上式可知,总有或。这说明训练完成后,最终模型仅与支持向量有关。

    二、算法实现

    为简明起见,本文采用sklearn的svm包实现二分类问题。首先是二维线性可分问题,如下所示:

    import numpy as np
    import scipy.io as spio
    import matplotlib.pyplot as plt
    from sklearn import svm
    datafile = 'data1.mat'
    
    def svmLinear():
        data = spio.loadmat(datafile)
        X = data['X']
        y = data['y'].ravel()
        
        svm_linear = svm.SVC(C=1.0,kernel='linear').fit(X,y)
        plot_linearBoundary(X,y,svm_linear)
        
    def plot_linearBoundary(X,y,model):
        class1 = np.where(y==1)
        class0 = np.where(y==0)
        plt.plot(X[class1,0].ravel(),X[class1,1].ravel(),'ro')
        plt.plot(X[class0,0].ravel(),X[class0,1].ravel(),'g*')
        plt.xlabel('x1')
        plt.ylabel('x2')
        plt.legend(['y=1','y=-1'])
        
        w = model.coef_
        b = model.intercept_
        xp = np.linspace(min(X[:,0]),max(X[:,0]),100)
        yp = -(w[0,0]*xp+b)/w[0,1]
        plt.plot(xp,yp,'b')
        sv = model.support_vectors_
        plt.scatter(sv[:,0],sv[:,1],s=150,c='none',alpha=0.7,edgecolor='black')
        plt.show()
    if __name__ == '__main__':    
        svmLinear()
    

    下图显示了原始数据、支持向量和划分超平面,说明了SVM的分类效果。


    二维线性可分情形

    以下为二维线性不可分的情形,采用径向基核函数,实现过程如下:

    def svmKernel():
        data = spio.loadmat('data2.mat')
        X = data['X']
        y = data['y'].ravel()
        
        svm_notlinear = svm.SVC(C=10,gamma=200,kernel='rbf').fit(X,y)
        plot_notlinearBoundary(X,y,svm_notlinear)
        
    def plot_notlinearBoundary(X,y,model):
        class1 = np.where(y==1)
        class0 = np.where(y==0)
        plt.plot(X[class1,0].ravel(),X[class1,1].ravel(),'ro')
        plt.plot(X[class0,0].ravel(),X[class0,1].ravel(),'g*')
        plt.xlabel('x1')
        plt.ylabel('x2')
        plt.legend(['y=1','y=-1'])
        
        x1 = np.linspace(min(X[:,0]),max(X[:,0]),100).reshape(1,-1).transpose()
        x2 = np.linspace(min(X[:,1]),max(X[:,1]),100).reshape(1,-1).transpose()
        X1,X2 = np.meshgrid(x1,x2)
        
        vals = np.zeros(X1.shape)
        for i in range(X1.shape[1]):
            X = np.hstack((X1[:,i].reshape(-1,1),X2[:,i].reshape(-1,1)))
            vals[:,i] = model.predict(X)
        plt.contour(X1,X2,vals,[0,1],color='b')
        sv = model.support_vectors_
        plt.scatter(sv[:,0],sv[:,1],s=150,c='none',alpha=0.7,edgecolor='black')
        plt.show()
    
    if __name__ == '__main__':    
        svmKernel()
    

    下图显示了原始数据、支持向量和划分超平面,说明了SVM的分类效果,之所以有些支持向量分布在外围,是因为在高维空间中其与划分超平面距离较近。


    二维线性不可分情形

    三、问题探讨

    3.1、序列最小优化

    可以看到最终得到的优化问题是一个二次规划问题,可以使用二次规划算法求解,对于此问题更高效的做法是序列最小优化(sequential minimial optimization, SMO)
    其基本思路是:先固定\alpha_{i}之外的参数,求\alpha_{i}的极值。由于存在约束\sum_{i=1}^{m} \alpha_{i} y_{i}=0,若固定单个\alpha_{i}之外的参数,\alpha_{i}可由其他变量导出,因此每次选择两个变量\alpha_{i}\alpha_{j},固定其他参数,重复执行以下步骤:1. 选取一对新的变量\alpha_{i}\alpha_{j}; 2. 固定\alpha_{i}\alpha_{j}以外的参数,通过优化方程计算得到更新后的\alpha_{i}\alpha_{j}
    由约束条件可以得出\alpha_{i}取值的意义:\begin{aligned} \alpha_{i}=0 & \Leftrightarrow y_{i} f\left(x_{i}\right) \geq 1 \\ 0<\alpha_{i}<C & \Leftrightarrow y_{i} f\left(x_{i}\right)=1 \end{aligned} 对于第1种情况,表明\alpha_{i}是正常分类,在边界内部;
    对于第2种情况,表明\alpha_{i}是支持向量,在边界上
    固定其他变量,考虑\alpha_{i}\alpha_{j}时:\alpha_{i} y_{i}+\alpha_{j} y_{j}=c, \quad \alpha_{i} \geqslant 0, \quad \alpha_{j} \geqslant 0 其中c是常数。

    SMO二变量优化问题

    将上式带入到原优化函数中,由于只有两个变量\alpha_{i}\alpha_{j},因此要求的目标即变成优化函数在如图对角线上的最优值,实质上使得两变量的最优化问题变为单变量的最优化问题。

    3.2、核方法

    对于一个线性可分的问题,可以用一条直线或者一个平面将其划分,而对于非线性问题(例如异或问题),就无法这样划分。一个解决的思路就是通过非线性变换,将非线性问题转化为线性问题,核方法就是这样的一个方法。其基本想法是:使用一个变换将低维空间的数据映射到高维空间,在新空间中学习到超平面将数据线性可分。
    核函数就是一个从原空间到新空间的映射,常见的核函数有:
    线性核:\kappa\left(\boldsymbol{x}_{i}, \boldsymbol{x}_{j}\right)=\boldsymbol{x}_{i}^{\mathrm{T}} \boldsymbol{x}_{j}
    多项式核:\kappa\left(\boldsymbol{x}_{i}, \boldsymbol{x}_{j}\right)=\left(\boldsymbol{x}_{i}^{\mathrm{T}} \boldsymbol{x}_{j}\right)^{d}
    高斯核:\kappa\left(\boldsymbol{x}_{i}, \boldsymbol{x}_{j}\right)=\exp \left(-\frac{\left\|\boldsymbol{x}_{i}- \boldsymbol{x}_{j}\right\|^{2}}{2 \sigma^{2}}\right)
    拉普拉斯核:\kappa\left(\boldsymbol{x}_{i}, \boldsymbol{x}_{j}\right)=\exp \left(-\frac{\left\|\boldsymbol{x}_{i}-\boldsymbol{x}_{j}\right\|}{\sigma}\right)
    sigmiod核:\kappa\left(\boldsymbol{x}_{i}, \boldsymbol{x}_{j}\right)=\tanh \left(\beta \boldsymbol{x}_{i}^{\mathrm{T}} \boldsymbol{x}_{j}+\theta\right)

    高斯核分类示意图

    参考资料

    [1] https://github.com/lawlite19/MachineLearning_Python
    [2] 周志华 著. 机器学习. 北京:清华大学出版社,2016
    [3] 李航 著. 统计学习方法. 北京:清华大学出版社,2012
    [4] 史春奇等 著. 机器学习算法背后的理论与优化. 北京:清华大学出版社,2019
    [5] Peter Harrington 著. 李锐等 译. 机器学习实战. 北京:人民邮电出版社,2013

    不见可欲,使心不乱。 ——《老子》

    相关文章

      网友评论

        本文标题:机器学习(四):支持向量机

        本文链接:https://www.haomeiwen.com/subject/lxryhctx.html