Python手撸机器学习系列(九):硬间隔SVM(对偶形式SMO算法求解)

目录

    • 1、对偶形式求解原理
    • 2、SMO算法求 λ \lambda λ
      • 2.1 原始解
      • 2.2 对原始解进行修剪
      • 2.2 更新 b b b
    • 3、代码实现
    • 4、参考文献及联系方式

原始形式梯度下降法求解请参考我的上一篇博客: 硬间隔SVM原始形式梯度下降法求解

1、对偶形式求解原理

引入拉格朗日乘子法
L ( w , b , λ ) = 1 2 ∣ ∣ w ∣ ∣ 2 + ∑ i = 1 N λ i ( 1 − y i ( w T x i + b ) ) L(w,b,\lambda) = \frac{1}{2}||w||^2+\displaystyle\sum_{i=1}^N\lambda_i(1-y_i(w^Tx_i+b)) L(w,b,λ)=21w2+i=1Nλi(1yi(wTxi+b))
则原问题可以写作:
min ⁡ w , b   max ⁡ λ   L ( w , b , λ ) s . t . λ i ≥ 0 \min\limits_{w,b}\ \max\limits_{\lambda} \ L(w,b,\lambda) \\s.t. \lambda_i\geq 0 w,bmin λmax L(w,b,λ)s.t.λi0
这样写的好处在于:任取一点 ( x i , y i ) (x_i,y_i) (xi,yi)

1 − y i ( w T x i + b ) > 0 1-y_i(w^Tx_i+b)>0 1yi(wTxi+b)>0时, max ⁡ λ   L ( w , b , λ ) = + ∞ \max\limits_{\lambda}\ L(w,b,\lambda) = +\infin λmax L(w,b,λ)=+,而当当 1 − y i ( w T x i + b ) < = 0 1-y_i(w^Tx_i+b)<=0 1yi(wTxi+b)<=0时, max ⁡ λ   L ( w , b , λ ) = 1 2 ∣ ∣ w ∣ ∣ 2 \max\limits_{\lambda}\ L(w,b,\lambda) = \frac{1}{2}||w||^2 λmax L(w,b,λ)=21w2

这样 min ⁡ w , b   max ⁡ λ   L ( w , b , λ ) = min ⁡ w , b ( + ∞ , 1 2 ∣ ∣ w ∣ ∣ 2 ) = min ⁡ w , b 1 2 ∣ ∣ w ∣ ∣ 2 \min\limits_{w,b}\ \max\limits_{\lambda} \ L(w,b,\lambda) = \min\limits_{w,b} (+\infin,\frac{1}{2}||w||^2) = \min\limits_{w,b}\frac{1}{2}||w||^2 w,bmin λmax L(w,b,λ)=w,bmin(+,21w2)=w,bmin21w2

相当于把不符合条件的点给筛除,而且将约束条件写在了 L L L里,把带约束的原问题变为无约束的原问题

但现,我们首先就要面对带有需要求解的参数 w , b w,b w,b的方程,而 λ \lambda λ又是不等式约束,这个求解过程不好做。所以,我们需要使用拉格朗日函数对偶性,将最小和最大的位置交换一下,这样就变成了:
max ⁡ λ   min ⁡ w , b   L ( w , b , λ ) s . t . λ i ≥ 0 \max\limits_{\lambda}\ \min\limits_{w,b}\ L(w,b,\lambda) \\s.t. \lambda_i\geq 0 λmax w,bmin L(w,b,λ)s.t.λi0
要实现这样的转化,需要满足两个条件:

  1. 是凸优化问题
  2. 满足KKT条件

显然我们以及满足了第一个条件,而要满足第二个条件,即要求:
{ ∂ L ∂ w = 0   ,   ∂ L ∂ b = 0 λ i ( 1 − y i ( w T x i + b ) ) = 0 λ i ≥ 0 1 − y i ( w T x i + b ) ≤ 0 \large\begin{cases}\large\frac{\partial L}{\partial w}=0\ ,\ \frac{\partial L}{\partial b }=0 \\ \lambda_i(1-y_i(w^Tx_i+b))=0 \\\lambda_i\geq0\\1-y_i(w^Tx_i+b)\leq0\end{cases} wL=0 , bL=0λi(1yi(wTxi+b))=0λi01yi(wTxi+b)0
让我们重新回到原问题,对于 w , b w,b w,b而言, min ⁡ w , b L ( w , b , λ ) \min\limits_{w,b}L(w,b,\lambda) w,bminL(w,b,λ)是一个无约束问题,那么对他两求偏导就好了:

b b b求偏导, ∂ L ∂ b = ∑ i = 1 N λ i y i = 0 \frac{\partial L}{\partial b} = \displaystyle\sum_{i=1}^N\lambda_iy_i = 0 bL=i=1Nλiyi=0,其中( ∣ ∣ w ∣ ∣ 2 ||w||^2 w2可以写作 w T w w^Tw wTw

带入 L ( w , b , λ ) = 1 2 ∣ ∣ w ∣ ∣ 2 + ∑ i = 1 N λ i ( 1 − y i ( w T x i + b ) ) L(w,b,\lambda) = \frac{1}{2}||w||^2+\displaystyle\sum_{i=1}^N\lambda_i(1-y_i(w^Tx_i+b)) L(w,b,λ)=21w2+i=1Nλi(1yi(wTxi+b)),得:
L ( w , b , λ ) = 1 2 ∣ ∣ w ∣ ∣ 2 + ∑ i = 1 N λ i − ∑ i = 1 N λ i y i w T x i L(w,b,\lambda) = \frac{1}{2}||w||^2+\displaystyle\sum_{i=1}^N\lambda_i-\displaystyle\sum_{i=1}^N\lambda_iy_iw^Tx_i L(w,b,λ)=21w2+i=1Nλii=1NλiyiwTxi
再对 w w w求导, ∂ L ∂ w = w − ∑ i = 1 N λ i y i x i = 0 \large\frac{\partial L}{\partial w} =w-\displaystyle\sum_{i=1}^N\lambda_iy_ix_i = 0 wL=wi=1Nλiyixi=0,可得 w = ∑ i = 1 N λ i y i x i w = \displaystyle\sum_{i=1}^N\lambda_iy_ix_i w=i=1Nλiyixi

带入 L L L,得:
L ( w , b , λ ) = − 1 2 ∑ i = 1 N ∑ j = 1 N λ i λ j y i y j x i T x j + ∑ i = 1 N λ i L(w,b,\lambda) = -\frac{1}{2}\displaystyle\sum_{i=1}^N\displaystyle\sum_{j=1}^N \lambda_i\lambda_jy_iy_jx_i^Tx_j + \displaystyle\sum_{i=1}^N\lambda_i L(w,b,λ)=21i=1Nj=1NλiλjyiyjxiTxj+i=1Nλi
最后得到:
min ⁡ w , b   max ⁡ λ   L ( w , b , λ ) = − 1 2 ∑ i = 1 N ∑ j = 1 N λ i λ j y i y j x i T x j + ∑ i = 1 N λ i s . t .   λ i ≥ 0 ,    ∑ i = 1 N λ i y i = 0 \min\limits_{w,b}\ \max\limits_{\lambda} \ L(w,b,\lambda) = -\frac{1}{2}\displaystyle\sum_{i=1}^N\displaystyle\sum_{j=1}^N \lambda_i\lambda_jy_iy_jx_i^Tx_j + \displaystyle\sum_{i=1}^N\lambda_i\\s.t.\ \lambda_i\geq0, \ \ \displaystyle\sum_{i=1}^N\lambda_iy_i=0 w,bmin λmax L(w,b,λ)=21i=1Nj=1NλiλjyiyjxiTxj+i=1Nλis.t. λi0,  i=1Nλiyi=0
其中, λ = { λ 1 , λ 2 . . . , λ N } \lambda=\{\lambda_1,\lambda_2...,\lambda_N\} λ={λ1,λ2...,λN}为一组向量

在求梯度时已经得到 w = ∑ i = 1 N λ i y i x i w = \displaystyle\sum_{i=1}^N\lambda_iy_ix_i w=i=1Nλiyixi,而对于支持向量 ( x k , y k ) (x_k,y_k) (xk,yk),总有 1 − y k ( w T x k + b ) = 0 1-y_k(w^Tx_k+b) = 0 1yk(wTxk+b)=0,转化一下:
y k ( w T x k + b ) = 1 y k 2 ( w T x k + b ) = y k w T x k + b = y k b = y k − w T x k \begin{aligned} y_k(w^Tx_k+b ) &= 1\\ y_k^2(w^Tx_k+b)&=y_k\\ w^Tx_k+b &= y_k\\ b &= y_k - w^Tx_k \end{aligned} yk(wTxk+b)yk2(wTxk+b)wTxk+bb=1=yk=yk=ykwTxk
即最后可根据 λ \lambda λ算出 w w w b b b,即确定分离超平面。
而求解 λ \lambda λ,需要用到SMO算法

2、SMO算法求 λ \lambda λ

2.1 原始解

对于对偶问题
max ⁡ λ   L ( w , b , λ ) = − 1 2 ∑ i = 1 N ∑ j = 1 N λ i λ j y i y j x i T x j + ∑ i = 1 N λ i s . t .   λ i ≥ 0     ,   ∑ i = 1 N λ i y i = 0 \max\limits_{\lambda} \ L(w,b,\lambda) = -\frac{1}{2}\displaystyle\sum_{i=1}^N\displaystyle\sum_{j=1}^N \lambda_i\lambda_jy_iy_jx_i^Tx_j + \displaystyle\sum_{i=1}^N\lambda_i\\s.t.\ \lambda_i\geq0\ \ \ ,\ \displaystyle\sum_{i=1}^N \lambda_iy_i = 0 λmax L(w,b,λ)=21i=1Nj=1NλiλjyiyjxiTxj+i=1Nλis.t. λi0   , i=1Nλiyi=0
SMO算法每次选择一对变量 ( λ i , λ j ) (\lambda_i,\lambda_j) (λi,λj)优化,剩下的固定

在优化中,谨记 y i ⋅ y i = 1 y_i·y_i=1 yiyi=1,这个式子可以正反互相转化,在SMO中多处用到

假设选取 λ 1 , λ 2 \lambda_1,\lambda_2 λ1λ2进行优化, λ 3 , λ 4 , . . . , λ N \lambda_3,\lambda_4,...,\lambda_N λ3,λ4,...,λN固定,做常数处理,将SVM的优化问题展开可得:
W ( λ 1 , λ 2 ) = λ 1 + λ 2 − 1 2 K 1 , 1 y 1 2 λ 1 2 − 1 2 K 2 , 2 y 2 2 λ 2 2 − K 1 , 2 y 1 y 2 λ 1 λ 2 − y 1 λ 1 ∑ i = 3 N λ i y i K i , 1 − y 2 λ 2 ∑ i = 3 N λ i y i K i , 2 + C W (\lambda_1,\lambda_2) = \lambda_1+\lambda_2-\frac{1}{2}K_{1,1}y_1^2\lambda_1^2-\frac{1}{2}K_{2,2}y_2^2\lambda_2^2-K_{1,2}y_1y_2\lambda_1\lambda_2 - y_1\lambda_1\displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,1} - y_2\lambda_2\displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,2}+C W(λ1,λ2)=λ1+λ221K1,1y12λ1221K2,2y22λ22K1,2y1y2λ1λ2y1λ1i=3NλiyiKi,1y2λ2i=3NλiyiKi,2+C
其中 C C C表示与 λ 1 , λ 2 \lambda_1,\lambda_2 λ1,λ2无关的常数, K i , j K_{i,j} Ki,j表示 x i T x j x_i^Tx_j xiTxj,即 x i , x j x_i,x_j xi,xj的内积

根据条件 ∑ i = 1 N λ i y i = 0 \displaystyle\sum_{i=1}^N\lambda_iy_i=0 i=1Nλiyi=0,可得:

λ 1 y 1 + λ 2 y 2 = − ∑ i = 3 N λ i y i = ζ \lambda_1y_1+\lambda_2y_2 = -\displaystyle\sum_{i=3}^N\lambda_iy_i=\zeta λ1y1+λ2y2=i=3Nλiyi=ζ

两边同乘 y 1 y_1 y1,由于 y i ⋅ y i = 1 y_i·y_i = 1 yiyi=1可得

λ 1 = y 1 ζ − λ 2 y 1 y 2 \lambda_1 = y_1\zeta-\lambda_2y_1y_2 λ1=y1ζλ2y1y2

即得到一个 λ i \lambda_i λi的值可以换算出另一个

为了便于计算,我们引入:
v 1 = ∑ i = 3 N λ i y i K i , 1 v 2 = ∑ i = 3 N λ i y i K i , 2 v_1 = \displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,1}\\ v_2 = \displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,2} v1=i=3NλiyiKi,1v2=i=3NλiyiKi,2
联合 λ 1 、 λ 2 \lambda_1、\lambda_2 λ1λ2的关系式带入 W ( λ 1 , λ 2 ) W(\lambda_1,\lambda_2) W(λ1,λ2)中,得:
W ( λ 2 ) = − 1 2 K 1 , 1 ( ζ − λ 2 y 2 ) 2 − 1 2 K 2 , 2 λ 2 2 − y 2 ( ζ − λ 2 y 2 ) λ 2 K 1 , 2 − v 1 ( ζ − λ 2 y 2 ) − v 2 y 2 λ 2 + ζ y 1 − λ 2 y 1 y 2 + λ 2 + C W(\lambda_2) =-\frac{1}{2}K_{1,1}(\zeta-\lambda_2y_2)^2-\frac{1}{2}K_{2,2}\lambda_2^2-y_2(\zeta-\lambda_2y_2)\lambda_2K_{1,2}-v_1(\zeta-\lambda_2y_2)-v_2y_2\lambda_2+\zeta y_1-\lambda_2y_1y_2+\lambda_2+C W(λ2)=21K1,1(ζλ2y2)221K2,2λ22y2(ζλ2y2)λ2K1,2v1(ζλ2y2)v2y2λ2+ζy1λ2y1y2+λ2+C
就变为了只包含 λ 2 \lambda_2 λ2的式子,此时可直接对 λ 2 \lambda_2 λ2求导:
∂ W ( λ 2 ) ∂ λ 2 = K 1 , 1 y 2 ( ζ − λ 2 y 2 ) − K 2 , 2 λ 2 + 2 K 1 , 2 λ 2 − K 1 , 2 y 2 ζ + v 1 y 2 − v 2 y 2 − y 1 y 2 + 1 = − ( K 1 , 1 + K 2 , 2 − 2 K 1 , 2 ) λ 2 + K 1 , 1 ζ y 2 − K 1 , 2 y 2 ζ + v 1 y 2 − v 2 y 2 − y 1 y 2 + 1 \begin{aligned} \frac{\partial W(\lambda_2)}{\partial \lambda_2} &= K_{1,1}y_2(\zeta-\lambda_2y_2)-K_{2,2}\lambda_2+2K_{1,2}\lambda_2-K_{1,2}y_2\zeta+v_1y_2-v_2y_2-y_1y_2+1 \\&=-(K_{1,1}+K_{2,2}-2K_{1,2})\lambda_2+K_{1,1}\zeta y_2-K_{1,2}y_2\zeta+v_1y_2-v_2y_2-y_1y_2+1 \end{aligned} λ2W(λ2)=K1,1y2(ζλ2y2)K2,2λ2+2K1,2λ2K1,2y2ζ+v1y2v2y2y1y2+1=(K1,1+K2,22K1,2)λ2+K1,1ζy2K1,2y2ζ+v1y2v2y2y1y2+1
这里需要变换一下,使得我们能使用更新前的 λ 2 o l d \lambda_2^{old} λ2old表示更新后的 λ 2 n e w \lambda_2^{new} λ2new,而不是难以计算的 ζ \zeta ζ

SVM模型对数据点的预测为: f ( x ) = ∑ i = 1 N λ i y i K ( x i , x ) + b f(x) = \displaystyle\sum_{i=1}^N\lambda_iy_iK(x_i,x)+b f(x)=i=1NλiyiK(xi,x)+b

注意,在对偶形式中,可以看做将原始形式的 w T x w^Tx wTx替换为 ∑ i = 1 N λ i y i K ( x i , x ) \displaystyle\sum_{i=1}^N\lambda_iy_iK(x_i,x) i=1NλiyiK(xi,x)

v 1 , v 2 v_1,v_2 v1,v2可以表示为:
v 1 = ∑ i = 3 N λ i y i K 1 , i = f ( x 1 ) − λ 1 y 1 K 1 , 1 − λ 2 y 2 K 1 , 2 − b v 2 = ∑ i = 3 N λ i y i K 2 , i = f ( x 2 ) − λ 1 y 1 K 1 , 2 − λ 2 y 2 K 2 , 2 − b v_1 = \displaystyle\sum_{i=3}^N\lambda_iy_iK_{1,i}=f(x_1)-\lambda_1y_1K_{1,1}-\lambda_2y_2K_{1,2}-b \\ v_2 = \displaystyle\sum_{i=3}^N\lambda_iy_iK_{2,i}=f(x_2)-\lambda_1y_1K_{1,2}-\lambda_2y_2K_{2,2}-b v1=i=3NλiyiK1,i=f(x1)λ1y1K1,1λ2y2K1,2bv2=i=3NλiyiK2,i=f(x2)λ1y1K1,2λ2y2K2,2b
且已知 λ 1 = ( ζ − λ 2 y 2 ) y 1 \lambda_1 = (\zeta-\lambda_2y_2)y_1 λ1=(ζλ2y2)y1,可得:
v 1 − v 2 = f ( x 1 ) − f ( x 2 ) − ζ K 1 , 1 + ζ K 1 , 2 + ( K 1 , 1 + K 2 , 2 − 2 K 1 , 2 ) λ 2 y 2 v_1-v_2 = f(x_1)-f(x_2)-\zeta K_{1,1}+\zeta K_{1,2}+(K_{1,1}+K_{2,2}-2K_{1,2})\lambda_2y_2 v1v2=f(x1)f(x2)ζK1,1+ζK1,2+(K1,1+K2,22K1,2)λ2y2
v 1 − v 2 v_1-v_2 v1v2的表达式带入 ∂ W ( λ 2 ) ∂ λ 2 \frac{\partial W(\lambda_2)}{\partial\lambda_2} λ2W(λ2)中,得:

∂ W ∂ λ 2 = − ( K 1 , 1 + K 2 , 2 − 2 K 1 , 2 ) λ 2 n e w + ( K 1 , 1 + K 2 , 2 − 2 K 1 , 2 ) λ 2 o l d + y 2 ( y 2 − y 1 + f ( x 1 ) − f ( x 2 ) \frac{\partial W}{\partial \lambda_2} = -(K_{1,1}+K_{2,2}-2K_{1,2})\lambda_2^{new}+(K_{1,1}+K_{2,2}-2K_{1,2})\lambda_2^{old}+y_2(y_2-y_1+f(x_1)-f(x_2) λ2W=(K1,1+K2,22K1,2)λ2new+(K1,1+K2,22K1,2)λ2old+y2(y2y1+f(x1)f(x2)

在这里, v 1 v_1 v1 v 2 v_2 v2中的 λ 2 \lambda_2 λ2是初始化(或更新前)确认的值, λ 2 \lambda_2 λ2,记为 λ 2 o l d \lambda_2^{old} λ2old,而求导求出的值是新的 λ 2 \lambda_2 λ2,记为 λ 2 n e w \lambda_2^{new} λ2new

为了进一步精简式子,我们记 E i E_i Ei为数据 x i x_i xiSVM预测值与真实值之间的误差: E i = f ( x i ) − y i E_i= f(x_i)-y_i Ei=f(xi)yi

η = K 1 , 1 + K 1 , 2 − 2 K 1 , 2 \eta=K_{1,1}+K_{1,2}-2K_{1,2} η=K1,1+K1,22K1,2,得:
∂ W ( λ 2 ) ∂ λ 2 = − η λ 2 n e w + η λ 2 o l d + y 2 ( E 1 − E 2 ) = 0 \frac{\partial W(\lambda_2)}{\partial \lambda_2} = -\eta\lambda_2^{new}+\eta\lambda_2^{old}+y_2(E_1-E_2) = 0 λ2W(λ2)=ηλ2new+ηλ2old+y2(E1E2)=0
得:
λ 2 n e w = λ 2 o l d + y 2 ( E 1 − E 2 ) η \lambda_2^{new} = \lambda_2^{old}+\frac{y_2(E_1-E_2)}{\eta} λ2new=λ2old+ηy2(E1E2)
这样便通过旧的 λ 2 \lambda_2 λ2获得了新的 λ 2 \lambda_2 λ2,再根据两个因子之间的关系求出更新后的 λ 1 \lambda_1 λ1

2.2 对原始解进行修剪

上述得到的原始解 λ 2 n e w \lambda_2^{new} λ2new是未考虑约束条件得到的,记为 λ 2 n e w , u n c l i p p e d \lambda_2^{new,unclipped} λ2new,unclipped

但在SVM中有约束,即:
{ λ 1 y 1 + λ 2 y 2 = ζ 0 ≤ λ i ≤ C \begin{cases}\lambda_1y_1+\lambda_2y_2 = \zeta \\ 0\leq\lambda_i\leq C \end{cases} {λ1y1+λ2y2=ζ0λiC
说明:这里的C是在软间隔SVM中的惩罚因子,在硬间隔SVM中可以看作无穷大
画成图:

Python手撸机器学习系列(九):硬间隔SVM(对偶形式SMO算法求解)_第1张图片

说明:其实这里的 k k k就是公式中的 ζ \zeta ζ

边界为边长为 C C C的正方形,而 λ 1 \lambda_1 λ1 λ 2 \lambda_2 λ2的约束可以用图中平行于对角线的红蓝两条线表示

y 1 ≠ y 2 y_1≠y_2 y1=y2的时候,设 y 1 − y 2 = k y_1-y_2=k y1y2=k

由于直线可以平行移动,所以分情况讨论,当直线在对角线下侧时(k>0),此时

λ 2 \lambda_2 λ2的下界 L L L为0,上界 H H H C − k = C − λ 1 + λ 2 C-k = C-\lambda_1+\lambda_2 Ck=Cλ1+λ2

而当直线在对角线上侧时(k<0),此时

λ 2 \lambda_2 λ2的下界 L L L − k = λ 2 − λ 1 -k = \lambda_2-\lambda_1 k=λ2λ1,上界 H H H C C C

写在一起:
{ L = m a x ( 0 , λ 2 − λ 1 ) H = m i n ( C , C + λ 2 − λ 1 ) \begin{cases} L = max(0,\lambda_2-\lambda_1) \\ H = min(C,C+\lambda_2-\lambda_1) \end{cases} {L=max(0,λ2λ1)H=min(C,C+λ2λ1)
同理,对于 y 1 = y 2 y_1=y_2 y1=y2的情况,有 λ 1 + λ 2 = k \lambda_1+\lambda_2=k λ1+λ2=k,此时 λ 2 \lambda_2 λ2上下界为:
{ L = m a x ( 0 , λ 1 + λ 1 − C ) H = m i n ( C , λ 1 + λ 2 ) \begin{cases} L = max(0,\lambda_1+\lambda_1-C) \\ H = min(C,\lambda_1+\lambda_2) \end{cases} {L=max(0,λ1+λ1C)H=min(C,λ1+λ2)
注意,上下界中的 λ i \lambda_i λi均为修剪之前的 λ i o l d \lambda_i^{old} λiold

根据上下界,我们可以得到修剪后的 λ 2 n e w \lambda_2^{new} λ2new
λ 2 n e w = { H λ 2 n e w , u n c l i p p e d > H λ 2 n e w , u n c l i p p e d L ≤ λ 2 n e w , u n c l i p p e d ≤ H L λ 2 n e w , u n c l i p p e d < L \lambda_2^{new} = \begin{cases} H &\lambda_2^{new,unclipped}>H \\ \lambda_2^{new,unclipped} & L\leq\lambda_2^{new,unclipped}\leq H \\ L &\lambda_2^{new,unclipped}λ2new=Hλ2new,unclippedLλ2new,unclipped>HLλ2new,unclippedHλ2new,unclipped<L
最后得到 λ 2 n e w \lambda_2^{new} λ2new即可根据 λ 1 o l d y 1 + λ 2 o l d y 2 = λ 1 n e w y 1 + λ 2 n e w y 2 \lambda_1^{old}y_1+\lambda_2^{old}y_2 = \lambda_1^{new}y_1+\lambda_2^{new}y_2 λ1oldy1+λ2oldy2=λ1newy1+λ2newy2得到 λ 1 n e w \lambda_1^{new} λ1new,即:
λ 1 n e w = λ 1 o l d + y 1 y 2 ( λ 2 o l d − λ 2 n e w ) \lambda_1^{new} = \lambda_1^{old}+y_1y_2(\lambda_2^{old}-\lambda_2^{new}) λ1new=λ1old+y1y2(λ2oldλ2new)
原因是这两个值都等于固定的其他值

2.2 更新 b b b

因为 b b b涉及到SVM中 f ( x ) f(x) f(x)的计算以及误差 E i E_i Ei的计算,所以每次需要额外更新 b b b

0 < λ 1 n e w < C 0<\lambda_1^{new}0<λ1new<C时,根据 K K T KKT KKT条件 λ i ( 1 − y i ( w T x i + b ) ) = 0 \lambda_i(1-y_i(w^Tx_i+b))=0 λi(1yi(wTxi+b))=0 可知此时

y 1 ( w T x 1 + b ) = 1 y_1(w^Tx_1+b)=1 y1(wTx1+b)=1,换算成对偶形式为: y 1 ∑ i = 1 N λ i y i K i , 1 + b = 1 y_1\displaystyle\sum_{i=1}^N\lambda_iy_iK_{i,1}+b=1 y1i=1NλiyiKi,1+b=1

即相应的数据点为支持向量

两边同时乘上 y 1 y_1 y1

∑ i = 1 N λ i y i K i , 1 + b = y 1 \displaystyle\sum_{i=1}^N\lambda_iy_iK_{i,1}+b=y_1 i=1NλiyiKi,1+b=y1

即可得 b 1 n e w b_1^{new} b1new的值:
b 1 n e w = y 1 − ∑ i = 3 N λ i y i K i , 1 − λ 1 n e w y 1 K 1 , 1 − λ 2 n e w y 2 K 2 , 1 b_1^{new} = y_1-\displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,1}-\lambda_1^{new}y_1K_{1,1}-\lambda_2^{new}y_2K_{2,1} b1new=y1i=3NλiyiKi,1λ1newy1K1,1λ2newy2K2,1
其中前两项可以变形:
y 1 − ∑ i = 3 N λ i y i K i , 1 = − E 1 + λ 1 o l d y 1 K 1 , 1 + λ 2 o l d y 2 K 2 , 1 + b o l d y_1-\displaystyle\sum_{i=3}^N\lambda_iy_iK_{i,1} = -E_1+\lambda_1^{old}y_1K_{1,1}+\lambda_2^{old}y_2K_{2,1}+b^{old} y1i=3NλiyiKi,1=E1+λ1oldy1K1,1+λ2oldy2K2,1+bold
0 < λ 2 n e w < C 0<\lambda_2^{new}0<λ2new<C,即可得到:

b 2 n e w = − E 2 − y 1 K 1 , 2 ( λ 1 n e w − λ 1 o l d ) − y 2 K 2 , 2 ( λ 2 n e w − λ 2 o l d ) + b o l d b_2^{new} = -E_2-y_1K_{1,2}(\lambda_1^{new}-\lambda_1^{old})-y_2K_{2,2}(\lambda_2^{new}-\lambda_2^{old})+b^{old} b2new=E2y1K1,2(λ1newλ1old)y2K2,2(λ2newλ2old)+bold

此时他们相等,即 b n e w = b 1 n e w = b 2 n e w b^{new}=b_1^{new}=b_2^{new} bnew=b1new=b2new

λ 1 , λ 2 \lambda_1,\lambda_2 λ1,λ2都在边界上且 L ≠ H L≠H L=H时, b 1 , b 2 b_1,b_2 b1,b2之间的值就是KKT条件的阈值,SMO算法选取中点作为新的阈值:
b n e w = 1 2 ( b 1 n e w + b 2 n e w ) b^{new} = \frac{1}{2}(b_1^{new}+b_2^{new}) bnew=21(b1new+b2new)

3、代码实现

其实只需要最后的公式,就足够写出代码了

import numpy as np
import random
import matplotlib.pyplot as plt

def simple_smo(dataset, labels, C, max_iter):
  
    dataset = np.array(dataset)
    m, n = dataset.shape #样本数量,特征数量
    labels = np.array(labels)

    # 初始化参数λ,b为0
    lambds = np.zeros(m) #每个样本都有一个λ乘子
    b = 0
    it = 0


    while it < max_iter:
        pair_changed = 0 #选取的一对值相较于之前是否有变化
        for i in range(m):
            λ_i, x_i, y_i = lambds[i], dataset[i], labels[i] #选取一组λ
            fx_i = SVM_predict(x_i,lambds,dataset,labels,b)
            E_i = fx_i - y_i
            j = select_j(i, m) #选取另一个λ
            λ_j, x_j, y_j = lambds[j], dataset[j], labels[j]
            fx_j = SVM_predict(x_j,lambds,dataset,labels,b)
            E_j = fx_j - y_j
            K_ii, K_jj, K_ij = np.dot(x_i, x_i), np.dot(x_j, x_j), np.dot(x_i, x_j)
            eta = K_ii + K_jj - 2*K_ij #
            if eta <= 0:
                print('WARNING  eta <= 0')
                continue
            # 获取更新的alpha对
            λ_i_old, λ_j_old = λ_i, λ_j #未更新前的参数
            λ_j_new = λ_j_old + y_j*(E_i - E_j)/eta
            # 对alpha进行修剪
            if y_i != y_j:
                L = max(0, λ_j_old - λ_i_old)
                H = min(C, C + λ_j_old - λ_i_old)
            else:
                L = max(0, λ_i_old + λ_j_old - C)
                H = min(C, λ_j_old + λ_i_old)
            λ_j_new = clip(λ_j_new, L, H) #根据上下界修剪
            λ_i_new = λ_i_old + y_i*y_j*(λ_j_old - λ_j_new) #根据公式反推另一个参数
            if abs(λ_j_new - λ_j_old) < 0.00001: #这个参数已经优化到最佳,换下一个
                #print('WARNING   alpha_j not moving enough')
                continue

            #更新b
            lambds[i], lambds[j] = λ_i_new, λ_j_new
            b_i = -E_i - y_i*K_ii*(λ_i_new - λ_i_old) - y_j*K_ij*(λ_j_new - λ_j_old) + b
            b_j = -E_j - y_i*K_ij*(λ_i_new - λ_i_old) - y_j*K_jj*(λ_j_new - λ_j_old) + b
            if 0 < λ_i_new < C:
                b = b_i
            elif 0 < λ_j_new < C:
                b = b_j
            else:
                b = (b_i + b_j)/2
            pair_changed += 1
            print('INFO   iteration:{}  i:{}  pair_changed:{}'.format(it, i, pair_changed))
        if pair_changed == 0: #参数优化完成,下一轮
            it += 1
        else: #参数没有优化完成,继续迭代
            it = 0
        print('iteration number: {}'.format(it))
    return lambds, b

def SVM_predict(x,lambds,data,label,b):
    "SVM分类器函数 y = w^Tx + b,即文中的f(x)"
    res = 0
    for i in range(data.shape[0]):
        res += lambds[i]*label[i]*(data[i].dot(x.T))
    return res + b


def get_w(lambdas, dataset, labels):
    #通过λ求w
    w = 0
    for i in range(len(dataset)):
        w += lambdas[i]*y[i]*dataset[i]
    return w

def clip(alpha, L, H):
    #修建λ的值到L和H之间.

    if alpha < L:
        return L
    elif alpha > H:
        return H
    else:
        return alpha

def select_j(i, m):
    #在m中随机选择除了i之外剩余的
    l = list(range(m))
    seq = l[: i] + l[i+1:]
    return random.choice(seq)

def get_point():
    x_true =  [[1,1.5],[1,3],[4,5],[2,4]]
    x_false = [[1,0.5],[4,2],[5,1],[4,1]]
    x_all = np.array(x_true+x_false)
    y = [1]*len(x_true) + [-1]*len(x_false)
    return x_all,y,x_true,x_false

def plot(x_true,x_false,w,b):
    plot_x = np.arange(0,7)
    plot_y = -(w[0]*plot_x+b)/w[1]
    plt.scatter([x[0] for x in x_true],[x[1] for x in x_true] , c='r' , label='+1')
    plt.scatter([x[0] for x in x_false],[x[1] for x in x_false] , c='b',label='-1')
    plt.plot(plot_x,plot_y,c = 'green')
    plt.xlim(0,6)
    plt.ylim(0,6)
    plt.legend()
    plt.plot()
    plt.show()

if __name__ == '__main__':
    x,y,x_true,x_false = get_point()
    lambdas, b = simple_smo(x, y, 10, 10)
    w = get_w(lambdas, x, y)
    print('-'*40+'result'+'-'*40)
    print('lambdas:{}\nw:{}\nb:{}'.format(lambdas,w,b))
    plot(x_true,x_false,w,b)

实验结果:

Python手撸机器学习系列(九):硬间隔SVM(对偶形式SMO算法求解)_第2张图片

测试一下支持向量到直线的距离(忽略相同的分母):

print(w.dot(np.array([1,1.5]))+b)
print(w.dot(np.array([1, 0.5])) + b)

结果:

请添加图片描述
除了精度上的差异,基本上已经相等

4、参考文献及联系方式

SMO算法部分参考https://zhuanlan.zhihu.com/p/29212107
对偶原理部分参考:https://www.bilibili.com/video/BV1aE411o7qd?from=search&seid=7374859475814254502&spm_id_from=333.337.0.0

以上仅为我的理解,新人自学,自知才疏学浅,如有纰漏谬误恳请指出
如有问题,欢迎评论留言,或者联系我的邮箱:
[email protected]

你可能感兴趣的:(机器学习,机器学习,支持向量机,python)