支持向量机模型 0基础小白也能懂(附代码)
原文链接
啥是向量机模型
本篇我们要讲解的模型是大名鼎鼎的支持向量机 SVM,这是曾经在机器学习界有着近乎「垄断」地位的模型,影响力持续了好多年。直至今日,即使深度学习神经网络的影响力逐渐增强,但 SVM 在中小型数据集上依旧有着可以和神经网络抗衡的极好效果和模型鲁棒性。
支持向量机学习方法,针对不同的情况,有由简至繁的不同模型:
线性可分支持向量机(linear support vector machine in linearly separable case):训练数据线性可分的情况下,通过硬间隔最大化(hard margin maximization),学习一个线性的分类器,即线性可分支持向量机(亦称作硬间隔支持向量机)。
线性支持向量机(linear support vector machine):训练数据近似线性可分的情况下,通过软间隔最大化(soft margin maximization),学习一个线性的分类器,称作线性支持向量机(又叫软间隔支持向量机)。
非线性支持向量机(non-linear support vector machine):训练数据线性不可分的情况下,通过使用核技巧(kernel trick)及软间隔最大化,学习非线性分类器,称作非线性支持向量机。
支持向量机可以借助核技巧完成复杂场景下的非线性分类,当输入空间为欧式空间或离散集合、特征空间为希尔贝特空间时,核函数(kernel function)表示将输入从输入空间映射到特征空间得到的特征向量之间的内积,先可以简单的把希尔贝特空间视作一个高维空间,核函数就是一种将低维数据映射到高维空间的方式,以便在高维空间中处理复杂的非线性问题。
通过使用核函数可以学习非线性支持向量机,等价于隐式地在高维的特征空间中学习线性支持向量机。这样的方法称为核技巧。
最大间隔分类器
1)分类问题与线性模型
分类问题是监督学习的一个核心问题。在监督学习中,当输出变量取有限个离散值时,预测问题便成为分类问题。
实际生活中,有很多问题的本质都是分类,如识别某种模式:文本分类、分词、词性标注、图像内容识别和目标检测等。
2)最大间隔分类器
不同的模型在解决分类问题时,会有不同的处理方式,直观上看,我们会使用不同的决策边界对样本进行划分。
如图中「冰墩墩」与「雪容融」两类样本点,我们对其进行分类,可以完成该分类任务的决策边界有无数个。而我们这里介绍到的 SVM 模型,要求更高一些,它不仅仅希望把两类样本点区分开,还希望找到鲁棒性最高、稳定性最好的决策边界(对应图中的黑色直线)。
这个决策边界与两侧「最近」的数据点有着「最大」的距离,这意味着决策边界具有最强的容错性,不容易受到噪声数据的干扰。直观的理解就是,如果决策边界抖动,最不容易「撞上」样本点或者进而导致误判。
支持向量机详解
1)线性可分 SVM 与硬间隔最大化
我们要找到把下图中红蓝两色的图标点分开的最优分界线。令红色的图标点\(=+1\),蓝色的图标的点\(=-1\),直线\(f(x)=w*x+b\),这里\(w,x\)是向量,其实公式等价于\(f(x)=w_1x_1+w_2x_2+...+w_nx_n+b\)
-
当向量\(x\)为二维向量时,\(f(x)\)表示二维空间中的一条直线。
-
当向量\(x\)为三维向量时,\(f(x)\)表示三维空间中的一个平面。
-
当向量\(x\)的\(n\)维向量(\(f(n)>3\))时,\(f(x)\)表示\(n\)维空间中的\(n-1\)维超平面。
当有一个新的点\(x\)需要预测属于哪个分类的时候,我们用\(sgn(f(x))\)就可以预测了。sgn表示符号函数:
-
当\(f(x)>0\)的时候,\(sgn(f(x))=+1\)。
-
当\(f(x)<0\)的时候,\(sgn(f(x))=-1\)。
回到重点,我们怎样才能取得一个最优的划分直线\(f(x)\)呢?下图的直线表示几条可能的线:
我们希望这条直线满足「最大间隔」原则,也就是如下图的形态。图中位于红色和蓝色线上的图标就是所谓的支持向量(support vector),也就是刚好卡在线上的那个数据点。
决策边界就是\(f(x)\),红色和蓝色的线是支持向量(support vector)所在的面,红色、蓝色线之间的间隙就是我们要最大化的分类间的间隙M(Margin Width)。
这里直接给出间隔\(M\)的计算公式:\(M=\frac{2}{||w||}\)。
SVM 要求解能够正确划分训练数据集并且「几何间隔」最大的分离超平面。
如下图所示,\(w*x+b\)即为分离超平面。对于线性可分的数据集来说,这样的超平面有无穷多个(即感知机),但是几何间隔最大的分离超平面却是唯一的。
- 其中\(x_i\)为第\(i\)个特征向量。
- \(y_i\)是第i个数据点的类别标签
间隔咋求,文中提到了两步如下。
1 几何间隔
公式中 s.t 是 subject to 的缩写,也就是限制条件的意思。SVM 模型的「求解最大分割超平面问题」可以表示为上面的约束最优化问题,化简的步骤中首先是先除了个\(\gamma\),然后重新代换了w和b(意义变了),最后他吧\(max(\gamma)\)也变了,最大化\(\gamma\)其实就是最大化\(\frac{2}{||w||}\)也就是\(\frac{1}{||w||}\),也就等价于最小化\(\frac{1}{2}||w||^2\),这里是把\(w\)转换了一下,方便之后的求导计算
2 对偶算法
求解线性可分支持向量机的最优化问题,我们很多时候会将它转化为对偶问题(dual problem)来求解,也就是应用「拉格朗日对偶性」,通过求解「对偶问题(dual problem)」得到「原始问题(primal problem)」的最优解
这样做有一些优点:
- 对偶问题往往更容易求解。
- 引入自然核函数,进而可以推广到非线性分类问题。
① 我们首先构建拉格朗日函数(Lagrange function)。为此,对每一个不等式约束引进拉格朗日乘子
左上角的拉格朗日函数咋来的呢?通过拉格朗日乘子\(\alpha_i\)的引入,约束条件\(y_i(w*x_i+b)\geq1\)被融入到目标函数中,而不再是外部的约束条件。这使得我们可以用标准的优化方法来处理它。如果某个解违背了约束,那么拉格朗日函数中的惩罚项就会变得很大,从而惩罚不合适的解。这样,我们通过优化拉格朗日函数,间接确保了原始约束的满足。至于\(\frac{1}{2}w^Tw\)就是之前的是向量𝑤的范数平方。
② 求\(L(w,b,\alpha)\)对w,b的极小值
首先看右上角,先将拉格朗日函数\(L(w,b,\alpha)\)分别对\(w,b\)求偏导,并令其值为0。可以得到两个式子,后面再代入到原式子中即可,这样可以得到新的仅依赖于\(\alpha_i\)的表达式。这时候,目标函数就变成了求\(\alpha_i\)的最大化问题。
③ 求\(minL(w,b,\alpha)\)对\(\alpha\)的极大值,即对偶问题
④ 通过对偶问题的解\(\alpha^*\)来求得原始优化问题中的最优解\(w^*\)和\(b^*\)
有下面的定理:设 \(a^*=(a_1^*,a_2^*,...,a_N^*)^T\)是对偶最优化问题的解,则存在下标\(j\),使得\(a_j^*>0\),并可按下式求得原始最优化问题的解\(w^*,b^*:\)
证明略过。
⑤ 由此定理可知,分离超平面可以写成
\(\sum_{i=1}^N\alpha_i^*y_i(x*x_i)+b^*=0\)
⑥ 分类决策函数可以写成
\(f(x)=sign(\sum_{i=1}^Na_i^*y_i(x*x_i)+b^*)\)
综上所述,对于给定得线性可分训练数据集,可以首先求对偶问题的解\(\alpha^*\);再利用公式求得原始问题的解 \(w^*,b^*\);从而得到分离超平面及分类决策函数。这种算法称为线性可分支持向量机的对偶学习算法,是线性可分支持向量机学习的基本算法。
线性 SVM 与软间隔最大化
我们前面提到的是线性可分的情况,但实际应用中完全线性可分的情况太少见了。如下图就是一个典型的线性不可分的分类图(我们没有办法找到一条直线,把空间划分为 个区域,一个区域只有黑点,一个区域只有白点)。
要对其进行切分,有2种方案:
图上黄色、蓝色的直线分别为支持向量所在的边界,黑色的线为决策函数,那些绿色的线表示分错的点到其相应的决策面的距离,这样我们可以在原函数上面加上一个惩罚函数,并且带上其限制条件为:
当C很大的时候,分错的点就会更少,但是过拟合的情况可能会比较严重。
当C很小的时候,分错的点可能会很多,不过可能由此得到的模型也会不太正确。
同样求解一个拉格朗日对偶问题,就能得到原问题的对偶问题的表达式
非线性 SVM 与核函数
如果我们要处理的分类问题更加复杂,甚至不能像上面一样近似线性可分呢,这种情况下找到的超平面分错的程度太高不太可接受。
对于这样的问题,一种解决方案是将样本从原始空间映射到一个更高维的特征空间(希尔贝特空间),使得样本在这个特征空间内线性可分,然后再运用 SVM 求解,如下图所示:
比如下图中的典型线性不可分的情况:
我们回忆一下之前得到的对偶问题表达式如下,做一点小小的改造,令:\(x_i^Tx_j=k(s_i,x_j)\),这个式子所做的事情就是将线性的空间映射到高维的空间,\(x_i^Tx_j=k(s_i,x_j)\)有很多种右下是比较典型的两种,上面的是多项式核,下面的是高斯径向基核,高斯核甚至是将原始空间映射为无穷维空间,另外核函数有一些比较好的性质,比如说不会比线性条件下增加多少额外的计算量,等等,此处我们不深入。对于一个问题,不同的核函数可能会带来不同的结果,我们需要做一些尝试来支撑选择(关于这个部分,大家可以看最下方的 python 实现部分)。:
SVM 总结
实现代码
不同的核函数需要指定不同的参数。
针对线性函数,只需要指定参数 \(C\),它表示对不符合最大间距规则的样本的惩罚力度。
针对多项式核函数,除了参数\(C\)外,还需要指定degree,它表示多项式的阶数。
针对高斯核函数,除了参数\(C\)外,还需要指定gamma值,这个值对应的是高斯函数公式中\(\frac{1}{2\sigma^2}\)的值。
先来看看线性函数
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm, datasets
iris = datasets.load_iris()
X = iris.data[:, :2] #只取前两维特征,方便可视化
y = iris.targetsvc = svm.SVC(kernel='linear', C=1).fit(X, y)x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
h = (x_max / x_min) / 100
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
plt.subplot(1, 1, 1)
Z = svc.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.8)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.title('SVC with linear kernel')
plt.show()
结果如下,分成了三块,分离超平面为交界线
我们再使用多项式核函数,改成svc = svm.SVC(kernel='poly', degree=3).fit(X, y)
,最高三阶多项式,结果如下
再换成高斯核函数,改成svc = svm.SVC(kernel='rbf', C=1).fit(X, y)
,这才一核
其中的C是错误项的惩罚参数C。它还控制平滑决策边界和正确分类训练点之间的权衡。
下面是c=10,100,1000的结果
gamma 值越大,SVM 就会倾向于越准确的划分每一个训练集里的数据,这会导致泛化误差较大和过拟合问题,先把gamma设置成1,svc = svm.SVC(kernel='rbf', C=1, gamma=1).fit(X, y)
。
下面是gamma参数改为10和100的结果,可以看到越来越拟合。
再把gamma加到1000的时候已经过拟合了。