【Matlab】【机器学习】SVM快速算法 - SMO(序列最小优化)从推理到实现

支持向量机(SVM)---------------------------------------------------------

支持向量机(support vector machines, SVM)是一种监督二分类模型,具有完善的数学理论,其目标函数具有良好的凸性,可直接运用凸优化方法一次性找到最佳分类超平面。

K i j = K ( x i , x j ) K_{ij}=K(x_i,x_j) Kij=K(xi,xj)
是数据向量 x i x_i xi x j x_j xj的内积,可以是线性内积(线性核函数),也可以是高斯内积(高斯核函数)。若为高斯内积,则为非线性SVM。
由内积表达式,有
K i j = K j i K_{ij}=K_{ji} Kij=Kji
则SVM的优化目标可写为:
max ⁡ α i J = ∑ i = 1 N α i − 1 2 ∑ i = 1 N ∑ j = 1 N α i α j y i y j K ( x i , x j ) s . t . { 0 ≤ α i ≤ C ∑ i = 1 N α i y i = 0 y i = 1 或 − 1 \begin{aligned} &\max_{\alpha_i} J = \sum_{i=1}^N\alpha_i-\frac{1}{2}\sum_{i=1}^N\sum_{j=1}^N\alpha_i\alpha_jy_iy_jK(x_i,x_j)\\ &s.t. \quad \begin{cases}0\le\alpha_i\le C\\\sum_{i=1}^N\alpha_iy_i=0\\y_i=1或-1\end{cases} \end{aligned} αimaxJ=i=1Nαi21i=1Nj=1NαiαjyiyjK(xi,xj)s.t.0αiCi=1Nαiyi=0yi=11
其中, y i y_i yi y j y_j yj分别是第 i i i个和第 j j j个训练集数据向量的标签,易得
y i 2 = 1 y_i^2=1 yi2=1
α i \alpha_i αi α j \alpha_j αj是需要优化的变量。
找到分类超平面以后,数据向量 x i x_i xi的预测公式可写为
y i = ω x i + b = ∑ j = 1 N y j α j K i j + b y_i=\omega x_i+b=\sum_{j=1}^Ny_j\alpha_jK_{ij}+b yi=ωxi+b=j=1NyjαjKij+b
{ l a b e l i = 1 , y i > 1 l a b e l i = 1 且 x i 是 支 持 向 量 , y i = 1 l a b e l i = 1 且 x i 是 软 间 隔 引 入 的 误 分 类 支 持 向 量 , 0 < y i < 1 l a b e l i 不 存 在 , x i 在 分 类 超 平 面 上 , y i = 0 l a b e l i = − 1 且 x i 是 软 间 隔 引 入 的 误 分 类 支 持 向 量 , − 1 < y i < 0 l a b e l i = − 1 且 x i 是 支 持 向 量 , y i = − 1 l a b e l i = − 1 , y i < − 1 \begin{cases} label_i=1,\quad y_i>1\\ label_i=1且x_i是支持向量, \quad y_i=1\\ label_i=1且x_i是软间隔引入的误分类支持向量, \quad 0<y_i<1\\ label_i不存在,x_i在分类超平面上,\quad y_i=0\\ label_i=-1且x_i是软间隔引入的误分类支持向量, \quad -1<y_i<0\\ label_i=-1且x_i是支持向量,\quad y_i=-1\\ label_i=-1,\quad y_i<-1 \end{cases} labeli=1,yi>1labeli=1xi,yi=1labeli=1xi,0<yi<1labelixi,yi=0labeli=1xi,1<yi<0labeli=1xi,yi=1labeli=1,yi<1
其中, l a b e l i label_i labeli是数据向量 x i x_i xi所属类别。

序列最小优化(SMO)------------------------------------------------------

原始论文:J. C. Platt, Sequential Minimal Optimization:A Fast Algorithm for Training Support Vector Machines (1998) Microsoft Research
传统的SVM凸优化计算效率很低。1998年,来自微软研究院的John C. Platt提出了目前使用最为广泛的快速SVM算法——SMO(Sequential Minimal Optimization,序列最小优化)算法,已用于LibSVM软件包中。该算法每次选择两个 α \alpha α,固定其他 α \alpha α进行优化,直到收敛。
SMO算法实际上与支持向量机本身没有任何关系,它只是一种解决函数凸优化问题的快速方法,所以,该方法的思想一样可以用于解决其他凸函数的凸优化问题。
SMO算法在每一次迭代中,分为内循环和外循环。在外循环中,算法逐一选择每个 α \alpha α。若算法在外循环中的某一步选择了 α i \alpha_i αi,则此时进入内循环,在所有 α \alpha α中选择一个作为 α j \alpha_j αj
根据《机器学习实战》这本书的介绍:
1、如果 α j \alpha_j αj是随机不重复选择的,则叫做简易SMO算法,此时得到的分类超平面是全局最佳。
2、如果根据原始SMO算法里的启发式方法,若找到一个 α j \alpha_j αj,使得 f ( x j ) − y j f(x_j)-y_j f(xj)yj α i \alpha_i αi的误差 f ( x i ) − y i f(x_i)-y_i f(xi)yi相差最大,则目标函数就能以最快速度收敛,此时得到的分类超平面是在最佳分类超平面附近,且每次算法得到的分类边界都不一样。
不失一般性,假设在某次迭代中,选择了 α 1 \alpha_1 α1 α 2 \alpha_2 α2,在SVM的目标函数J中,将与 α 1 \alpha_1 α1 α 2 \alpha_2 α2有关的项单独写出,可构成SMO的目标函数 W S M O W_{SMO} WSMO,为

W S M O = α 1 + α 2 + ∑ i = 3 N α i − [ 1 2 α 1 y 1 ( α 1 y 1 K 11 + α 2 y 2 K 12 + ∑ j = 3 N α j y j K 1 j ) + 1 2 α 2 y 2 ( α 1 y 1 K 21 + α 2 y 2 K 22 + ∑ j = 3 N α j y j K 2 j ) + 1 2 ∑ i = 3 N α i y i ( α 1 y 1 K i 1 + α 2 y 2 K i 2 + ∑ j = 3 N α j y j K i j ) ] = α 1 + α 2 − 1 2 y 1 2 α 1 2 K 11 − y 1 y 2 α 1 α 2 K 12 − 1 2 y 2 2 α 2 2 K 22 − y 1 α 1 ∑ i = 3 N y i α i K 1 i − y 2 α 2 ∑ i = 3 N y i α i K 2 i + A {\begin{aligned} W_{SMO}&=\alpha_1+\alpha_2+\sum_{i=3}^N\alpha_i-\begin{aligned} [&\frac{1}{2}\alpha_1y_1(\alpha_1y_1K_{11}+\alpha_2y_2K_{12}+\sum_{j=3}^N\alpha_jy_jK_{1j})+\\&\frac{1}{2}\alpha_2y_2(\alpha_1y_1K_{21}+\alpha_2y_2K_{22}+\sum_{j=3}^N\alpha_jy_jK_{2j})+\\&\frac{1}{2}\sum_{i=3}^N\alpha_iy_i(\alpha_1y_1K_{i1}+\alpha_2y_2K_{i2}+\sum_{j=3}^N\alpha_jy_jK_{ij})]\end{aligned}\\&=\alpha_1+\alpha_2-\frac{1}{2}y_1^2\alpha_1^2K_{11}-y_1y_2\alpha_1\alpha_2K_{12}-\frac{1}{2}y_2^2\alpha_2^2K_{22}-y_1\alpha_1\sum_{i=3}^Ny_i\alpha_iK_{1i}-y_2\alpha_2\sum_{i=3}^Ny_i\alpha_iK_{2i}+A\end{aligned}} WSMO=α1+α2+i=3Nαi[21α1y1(α1y1K11+α2y2K12+j=3NαjyjK1j)+21α2y2(α1y1K21+α2y2K22+j=3NαjyjK2j)+21i=3Nαiyi(α1y1Ki1+α2y2Ki2+j=3NαjyjKij)]=α1+α221y12α12K11y1y2α1α2K1221y22α22K22y1α1i=3NyiαiK1iy2α2i=3NyiαiK2i+A

其中
A = ∑ i = 3 N α i − 1 2 ∑ i = 3 N ∑ j = 3 N y i y j α i α j K i j A=\sum_{i=3}^N\alpha_i-\frac{1}{2}\sum_{i=3}^N\sum_{j=3}^Ny_iy_j\alpha_i\alpha_jK_{ij} A=i=3Nαi21i=3Nj=3NyiyjαiαjKij
由于 A A A α 1 \alpha_1 α1 α 2 \alpha_2 α2无关,所以是一个常数,单独写出来。
因此,SVM的目标变为
max ⁡ α 1 , α 2 W S M O = α 1 + α 2 − 1 2 y 1 2 α 1 2 K 11 − y 1 y 2 α 1 α 2 K 12 − 1 2 y 2 2 α 2 2 K 22 − y 1 α 1 ∑ i = 3 N y i α i K 1 i − y 2 α 2 ∑ i = 3 N y i α i K 2 i + A \begin{aligned} &\max_{\alpha_1,\alpha_2} W_{SMO} = \alpha_1+\alpha_2-\frac{1}{2}y_1^2\alpha_1^2K_{11}-y_1y_2\alpha_1\alpha_2K_{12}-\frac{1}{2}y_2^2\alpha_2^2K_{22}-y_1\alpha_1\sum_{i=3}^Ny_i\alpha_iK_{1i}-y_2\alpha_2\sum_{i=3}^Ny_i\alpha_iK_{2i}+A\end{aligned} α1,α2maxWSMO=α1+α221y12α12K11y1y2α1α2K1221y22α22K22y1α1i=3NyiαiK1iy2α2i=3NyiαiK2i+A
s . t . { 0 ≤ α i ≤ C ∑ i = 1 N α i y i = 0 y i = 1 或 − 1 s.t. \quad \begin{cases}0\le\alpha_i\le C\\\sum_{i=1}^N\alpha_iy_i=0\\y_i=1或-1\end{cases} s.t.0αiCi=1Nαiyi=0yi=11
现在,可找出 α 1 \alpha_1 α1 α 2 \alpha_2 α2之间的关系表达式。由 ∑ i = 1 N α i y i = 0 \sum_{i=1}^N\alpha_iy_i=0 i=1Nαiyi=0,则
y 1 α 1 + y 2 α 2 = − ∑ i = 3 N y i α i = ζ y_1\alpha_1+y_2\alpha_2=-\sum_{i=3}^Ny_i\alpha_i=\zeta y1α1+y2α2=i=3Nyiαi=ζ
注意, ζ \zeta ζ A A A中的项,所以是常数。两边同乘 y 1 y_1 y1,有 α 1 + y 1 y 2 α 2 = y 1 ζ \alpha_1+y_1y_2\alpha_2=y_1\zeta α1+y1y2α2=y1ζ

α 1 = y 1 ζ − y 1 y 2 α 2 ( 1 ) \alpha_1=y_1\zeta-y_1y_2\alpha_2\quad(1) α1=y1ζy1y2α2(1)
对于 W S M O W_{SMO} WSMO,令
v 1 = ∑ i = 3 N y i α i K 1 i v_1=\sum_{i=3}^Ny_i\alpha_iK_{1i} v1=i=3NyiαiK1i v 2 = ∑ i = 3 N y i α i K 2 i v_2=\sum_{i=3}^Ny_i\alpha_iK_{2i} v2=i=3NyiαiK2i
注意, v 1 v_1 v1 v 2 v_2 v2 α 1 \alpha_1 α1 α 2 \alpha_2 α2无关,所以都是常数。则
W S M O = α 1 + α 2 − 1 2 y 1 2 α 1 2 K 11 − y 1 y 2 α 1 α 2 K 12 − 1 2 y 2 2 α 2 2 K 22 − y 1 α 1 v 1 − y 2 α 2 v 2 + A W_{SMO} = \alpha_1+\alpha_2-\frac{1}{2}y_1^2\alpha_1^2K_{11}-y_1y_2\alpha_1\alpha_2K_{12}-\frac{1}{2}y_2^2\alpha_2^2K_{22}-y_1\alpha_1v_1-y_2\alpha_2v_2+A WSMO=α1+α221y12α12K11y1y2α1α2K1221y22α22K22y1α1v1y2α2v2+A
将(1)式代入 W S M O W_{SMO} WSMO,经化简,有
W S M O = y 1 ζ − y 1 y 2 α 2 + α 2 − 1 2 ( ζ − y 2 α 2 ) 2 K 11 − 1 2 α 2 2 K 22 − y 2 α 2 ( ζ − y 2 α 2 ) K 12 − ( ζ − y 2 α 2 ) v 1 − y 2 α 2 v 2 + A W_{SMO}=y_1\zeta -y_1y_2\alpha_2+\alpha_2-\frac{1}{2}(\zeta -y_2\alpha_2)^2K_{11}-\frac{1}{2}\alpha_2^2K_{22}-y_2\alpha_2(\zeta-y_2\alpha_2)K_{12}-(\zeta-y_2\alpha_2)v_1-y_2\alpha_2v_2+A WSMO=y1ζy1y2α2+α221(ζy2α2)2K1121α22K22y2α2(ζy2α2)K12(ζy2α2)v1y2α2v2+A
由于 W S M O W_{SMO} WSMO中的量 y 1 , y 2 , ζ , K 11 , K 12 , K 22 , v 1 , v 2 , A y_1,y_2,\zeta,K_{11},K_{12},K_{22},v_1,v_2,A y1y2ζK11K12K22v1v2A都是常量,所以到此,SVM的多元函数优化问题,转化为了一元函数优化问题,即函数 W S M O W_{SMO} WSMO只与 α 2 \alpha_2 α2有关,即
max ⁡ α 1 , α 2 W S M O = y 1 ζ − y 1 y 2 α 2 + α 2 − 1 2 ( ζ − y 2 α 2 ) 2 K 11 − 1 2 α 2 2 K 22 − y 2 α 2 ( ζ − y 2 α 2 ) K 12 − ( ζ − y 2 α 2 ) v 1 − y 2 α 2 v 2 + A \begin{aligned} &\max_{\alpha_1,\alpha_2} W_{SMO} =y_1\zeta -y_1y_2\alpha_2+\alpha_2-\frac{1}{2}(\zeta -y_2\alpha_2)^2K_{11}-\frac{1}{2}\alpha_2^2K_{22}-y_2\alpha_2(\zeta-y_2\alpha_2)K_{12}-(\zeta-y_2\alpha_2)v_1-y_2\alpha_2v_2+A \end{aligned} α1,α2maxWSMO=y1ζy1y2α2+α221(ζy2α2)2K1121α22K22y2α2(ζy2α2)K12(ζy2α2)v1y2α2v2+A s . t . 0 ≤ α 2 ≤ C s.t. \quad 0\le\alpha_2\le C s.t.0α2C
显然,对于一元函数优化问题,首先需要求函数的一阶导函数,即
d W S M O d α 2 = − y 1 y 2 + 1 + y 2 ( ζ − α 2 y 2 ) K 11 − α 2 K 22 − y 2 ( ζ − 2 α 2 y 2 ) K 12 + y 2 v 1 − y 2 v 2 = 0 \frac{dW_{SMO}}{d\alpha_2}=-y_1y_2+1+y_2(\zeta-\alpha_2y_2)K_{11}-\alpha_2K_{22}-y_2(\zeta-2\alpha_2y_2)K_{12}+y_2v_1-y_2v_2=0 dα2dWSMO=y1y2+1+y2(ζα2y2)K11α2K22y2(ζ2α2y2)K12+y2v1y2v2=0
经化简,有
d W S M O d α 2 = − y 1 y 2 + 1 − ( K 11 + K 22 − 2 K 12 ) α 2 + y 2 ζ ( K 11 − K 12 ) + y 2 ( v 1 − v 2 ) = 0 \frac{dW_{SMO}}{d\alpha_2}=-y_1y_2+1-(K_{11}+K_{22}-2K_{12})\alpha_2+y_2\zeta(K_{11}-K_{12})+y_2(v_1-v_2)=0 dα2dWSMO=y1y2+1(K11+K222K12)α2+y2ζ(K11K12)+y2(v1v2)=0
注意到, d W S M O d α 2 \frac{dW_{SMO}}{d\alpha_2} dα2dWSMO中的 v 1 v_1 v1 v 2 v_2 v2形式不够简洁,考察其是否可与前次迭代的结果联系起来,从而减少运算量。
首先,给出SVM对数据向量 x i x_i xi的预测结果 f ( x i ) f(x_i) f(xi)表达式
f ( x i ) = b + ∑ j = 1 N y j α j K i j f(x_i)=b+\sum_{j=1}^Ny_j\alpha_jK_{ij} f(xi)=b+j=1NyjαjKij
观察 v 1 v_1 v1 v 2 v_2 v2的形式,发现其与 f ( x i ) f(x_i) f(xi)较为相似,可对其进行改写,有
v 1 = ∑ i = 3 N y i α i K 1 i = f ( x 1 ) − b − y 1 α 1 K 11 − y 2 α 2 K 12 v_1=\sum_{i=3}^Ny_i\alpha_iK_{1i}=f(x_1)-b-y_1\alpha_1K_{11}-y_2\alpha_2K_{12} v1=i=3NyiαiK1i=f(x1)by1α1K11y2α2K12 v 2 = ∑ i = 3 N y i α i K 2 i = f ( x 2 ) − b − y 1 α 1 K 21 − y 2 α 2 K 22 v_2=\sum_{i=3}^Ny_i\alpha_iK_{2i}=f(x_2)-b-y_1\alpha_1K_{21}-y_2\alpha_2K_{22} v2=i=3NyiαiK2i=f(x2)by1α1K21y2α2K22
必须注意,上述两个式子中的 f ( x 1 ) , f ( x 2 ) , b , α 1 , α 2 f(x_1),f(x_2),b,\alpha_1,\alpha_2 f(x1)f(x2)bα1α2都是上一次迭代计算出的结果,为了与本次迭代计算出的所有新变量进行区分,令上一次迭代的 f ( x 1 ) , f ( x 2 ) , b , α 1 , α 2 f(x_1),f(x_2),b,\alpha_1,\alpha_2 f(x1)f(x2)bα1α2分别为 f ( x 1 ) o l d , f ( x 2 ) o l d , b o l d , α 1 o l d , α 2 o l d f(x_1)^{old},f(x_2)^{old},b^{old},\alpha_1^{old},\alpha_2^{old} f(x1)oldf(x2)oldboldα1oldα2old,则
v 1 − v 2 = f ( x 1 ) o l d − f ( x 2 ) o l d − y 1 α 1 o l d ( K 11 − K 21 ) − y 2 α 2 o l d ( K 12 − K 22 ) v_1-v_2=f(x_1)^{old}-f(x_2)^{old}-y_1\alpha_1^{old}(K_{11}-K_{21})-y_2\alpha_2^{old}(K_{12}-K_{22}) v1v2=f(x1)oldf(x2)oldy1α1old(K11K21)y2α2old(K12K22)
将(1)式代入,消去 α 1 o l d \alpha_1^{old} α1old,同时为统一形式,令 K 12 K_{12} K12表示 K 21 K_{21} K21,化简,有
v 1 − v 2 = f ( x 1 ) o l d − f ( x 2 ) o l d − ζ ( K 11 − K 12 ) + y 2 α 2 o l d ( K 11 + K 22 − 2 K 12 ) v_1-v_2=f(x_1)^{old}-f(x_2)^{old}-\zeta(K_{11}-K_{12})+y_2\alpha_2^{old}(K_{11}+K_{22}-2K_{12}) v1v2=f(x1)oldf(x2)oldζ(K11K12)+y2α2old(K11+K222K12)
代入 d W S M O d α 2 \frac{dW_{SMO}}{d\alpha_2} dα2dWSMO,有

d W S M O d α 2 = \begin{aligned}\frac{dW_{SMO}}{d\alpha_2}=\end{aligned} dα2dWSMO=
− y 1 y 2 + 1 − ( K 11 + K 22 − 2 K 12 ) α 2 + y 2 ζ ( K 11 − K 12 ) + y 2 [ f ( x 1 ) o l d − f ( x 2 ) o l d − ζ ( K 11 − K 12 ) + y 2 α 2 o l d ( K 11 + K 22 − 2 K 12 ) ] = 0 \begin{aligned}-y_1y_2+1-(K_{11}+K_{22}-2K_{12})\alpha_2+y_2\zeta(K_{11}-K_{12})+y_2[f(x_1)^{old}-f(x_2)^{old}-\zeta(K_{11}-K_{12})+y_2\alpha_2^{old}(K_{11}+K_{22}-2K_{12})]=0\end{aligned} y1y2+1(K11+K222K12)α2+y2ζ(K11K12)+y2[f(x1)oldf(x2)oldζ(K11K12)+y2α2old(K11+K222K12)]=0

化简,有
d W S M O d α 2 = − y 1 y 2 + 1 − ( K 11 + K 22 − 2 K 12 ) α 2 + y 2 ( f ( x 1 ) o l d − f ( x 2 ) o l d ) + α 2 o l d ( K 11 + K 22 − 2 K 12 ) = 0 \frac{dW_{SMO}}{d\alpha_2}=-y_1y_2+1-(K_{11}+K_{22}-2K_{12})\alpha_2+y_2(f(x_1)^{old}-f(x_2)^{old})+\alpha_2^{old}(K_{11}+K_{22}-2K_{12})=0 dα2dWSMO=y1y2+1(K11+K222K12)α2+y2(f(x1)oldf(x2)old)+α2old(K11+K222K12)=0
η = K 11 + K 22 − 2 K 12 \eta=K_{11}+K_{22}-2K_{12} η=K11+K222K12,有
d W S M O d α 2 = − y 1 y 2 + 1 − η α 2 + y 2 ( f ( x 1 ) o l d − f ( x 2 ) o l d ) + α 2 o l d η = 0 \frac{dW_{SMO}}{d\alpha_2}=-y_1y_2+1-\eta\alpha_2+y_2(f(x_1)^{old}-f(x_2)^{old})+\alpha_2^{old}\eta=0 dα2dWSMO=y1y2+1ηα2+y2(f(x1)oldf(x2)old)+α2oldη=0 y 2 2 = 1 y_2^2=1 y22=1,则有
d W S M O d α 2 = − y 1 y 2 + y 2 2 + α 2 o l d η − α 2 η + y 2 ( f ( x 1 ) o l d − f ( x 2 ) o l d ) = 0 \frac{dW_{SMO}}{d\alpha_2}=-y_1y_2+y_2^2+\alpha_2^{old}\eta-\alpha_2\eta+y_2(f(x_1)^{old}-f(x_2)^{old})=0 dα2dWSMO=y1y2+y22+α2oldηα2η+y2(f(x1)oldf(x2)old)=0

d W S M O d α 2 = α 2 o l d η − α 2 η + y 2 ( f ( x 1 ) o l d − f ( x 2 ) o l d − y 1 + y 2 ) = 0 \frac{dW_{SMO}}{d\alpha_2}=\alpha_2^{old}\eta-\alpha_2\eta+y_2(f(x_1)^{old}-f(x_2)^{old}-y_1+y_2)=0 dα2dWSMO=α2oldηα2η+y2(f(x1)oldf(x2)oldy1+y2)=0

E 1 o l d = f ( x 1 ) o l d − y 1 E_1^{old}=f(x_1)^{old}-y_1 E1old=f(x1)oldy1 E 2 o l d = f ( x 2 ) o l d − y 2 E_2^{old}=f(x_2)^{old}-y_2 E2old=f(x2)oldy2

d W S M O d α 2 = α 2 o l d η − α 2 η + y 2 ( E 1 o l d − E 2 o l d ) = 0 \frac{dW_{SMO}}{d\alpha_2}=\alpha_2^{old}\eta-\alpha_2\eta+y_2(E_1^{old}-E_2^{old})=0 dα2dWSMO=α2oldηα2η+y2(E1oldE2old)=0
此时 α 2 \alpha_2 α2的表达式可由上一次迭代计算好的 α 2 o l d \alpha_2^{old} α2old表示,即
α 2 = α 2 o l d + y 2 ( E 1 o l d − E 2 o l d ) η \alpha_2=\alpha_2^{old}+\frac{y_2(E_1^{old}-E_2^{old})}{\eta} α2=α2old+ηy2(E1oldE2old)
到此为止, α 2 \alpha_2 α2计算出来了,但是还从没有考虑过 α 2 \alpha_2 α2的取值范围问题。然而在SVM优化问题中, α i \alpha_i αi的取值范围规定为 0 ≤ α i ≤ C 0\le\alpha_i\le C 0αiC,且满足 y 1 α 1 + y 2 α 2 = − ∑ i = 3 N y i α i = ζ y_1\alpha_1+y_2\alpha_2=-\sum_{i=3}^Ny_i\alpha_i=\zeta y1α1+y2α2=i=3Nyiαi=ζ

接下来对 α 2 \alpha_2 α2进行范围限制

接下来,必须对 α 2 \alpha_2 α2的取值范围加以限制,以满足SVM优化问题的约束条件。
已知, y i = 1 或 − 1 y_i=1或-1 yi=11,则 y 1 α 1 + y 2 α 2 = ζ y_1\alpha_1+y_2\alpha_2=\zeta y1α1+y2α2=ζ会出现4种情况,即
{ α 1 + α 2 = ζ α 1 − α 2 = ζ − α 1 + α 2 = ζ − α 1 − α 2 = ζ ⇒ { α 1 = − α 2 + ζ α 1 = α 2 + ζ α 1 = α 2 − ζ α 1 = − α 2 − ζ ⇒ { 0 ≤ − α 2 + ζ ≤ C 0 ≤ α 2 + ζ ≤ C 0 ≤ α 2 − ζ ≤ C 0 ≤ − α 2 − ζ ≤ C ⇒ { ζ − C ≤ α 2 ≤ ζ ① − ζ ≤ α 2 ≤ C − ζ ② ζ ≤ α 2 ≤ C + ζ ③ − ( C + ζ ) ≤ α 2 ≤ − ζ ④ \begin{cases} \alpha_1+\alpha_2=\zeta\\ \alpha_1-\alpha_2=\zeta\\ -\alpha_1+\alpha_2=\zeta\\ -\alpha_1-\alpha_2=\zeta \end{cases} \Rightarrow \begin{cases} \alpha_1=-\alpha_2+\zeta\\ \alpha_1=\alpha_2+\zeta\\ \alpha_1=\alpha_2-\zeta\\ \alpha_1=-\alpha_2-\zeta \end{cases} \Rightarrow \begin{cases} 0\le-\alpha_2+\zeta\le C\\ 0\le\alpha_2+\zeta\le C\\ 0\le\alpha_2-\zeta\le C\\ 0\le-\alpha_2-\zeta\le C \end{cases} \Rightarrow \begin{cases} \zeta-C\le\alpha_2\le\zeta \quad ①\\ -\zeta\le\alpha_2\le C-\zeta \quad ②\\ \zeta\le\alpha_2\le C+\zeta \quad ③\\ -(C+\zeta)\le\alpha_2\le -\zeta \quad ④\\ \end{cases} α1+α2=ζα1α2=ζα1+α2=ζα1α2=ζα1=α2+ζα1=α2+ζα1=α2ζα1=α2ζ0α2+ζC0α2+ζC0α2ζC0α2ζCζCα2ζζα2Cζζα2C+ζ(C+ζ)α2ζ
在四种情况中,只有 ζ \zeta ζ是变化的,现在需要讨论在不同 ζ \zeta ζ下的情况。

A. 对于情况① y 1 = y 2 = 1 y_1=y_2=1 y1=y2=1,方程为 α 1 = − α 2 + ζ \alpha_1=-\alpha_2+\zeta α1=α2+ζ,绘制出其图像
在这里插入图片描述

图中,直线 α 1 = − α 2 + ζ \alpha_1=-\alpha_2+\zeta α1=α2+ζ从下到上扫过方形区域, ζ \zeta ζ是直线与 α 1 \alpha_1 α1轴的交点,即直线的截距。由图知,可以将 ζ \zeta ζ的取值范围分为四个部分看待:
ζ < 0 , 0 ≤ ζ < C , C ≤ ζ < 2 C , 2 C ≤ ζ \zeta<0,\quad 0\le\zeta<C,\quad C\le\zeta<2C,\quad2C\le\zeta ζ<0,0ζ<C,Cζ<2C,2Cζ
1、当 ζ < 0 \zeta<0 ζ<0时,为图中最下面的那条直线的情况,直线与方形区域没有交点。将 ζ < 0 \zeta<0 ζ<0代入①式,有 ζ − C < 0 \zeta-C<0 ζC<0,则
( ζ − C ≤ α 2 ≤ ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = ∅ (\zeta-C\le\alpha_2\le\zeta)\cap(0\le\alpha_2\le C)=\varnothing (ζCα2ζ)(0α2C)=
2、当 0 ≤ ζ < C 0\le\zeta<C 0ζ<C时,直线扫过方形区域下半部分。将 0 ≤ ζ < C 0\le\zeta<C 0ζ<C代入①式,有 − C ≤ ζ − C < 0 -C\le\zeta-C<0 CζC<0
( ζ − C ≤ α 2 ≤ ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = 0 ≤ α 2 ≤ ζ (\zeta-C\le\alpha_2\le\zeta)\cap(0\le\alpha_2\le C)=0\le\alpha_2\le\zeta (ζCα2ζ)(0α2C)=0α2ζ
3、当 C ≤ ζ < 2 C C\le\zeta<2C Cζ<2C时,直线扫过方形区域上半部分。将 C ≤ ζ < 2 C C\le\zeta<2C Cζ<2C代入①式,有 0 ≤ ζ − C < C 0\le\zeta-C<C 0ζC<C,则
( ζ − C ≤ α 2 ≤ ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = ζ − C ≤ α 2 ≤ C (\zeta-C\le\alpha_2\le\zeta)\cap(0\le\alpha_2\le C)=\zeta-C\le\alpha_2\le C (ζCα2ζ)(0α2C)=ζCα2C
4、当 2 C ≤ ζ 2C\le\zeta 2Cζ时,为图中最上方的直线的情况,直线与方形区域没有交点。将 2 C ≤ ζ 2C\le\zeta 2Cζ代入①式,有 C ≤ ζ − C C\le\zeta-C CζC,则
( ζ − C ≤ α 2 ≤ ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = ∅ (\zeta-C\le\alpha_2\le\zeta)\cap(0\le\alpha_2\le C)=\varnothing (ζCα2ζ)(0α2C)=
综上,有
{ ∅ , ζ < 0 0 ≤ α 2 ≤ ζ , 0 ≤ ζ < C ζ − C ≤ α 2 ≤ C , C ≤ ζ < 2 C ∅ , 2 C ≤ ζ \begin{cases} \varnothing,\quad\zeta<0\\ 0\le\alpha_2\le\zeta,\quad0\le\zeta<C\\ \zeta-C\le\alpha_2\le C,\quad C\le\zeta<2C\\ \varnothing,\quad 2C\le\zeta \end{cases} ,ζ<00α2ζ,0ζ<CζCα2C,Cζ<2C,2Cζ
将该不等式组写成一个不等式,有
m a x ( 0 , ζ − C ) ≤ α 2 ≤ m i n ( ζ , C ) max(0,\zeta-C)\le\alpha_2\le min(\zeta,C) max(0,ζC)α2min(ζ,C)
注意到,对于情况①,虽然 α 1 + α 2 = ζ \alpha_1+\alpha_2=\zeta α1+α2=ζ,但是此时的 α 2 \alpha_2 α2没有完全计算完,而对 α 2 \alpha_2 α2的范围规定又需要 ζ \zeta ζ,这就造成了矛盾。为了避免这种情况,令 α 1 o l d + α 2 o l d = ζ \alpha_1^{old}+\alpha_2^{old}=\zeta α1old+α2old=ζ,则
m a x ( 0 , α 1 o l d + α 2 o l d − C ) ≤ α 2 ≤ m i n ( α 1 o l d + α 2 o l d , C ) max(0,\alpha_1^{old}+\alpha_2^{old}-C)\le\alpha_2\le min(\alpha_1^{old}+\alpha_2^{old},C) max(0,α1old+α2oldC)α2min(α1old+α2old,C)
B. 对于情况② y 1 = 1 , y 2 = − 1 y_1=1,y_2=-1 y1=1y2=1,方程为 α 1 = α 2 + ζ \alpha_1=\alpha_2+\zeta α1=α2+ζ,绘制出其图像
在这里插入图片描述

图中,直线 α 1 = α 2 + ζ \alpha_1=\alpha_2+\zeta α1=α2+ζ从下到上扫过方形区域, ζ \zeta ζ是直线与 α 1 \alpha_1 α1轴的交点,即直线的截距。由图知,可以将 ζ \zeta ζ的取值范围分为四个部分看待:
ζ < − C , − C ≤ ζ < 0 , 0 ≤ ζ < C , C ≤ ζ \zeta<-C,\quad -C\le\zeta<0,\quad 0\le\zeta<C,\quad C\le\zeta ζ<C,Cζ<0,0ζ<C,Cζ
1、当 ζ < − C \zeta<-C ζ<C时,为图中最下面的那条直线的情况,直线与方形区域没有交点。将 ζ < − C \zeta<-C ζ<C代入②式,有 − ζ > C -\zeta>C ζ>C C − ζ > 2 C C-\zeta>2C Cζ>2C,则
( − ζ ≤ α 2 ≤ C − ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = ∅ (-\zeta\le\alpha_2\le C-\zeta)\cap(0\le\alpha_2\le C)=\varnothing (ζα2Cζ)(0α2C)=
2、当 − C ≤ ζ < 0 -C\le\zeta<0 Cζ<0时,直线扫过方形区域下半部分。将 − C ≤ ζ < 0 -C\le\zeta<0 Cζ<0代入②式,有 0 < − ζ ≤ C 0<-\zeta\le C 0<ζC C < C − ζ ≤ 2 C C<C-\zeta\le 2C C<Cζ2C
( − ζ ≤ α 2 ≤ C − ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = − ζ ≤ α 2 ≤ C (-\zeta\le\alpha_2\le C-\zeta)\cap(0\le\alpha_2\le C)=-\zeta\le\alpha_2\le C (ζα2Cζ)(0α2C)=ζα2C
3、当 0 ≤ ζ < C 0\le\zeta<C 0ζ<C时,直线扫过方形区域上半部分。将 0 ≤ ζ < C 0\le\zeta<C 0ζ<C代入②式,有 − C < − ζ ≤ 0 -C<-\zeta\le0 C<ζ0, 0 < C − ζ ≤ C 0< C-\zeta\le C 0<CζC,则
( − ζ ≤ α 2 ≤ C − ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = 0 ≤ α 2 ≤ C − ζ (-\zeta\le\alpha_2\le C-\zeta)\cap(0\le\alpha_2\le C)=0\le\alpha_2\le C-\zeta (ζα2Cζ)(0α2C)=0α2Cζ
4、当 C ≤ ζ C\le\zeta Cζ时,为图中最上方的直线的情况,直线与方形区域没有交点。将 2 C ≤ ζ 2C\le\zeta 2Cζ代入②式,有 − ζ ≤ − 2 C -\zeta\le -2C ζ2C C − ζ ≤ − C C-\zeta\le-C CζC
( − ζ ≤ α 2 ≤ C − ζ ) ∩ ( 0 ≤ α 2 ≤ C ) = ∅ (-\zeta\le\alpha_2\le C-\zeta)\cap(0\le\alpha_2\le C)=\varnothing (ζα2Cζ)(0α2C)=
综上,有
{ ∅ , ζ < − C − ζ ≤ α 2 ≤ C , − C ≤ ζ < 0 0 ≤ α 2 ≤ C − ζ , 0 ≤ ζ < C ∅ , C ≤ ζ \begin{cases} \varnothing,\quad\zeta<-C\\ -\zeta\le\alpha_2\le C,\quad-C\le\zeta<0\\ 0\le\alpha_2\le C-\zeta,\quad 0\le\zeta<C\\ \varnothing,\quad C\le\zeta \end{cases} ,ζ<Cζα2C,Cζ<00α2Cζ,0ζ<C,Cζ
将该不等式组写成一个不等式,有
m a x ( 0 , − ζ ) ≤ α 2 ≤ m i n ( C , C − ζ ) max(0,-\zeta)\le\alpha_2\le min(C,C-\zeta) max(0,ζ)α2min(C,Cζ)
将②式中的 α 1 o l d − α 2 o l d = ζ \alpha_1^{old}-\alpha_2^{old}=\zeta α1oldα2old=ζ代入,有
m a x ( 0 , α 2 o l d − α 1 o l d ) ≤ α 2 ≤ m i n ( C , C + α 2 o l d − α 1 o l d ) max(0,\alpha_2^{old}-\alpha_1^{old})\le\alpha_2\le min(C,C+\alpha_2^{old}-\alpha_1^{old}) max(0,α2oldα1old)α2min(C,C+α2oldα1old)
C. 对于情况③ y 1 = − 1 , y 2 = 1 y_1=-1,y_2=1 y1=1y2=1,方程为 α 1 = α 2 − ζ \alpha_1=\alpha_2-\zeta α1=α2ζ,可以发现方程中的 − ζ -\zeta ζ与情况②的 ζ \zeta ζ差一个负号,所以只需将 − ζ -\zeta ζ代替情况②中的所有 ζ \zeta ζ,即可得到
m a x ( 0 , ζ ) ≤ α 2 ≤ m i n ( C , C + ζ ) max(0,\zeta)\le\alpha_2\le min(C,C+\zeta) max(0,ζ)α2min(C,C+ζ)
将③式中的 − α 1 o l d + α 2 o l d = ζ -\alpha_1^{old}+\alpha_2^{old}=\zeta α1old+α2old=ζ代入,有
m a x ( 0 , α 2 o l d − α 1 o l d ) ≤ α 2 ≤ m i n ( C , C + α 2 o l d − α 1 o l d ) max(0,\alpha_2^{old}-\alpha_1^{old})\le\alpha_2\le min(C,C+\alpha_2^{old}-\alpha_1^{old}) max(0,α2oldα1old)α2min(C,C+α2oldα1old)
D. 对于情况④ y 1 = y 2 = − 1 y_1=y_2=-1 y1=y2=1,方程为 α 1 = − α 2 − ζ \alpha_1=-\alpha_2-\zeta α1=α2ζ,可以发现方程中的 − ζ -\zeta ζ与情况①的 ζ \zeta ζ差一个负号,所以只需将 − ζ -\zeta ζ代替情况①中的所有 ζ \zeta ζ,即可得到
m a x ( 0 , − ζ − C ) ≤ α 2 ≤ m i n ( − ζ , C ) max(0,-\zeta-C)\le\alpha_2\le min(-\zeta,C) max(0,ζC)α2min(ζ,C)
将④式中的 − α 1 o l d − α 2 o l d = ζ -\alpha_1^{old}-\alpha_2^{old}=\zeta α1oldα2old=ζ代入,有
m a x ( 0 , α 1 o l d + α 2 o l d − C ) ≤ α 2 ≤ m i n ( α 1 o l d + α 2 o l d , C ) max(0,\alpha_1^{old}+\alpha_2^{old}-C)\le\alpha_2\le min(\alpha_1^{old}+\alpha_2^{old},C) max(0,α1old+α2oldC)α2min(α1old+α2old,C)
综上讨论,可以得到 α 2 \alpha_2 α2的取值范围,即
{ m a x ( 0 , α 1 o l d + α 2 o l d − C ) ≤ α 2 ≤ m i n ( α 1 o l d + α 2 o l d , C ) , y 1 = y 2 m a x ( 0 , α 2 o l d − α 1 o l d ) ≤ α 2 ≤ m i n ( C , C + α 2 o l d − α 1 o l d ) , y 1 ≠ y 2 \begin{cases} max(0,\alpha_1^{old}+\alpha_2^{old}-C)\le\alpha_2\le min(\alpha_1^{old}+\alpha_2^{old},C),\quad y_1=y_2\\ max(0,\alpha_2^{old}-\alpha_1^{old})\le\alpha_2\le min(C,C+\alpha_2^{old}-\alpha_1^{old}),\quad y_1\neq y_2\\ \end{cases} {max(0,α1old+α2oldC)α2min(α1old+α2old,C),y1=y2max(0,α2oldα1old)α2min(C,C+α2oldα1old),y1=y2
α 2 \alpha_2 α2按照上述范围进行裁剪,任何大于或小于上下界的 α 2 \alpha_2 α2都强制赋值为上界的值或下界的值。

现在完成了对 α 2 \alpha_2 α2的完整计算。

α 1 \alpha_1 α1 α 2 \alpha_2 α2之间的关系表达式 y 1 α 1 + y 2 α 2 = ζ = − ∑ i = 3 N y i α i y_1\alpha_1+y_2\alpha_2=\zeta=-\sum_{i=3}^Ny_i\alpha_i y1α1+y2α2=ζ=i=3Nyiαi,有
α 1 = y 1 ζ − y 1 y 2 α 2 \alpha_1=y_1\zeta-y_1y_2\alpha_2 α1=y1ζy1y2α2
现在,需要对 ζ \zeta ζ进行表达。
在本次迭代中, ζ = − ∑ i = 3 N y i α i \zeta=-\sum_{i=3}^Ny_i\alpha_i ζ=i=3Nyiαi始终与 α 1 和 α 2 \alpha_1和\alpha_2 α1α2无关,所以 ζ \zeta ζ是常数,没有发生变化,所以 y 1 α 1 + y 2 α 2 = y 1 α 1 o l d + y 2 α 2 o l d y_1\alpha_1+y_2\alpha_2=y_1\alpha_1^{old}+y_2\alpha_2^{old} y1α1+y2α2=y1α1old+y2α2old,所以有
α 1 = α 1 o l d + y 1 y 2 ( α 2 o l d − α 1 o l d ) \alpha_1=\alpha_1^{old}+y_1y_2(\alpha_2^{old}-\alpha_1^{old}) α1=α1old+y1y2(α2oldα1old)
计算出了 α 1 \alpha_1 α1 α 2 \alpha_2 α2后,就可以计算偏置 b b b了。

现在开始计算偏置 b b b

0 < α 1 < C 0<\alpha_1<C 0<α1<C,可知 x 1 x_1 x1是支持向量,有
y 1 ( ω x 1 + b 1 ) = 1 y_1(\omega x_1+b_1)=1 y1(ωx1+b1)=1

y 1 y 1 ( ω x 1 + b 1 ) = y 1 y_1y_1(\omega x_1+b_1)=y_1 y1y1(ωx1+b1)=y1

ω x 1 + b 1 = y 1 \omega x_1+b_1=y_1 ωx1+b1=y1

f ( x 1 ) = ∑ i = 1 N y i α i K 1 i + b 1 = y 1 α 1 K 11 + y 2 α 2 K 12 + ∑ i = 3 N y i α i K 1 i + b 1 = y 1 f(x_1)=\sum_{i=1}^Ny_i\alpha_iK_{1i}+b_1=y_1\alpha_1K_{11}+y_2\alpha_2K_{12}+\sum_{i=3}^Ny_i\alpha_iK_{1i}+b_1=y_1 f(x1)=i=1NyiαiK1i+b1=y1α1K11+y2α2K12+i=3NyiαiK1i+b1=y1

b 1 = y 1 − y 1 α 1 K 11 − y 2 α 2 K 12 − ∑ i = 3 N y i α i K 1 i b_1=y_1-y_1\alpha_1K_{11}-y_2\alpha_2K_{12}-\sum_{i=3}^Ny_i\alpha_iK_{1i} b1=y1y1α1K11y2α2K12i=3NyiαiK1i

y 1 − ∑ i = 3 N y i α i K 1 i = y 1 + f ( x 1 ) o l d − f ( x 1 ) o l d − ∑ i = 3 N y i α i K 1 i y_1-\sum_{i=3}^Ny_i\alpha_iK_{1i}=y_1+f(x_1)^{old}-f(x_1)^{old}-\sum_{i=3}^Ny_i\alpha_iK_{1i} y1i=3NyiαiK1i=y1+f(x1)oldf(x1)oldi=3NyiαiK1i

y 1 − ∑ i = 3 N y i α i K 1 i = y 1 − f ( x 1 ) o l d + y 1 α 1 o l d K 11 + y 2 α 2 o l d K 12 + ∑ i = 3 N y i α i K 1 i + b 1 o l d − ∑ i = 3 N y i α i K 1 i y_1-\sum_{i=3}^Ny_i\alpha_iK_{1i}=y_1-f(x_1)^{old}+y_1\alpha_1^{old}K_{11}+y_2\alpha_2^{old}K_{12}+\sum_{i=3}^Ny_i\alpha_iK_{1i}+b_1^{old}-\sum_{i=3}^Ny_i\alpha_iK_{1i} y1i=3NyiαiK1i=y1f(x1)old+y1α1oldK11+y2α2oldK12+i=3NyiαiK1i+b1oldi=3NyiαiK1i
E 1 o l d = f ( x 1 ) o l d − y 1 E_1^{old}=f(x_1)^{old}-y_1 E1old=f(x1)oldy1,则
y 1 − ∑ i = 3 N y i α i K 1 i = b 1 o l d − E 1 o l d + y 1 α 1 o l d K 11 + y 2 α 2 o l d K 12 y_1-\sum_{i=3}^Ny_i\alpha_iK_{1i}=b_1^{old}-E_1^{old}+y_1\alpha_1^{old}K_{11}+y_2\alpha_2^{old}K_{12} y1i=3NyiαiK1i=b1oldE1old+y1α1oldK11+y2α2oldK12
代回 b 1 b_1 b1的表达式,有
b = b 1 = b 1 o l d − E 1 o l d + y 1 ( α 1 o l d − α 1 ) K 11 + y 2 ( α 2 o l d − α 2 ) K 12 b=b_1=b_1^{old}-E_1^{old}+y_1(\alpha_1^{old}-\alpha_1)K_{11}+y_2(\alpha_2^{old}-\alpha_2)K_{12} b=b1=b1oldE1old+y1(α1oldα1)K11+y2(α2oldα2)K12
0 < α 2 < C 0<\alpha_2<C 0<α2<C,可知 x 2 x_2 x2是支持向量,与上述同理,有
b = b 2 = b 2 o l d − E 2 o l d + y 1 ( α 2 o l d − α 2 ) K 21 + y 2 ( α 2 o l d − α 2 ) K 12 b=b_2=b_2^{old}-E_2^{old}+y_1(\alpha_2^{old}-\alpha_2)K_{21}+y_2(\alpha_2^{old}-\alpha_2)K_{12} b=b2=b2oldE2old+y1(α2oldα2)K21+y2(α2oldα2)K12
α 1 和 α 2 \alpha_1和\alpha_2 α1α2都在开区间(0, C)中,即如果 x 1 和 x 2 x_1和x_2 x1x2都是支持向量,则 b 1 和 b 2 b_1和b_2 b1b2实际上表达的是同一个超平面的偏置,即 b = b 1 = b 2 b=b_1=b_2 b=b1=b2
α 1 和 α 2 \alpha_1和\alpha_2 α1α2都在开区间(0, C)以外,则 x 1 和 x 2 x_1和x_2 x1x2要么不是支持向量,要么就是软间隔引入的误分类点,此时
b = b 1 + b 2 2 b=\frac{b_1+b_2}{2} b=2b1+b2

到此, α 1 , α 2 , b \alpha_1,\alpha_2,b α1α2b都计算完成。

等算法执行完外循环时,即可得到所有的 α \alpha α和最佳的 b b b,则可确定分类超平面。

●═══════════════════════════════我是分割线═════════════════════════════●

下面给出代码

代码基于Matlab R2018b,翻译自《机器学习实战》SVM一章的Python代码,如果存在任何不能运行的问题,请仔细检查程序中的函数用法是否匹配您所使用的Matlab版本。

简化版SMO:

clear all
close all
clc
%% 读数据
% 人工数据集
filename = '您想要测试的数据集txt文件,每一行是每一个数据点的横坐标,纵坐标和标签,标签只能是1或-1';
[dataMat, labelMat] = loadDataSet(filename);
[N, D] = size(dataMat);
% 绘图
if D == 2
    figure(1)
    indices0 = find(labelMat == -1);
    indices1 = find(labelMat == 1);
    dataMat0 = dataMat(indices0, :);
    dataMat1 = dataMat(indices1, :);
    scatter(dataMat0(:, 1), dataMat0(:, 2), 50, 'k.');
    hold on;
    scatter(dataMat1(:, 1), dataMat1(:, 2), 50, 'k+');
    hold on;
end
%% 运行简易SMO算法,执行SVM分类
% 赋超参数
kTup = {'RBF', 10}; % 线性核为'linear',高斯核为'RBF'10为高斯核标准差
C = 10; % 控制软间隔中误分类程度的参数,C越大,误分类越少,或软间隔越“硬”,即支持向量的位置与分类超平面越近
toler = 0.001; % 检查
maxIter = 200;
[b, alphas] = smoSimple(dataMat, labelMat, C, toler, maxIter, kTup);
% 得到支持向量
supportVectorsIndices = find(alphas > 0);
supportVectors = dataMat(supportVectorsIndices, :);
% 计算运用核函数后任意两条数据的内积kernelEval
errorCount = 0;
for i = 1: N
    kernelEval(:, i) = kernelTrans(supportVectors, dataMat(i, :), kTup);
    predict = kernelEval(:, i)' * (labelMat(supportVectorsIndices) .* alphas(supportVectorsIndices)) + b;
    if sign(predict) ~= sign(labelMat(i))
        errorCount = errorCount + 1;
    end
end
fprintf('训练误差为: %.2f%%\n', errorCount / N * 100);
% 绘图
accBound = 0.1; % 决定分类线的精度。值越小,分类线越精确,同时绘制速度越慢
plotSVM(kTup, D, dataMat, labelMat, b, alphas, supportVectors, supportVectorsIndices, accBound);

%% 生成线性可分数据集
function [feature, category]=generate_sample(step,error,b1)
aa=3*rand(1); %斜率
bb=3; %截距   
rr =error;
s=step;
x1(:,1) = -2.5:s:2.5;
n = length(x1(:,1));
x1(:,2) = aa.*x1(:,1) + bb + b1 + rr*abs(randn(n,1));
y1 = ones(n,1);
x2(:,1) =  -2.5:s:2.5;
x2(:,2) = aa.*x2(:,1) + bb - b1 - rr*abs(randn(n,1));
y2 = -ones(n,1);
feature=[x1;x2];
category=[y1;y2];
end

%% 若数据维数为2,则可绘图
function plotSVM(kTup, D, dataMat, labelMat, b, alphas, supportVectors, supportVectorsIndices, accBound)
if D == 2
    % 分类线位于所有预测值为0的数据点位置上。
    % 1、对屏幕空间的矩形范围(至少包含所有训练数据点)内的所有坐标点进行预测
    %       点与点的间隔越小,分类边界线越精确
    % 2、画出预测值为0的点
    % 3、将所有标出的点连起来,构成高维分类超平面在二维上的投影边界
    %2和第3步可以用contour函数直接实现
    % 构建屏幕空间坐标集合screenCorMat,第一页为X坐标,第二页为Y坐标
    screenCorX = min(dataMat(:, 1)): accBound: max(dataMat(:, 1));
    screenCorY = min(dataMat(:, 2)): accBound: max(dataMat(:, 2));
    M = length(screenCorY);
    N = length(screenCorX);
    screenCorX = repmat(screenCorX, [M , 1]);
    screenCorY = repmat(screenCorY',[1, N]);
    screenCorMat = cat(3, screenCorX, screenCorY);
    % 平铺屏幕空间所有点,便于预测
    screenCorMat = reshape(screenCorMat, [M * N, 2]);
    % 对屏幕空间所有点进行预测,得到预测结果矩阵predictCor
    for i = 1: M * N
        kernelCor(:, i) = kernelTrans(supportVectors, screenCorMat(i, :), kTup);
        predictCor(i) = kernelCor(:, i)' * (labelMat(supportVectorsIndices) .* alphas(supportVectorsIndices)) + b;
    end
    predictCor = reshape(predictCor, [M, N]);
    % 绘制预测结果为0的所有点,连起来,构成分类边界线
    figure(1), contour(screenCorX, screenCorY, predictCor, [0, 0], 'k--'); hold on;
    hold on;
    % 圈出所有支持向量
    figure(1), scatter(supportVectors(:, 1), supportVectors(:, 2), 100, 'k'); hold on;
    % 绘制出边界点所在曲线
    figure(1), contour(screenCorX, screenCorY, predictCor, [1 1], 'r--'); hold on;
    figure(1), contour(screenCorX, screenCorY, predictCor, [-1 -1], 'r--');
else
    fprintf('数据维数高于2维,无法绘图\n');
end
end

%% 读取数据函数
function [dataMat, labelMat] = loadDataSet(filename)
fid = fopen(filename);
format = [repmat('%f', [1, 3])];
data = cell2mat(textscan(fid, format));
dataMat = data(:, 1: end - 1);
labelMat = data(:, end);
end

%%1到m之间随机选取一个整数j
function j = selectJrand(i, m)
j = i;
while (j == i)
    j = randperm(m, 1);
end
end

%% 调整大于H或小于L的alpha,即掐头去尾
function aj = clipAlpha(aj, H, L)
% 令大于H的alpha等于H
if aj > H
    aj = H;
end
% 令小于L的alpha等于L
if aj < L
    aj = L;
end
end

%% 简化版SMO(序列最小优化)算法
function [b, alphas] = smoSimple(dataMat, labelMat, C, toler, maxIter, kTup)
b = 0;
[N, D] = size(dataMat);
alphas = zeros(N, 1);
iter = 0;
for i = 1: N
    kernalData(:, i) = kernelTrans(dataMat, dataMat(i, :), kTup);
end
while (iter < maxIter)
    alphaPairsChanged = 0; % 记录alpha已经优化的数量
    for i = 1: N
        fXi = (alphas .* labelMat)' * kernalData(:, i) + b; % fXi为预测结果
        Ei = fXi - labelMat(i); % Ei为使用alpha_i计算时的预测误差
        % 接下来的if语句判断某条数据是否符合KKT条件
        if ((labelMat(i) * Ei < -toler) && (alphas(i) < C)) || ((labelMat(i) * Ei > toler) && (alphas(i) > 0))
            % 若alpha可更改,则执行如下语句
            % 随机选一个alpha的下标j
            j = selectJrand(i, N);
            % 使用选出来的alpha_j计算预测结果fXj
            fXj = (alphas .* labelMat)' * kernalData(:, j) + b;
            Ej = fXj - labelMat(j); % Ej为使用alpha_j计算时的预测误差
            alphaIold = alphas(i);
            alphaJold = alphas(j);
            % 计算alpha_j的上下界
            if labelMat(i) ~= labelMat(j)
                L = max(0, alphas(j) - alphas(i));
                H = min(C, C + alphas(j) - alphas(i));
            else
                L = max(0, alphas(j) + alphas(i) - C);
                H = min(C, alphas(j) + alphas(i));
            end
            if L == H
                fprintf('上下界相等,跳过此步循环,不再计算alpha_j\n');
                continue;
            end
            eta = 2.0 * kernalData(i, j) - kernalData(i, i) - kernalData(j, j);
            if eta >= 0
                fprintf("eta >= 0\n");
                continue;
            end
            alphas(j) = alphas(j) - labelMat(j) * (Ei - Ej) / eta;
            alphas(j) = clipAlpha(alphas(j), H, L);
            if (abs(alphas(j) - alphaJold) < 0.00001)
                fprintf("新alpha_j与旧alpha_j没有变化,重新选alpha_i\n");
                continue;
            end
            % 至此,alpha_j计算完成
            % 根据alpha_i和alpha_j的关系式,计算alpha_i
            alphas(i) = alphaIold + labelMat(j) * labelMat(i) * (alphaJold - alphas(j));
            % 计算分类超平面的偏置
            b1 = b - Ei - labelMat(i) * (alphas(i) - alphaIold) * kernalData(i, i) - ...
                                  labelMat(j) * (alphas(j) - alphaJold) * kernalData(i, j);
            b2 = b - Ej - labelMat(i) * (alphas(i) - alphaIold) * kernalData(i, j) - ...
                                  labelMat(j) * (alphas(j) - alphaJold) * kernalData(j, j);
            if (0 < alphas(i)) && (C > alphas(i))
                b = b1;
            elseif (0 < alphas(j)) && (C > alphas(j))
                b = b2;
            else
                b = (b1 + b2) / 2;
            end
            alphaPairsChanged = alphaPairsChanged + 1;
            fprintf('迭代 %d 中,第一个alpha的序号i: %d, 改变的alpha值对: %d\n', iter, i, alphaPairsChanged);
        end
    end
    if alphaPairsChanged == 0
        iter = iter + 1;
    else
        iter = 0;
    end
    fprintf('迭代: %d\n', iter);
end
end
%% 核函数
function K = kernelTrans(X, A, kTup)
m = size(X, 1);
if ismember(kTup{1}, 'linear')
    K = X * A';
elseif ismember(kTup{1}, 'RBF')
    deltaRow = X - repmat(A, [m, 1]);
    K = exp(-sum(deltaRow .^ 2, 2) ./ (kTup{2} ^ 2));
else
    error('无法识别的核函数.');
end
end

测试分类效果

1、线性核分类

在这里插入图片描述 C = 0.01 , 时 间 0.095 秒 C=0.01,时间0.095秒 C=0.010.095
在这里插入图片描述 C = 0.1 , 时 间 0.068 秒 C=0.1,时间0.068秒 C=0.10.068在这里插入图片描述 C = 1 , 时 间 0.121 秒 C=1,时间0.121秒 C=10.121在这里插入图片描述 C = 1000 , 时 间 0.106 秒 C=1000,时间0.106秒 C=10000.106

2、非线性核分类

在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 0.5 , 时 间 0.211 秒 C=1,\quad高斯核标准差\sigma=0.5,时间0.211秒 C=1,σ=0.50.211在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 1 , 时 间 0.202 秒 C=1,\quad高斯核标准差\sigma=1,时间0.202秒 C=1,σ=10.202在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 2 , 时 间 0.100 秒 C=1,\quad高斯核标准差\sigma=2,时间0.100秒 C=1,σ=20.100在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 5 , 时 间 0.169 秒 C=1,\quad高斯核标准差\sigma=5,时间0.169秒 C=1,σ=50.169在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 10 , 时 间 0.101 秒 C=1,\quad高斯核标准差\sigma=10,时间0.101秒 C=1,σ=100.101在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 30 , 时 间 0.097 秒 C=1,\quad高斯核标准差\sigma=30,时间0.097秒 C=1,σ=300.097
完整版SMO:

clear all
close all
clc
%% 读数据
% 人工数据集
filename = '您想要测试的数据集txt文件,每一行是每一个数据点的横坐标,纵坐标和标签,标签只能是1或-1';
[dataMat, labelMat] = loadDataSet(filename);
[N, D] = size(dataMat);
% 绘图
if D == 2
    figure(1)
    indices0 = find(labelMat == -1);
    indices1 = find(labelMat == 1);
    dataMat0 = dataMat(indices0, :);
    dataMat1 = dataMat(indices1, :);
    scatter(dataMat0(:, 1), dataMat0(:, 2), 50, 'k.');
    hold on;
    scatter(dataMat1(:, 1), dataMat1(:, 2), 50, 'k+');
    hold on;
end

%% 使用完整版SMO --------------
% 构造一个数据结构保存重要值
tic;
kTup = {'linear', 1};
% kTup = {'linear'};
optStruct.X = dataMat;
optStruct.labelMat = labelMat;
optStruct.C = 10;
optStruct.tol = 0.0001;
optStruct.m = size(dataMat, 1);
optStruct.D = size(dataMat, 2);
optStruct.alphas = zeros(optStruct.m, 1);
optStruct.b = 0;
optStruct.eCache = zeros(optStruct.m, 2);
optStruct.K = zeros(optStruct.m); % 存储任意两条数据的内积
for i = 1: optStruct.m
    optStruct.K(:, i) = kernelTrans(optStruct.X, optStruct.X(i, :), kTup);
end
% 更新数据结构
maxIter = 40;
optStruct = smoP(optStruct, maxIter);
% 得到支持向量
supportVectorsIndices = find(optStruct.alphas > 0);
supportVectors = dataMat(supportVectorsIndices, :);
% 计算运用核函数后任意两条数据的内积kernelEval
errorCount = 0;
for i = 1: optStruct.m
    kernelEval(:, i) = kernelTrans(supportVectors, optStruct.X(i, :), kTup);
    predict = kernelEval(:, i)' * (optStruct.labelMat(supportVectorsIndices) .* optStruct.alphas(supportVectorsIndices)) + optStruct.b;
    if sign(predict) ~= sign(optStruct.labelMat(i))
        errorCount = errorCount + 1;
    end
end
fprintf('训练集误分率: %.2f%%\n', errorCount / optStruct.m * 100);
toc
% 绘图
accBound = 0.1; % 决定分类线的精度。值越小,分类线越精确,同时绘制速度越慢
plotSVM(kTup, optStruct, supportVectors, supportVectorsIndices, accBound);

%% 若数据维数为2,则可绘图
function plotSVM(kTup, oS, supportVectors, supportVectorsIndices, accBound)
if oS.D == 2
    % 分类线位于所有预测值为0的数据点位置上。
    % 1、对屏幕空间的矩形范围(至少包含所有训练数据点)内的所有坐标点进行预测
    %       点与点的间隔越小,分类边界线越精确
    % 2、画出预测值为0的点
    % 3、将所有标出的点连起来,构成高维分类超平面在二维上的投影边界
    %2和第3步可以用contour函数直接实现
    % 构建屏幕空间坐标集合screenCorMat,第一页为X坐标,第二页为Y坐标
    screenCorX = min(oS.X(:, 1)): accBound: max(oS.X(:, 1));
    screenCorY = min(oS.X(:, 2)): accBound: max(oS.X(:, 2));
    M = length(screenCorY);
    N = length(screenCorX);
    screenCorX = repmat(screenCorX, [M , 1]);
    screenCorY = repmat(screenCorY',[1, N]);
    screenCorMat = cat(3, screenCorX, screenCorY);
    % 平铺屏幕空间所有点,便于预测
    screenCorMat = reshape(screenCorMat, [M * N, 2]);
    % 对屏幕空间所有点进行预测,得到预测结果矩阵predictCor
    for i = 1: M * N
        kernelCor(:, i) = kernelTrans(supportVectors, screenCorMat(i, :), kTup);
        predictCor(i) = kernelCor(:, i)' * (oS.labelMat(supportVectorsIndices) .* oS.alphas(supportVectorsIndices)) + oS.b;
    end
    predictCor = reshape(predictCor, [M, N]);
    % 绘制预测结果为0的所有点,连起来,构成分类边界线
    figure(1), contour(screenCorX, screenCorY, predictCor, [0, 0], 'k--'); hold on;
    hold on;
    % 圈出所有支持向量
    figure(1), scatter(supportVectors(:, 1), supportVectors(:, 2), 100, 'k'); hold on;
    % 绘制出边界点所在曲线
    figure(1), contour(screenCorX, screenCorY, predictCor, [1 1], 'r--'); hold on;
    figure(1), contour(screenCorX, screenCorY, predictCor, [-1 -1], 'r--');
else
    fprintf('数据维数高于2维,无法绘图\n');
end
end

%% 读取数据函数
function [dataMat, labelMat] = loadDataSet(filename)
fid = fopen(filename);
format = [repmat('%f', [1, 3])];
data = cell2mat(textscan(fid, format));
dataMat = data(:, 1: end - 1);
labelMat = data(:, end);
end

%%1到m之间随机选取一个整数j
function j = selectJrand(i, m)
j = i;
while (j == i)
    j = randperm(m, 1);
end
end

%% 调整大于H或小于L的alpha,即掐头去尾
function aj = clipAlpha(aj, H, L)
% 令大于H的alpha等于H
if aj > H
    aj = H;
end
% 令小于L的alpha等于L
if aj < L
    aj = L;
end
end

%% ---------------------完整版SMO算法 ------------------------

%% 对于给定alpha,计算误差E
function Ek = calcEk(oS, k)
fXk = (oS.alphas .* oS.labelMat)' * oS.K(:, k) + oS.b; % 对x_k的预测值
Ek = fXk - oS.labelMat(k); % x_k的预测值与x_k的标签的误差
end

%% 选择j,保证每次优化采用最大步长
function [returnValue, Ej] = selectJ(i, oS, Ei)
maxK = -1;
maxDeltaE = 0;
Ej = 0;
oS.eCache(i, :) = [1, Ei];
% E_i=f(x_i)-y_i,即真实预测值与标签的误差,E_j同理;
% 找出在之前迭代中计算出的所有误差,即Ei和Ej
validEcacheList = find(oS.eCache(:, 1) ~= 0);
if length(validEcacheList) > 1
    % 如果之前迭代中计算好的误差多于1% 则以下循环实际上是在所有误差中,找出与alpha_i的误差Ei相差最大的alpha_j的误差Ej
    for a = 1: length(validEcacheList)
        k = validEcacheList(a);
        if k == i
            continue;
        end
        Ek = calcEk(oS, k);
        deltaE = abs(Ei - Ek);
        if deltaE > maxDeltaE
            % 如果找到的新alpha_j计算出的误差比上一次找到的alpha_j的误差更大
            % 则令新误差对应的alpha_j为找到的alpha_j
            maxK = k;
            % 则令新误差为此时更大的误差
            maxDeltaE = deltaE;
            Ej = Ek;
        end
    end
    returnValue = maxK;
    return;
else
    % 如果目前不存在1个以上的有效误差,则在所有alpha中随机选一个作为alpha_j
    % 一般会发生于某次迭代中第一次寻找alpha_j时
    j = selectJrand(i, oS.m);
    Ej = calcEk(oS, j);
    returnValue = j;
end
end

%% 计算误差值,放入缓存
function oS = updateEk(oS, k)
Ek = calcEk(oS, k);
oS.eCache(k, :) = [1, Ek];
end

%% 寻找决策边界
function [flag, oS] = innerL(i, oS)
Ei = calcEk(oS, i);
if ((oS.labelMat(i) * Ei < -oS.tol) && (oS.alphas(i) < oS.C)) || ((oS.labelMat(i) * Ei > oS.tol) && (oS.alphas(i) > 0))
    [j, Ej] = selectJ(i, oS, Ei);
    alphaIold = oS.alphas(i);
    alphaJold = oS.alphas(j);
    % 求alpha的上下界
    if oS.labelMat(i) ~= oS.labelMat(j)
        L = max(0, oS.alphas(j) - oS.alphas(i));
        H = min(oS.C, oS.C + oS.alphas(j) - oS.alphas(i));
    else
        L = max(0, oS.alphas(j) + oS.alphas(i) - oS.C);
        H = min(oS.C, oS.alphas(j) + oS.alphas(i));
    end
    if L == H
        fprintf('alpha的上界和下界相同,重新选第一个alpha\n');
        flag = 0;
        return;
    end
    eta = 2.0 * oS.K(i, j) - oS.K(i, i) - oS.K(j, j);
    if eta >= 0
        fprintf("eta >= 0\n");
        flag = 0;
        return;
    end
    oS.alphas(j) = oS.alphas(j) - oS.labelMat(j) * (Ei - Ej) / eta;
    oS.alphas(j) = clipAlpha(oS.alphas(j), H, L);
    % 更新误差缓存
    oS = updateEk(oS, j);
    if (abs(oS.alphas(j) - alphaJold) < 0.00001)
        fprintf("新alpha_j与旧alpha_j没有变化,重新选第一个alpha\n");
        flag = 0;
        return;
    end
    oS.alphas(i) = alphaIold + oS.labelMat(j) * oS.labelMat(i) * (alphaJold - oS.alphas(j));
    % 更新误差缓存
    oS = updateEk(oS, i);
    % 求分类超平面的偏置
    b1 = oS.b - Ei - oS.labelMat(i) * (oS.alphas(i) - alphaIold) * oS.K(i, i) - ...
                               oS.labelMat(j) * (oS.alphas(j) - alphaJold) * oS.K(i, j);
    b2 = oS.b - Ej - oS.labelMat(i) * (oS.alphas(i) - alphaIold) * oS.K(i, j) - ...
                               oS.labelMat(j) * (oS.alphas(j) - alphaJold) * oS.K(j, j);
    if (0 < oS.alphas(i)) && (oS.C > oS.alphas(i))
        oS.b = b1;
    elseif (0 < oS.alphas(j)) && (oS.C > oS.alphas(j))
        oS.b = b2;
    else
        oS.b = (b1 + b2) / 2;
    end
    flag = 1;
else
    flag = 0;
end
end

%% SMO
function oS = smoP(oS, maxIter)
iter = 0;
entireSet = true(1);
alphaPairsChanged = 0;
while (iter < maxIter) && ((alphaPairsChanged > 0) || entireSet)
    alphaPairsChanged = 0;
    if entireSet
        % 遍历所有值
        for i = 1: oS.m
            [value, oS] = innerL(i, oS);
            alphaPairsChanged = alphaPairsChanged + value;
        end
        fprintf('迭代 %d 中,第一个alpha的序号i: %d, 改变的alpha值对: %d\n', iter, i, alphaPairsChanged);
        iter = iter + 1;
    else
        % 找出所有在0C之间的alpha
        nonBoundIs = find((oS.alphas > 0) .* (oS.alphas < oS.C) ~= 0);
        for a = 1: length(nonBoundIs)
            i = nonBoundIs(a);
            [value, oS] = innerL(i, oS);
            alphaPairsChanged = alphaPairsChanged + value;
            fprintf('边界alpha, 迭代: %d,第一个alpha的序号i: %d, 改变的alpha值对: %d\n', iter, i, alphaPairsChanged);
        end
        iter = iter + 1;
    end
    if entireSet
        % 遍历所有alpha,且有alpha值对发生改变后,置entireSet为假,以便于在下一次迭代中只更新不为0的alpha
        entireSet = false(1);
    elseif alphaPairsChanged == 0
        % 若没有更改的alpha值对,则置entireSet为真,即重新在所有alpha中找新的alpha值对进行优化
        entireSet = true(1);
    end
    fprintf('迭代: %d\n', iter);
end
end

%% 核函数
function K = kernelTrans(X, A, kTup)
m = size(X, 1);
if ismember(kTup{1}, 'linear')
    K = X * A';
elseif ismember(kTup{1}, 'RBF')
    deltaRow = X - repmat(A, [m, 1]);
    K = exp(-sum(deltaRow .^ 2, 2) ./ (kTup{2} ^ 2));
else
    error('核函数不识别.');
end
end

测试分类效果

1、线性核分类

在这里插入图片描述 C = 0.01 , 时 间 0.049 秒 C=0.01,时间0.049秒 C=0.010.049在这里插入图片描述 C = 0.1 , 时 间 0.042 秒 C=0.1,时间0.042秒 C=0.10.042
在这里插入图片描述 C = 1 , 时 间 0.046 秒 C=1,时间0.046秒 C=10.046在这里插入图片描述 C = 1000 , 时 间 0.046 秒 C=1000,时间0.046秒 C=10000.046

2、非线性核分类

在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 0.5 , 时 间 0.133 秒 C=1,\quad高斯核标准差\sigma=0.5,时间0.133秒 C=1,σ=0.50.133在这里插入图片描述 C = 1 , 高 斯 核 标 准 差 σ = 1 , 时 间 0.086 秒 C=1,\quad高斯核标准差\sigma=1,时间0.086秒 C=1,σ=10.086

●═══════════════════════════════我是分割线═════════════════════════════●

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值