【复现SVM】使用梯度下降法代替SMO算法求解SVM对偶问题

import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
import torch

%matplotlib inline

生成数据

max_r = 0.4
X = []
y = []
for i in range(20):
    r = max_r * np.random.rand()
    rand_num = np.random.rand()
    X.append([0.5 + r * np.cos(2*np.pi * rand_num), 0.5 + r * np.sin(2*np.pi * rand_num)])
    y.append(1)
for i in range(20):
    r = max_r * np.random.rand()
    rand_num = np.random.rand()
    X.append([-0.5 + r * np.cos(2*np.pi * rand_num), -0.5 + r * np.sin(2*np.pi * rand_num)])
    y.append(-1)
plt.subplots(figsize=(10,5))
for i, [x1, x2] in enumerate(X):
    if y[i] == 1:
        plt.scatter( x1, x2, s=30, c='b', marker='o')
    else:
        plt.scatter( x1, x2, s=30, c='r', marker='x')
plt.xlabel("x1") 
plt.ylabel("x2")
plt.show()

在这里插入图片描述

高斯核

k ( x ⃗ i , x ⃗ j ) = e x p ( − ∣ ∣ x ⃗ i − x ⃗ j ∣ ∣ 2 2 σ 2 ) k(\vec{x}_i, \vec{x}_j) = exp(-\frac{||\vec{x}_i - \vec{x}_j||^2}{2\sigma^2}) k(x i,x j)=exp(2σ2x ix j2)

def gaussKernel(vec1, vec2, _sigma = 0.2):
    vec1 = np.array(vec1).reshape(1, -1)
    vec2 = np.array(vec2).reshape(1, -1)
    return torch.FloatTensor([np.exp(- _sigma * np.linalg.norm(vec1- vec2, ord=2)**2)])

SVM

max ⁡ α ∑ i = 1 m α i − 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j K ( x ⃗ i , x ⃗ j ) \max_{\alpha} \sum^{m}_{i=1} \alpha_i - \frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha_i\alpha_j y_i y_j K(\vec{x}_i, \vec{x}_j) αmaxi=1mαi21i=1mj=1mαiαjyiyjK(x i,x j)
s . t . ∑ i = 1 m α i y i = 0 s.t. \sum^m_{i=1}\alpha_iy_i = 0 s.t.i=1mαiyi=0
0 ≤ α i ≤ C , i = 1 , 2 , . . . , m 0 \leq \alpha_i \leq C, i = 1,2,...,m 0αiC,i=1,2,...,m

转换为为编程需求形式

min ⁡ α 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j K ( x ⃗ i , x ⃗ j ) − ∑ i = 1 m α i \min_{\alpha}\frac{1}{2}\sum^m_{i=1}\sum^m_{j=1}\alpha_i\alpha_j y_i y_j K(\vec{x}_i, \vec{x}_j) - \sum^{m}_{i=1} \alpha_i αmin21i=1mj=1mαiαjyiyjK(x i,x j)i=1mαi
α m = − α ⃗ 1 ⋅ ⋅ m − 1 ⋅ y ⃗ 1 ⋅ ⋅ m − 1 y m \alpha_m = -\frac{\vec{\alpha}_{1 \cdot \cdot m-1} \cdot \vec{y}_{1 \cdot \cdot m-1}}{y_m} αm=ymα 1m1y 1m1

用梯度下降方式求解 α ⃗ \vec \alpha α

M = len(X)
y = torch.Tensor(np.array(y)).reshape(-1, 1)
# vector alpha
alphaLack = torch.zeros((1, M-1), requires_grad = True)
alphaLast = 0
from IPython.display import clear_output 
epochs = 500
lr = 0.1
K = gaussKernel
C = 10.0

for epoch in range(epochs):
    objFunc = 0.0

    for i in range(M):
        for j in range(M):
            if i != M-1 and j != M-1:
                objFunc += 0.5*alphaLack[0,i] * alphaLack[0,j] * y[i,0] * y[j,0] * K(X[i],X[j])
            elif  i == M-1 and j != M-1: 
                objFunc += 0.5*alphaLast * alphaLack[0,j] * y[i,0] * y[j,0] * K(X[i],X[j])
            elif  i != M-1 and j == M-1: 
                objFunc += 0.5*alphaLack[0,i] * alphaLast * y[i,0] * y[j,0] * K(X[i],X[j])
            else:
                objFunc += 0.5*alphaLast * alphaLast * y[i,0] * y[j,0] * K(X[i],X[j])
    objFunc -= (torch.sum(alphaLack)+ alphaLast)
    objFunc.backward()
#     if epoch%300 == 0:
#         lr = lr/2
    alphaLack.data -= lr*alphaLack.grad
    alphaLack.grad.zero_()
    
    # 软间隔
    for k in range(alphaLack.shape[1]):
        if alphaLack[0,k] > C:
            alphaLack[0,k] = C
        elif alphaLack[0,k] < 0:
            alphaLack[0,k] = 0
    alphaLack = torch.FloatTensor(alphaLack.data).requires_grad_(True)
    
    alphaLast = - (torch.mm(alphaLack, y[0:-1,0].reshape(-1, 1))/y[-1])[0]
    if alphaLast < 0:
        alphaLast = torch.tensor([0])
    elif alphaLast > 10:
        alphaLast = torch.tensor([10])
    
    # 迭代信息
    clear_output(wait=True)
    print("epoch: ", epoch + 1)
    print("objFunc = ", objFunc)
    print("alphaLack = ", alphaLack)
    print("alphaLast = ", alphaLast)
epoch:  500
objFunc =  tensor([-6.3391], grad_fn=<SubBackward0>)
alphaLack =  tensor([[0.0000, 0.0000, 0.0000, 5.8167, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
         0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
         0.2983, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 6.1422,
         0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
         0.0000, 0.0000, 0.0000]], requires_grad=True)
alphaLast =  tensor([0])

合成 α ⃗ \vec \alpha α &找出所有的支持向量对应下标

alpha = alphaLack.detach().numpy().reshape(1,-1)
alpha = np.append(alpha[0], alphaLast.detach().numpy().reshape(1,-1))
points = []
for i in range(M):
    if alpha[i] > 0.0001:
        points.append(i)
print("alpha = ",alpha)
alpha =  [0.         0.         0.         5.8166852  0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.29833502 0.         0.         0.         0.         0.
 0.         0.         6.14217091 0.         0.         0.
 0.         0.         0.         0.         0.         0.
 0.         0.         0.         0.        ]

求解 b b b

b = 1 S ∑ s ( y s ∈ S − ∑ s ∈ S α i y i x ⃗ i T x ⃗ s ) b = \frac{1}{S} \sum_s (y_{s\in S} - \sum_{s\in S} \alpha_i y_i \vec x_i^T \vec x_s) b=S1s(ysSsSαiyix iTx s)
S = { i ∣ α i > 0 , i = 1 , 2... m } S = \{i|\alpha_i \gt 0, i = 1,2...m\} S={iαi>0,i=1,2...m}

ans = []
b = 0
for p in points:
    ys = y[p, 0]
    sum_record = 0.0
    K = gaussKernel
    for i in points:
        b += alphaLack[0,i] * y[i,0] * K(X[i], X[p])
    b = (1/ys) - b
    ans.append(b.detach().numpy())
b = sum(ans)/len(ans)
print("b = ", b)
b =  [0.04126883]

求解 w ⃗ \vec w w

w ⃗ = ∑ i = 1 m α i y i x ⃗ i \vec w = \sum^m_{i=1}\alpha_iy_i\vec x_i w =i=1mαiyix i

W = torch.FloatTensor(np.zeros((2,1)))
for i in range(M):
    W = W + alpha[i] * y[i,0] * torch.FloatTensor(np.array(X[i]).reshape(-1, 1))
W = W.detach().numpy()
print("W = ", W)
W =  [[4.8299384]
 [2.977161 ]]

绘制划分方程&标记出支持向量

[ x 1 x 2 ] [ w 1 w 2 ] + b = 0 \begin{bmatrix}x1 & x2\\ \end{bmatrix} \begin{bmatrix}w1 \\ w2\\ \end{bmatrix} + b = 0 [x1x2][w1w2]+b=0

def func(x):
    return - (W[0]*x + b)/W[1]

nums = np.arange(-0.8,0.8,step=.01)
fig, ax = plt.subplots(figsize=(8,7))
ax.plot(nums, func(nums))

for i, [x1, x2] in enumerate(X):
    if y[i] == 1:
        c, marker = 'b', 'o'
    else:
        c, marker = 'r', 'x'
    if alpha[i] > 0.0001:
        c = 'g'
    plt.scatter( x1, x2, s=30, c=c, marker=marker)

plt.xlabel("x1") 
plt.ylabel("x2")
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值