《机器学习_07_02_svm_软间隔支持向量机》
一.简介
上一节介绍了硬间隔支持向量机,它可以在严格线性可分的数据集上工作的很好,但对于非严格线性可分的情况往往就表现很差了,比如:
import numpy as np
import matplotlib.pyplot as plt
import copy
import random
import os
os.chdir('../')
from ml_models import utils
from ml_models.svm import HardMarginSVM
%matplotlib inline
*** PS:请多试几次,生成含噪声点的数据***
from sklearn.datasets import make_classification
data, target = make_classification(n_samples=100, n_features=2, n_classes=2, n_informative=1, n_redundant=0,
n_repeated=0, n_clusters_per_class=1, class_sep=2.0)
plt.scatter(data[:,0],data[:,1],c=target)
<matplotlib.collections.PathCollection at 0x202a6f55a58>

#训练
svm = HardMarginSVM()
svm.fit(data, target)
utils.plot_decision_function(data, target, svm, svm.support_vectors)

那怕仅含有一个异常点,对硬间隔支持向量机的训练影响就很大,我们希望它能具有一定的包容能力,容忍哪些放错的点,但又不能容忍过度,我们可以引入变量\(\xi\)和一个超参\(C\)来进行控制,原始的优化问题更新为如下:
s.t.y_i(w^Tx_i+b)\geq 1-\xi_i,i=1,2,...,N\\
\xi_i\geq0,i=1,2,...,N
\]
这里\(C\)若越大,包容能力就越小,当取值很大时,就等价于硬间隔支持向量机,而\(\xi\)使得支持向量的间隔可以调整,不必像硬间隔那样,严格等于1
Lagrange函数
关于原问题的Lagrange函数:
s.t.\mu_i\geq 0,\alpha_i\geq0,i=1,2,...,N
\]
二.对偶问题
对偶问题的求解过程我就省略了,与硬间隔类似,我这里就直接写最终结果:
s.t.\sum_{i=1}^N\alpha_iy_i=0,\\
0\leq\alpha_i\leq C,i=1,2,...,N
\]
可以发现与硬间隔的不同是\(\alpha\)加了一个上界的约束\(C\)
三.KKT条件
这里就直接写KKT条件看原优化变量与拉格朗日乘子之间的关系:
\frac{\partial L}{\partial b}=0\Rightarrow \alpha_i^*y_i=0(关系2)\\
\frac{\partial L}{\partial \xi}=0\Rightarrow C-\alpha_i^*-\mu_i^*=0(关系3)\\
\alpha_i^*(1-\xi_i^*-y_i({w^*}^Tx_i+b^*))=0(关系4)\\
\mu_i^*\xi_i^*=0(关系5)\\
y_i({w^*}^Tx_i+b^*)-1-\xi_i^*\geq0(关系6)\\
\xi_i^*\geq0(关系7)\\
\alpha_i^*\geq0(关系8)\\
\mu_i^*\geq0(关系9)\\
\]
四.\(w^*,b^*\)的求解
由KKT条件中的关系1,我们可以知道:
\]
对于\(b^*\)的求解,我们可以取某点,其\(0<\alpha_k^*<C\),由关系3,4,5可以推得到:\({w^*}^Tx_k+b^*=y_k\),所以:
\]
五.SMO求\(\alpha^*\)
好了,最终模型得求解落到了对\(\alpha^*\)得求解上,求解过程与硬间隔一样,无非就是就是对\(\alpha\)多加了一个约束:\(\alpha_i^*<=C\),具体而言需要对\(\alpha_2^{new}\)的求解进行更新:
当\(y_1\neq y_2\)时:
H=min(C,C+\alpha_2^{old}-\alpha_1^{old})
\]
当\(y_1=y_2\)时:
H=min(C,\alpha_2^{old}+\alpha_1^{old})
\]
更新公式:
H & \alpha_2^{unc}> H\\
\alpha_2^{unc} & L \leq \alpha_2^{unc} \leq H\\
L & \alpha_2^{unc}<L
\end{matrix}\right.
\]
六.代码实现
"""
软间隔支持向量机的smo实现,放到ml_models.svm模块中
"""
class SoftMarginSVM(object):
def __init__(self, epochs=100, C=1.0):
self.w = None
self.b = None
self.alpha = None
self.E = None
self.epochs = epochs
self.C = C
# 记录支持向量
self.support_vectors = None
def init_params(self, X, y):
"""
:param X: (n_samples,n_features)
:param y: (n_samples,) y_i\in\{0,1\}
:return:
"""
n_samples, n_features = X.shape
self.w = np.zeros(n_features)
self.b = .0
self.alpha = np.zeros(n_samples)
self.E = np.zeros(n_samples)
# 初始化E
for i in range(0, n_samples):
self.E[i] = np.dot(self.w, X[i, :]) + self.b - y[i]
def _select_j(self, best_i):
"""
选择j
:param best_i:
:return:
"""
valid_j_list = [i for i in range(0, len(self.alpha)) if self.alpha[i] > 0 and i != best_i]
best_j = -1
# 优先选择使得|E_i-E_j|最大的j
if len(valid_j_list) > 0:
max_e = 0
for j in valid_j_list:
current_e = np.abs(self.E[best_i] - self.E[j])
if current_e > max_e:
best_j = j
max_e = current_e
else:
# 随机选择
l = list(range(len(self.alpha)))
seq = l[: best_i] + l[best_i + 1:]
best_j = random.choice(seq)
return best_j
def _meet_kkt(self, w, b, x_i, y_i, alpha_i):
"""
判断是否满足KKT条件
:param w:
:param b:
:param x_i:
:param y_i:
:return:
"""
if alpha_i < self.C:
return y_i * (np.dot(w, x_i) + b) >= 1
else:
return y_i * (np.dot(w, x_i) + b) <= 1
def fit(self, X, y2, show_train_process=False):
"""
:param X:
:param y2:
:param show_train_process: 显示训练过程
:return:
"""
y = copy.deepcopy(y2)
y[y == 0] = -1
# 初始化参数
self.init_params(X, y)
for _ in range(0, self.epochs):
if_all_match_kkt = True
for i in range(0, len(self.alpha)):
x_i = X[i, :]
y_i = y[i]
alpha_i_old = self.alpha[i]
E_i_old = self.E[i]
# 外层循环:选择违反KKT条件的点i
if not self._meet_kkt(self.w, self.b, x_i, y_i, alpha_i_old):
if_all_match_kkt = False
# 内层循环,选择使|Ei-Ej|最大的点j
best_j = self._select_j(i)
alpha_j_old = self.alpha[best_j]
x_j = X[best_j, :]
y_j = y[best_j]
E_j_old = self.E[best_j]
# 进行更新
# 1.首先获取无裁剪的最优alpha_2
eta = np.dot(x_i - x_j, x_i - x_j)
# 如果x_i和x_j很接近,则跳过
if eta < 1e-3:
continue
alpha_j_unc = alpha_j_old + y_j * (E_i_old - E_j_old) / eta
# 2.裁剪并得到new alpha_2
if y_i == y_j:
L = max(0., alpha_i_old + alpha_j_old - self.C)
H = min(self.C, alpha_i_old + alpha_j_old)
else:
L = max(0, alpha_j_old - alpha_i_old)
H = min(self.C, self.C + alpha_j_old - alpha_i_old)
if alpha_j_unc < L:
alpha_j_new = L
elif alpha_j_unc > H:
alpha_j_new = H
else:
alpha_j_new = alpha_j_unc
# 如果变化不够大则跳过
if np.abs(alpha_j_new - alpha_j_old) < 1e-5:
continue
# 3.得到alpha_1_new
alpha_i_new = alpha_i_old + y_i * y_j * (alpha_j_old - alpha_j_new)
# 4.更新w
self.w = self.w + (alpha_i_new - alpha_i_old) * y_i * x_i + (alpha_j_new - alpha_j_old) * y_j * x_j
# 5.更新alpha_1,alpha_2
self.alpha[i] = alpha_i_new
self.alpha[best_j] = alpha_j_new
# 6.更新b
b_i_new = y_i - np.dot(self.w, x_i)
b_j_new = y_j - np.dot(self.w, x_j)
if self.C > alpha_i_new > 0:
self.b = b_i_new
elif self.C > alpha_j_new > 0:
self.b = b_j_new
else:
self.b = (b_i_new + b_j_new) / 2.0
# 7.更新E
for k in range(0, len(self.E)):
self.E[k] = np.dot(self.w, X[k, :]) + self.b - y[k]
# 显示训练过程
if show_train_process is True:
utils.plot_decision_function(X, y2, self, [i, best_j])
utils.plt.pause(0.1)
utils.plt.clf()
# 如果所有的点都满足KKT条件,则中止
if if_all_match_kkt is True:
break
# 计算支持向量
self.support_vectors = np.where(self.alpha > 1e-3)[0]
# 显示最终结果
if show_train_process is True:
utils.plot_decision_function(X, y2, self, self.support_vectors)
utils.plt.show()
def get_params(self):
"""
输出原始的系数
:return: w
"""
return self.w, self.b
def predict_proba(self, x):
"""
:param x:ndarray格式数据: m x n
:return: m x 1
"""
return utils.sigmoid(x.dot(self.w) + self.b)
def predict(self, x):
"""
:param x:ndarray格式数据: m x n
:return: m x 1
"""
proba = self.predict_proba(x)
return (proba >= 0.5).astype(int)
svm = SoftMarginSVM(C=3.0)
svm.fit(data, target)
utils.plot_decision_function(data, target, svm, svm.support_vectors)

通过控制C可以调节宽容度,设置一个大的C可以取得和硬间隔一样的效果
svm = SoftMarginSVM(C=1000000)
svm.fit(data, target)
utils.plot_decision_function(data, target, svm, svm.support_vectors)

有时,太过宽容也不一定好
svm = SoftMarginSVM(C=0.01)
svm.fit(data, target)
utils.plot_decision_function(data, target, svm, svm.support_vectors)

七.支持向量
软间隔支持向量机的支持向量复杂一些,因为对于\(\alpha>0\)有许多种情况,如下图所示,大概可以分为4类:
(1)\(0<\alpha_i<C,\xi_i=0\):位于间隔边界上;
(2)\(\alpha_i=C,0<\xi_i<1\):分类正确,位于间隔边界与分离超平面之间;
(3)\(\alpha_i=C,\xi_i=1\):位于分离超平面上;
(4)\(\alpha_i=C,\xi_i>1\):位于错误分类的一侧
《机器学习_07_02_svm_软间隔支持向量机》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- 2019-2020-1 20199308《Linux内核原理与分析》第五周作业
<Linux内核分析> 第四章 系统调用的三层机制(上) 4.1 用户态.内核态和中断 与系统调用打交道的方式是通过库函数的方式 用户态与内核态的区分 内核态:高的执行级别下,代码可以执行 ...
- 2019-2020-1 20199329《Linux内核原理与分析》第六周作业
<Linux内核原理与分析>第六周作业 一.本周内容概述: 学习系统调用的相关理论知识,并使用库函数API和C代码中嵌入汇编代码两种方式使用getpid()系统调用 学习系统调用syste ...
- java 8 stream reduce详解和误区
目录 简介 reduce详解 总结 java 8 stream reduce详解和误区 简介 Stream API提供了一些预定义的reduce操作,比如count(), max(), min(), ...
- CUBA:如何准备上线
"在我电脑上是好的呢!"现在看来,这句话更像是调侃开发人员的一个段子,但是"开发环境与生产环境"之间的矛盾依然存在.作为开发者,你需要记住,你写 ...
- THU OS
前言 最近在学清华的OS课程,实验课做的真厉害. 我们的操作系统课就是写一个系统调用,改下进程软中断通信的代码,代码量不足500...清华是借鉴MIT的课,实验课都是做一个完整的小型操作系统. 一共8 ...
- 矩阵快速幂--HDU 6030 Happy Necklace
Problem Description Little Q wants to buy a necklace for his girlfriend. Necklaces are single string ...
- 数学--数论--HDU1222 狼和兔子(最大公约数)
问题描述 有一座周围有n个洞的小山.孔从0到n-1有符号. 兔子必须藏在其中一个洞中.狼以逆时针方向搜索兔子.他第一个进入的洞是一个用0签名的洞.然后,他将每m个洞进入一个洞.例如,m = 2和n = ...
- POJ 2136 Vertical Histogram(当时写的比较恶心,优化一下)
Vertical Histogram Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 21223 Accepted: 10048 ...
- 图论--2-SAT--详解
问题描述: 现有一个由N个布尔值组成的序列A,给出一些限制关系,比如A[x]AND A[y]=0.A[x] OR A[y] OR A[z]=1等,要确定A[0..N-1]的值,使得其满足所有限制关系. ...
- RobotFrameWork 自动化环境搭建(基于 python2.7)
1.自动化工具安装顺序 robot Framework(两个RF框架) WXpython(不要更改安装路径,自动安装在python文件中) 安装依赖库 RF3.0 和 RF1.5.2.1 打开 rid ...