Оптимизация двойной задачи Вольфа в SVM - PullRequest
0 голосов
/ 09 марта 2020

Я работаю над машиной опорных векторов (SVM), чтобы написать ее с нуля. Как вы знаете, для двойной формулировки SVM требуется оптимизировать двойную задачу Вольфа относительно множителя Лагранжа следующим образом:

Wolfe dual problem

Я много искал, чтобы найти простое описание численного решения этой проблемы, но не смог найти подходящий пример. Наконец, после долгих усилий, я решил эту проблему в Python, используя алгоритм Gradient Descent, и решил поделиться своим решением, чтобы узнать отзывы других пользователей об этом. Пожалуйста, запустите мой код и дайте мне знать, если в нем есть ошибки. Я был бы рад, если вы дадите мне свой отзыв.

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(6)
import math
from sklearn import metrics

from sklearn.datasets.samples_generator import make_blobs
X,y =  make_blobs(n_samples=50,n_features=2,centers=2,cluster_std=1.05,random_state=40)
plt.scatter(X[:,0],X[:,1],marker='o',c=y)
plt.axis([-5,10,-12,-1])
plt.show()

y[y==0]=-1

#all the required variables 
w=[] #weights 2 dimensional vector
b=[] #bias

**# find max and min values of predictor variables (here X) to use it to specify initial values of w and b 

max_feature_value=np.amax(X)
min_feature_value=np.amin(X)**

w_optimum = max_feature_value*0.5
b_optimum = min_feature_value*0.5

w = [w_optimum for i in range(X.shape[1])]   # w shoulb be a vector with dimension of the independent features (here:2)
wt_b=w
#wt_b=[0.34,0.34]



# using the Gradient descent method to find maximum value of Wolfe dual Lagrangian function

l_rate=0.01
n_epoch = 100

# Create matrix of xi*xj
k_xi_xj=np.zeros((X.shape[0] , X.shape[0]))

for i in range (X.shape[0]):
    for j in range(X.shape[0]):
        k_xi_xj[i,j]=np.dot(X[i,:],X[j,:])


#alpha_i_t=[0.001 for i in range(X.shape[0])]
alpha_i_t=np.random.uniform(-10,10,X.shape[0])
alpha_i=alpha_i_t

wolfe_dual_list=[]
wolfe_dual_list_total=[]
wolfe_dual_list_total_ave=[]
for epoch in range(n_epoch):
    for i in range (X.shape[0]):
        wolfe_dual = 0
        for i in range (X.shape[0]):
            for j in range(X.shape[0]):
                wolfe_dual +=((np.sum(alpha_i))-0.5*(alpha_i[i]*alpha_i[j]*y[i]*y[j]*k_xi_xj[i,j]))
        wolfe_dual_list.append(wolfe_dual)
        wolfe_dual_list_total.append(wolfe_dual)

        alpha_i[i] = alpha_i[i] + l_rate* np.dot(alpha_i,y)

        print('>epoch=%d, lrate=%.3f,wolfe_dual=%.3f' % (epoch, l_rate,wolfe_dual))
    wolfe_dual_list_total_ave.append(np.mean(wolfe_dual_list_total))
    wolfe_dual_list_total=[]

# plot wolfe dual lagrangian function  values
fig,ax = plt.subplots(1, 1,constrained_layout=True,figsize=(8, 4))
ax.plot(wolfe_dual_list)
ax.set_xlabel('iterate',fontsize=15)
ax.set_ylabel('wolfe dual values',fontsize=15)
#plt.grid(True)
plt.show()

# plot average wolfe dual lagrangian function values in each epoch
fig,ax = plt.subplots(1, 1,constrained_layout=True,figsize=(8, 4))
ax.plot(wolfe_dual_list_total_ave)
ax.set_xlabel('iterate',fontsize=15)
ax.set_ylabel('wolfe dual values',fontsize=15)
#plt.grid(True)
plt.show()

# Compute w and b

# Because Lagrange multipliers for non-support vectors are almost zero, we can also compute w using only support vectors
# data and their multipliers

# find all vectors with positive multipliers (Support vectors have positive multipliers)

support_vectors=X[alpha_i>1e-7]
support_vectors_y=y[alpha_i>1e-7]
sv_alpha_i=alpha_i[alpha_i>1e-7]

#Compute w
wt_b=0
for i in range (support_vectors.shape[0]):
    wt_b=wt_b+sv_alpha_i[i]*support_vectors_y[i]*support_vectors[i,:]

#Compute b
sum=0
for i in range (support_vectors.shape[0]):
    sum=sum+support_vectors_y[i]-np.dot(wt_b,support_vectors[i,:])

b=sum/len(support_vectors)


# find two best support vectors to draw them in plot
positive_instances=[]
negative_instances=[]

for i in range(X.shape[0]):
    num=(np.dot(wt_b,X[i,:]))+b
    if  ((y[i]>=1) and (num>=1)):
        positive_instances.append([num,X[i,:]])
    elif ((y[i]<=-1) and (num<=-1)):
        negative_instances.append([num,X[i,:]]) 

sort_positive=sorted([n for n in positive_instances])
sort_negative=sorted([n for n in negative_instances])

positive_support_vector=sort_positive[0][1]
negative_support_vector=sort_negative[-1][1]

model_support_vectors=np.stack((positive_support_vector,negative_support_vector),axis=-1)

#wt_b=np.asarray([0.32,0.32])
#b=1.49

# visualize the data-set

colors = {1:'r',-1:'b'}
fig = plt.figure()
ax = fig.add_subplot(1,1,1)

plt.scatter(X[:,0],X[:,1],marker='o',c=y)

# plot support vectors
ax.scatter(model_support_vectors[0, :],model_support_vectors[1, :],s=200, linewidth=1,facecolors='none', edgecolors='b')

# hyperplane = x.w+b
# v = x.w+b
# psv = 1
# nsv = -1
# dec = 0
def hyperplane_value(x,w,b,v):
    return (-w[0]*x-b+v) / w[1]

datarange = (min_feature_value*0.9,max_feature_value*1.)
hyp_x_min = datarange[0]
hyp_x_max = datarange[1]

# (w.x+b) = 1
# positive support vector hyperplane
psv1 = hyperplane_value(hyp_x_min, wt_b, b, 1)
psv2 = hyperplane_value(hyp_x_max, wt_b, b, 1)
ax.plot([hyp_x_min,hyp_x_max],[psv1,psv2], 'k')

# (w.x+b) = -1
# negative support vector hyperplane
nsv1 = hyperplane_value(hyp_x_min, wt_b, b, -1)
nsv2 = hyperplane_value(hyp_x_max, wt_b, b, -1)
ax.plot([hyp_x_min,hyp_x_max],[nsv1,nsv2], 'k')

# (w.x+b) = 0
# positive support vector hyperplane
db1 = hyperplane_value(hyp_x_min, wt_b, b, 0)
db2 = hyperplane_value(hyp_x_max, wt_b, b, 0)
ax.plot([hyp_x_min,hyp_x_max],[db1,db2], 'y--')

#plt.axis([-5,10,-12,-1])
plt.show()

# Predict using the optimized values of w and b    
y_predict=[]
for i in range (X.shape[0]):
    y_hat=np.sign(np.dot(wt_b,X[i,:])+b)
    y_predict.append(y_hat)


from sklearn import metrics
metrics.accuracy_score(y_predict, y)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...