SVM算法
SVM算法
间隔的定义
在分隔超平面定义为\(w^Tx+b=0\)时,我们定义点到超平面的距离为\(\gamma=\frac{y(x^Tx+b)}{\lVert w\rVert_2}\)。
目标函数与优化
定义了点到超平面的距离后,我们的目标就是让所有的点到分隔超平面的距离之各最小,我们定义优化函数如下:
也就是说,我们在约束条件\(y_i(w^Tx+b)\ge1(i=1,2,..,m)\)下,最大化\(\frac{1}{\lVert w\rVert_2}\),等同于最小化\(\lVert w\rVert_2^2\),通过拉格朗日函数,做最优化的求解,引入拉格朗日函数,目标函数如下:
在引入拉格朗日乘子后,我们的优化目标变为:
我们可以先求优化函数对于\(b,w\)的极小值,再接着求拉格朗日乘子\(\alpha\)的极大值。
先求\(L(w,b,\alpha)\)基于\(w,b\)的极小值,即\(\min_{w,b}L(w,b,\alpha)\),可以通过求偏导得到
从以下两个式子中可以得到\(w\)与\(\alpha\)r的关系,只要能求出优化函数对应的\(\alpha\)就可以求出\(w\)了,至于\(b\),由于上两式不存在\(b\),所以\(b\)可以有多个。我们将\(w\)t和\(b\)的关系代入优化函数\(L(w,b,\alpha)\)消除\(w\),定义新的函数为:
优化函数的推导过程如下:
在如下推导过程中,用到了范数的定义\(\Vert w\rVert_2^2=w^Tw\),和求偏数为0得到的\(w=\sum_{i=1}^{m}\alpha_iy_ix_i\)和\(\sum_{i=1}^{m}\alpha_iy_i=0\),从上述可以看到,通过对\(w,b\)极小化后,我们的优化函数\(\psi(\alpha)\)只有\(\alpha\)做为参数,只要我们能够优化\(\psi(\alpha)\)就能够求出对应的\(\alpha\),进而求出\(w,b\)。
优化函数的极大化表示如下:
去掉负号后,将问题转为求最小值的优化问题,表示如下:
具体如何求得\(\alpha\)我们可以通过SMO算法,后续再学。
假设我们通过SMO算法,得到了对应\(\alpha\)的\(\alpha^*\),那么,根据\(w=\sum_{i=1}^{m}\alpha_i^*y_ix_i\),即可求得了\(w^*\)。
求b更麻烦一些,对任意支持向量\((x_x,y_s)\)都有
假设我们有s个支持向量,则对应我们求出s个\(b^*\),理论上这些\(b^*\)都可以作为最终结果。但我们一般采取更加健壮的解,即求出所有支持向量对应的\(b^*\),然后取平均值作为最终结果。注意,对于严格线性可分的SVM,b值具有唯一解,也就是说这里求出所有的\(b^*\)都是一样的。
如何得到支持向量
根据KKT条件中的对偶互补条件\(\alpha_i^*(y_i(w^Tx_i+b)-1)=0\),如果有\(\alpha_i\gt0\)则有\(y_i(w^Tx_i+b)=1\),即点在支持向量上,否则如果\(\alpha_i=0\)则有\(y_i(w^Tx_i+b)\ge1\),即样本在支持向量上或者已经被正确分类。
对偶与KKT条件
对偶就是把求max和min的顺序交换。
KKT条件
上述条件称为KKT条件,条件表明,如果\(\alpha^*\gt0\),那么\(g_i(w^*)=0\)
SVM软件间隔最大化模型
如样本中存在异常点,使得SVM分隔超平面不能够将样本分开,或都泛化性能较差,这时,需要引入松弛因子\(\xi_i\),使得$$y_i(w\cdot x_i+b)\ge1-\xi_i$$,优化目标变为如下:
这里的C为惩罚参数,可以人理解为正则化时的参数,C越大,对误分类的惩罚越大,C越小,对误分类的惩罚越小。通过推导后,最终的优化函数结果如下:
这里与前面不加惩罚项时,只有第3个条件不一样,不加惩罚项时为\(\alpha_i\ge0\ i=1,2,...,m\),多了一个\(\alpha_i\le C\),如果\(\alpha_i=C\)说明可能是一个异常点。
SVM另一种解释--合页损失函数
如果点被正确分类,且函数间隔大于1,损失是0;否则,损失是\(1-y(w\cdot x+b)\)
线性不可分SVM与核函数
将多项式回归转为线性回归:将高次项用其他一次项未知数代替。
核心思想:对于低维不可分的数据,将其映射到高维,就可能线性可分。
注意,由低维向高维映射时,可能产生维度爆炸,那么,核函数是解决该问题的有效手段:
假设\(\phi\)是一个从低维的输入空间\(\chi\)到高维空间\(H\)映射,那么存在函数\(K(x,z)\)对于任意的\(x,z\in\chi\)都有
我们称\(K(x,z)\)为核函数,其计算是在低维空间进行的,避免了维度爆炸问题。核函数要必须是正定核函数,常用的核函数有以下几个:
-
线性核函数
\[K(x,z)=x\dot z \] -
多项式核函数
\[K(x,z)=(\gamma x\cdot z+r)^d \] -
高斯核函数
\[K(x,z)=\exp(-\gamma\lVert x-z\rVert^2)\\ \gamma\gt0 \] -
Sigmoid核函数
\[K(x,z)=\tanh(\gamma x\cdot z+r) \]
SVM最终表示
加入了惩罚项和核函数,得到的解为:
SMO算法
为求优化函数的\(m个\alpha\)是比较困难的,SMO采用一种启发式的思想,每次只优化2个变量,其他变量视为常数,由于\(\sum_{i=1}^m\alpha_iy_i=0\),两个待求变量的关系也就定了。
只弄清了原理,没有太清楚过程和细节。
线性支持回归
SVM回归模型的损失函数度量
分类模型中,加入松弛变量,我们的目标函数为
回归模型下,让训练集中的每个点尽量拟合到一个线性模型\(y_i=w\cdot \phi(x_i)+b\),我们定义一个常量\(\epsilon\)对于某一个点\((x_i,y_y)\)如果\(\lvert y_i-w\cdot\phi(x_i)-b\rvert\le\epsilon\)则完全没有损失,否则,对应的损失为\(\lvert y_i-w\cdot\phi(x_i)-b\rvert-\epsilon\)
SVM回归模型求解决
此问题同样使用KKT条件求解,具体过程略。。。
scikit-learn支持向量算法使用
库与函数
分类算法库:SVC、NuSVC、LinearSVC
回归算法库:SVR、NuSVR、LinearSVR
都在sklearn.svm模块里,这三个类的区别是对损失函数的度量方式不同。如果知道数据是线性拟合的,则使用linear,如不知道数据分布,则使用SVC。
SVM核函数
- 线性核函数:\(K(x,z)=x\cdot z\),普通内积,Linear只能使用它。
- 多项式核函数:\(K(x,z)=(\gamma x\cdot z+r)^d\),其中\(\gamma ,r,d\)都需要调参,比较麻烦。
- 高斯核函数:\(K(x,z)=\exp(-\gamma\lVert x-z\rVert^2)\),其中\(\gamma\gt 0\)需要调参。
- sigmoid核函数:\(K(x,z)=\tanh(\gamma x\cdot z+r)\),其中\(\gamma r\)需要调参。
SVM分类算法参数
- C惩罚系数
- kernel核函数选择:poly多项式,rbf高斯核
- penalty正则化参数,只对线性一拟合有意义
- 其他。。。。
SVM算法库要点
- 在训练数据之前,数据要归一化
- 在特征非常多或样本数远小于特征数时,使用线性核已经效果很好,只需要调惩罚系数C即可。
- 选择核函数时,如线性拟合不好,一般推荐使用高斯核'rbf'。这时我们主要对惩罚系数C和核函数参数\(\gamma\)进行调参,可使用交叉验证的方式。
- 理论上高斯核不会比线性核差。
例子
lsvm = SVC(kernel='linear', C=1.0)
lsvm = SVC(kernel='poly', degree=3, C=1.0)
lsvm = SVC(kernel='rbf', gamma=100, C=1.0)
SVM 高斯核(RBF)调参总结
SVM 分类模型的主要参数是两个:一个是惩罚系数C,另一个是RVF的核函数系数\(\gamma\)。
惩罚系数即松弛变量,它主要是平衡支持向量和误分类两者之间的关系,可以理解为正则化系数,当C较大时,损失函数越大,意味着我们不愿意放弃比较远的离群点。这样会有更多的支持向量,支持向量和超平面越复杂,也容易过拟合。反之,我们选择较少的支持向量,超平面也简单,sklearn默认C取值为1。
另一个超参数\(\gamma\),在高斯函数\(K(x,z)=\exp(-\gamma\lVert x-z\rVert^2)\)中定义单个样本对整个分类超平面影响。当\(\gamma\)较小时,单个样本对整个分类影响较小,不容易被选为支持向量,支持向量总数会较少。sklearn默认值是\(\frac{1}{样本特征数}\)。
当C较大,\(\gamma\)较大时,我们会有更多的支持向量。
L1比L2更不容易过拟合
SVM RBF主要调参方法
在sklearn中,我们使用GridSearchCV进行交叉验证调参。
1)estimator:模型选择
2)param_grid:参数列表
3)sv:S折交叉的折数,默认是3,样本较多时可以增大该值
SVM RBF调参例子
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
grid = GridSearchCV(SVC(), param_grid={"c": [0.1, 1, 10], "gamma": [1, 0.1, 0.01]}, cv=4)
grid.fit(x,y)
print(grid.best_params_,grid.best_score_)

浙公网安备 33010602011771号