最近在做一个项目用到了支持向量机(SVM),在阅读支持向量机的原理的文章时遇到了很多困难,其中一个困扰我和很久的就是在对原方程进行了拉格朗日对偶变换后怎么求参数。书上介绍说应该用SMO算法,但因为我数学基础比较差,所以愣是没看懂书上讲的是什么意思,后来查了好多资料得知SMO算法脱胎于坐标上升算法。之后经过学习大概懂了这个算法的思路,接下来我写一下让数学基础不太好的人也能看懂的过程。
废话不多说,咱直接上个例子:
咱们要求当z取最大值时x和y的值该怎么求呢?
利用坐标上升算法就是先将x或者y当作一个常数,然后这个式子就变成了单变量求最值的问题了。
我们先令y为常数,然后对x求导数并令结果为零,即
再令x为常数,然后对y求导并令结果为零,即
之后我们给x和y赋初始值
具体的代码如下:
import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = -(X**2) #X**2为X的平方
Z2 = -(Y**2)
Z = 1.0 * (Z1 + 3 * Z2 + 2 * X * Y)+6.0
plt.figure() #创建一个绘画板
CS = plt.contour(X, Y, Z) #绘制等高线图
a = [] #a=[]
b = []
a.append(-2) #a=[2.0]
b.append(-2)
j = 1
for i in range(200):
a_tmp = b[j-1]
a.append(a_tmp)
b.append(b[j-1])
j = j+1
b_tmp = a[j-1] / 3
a.append(a[j-1])
b.append(b_tmp)
for i in range(200):
print(a[i],b[i])
plt.plot(a,b)
plt.title('Coordinate Ascent')
plt.xlabel('x')
plt.ylabel('y')
plt.show()
运行之后的效果为:
接下来我来对程序运行过程中自己遇到的一些问题做一下说明:
1、首先来说用这个方法来求解这个方程的过程中并没有求得一个真实的解而是逐渐逼近这个解,可以看到它是循环了200次,也可以循环300次;
2、循环的过程中a和b的值忽大忽小,最后一个循环求出来的值不一定就是最接近真实值的那个值,他把每一次循环求出的值都储存在一个矩阵当中,这个矩阵里面一定有一个是最接近真实值的值。
再加一个例子,不画出图形,这个程序比较简单,可读性强:
原式为:
分别对x1,x2,x3求导得:
然后给x1,x2,x3赋初值均为1,进行运算:
def f(x):
x_1 = x[0]
x_2 = x[1]
x_3 = x[2]
result = -(x_1*x_1)-2*(x_2*x_2)-3*(x_3*x_3)+2*x_1*x_2+2*x_1*x_3-4*x_2*x_3+6
return result
if __name__ == "__main__":
#print "hello world"
err = 1.0e-10
x = [1.0, 1.0, 1.0]
f_0 = f(x)
while 1:
#print "Hello"
x[0] = x[1] + x[2]
x[1] = x[0] / 2 - x[2]
x[2] = x[0] / 3 - 2 * x[1] / 3
f_t = f(x)
if (abs(f_t - f_0) < err):
break
f_0 = f_t
print ("max:" + str(f_0))
print (x)
这里没有规定循环的次数而是规定了当相邻两次f(x)改变的值小于err时跳出循环,这样就算出了答案
关于支持向量机(SVM)的文章我觉得以下这些很值得参考:
https://www.cnblogs.com/pinard/p/6097604.html
https://www.cnblogs.com/liaohuiqiang/p/7805954.html
梯度下降法:
https://www.jianshu.com/p/c7e642877b0e