[编程经验] TensorFlow实现非线性支持向量机

2017 年 8 月 8 日 机器学习和数学 Alvin_2580


[点击蓝字,一键关注~]


上一次说的是线性支持向量机的原理和tf实现问题,把SVM的原理简单用公式推导了一下,SVM这块还有几个问题没有解释,比如经验风险,结构风险,VC维,松弛变量等。今天主要是解释几个概念然后实现非线性的支持向量机。



  1.  风险最小化

  

期望风险

对于一个机器学习模型来说,我们的目的就是希望在预测新的数据的时候,准确率最高,风险最小,风险函数可以定义为:

其中L是损失函数,P(x,y)是训练数据和label标签的联合概率密度函数。这个风险函数的存在的问题是,我们无法知道x和y的联合概率密度,为什么? 

想一下,如果能知道所有x和y的联合概率密度,我们还需要去做预测吗?显然不需要了。

对于机器学习任务来说,训练集其实就相当于是样本,测试集也是样本,总体是我们无法穷尽的一个东东,x和y的联合概率密度就是对总体的一个描述,所以上面那个风险函数是无法计算的,期望风险由此得来。想一想概率统计中的平均值和期望的区别,这里你就能想明白了。


既然期望风险无法得到,那么机器学习算法就转化为求经验风险最小,经验就对应的是训练集,训练集是我们可以获得的东西,所以可以称为经验。


经验风险:


上式就是经验风险,L是损失函数,xi和yi是训练集,w是参数,对比一下这个式子和上面那个式子,就发现,区别在于一个是求积分,一个是求和,显然简单多了。其实最小二乘估计就是采用的经验风险最小为优化目标的,甚至说大多数的机器学习算法都是求经验风险最小的那一个模型。


2. VC维,Vapnik-Chervonenkis dimension


首先VC维描述了一族函数的复杂程度,而且并不是模型越复杂那么它的泛化能力就越好。如果一个模型在训练集上表现的很好,那么它的泛化能力一般较差,也就是说,如果一个简单的模型在训练集表现好,那么它的泛化能力往往比较好。


考虑一个二分类问题,假设现在有D维实数空间中的N个点,每个点有两种可能情况,+1和-1。那么N个点就有2^N中可能,举个栗子,N=3的时候,就有{(000), (001), (010), (011), (100), (101), (110), (111) }  。

一般对VC维的解释都是函数集可以打乱(shattered)的最大数据集的数目,怎么理解这句话呢? 我觉得是,假如一个函数集f(a)的VC维为h, 那么至少存在一个包含h个样本的数据集,可以被函数集f(a)分开。注意这里是至少存在一个,所以不是说只要是包含h个样本的数据,都可以被shatter!

还是不能理解? 举个栗子

假如在二维平面内有3个点,那么我们可以找到一个线性分类器,不论是哪一种可能的情况,都可以将这三个点正确分类。所以这个分类器的VC维就是3.


3. 结构风险最小化


结构风险一般表示为经验风险和置信风险的和

其中h是VC维,N是训练样本个数。当N/h变大的时候,N变大,h变小,置信风险趋于0,这时候结构风险约等于经验风险。也就是说当给定足够的样本的时候,结构风险就是经验风险。

而支持向量机是基于结构风险最小的,即使的经验风险和VC置信风险的和最小。

然后看下下面这个图,


下面的S1,S2,...,Sk表示的是不同VC维的函数族,当VC维增加的时候,经验风险在降低,置信风险却在增加,所以需要找到一个平衡点,这个平衡点就是最佳的模型。

到这里似乎问题已经解决了,但是VC维一般是很难计算的,尤其是对于像神经网络这样的非线性函数,Vapnik在1998年证明了下面这个公式:


其中m表示间隔(margin),D表示输入空间的维度,R是包含所有输入样本的组成的一个球体的最小的半径。上面这个式子说明,VC维最小等价于使得间隔最大,间隔最大也就是最小化经验风险的上界。

到这里其实是想说明,要使得结构风险最小,就要使得间隔最大。这就是为什么会提出支持向量机。



4. 松弛变量

上一次讲的时候,对于线性可分情况下,优化目标的约束条件是这个:

对于非线性可分情况下,就无法找到一个超平面来分类,为了实现最终分类,我们设计一种方法,使得用某一个超平面来分类的时候,误差最小。基于此,引入松弛变量,它表示了样本点与间隔的偏离,通俗点的理解是,对于非线性可分情况,有2种可能,一种是正类样本位于超平面的正确的一侧,虽然被正确分类,但是在间隔之内;还有一种可能是正类样本完全在负类样本中。下图是一个直观的解释,看图应该更容易理解。

上图中,凡是样本点在正类之外,松弛变量都是0,超平面右侧松弛变量小于1,左侧大于1。

引入松弛变量以后,约束条件就变为:

优化目标为:

其中C用来控制间隔和松弛变量之间的平衡关系;

还是用拉格朗日乘子法求解上述优化问题,只不过这里的乘子有2个,一个是a,一个是mu。

KKT条件:

分别令偏导数为0:

对偶形式:

对偶约束:


然后对KKT条件中第三个式子做个移项:

对于支持向量来说,松弛变量都是0,此时满足:

即:

求解上式就可以得到:

对比一下,线性可分情况:

其中Ns表示的是所有的支持向量。

我们发现,对于 非线性可分情况,其实就是为了去掉那些不是支持向量的点,使得最终还是满足线性可分。

最后大家可能对核函数怎么算的,不是很清楚,这里贴一个公式:

其中的函数fai,表示特征空间中的非线性映射关系;

常用的核函数,比如高斯核函数RBF:

对于怎么选择核函数,可以参考下面的参考文献。。。


下面就是如何用TF来实现非线性SVM了



# coding: utf-8
import numpy as np
import tensorflow as tf
from sklearn import datasets

x_data = tf.placeholder(shape=[None, 2], dtype=tf.float32)
y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)
prediction = tf.placeholder(shape=[None, 2], dtype=tf.float32)


def get_data():
iris = datasets.load_iris()
x_vals = np.array([[x[0], x[3]] for x in iris.data])
y_vals = np.array([1 if y == 0 else -1 for y in iris.target])
return x_vals, y_vals


def Gaussian_kernel(gamma):
g = tf.constant(gamma)
# 2 * (x_data * x_data^T)
   sq_dists = tf.multiply(2.,
       
tf.matmul(x_data, tf.transpose(x_data)))
# exp(g * abs(sq_dists))
   out = tf.exp(tf.multiply(g, tf.abs(sq_dists)))
return out


def non_linea_svm(my_kernel, batch_size, prediction, gamma=-25.0):
b = tf.Variable(tf.random_normal(shape=[1, batch_size]))
first_term = tf.reduce_sum(b)
b_vec_cross = tf.matmul(tf.transpose(b), b)
# 偏置的内积, b的转置乘以b
   y_target_cross = tf.matmul(y_target, tf.transpose(y_target))
# label的内积,y乘以y的转置
   second_term = tf.reduce_sum(tf.multiply(my_kernel,
           
tf.multiply(b_vec_cross, y_target_cross)))
# 偏置的内积乘以label 的内积,结果再乘以核函数
   loss = tf.negative(tf.subtract(first_term, second_term))
# 第一项和第二项做差,然后添加一个负号,
   # negative是取相反数的意思
   rA = tf.reshape(tf.reduce_sum(tf.square(x_data), 1),
                                
[-1, 1])
rB = tf.reshape(tf.reduce_sum(tf.square(prediction), 1),
                             
[-1, 1])
stra = tf.subtract(rA, tf.multiply(2.,
tf.matmul(x_data, tf.transpose(prediction))))
pred_sq_dist = tf.add(stra, tf.transpose(rB))
# (rA-2*x_data*预测值的转置)+rB的转置
   pred_kernel = tf.exp(tf.multiply(gamma,
                     
tf.abs(pred_sq_dist)))

prediction_output = tf.matmul(tf.multiply(
tf.transpose(y_target), b), pred_kernel)
prediction = tf.sign(prediction_output -
tf.reduce_mean(prediction_output))
accuracy = tf.reduce_mean(
tf.cast(tf.equal(tf.squeeze(prediction),
tf.squeeze(y_target)), tf.float32))
my_opt = tf.train.GradientDescentOptimizer(0.01)
train_step = my_opt.minimize(loss)
return loss, accuracy, train_step


def train_svm(sess, batch_size):
kernel = Gaussian_kernel(-25.0)
loss_vec = []
batch_accuracy = []
for i in range(300):
x_vals, y_vals = get_data()
loss, accuracy, train_step = non_linea_svm(
kernel, batch_size=batch_size,
                   
prediction=prediction)
init = tf.global_variables_initializer()
sess.run(init)
rand_index = np.random.choice(len(x_vals),
                     
size=batch_size)
rand_x = x_vals[rand_index]
rand_y = np.transpose([y_vals[rand_index]])
sess.run(train_step,
                feed_dict={x_data: rand_x,
                         
y_target: rand_y})

temp_loss = sess.run(loss,
                  feed_dict={x_data: rand_x,
                         
y_target: rand_y})
loss_vec.append(temp_loss)

acc_temp = sess.run(accuracy,feed_dict={x_data: rand_x,
                         y_target: rand_y,
                         prediction: rand_x})
batch_accuracy.append(acc_temp)

if (i + 1) % 100== 1:
print('Loss = ' + str(temp_loss))


def main(_):
with tf.Session() as sess:
train_svm(sess, batch_size=30)


if __name__ == "__main__":
tf.app.run()


最后说一下,哪里有看不懂的,欢迎与我交流~~


参考文献:

1. Pattern Recognition and Machine Learning

2. machine Learning A Probabilistic Perspective 

3. Introduction to Machine Learning 

4. https://www.zhihu.com/question/21883548



登录查看更多
0

相关内容

经验风险是对训练集中的所有样本点损失函数的平均最小化。经验风险越小说明模型f(X)对训练集的拟合程度越好。
【新书册】贝叶斯神经网络,41页pdf
专知会员服务
177+阅读 · 2020年6月3日
Sklearn 与 TensorFlow 机器学习实用指南,385页pdf
专知会员服务
129+阅读 · 2020年3月15日
《深度学习》圣经花书的数学推导、原理与Python代码实现
【经典书】精通机器学习特征工程,中文版,178页pdf
专知会员服务
354+阅读 · 2020年2月15日
【新书】Pro 机器学习算法Python实现,379页pdf
专知会员服务
198+阅读 · 2020年2月11日
一网打尽!100+深度学习模型TensorFlow与Pytorch代码实现集合
一文读懂线性回归、岭回归和Lasso回归
CSDN
34+阅读 · 2019年10月13日
从零推导支持向量机 (SVM)
AI科技评论
9+阅读 · 2019年2月7日
【机器学习理论】我所理解的 SVM(支持向量机)- 1
机器学习研究会
5+阅读 · 2018年3月16日
免费|机器学习算法Python实现
全球人工智能
5+阅读 · 2018年1月2日
动手写机器学习算法:SVM支持向量机(附代码)
七月在线实验室
12+阅读 · 2017年12月5日
机器学习(16)之支持向量机原理(二)软间隔最大化
机器学习算法与Python学习
6+阅读 · 2017年9月8日
机器学习(15)之支持向量机原理(一)线性支持向量机
机器学习算法与Python学习
6+阅读 · 2017年9月1日
机器学习(13)之最大熵模型详解
机器学习算法与Python学习
7+阅读 · 2017年8月24日
神经网络理论基础及 Python 实现
Python开发者
6+阅读 · 2017年7月15日
Bivariate Beta LSTM
Arxiv
5+阅读 · 2019年10月7日
Arxiv
19+阅读 · 2018年6月27日
VIP会员
相关VIP内容
相关资讯
一文读懂线性回归、岭回归和Lasso回归
CSDN
34+阅读 · 2019年10月13日
从零推导支持向量机 (SVM)
AI科技评论
9+阅读 · 2019年2月7日
【机器学习理论】我所理解的 SVM(支持向量机)- 1
机器学习研究会
5+阅读 · 2018年3月16日
免费|机器学习算法Python实现
全球人工智能
5+阅读 · 2018年1月2日
动手写机器学习算法:SVM支持向量机(附代码)
七月在线实验室
12+阅读 · 2017年12月5日
机器学习(16)之支持向量机原理(二)软间隔最大化
机器学习算法与Python学习
6+阅读 · 2017年9月8日
机器学习(15)之支持向量机原理(一)线性支持向量机
机器学习算法与Python学习
6+阅读 · 2017年9月1日
机器学习(13)之最大熵模型详解
机器学习算法与Python学习
7+阅读 · 2017年8月24日
神经网络理论基础及 Python 实现
Python开发者
6+阅读 · 2017年7月15日
Top
微信扫码咨询专知VIP会员