欢迎到B站搜SVM SMO Python,应该能找到我的视频讲座。
在前面的课程中,我们曾经介绍了一种暴力算法如何在一个平面(二维)空间中找到一些样本点的分割平面。那个算法是很直接的,能够方便大家更好地理解支持向量机的概念和一些参数的意义,但是显然不是一个成熟的、具有扩展性、具有实际使用价值的方法。
九十年代末的时候,如我们前面提到的,John Platt发表了一篇重要的论文,如何用一个叫做SMO的算法实现SVM问题的快速求解。当然,如我们前面所介绍用QP、Convex optimization也可以求解SVM的问题的,但是SMO有诸多优点。我们不讨论各种算法的优缺点,今天我们一起来看看用Python如何实现一个SMO的算法。其实在John的论文里已经阐述的比较清楚,而且他还给出了一个Pseudo Code,但是不得不说的是SMO理解起来仍然是非常困难,好在网上能找到很多资料可以作为理解这一算法的很好的补充。
先让我们简单回顾一下上次的讲座我们得到的结论:
我们的目的就是找到”一堆“ ={ 1 2 3..., }αi={α1α2α3...,αn}使得目标函数最优(最小或最大)。SMO的思路是:每次选取两个 α, 1α1和 2α2,固定其它 α乘子,使得目标函数只是关于 1α1和 2α2的函数,求最优解。然后在这个基础上迭代,直到找到所有的 α,得到目标函数的最优解。 1α1和 2α2的选取是heuristically,优化是analytically。
我们先来看看有了 1α1和 2α2,其它 α固定的情况下,我们如何通过找到最优的 1α1和 2α2进而找到目标函数的最优解,这个也是SMO算法的核心。为了表达方便,先定义如下几个简化形式:
对于 1α1, 2α2,固定其它 α后,目标函数为表示如下:
根据等式约束,
我们有:
把上式带入式($3_1$)使之成为只针对$\alpha_2$的优化问题,如下:
这个二维函数的驻点(stationary points)满足:
式(6)两边同乘$ ^(2)$,则有:
从而我们就得出一个非常关键的计算
公式:
同时根据式子(4)我们可以得出计算
的公式如下:
上面的(8)式并没有考虑
的取值范围,我们需要把它修剪(“夹”可能更准确)(clipped)到它的取值范围以内。那么什么是它的取值范围呢?让我们看下两图。
得到了新的
和
后,我们还要计算并更新
和
,根据最上面的(1),(2),(3)我们有:
合并以上(10)和(11),有:
从而有:
在特殊情况下, 的值可能为负,即如果核函数K不遵从(not obey)Mercer定理的时候,负的 值就会出现,导致目标函数非正定(indefinite)。当一个以上的训练样本有相同的向量x时, 值还可能为0。 算法在这些特殊情况下目标函数将人为地收敛到端点的值,即 或 。这样将η值还可能为0。SMO算法在这些特殊情况下目标函数将人为地收敛到端点的值,即H或L。这样将
分别代入目标函数中即可求得极值。具体计算公式如下:
最后我们看一下算法中如何选择
和
,看一下细化的KKT条件:
这个KKT条件说明,在两条间隔线外面的点所对应的拉格朗日乘子
为0,在两条间隔线里面的对应乘子
为C,只有在两条间隔线上对应乘子的值不为0,在0和C之间。 首先选择违反0<
< ↔
=1这个条件最严重的点。如果0<
< 对应的点都满足KKT条件,再选择违反
=0↔
≥1和
= ↔
≤1的点。第二个变量的选择标准是让| 1− 2|有足够大的变化。由于
定了的时候, 1也确定了,所以要想| 1− 2|最大,只需要在 1为正时,选择最小的 作为 2, 在 1为负时,选择最大的 作为 2,可以将所有的 保存下来加快迭代。