目录
(1)线性可分支持向量机
1.SVM的概念
支持向量机是一种二类分类模型。其基本模型为定义在特征空间上的间隔最大的线性分类器,间隔最大是它有别有感知机。支持向量机还包括核技巧,使它成为实质上的非线性分类器。支持向量机的学习策略就是间隔最大化,形式的化为求解凸二次规划问题,也等价于正则化的和业务损失函数的最小化问题。
支持向量机学习算法模型分类:
(1)线性可分支持向量机。当训练集线性可分的时候,通过硬间隔最大化,学习一个线性的分类器,即线性可分支持向量机。又称为硬间隔支持向量机。
(2)线性近似可分支持向量机。当训练集近似线性可分的时候,通过软间隔最大化,也学习一个线性的分类器,即线性支持向量机。又称为软间隔支持向量机。
(3)非线性支持向量机。当训练集线性不可分的时候,通过核技巧以及软间隔最大化,学习非线性支持向量机。
2.SVM原理
(1)线性可分支持向量机
给定线性可分训练集,通过硬间隔最大化或者等价的求相应的凸二次规划问题学习得到的分离超平面。
分离超平面为: w.x+b=0.
推导过程:一般来说,一个样本点距离分离超平面的远近可以表示分类预测的准确程度。如果分类正确,那么yi(w.xi+b)>0。所以可以用yi(w.xi+b)表示分类的正确性与确信度。这就是函数间隔的概念。
函数间隔:
样本点的函数间隔: Di= yi(w.xi+b)
训练集的函数间隔:定义为最小的函数间隔。
D= min Di= min yi(w.xi+b)
可以用函数间隔表示分类的正确性与确信度,但是选择分离超平面时,只有函数间隔是不够的。比如成比例的改变w和b,超平面没有变,但是函数间隔却变成了原来的2倍。于是引入了几何间隔。
样本点的几何间隔为 Mi= yi(w.xi+b)/||W||.即对W做了一个限制。
训练数据集的几何间隔:定义为最小的几何间隔。
M= min Mi = min yi(w.xi+b)/||W||
支持向量机学习的基本想法是求解能够正确划分训练数据集并且集合间隔最大的分离超平面。对线性可分的训练集而言,线性可分的分离超平面有无数多条,但是几何间隔最大的分离超平面是唯一的。
间隔最大化的直观解释就是:对训练数据集找到集合间隔最大的超平面意味着以充分大的确信度对训练数据进行分类。也就是说,不仅将正负实例点分开,而且对最难分的实例点(离超平面最近的的点)也有足够大的确信度将其分开。
即离超平面最近的点是最难分的点,反映了整个分类学习器的性能。
最大间隔分离超平面:
Max M
St:yi(w.xi+b)/||W||>=M i=1,2,….N
即我们希望最大化几何间隔M,约束条件表示每个样本点的集合间隔都至少是M。
考虑到几何间隔和函数间隔的关系,这个问题可以改写成:
Max D/||W||
St yi(w.xi+b)>=D i=1,2,….N
函数间隔D的取值并不会影响最优化问题的解,事实上,将w和b等比例的改变,对目标函数的优化没有任何影响。这样可以去D=1,那么目标函数变成了1/||W||。同时 1/||W||与1/2||W||^2是等价的。
即此时目标函数变成:
这是一个凸二次规划问题。
线性可分训练数据集的最大间隔分离超平面是存在且唯一的。
上述原始问题是标准的QP问题,除了QP现成的解法之外,还可以应用拉格朗日对偶性,通过求解对偶问题得到原始问题的最优解。引入对偶问题的好处:
(1) 对偶问题往往更容易求解
(2) 自然引入核函数,进而推广到非线性分类问题。
首先构建拉格朗日函数,将不等式约束加入到目标函数之中。
这就是原始问题。
根据拉格朗日对偶性,原始问题的对偶问题是极大极小问题。
通过对偶变换,我们将求解顺序做了一个变换。首先对w,b求导,并令其等于0,最后整理得到对偶问题为:
在最优化中,如果满足KKT条件,那么原始问题和对偶问题的最优值相等。
(2)线性近似可分支持向量机,即软间隔支持向量机
训练集数据并不总是线性可分的,通常情况下,训练集数据有一些异常点,将这些异常点去掉之后,剩下的大部分样本组成的集合是线性可分的。
线性不可分意味着某些样本点不满足函数间隔大于等于1的约束条件。为了解决这个问题,可以对每个样本点引入一个松弛变量。使得函数间隔加上松弛变量之后大于等于1.这样约束条件变成:
同时每个松弛变量,都要支付一个代价,目标函数由原来的,变成了
线性支持向量机的损失函数是合页损失。
(3)参数的求解
支持向量机参数的求解是利用SMO(序列最小最优化算法)算法的,其基本思路就是:所有所有变量的解都满足此最优化问题的KKT条件,那么这个最优化问题的解就找到了。其特点就是不断的将原二次规划问题分解为只有两个变量的二次规划子问题,并对子问题进行解析求解,直到所有变量满足KKT条件。
3.SVM优缺点
优缺点:
SVM有如下主要几个特点:
(1)非线性映射是SVM方法的理论基础,SVM利用内积核函数代替向高维空间的非线性映射;
(2)对特征空间划分的最优超平面是SVM的目标,最大化分类边际的思想是SVM方法的核心;
(3)支持向量是SVM的训练结果,在SVM分类决策中起决定作用的是支持向量;
(4)SVM 是一种有坚实理论基础的新颖的小样本学习方法。
它基本上不涉及概率测度及大数定律等,因此不同于现有的统计方法。
从本质上看,它避开了从归纳到演绎的传统过程,实现了高效的从训练样本到预报样本的“转导推理”,大大简化了通常的分类和回归等问题;
4.实例:SVM 实现数据集分类
1.问题描述
从 MNIST 数据集中任意选择两类,对其进行 SVM 分类,可调用现有的 SVM 工具如 LIBSVM,展示超参数 C 以及核函数参数的选择过程。
2.求解过程
第一步:数据集下载,代码如下:
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
第二步:选定核函数为 RBF
第三步:手动进行调参,调参过程如下,显示的准确率是测试集的,可以看出当 gamma 的值为 0.0001、0.001;C 的值为 0.1 以上时泛化性能较好。
from sklearn import svm
import numpy as np
import tensorflow as tf
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import time
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train = x_train.reshape([x_train.shape[0], -1])
x_test = x_test.reshape([x_test.shape[0], -1])
train_x = []
train_y = []
for i in range(x_train.shape[0]):
if y_train[i] == 0 or y_train[i] == 1:
train_x.append(x_train[i])
train_y.append(y_train[i])
train_x = np.array(train_x)
train_y = np.array(train_y)
test_x = []
test_y = []
for i in range(x_test.shape[0]):
if y_test[i] == 0 or y_test[i] == 1:
test_x.append(x_test[i])
test_y.append(y_test[i])
test_x = np.array(test_x)
test_y = np.array(test_y)
train_x = train_x[0:1000]
train_y = train_y[0:1000]
test_x = test_x[0:300]
test_y = test_y[0:300]
scaler = StandardScaler()
train_x = scaler.fit_transform(train_x)
test_x = scaler.fit_transform(test_x)
score = np.zeros([10,10])
C_range = np.logspace(-3, 6, 10)
gamma_range = np.logspace(-4, 5, 10)
for i,c in enumerate(C_range):
for j,g in enumerate(gamma_range):
start = time.time()
svc = svm.SVC(C=c, kernel='rbf', gamma=g, decision_function_shape='ovo')
svc.fit(train_x, train_y)
score[i,j] = svc.score(test_x, test_y)
end = time.time()
print('c:',c,'g:',g,'time:',(end-start))
plt.figure(figsize=(8, 6))
plt.subplots_adjust(left=.2, right=0.95, bottom=0.15, top=0.95)
plt.imshow(score, interpolation='nearest', cmap=plt.cm.hot)
plt.xlabel('gamma')
plt.ylabel('C')
plt.colorbar()
plt.xticks(np.arange(len(gamma_range)), gamma_range, rotation=45)
plt.yticks(np.arange(len(C_range)), C_range)
plt.title('Test accuracy')
plt.show()
第四步:网格调参,参数如下
输出为:The best parameters are {‘C’: 3, ‘gamma’: 0.0001, ‘kernel’: ‘rbf’} with a score of 1.00
from sklearn import svm
import numpy as np
import tensorflow as tf
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train = x_train.reshape([x_train.shape[0], -1])
x_test = x_test.reshape([x_test.shape[0], -1])
train_x = []
train_y = []
for i in range(x_train.shape[0]):
if y_train[i] == 0 or y_train[i] == 1:
train_x.append(x_train[i])
train_y.append(y_train[i])
train_x = np.array(train_x)
train_y = np.array(train_y)
test_x = []
test_y = []
for i in range(x_test.shape[0]):
if y_test[i] == 0 or y_test[i] == 1:
test_x.append(x_test[i])
test_y.append(y_test[i])
test_x = np.array(test_x)
test_y = np.array(test_y)
train_x = train_x[0:1000]
train_y = train_y[0:1000]
test_x = test_x[0:300]
test_y = test_y[0:300]
scaler = StandardScaler()
train_x = scaler.fit_transform(train_x)
test_x = scaler.fit_transform(test_x)
parameters = [
{
'C': [1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
'gamma': [0.00001, 0.0001, 0.001, 0.1, 1, 10, 100, 1000],
'kernel': ['rbf']
},
{
'C': [1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
'kernel': ['linear']
}
]
svc = svm.SVC()
clf = GridSearchCV(svc, parameters, cv=3, n_jobs=8)
clf.fit(train_x,train_y)
print("The best parameters are %s with a score of %0.2f"
% (clf.best_params_, clf.best_score_))
scores = clf.cv_results_['mean_test_score'][0:80].reshape(8,10)
plt.figure(figsize=(8, 6))
plt.subplots_adjust(left=.2, right=0.95, bottom=0.15, top=0.95)
plt.imshow(scores, interpolation='nearest', cmap=plt.cm.hot)
plt.xlabel('gamma')
plt.ylabel('C')
plt.colorbar()
plt.xticks(np.arange(8), [0.00001, 0.0001, 0.001, 0.1, 1, 10, 100, 1000], rotation=45)
plt.yticks(np.arange(10), [1, 3, 5, 7, 9, 11, 13, 15, 17, 19])
plt.title('RBF Validation accuracy')
plt.show()