白板推导系列Pytorch-支持向量机(SVM)

支持向量机的代码实现主要是SMO算法的实现,我参考了下面这篇博客

https://www.cnblogs.com/lsm-boke/p/12317200.html

该博客中使用numpy实现的svm,我对numpy版本做了一点修改,并且使用pytorch的API写了一个新版本,但除了函数名不同基本一致,只是numpy版本的收敛速度比pytorch要快很多。另外我调用了sklearn中的svm,速度都远超这两个实现

pytorch版本

导入所需的包

import torch

生成数据集

def create_dataset(n_samples=1000):x0 = torch.normal(2, 1, size=(n_samples // 2, 2), dtype=torch.float32)y0 = -torch.ones(n_samples // 2, dtype=torch.float32)x1 = torch.normal(-2, 1, size=(n_samples - n_samples // 2, 2), dtype=torch.float32)y1 = torch.ones(n_samples - n_samples // 2, dtype=torch.float32)# 合并数据x,yx = torch.cat((x0, x1), 0)y = torch.cat((y0, y1), 0)return x, y

定义SVM模型

class svm:def __init__(self,toler=0.001,max_iter=100, kernel='linear'):self.toler = tolerself.max_iter = max_iterself._kernel = kernel# 初始化模型def init_args(self, features, labels):self.m, self.n = features.shapeself.X = featuresself.Y = labelsself.b = 0.0# 将Ei保存在一个列表里self.alpha = torch.ones(self.m)self.E = torch.tensor([self._e(i) for i in range(self.m)], dtype=torch.float)# 错误惩罚参数self.C = 1.0# kkt条件def _kkt(self, i):y_g = self._g(self.X[i]) * self.Y[i]if self.alpha[i] == 0:return y_g >= 1elif 0 < self.alpha[i] < self.C:return y_g == 1else:return y_g <= 1# g(x)预测值,输入xi(X[i])def _g(self, xi):return (self.alpha * self.Y * self.kernel(self.X, xi)).sum() + self.b# 核函数,多项式添加二次项即可def kernel(self, X_data, x2, gamma=1, r=0, d=3):if len(X_data.shape) > 1:res = []for x1 in X_data:res.append(self.kernel(x1, x2).item())return torch.tensor(res, dtype=torch.float)else:x1 = X_dataif self._kernel == 'linear':return (x1 * x2).sum()elif self._kernel == 'poly':return (gamma * (x1 * x2).sum() + r) ** dreturn 0# E(x)为g(x)对输入x的预测值和y的差def _e(self, i):return self._g(self.X[i]) - self.Y[i]# 初始alphadef _init_alpha(self):# 外层循环首先遍历所有满足0<a<C的样本点,检验是否满足KKTindex_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]# 否则遍历整个训练集non_satisfy_list = [i for i in range(self.m) if i not in index_list]index_list.extend(non_satisfy_list)for i in index_list:if self._kkt(i):continueE1 = self.E[i]# 如果E2是+,选择最小的;如果E2是负的,选择最大的if E1 >= 0:j = torch.argmin(self.E)else:j = torch.argmax(self.E)return i, j# return -1,-1# 选择alpha参数@staticmethoddef _compare(_alpha, L, H):if _alpha > H:return Helif _alpha < L:return Lelse:return _alpha# 训练def fit(self, features, labels):self.init_args(features, labels)for t in range(self.max_iter):i1, i2 = self._init_alpha()# if i1==-1 and i2==-1:#     # 没有找到违背kkt条件的点#     return# 边界if self.Y[i1] == self.Y[i2]:L = max(0, self.alpha[i1] + self.alpha[i2] - self.C)H = min(self.C, self.alpha[i1] + self.alpha[i2])else:L = max(0, self.alpha[i2] - self.alpha[i1])H = min(self.C, self.C + self.alpha[i2] - self.alpha[i1])E1 = self.E[i1]E2 = self.E[i2]# eta=K11+K22-2K12eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(self.X[i2], self.X[i2]) - 2 * self.kernel(self.X[i1], self.X[i2])# 不懂为什么有下面这个判断,如果有读者知道不妨在评论区解释一下if eta <= 0:continuealpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E2 - E1) / etaalpha2_new = self._compare(alpha2_new_unc, L, H)alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (self.alpha[i2] - alpha2_new)b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i1]) * (alpha2_new - self.alpha[i2]) + self.bb2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i2]) * (alpha2_new - self.alpha[i2]) + self.bif 0 < alpha1_new < self.C:b_new = b1_newelif 0 < alpha2_new < self.C:b_new = b2_newelse:# 选择中点b_new = (b1_new + b2_new) / 2# 更新参数self.alpha[i1] = alpha1_newself.alpha[i2] = alpha2_newself.b = b_newself.E[i1] = self._e(i1)self.E[i2] = self._e(i2)def predict(self, X_data):y_pred = []for data in X_data:r = (self.Y * self.alpha * self.kernel(self.X, data)).sum()y_pred.append(torch.sign(r).item())return torch.tensor(y_pred, dtype=torch.float)def score(self, X_data, y_data):y_pred = self.predict(X_data)return (y_pred == y_data).sum() / len(y_data)

测试

X, y = create_dataset(1000)
model = svm(max_iter=100, kernel='linear')
model.fit(X[:800], y[:800])
model.score(X[800:], y[800:])

运行时间大概是11s左右,准确率1.0

numpy版本

# encoding=utf8
import numpy as npclass svm:def __init__(self, max_iter=100, kernel='linear'):'''input:max_iter(int):最大训练轮数kernel(str):核函数,等于'linear'表示线性,等于'poly'表示多项式'''self.max_iter = max_iterself._kernel = kernel# 初始化模型def init_args(self, features, labels):self.m, self.n = features.shapeself.X = featuresself.Y = labelsself.b = 0.0# 将Ei保存在一个列表里self.alpha = np.ones(self.m)self.E = [self._E(i) for i in range(self.m)]# 错误惩罚参数self.C = 1.0# kkt条件def _KKT(self, i):y_g = self._g(i) * self.Y[i]if self.alpha[i] == 0:return y_g >= 1elif 0 < self.alpha[i] < self.C:return y_g == 1else:return y_g <= 1# g(x)预测值,输入xi(X[i])def _g(self, i):r = self.bfor j in range(self.m):r += self.alpha[j] * self.Y[j] * self.kernel(self.X[i], self.X[j])return r# 核函数,多项式添加二次项即可def kernel(self, x1, x2):if self._kernel == 'linear':return sum([x1[k] * x2[k] for k in range(self.n)])elif self._kernel == 'poly':return (sum([x1[k] * x2[k] for k in range(self.n)]) + 1) ** 2return 0# E(x)为g(x)对输入x的预测值和y的差def _E(self, i):return self._g(i) - self.Y[i]# 初始alphadef _init_alpha(self):# 外层循环首先遍历所有满足0<a<C的样本点,检验是否满足KKTindex_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]# 否则遍历整个训练集non_satisfy_list = [i for i in range(self.m) if i not in index_list]index_list.extend(non_satisfy_list)for i in index_list:if self._KKT(i):continueE1 = self.E[i]# 如果E2是+,选择最小的;如果E2是负的,选择最大的if E1 >= 0:j = min(range(self.m), key=lambda x: self.E[x])else:j = max(range(self.m), key=lambda x: self.E[x])return i, j# 选择alpha参数def _compare(self, _alpha, L, H):if _alpha > H:return Helif _alpha < L:return Lelse:return _alpha# 训练def fit(self, features, labels):'''input:features(ndarray):特征label(ndarray):标签'''self.init_args(features, labels)for t in range(self.max_iter):i1, i2 = self._init_alpha()# 边界if self.Y[i1] == self.Y[i2]:L = max(0, self.alpha[i1] + self.alpha[i2] - self.C)H = min(self.C, self.alpha[i1] + self.alpha[i2])else:L = max(0, self.alpha[i2] - self.alpha[i1])H = min(self.C, self.C + self.alpha[i2] - self.alpha[i1])E1 = self.E[i1]E2 = self.E[i2]# eta=K11+K22-2K12eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(self.X[i2], self.X[i2]) - 2 * self.kernel(self.X[i1], self.X[i2])if eta <= 0:continuealpha2_new_unc = self.alpha[i2] + self.Y[i2] * (E2 - E1) / etaalpha2_new = self._compare(alpha2_new_unc, L, H)alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (self.alpha[i2] - alpha2_new)b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i1]) * (alpha2_new - self.alpha[i2]) + self.bb2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(self.X[i2], self.X[i2]) * (alpha2_new - self.alpha[i2]) + self.bif 0 < alpha1_new < self.C:b_new = b1_newelif 0 < alpha2_new < self.C:b_new = b2_newelse:# 选择中点b_new = (b1_new + b2_new) / 2# 更新参数self.alpha[i1] = alpha1_newself.alpha[i2] = alpha2_newself.b = b_newself.E[i1] = self._E(i1)self.E[i2] = self._E(i2)def predict(self, X_data):'''input:data(ndarray):单个样本output:预测为正样本返回+1,负样本返回-1'''y_pred = []for data in X_data:r = self.bfor i in range(self.m):r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])y_pred.append(1 if r > 0 else -1)return np.array(y_pred)def score(self, X_data, y_data):y_pred = self.predict(X_data)return np.sum(y_pred == y_data) / len(y_data)def create_dataset(n_samples=1000):x0 = np.random.normal(2, 1, size=(n_samples // 2, 2))y0 = -np.ones(n_samples // 2)x1 = np.random.normal(-2, 1, size=(n_samples - n_samples // 2, 2))y1 = np.ones(n_samples - n_samples // 2)# 合并数据x,yx = np.vstack((x0, x1))y = np.hstack((y0, y1))return x, yX, y = create_dataset(1000)
nb = svm()
nb.fit(X[:800], y[:800])
print(nb.score(X[800:], y[800:]))

运行时间3s左右,准确率1.0

sklearn

from sklearn.svm import SVCmodel = SVC(kernel='linear')
model.fit(X[:800],y[:800])
model.score(X[800:],y[800:])

运行时间0.5s,准确率1.0

所以我很好奇sklearn中svm是怎么实现的,之后了解到会加以补充

白板推导系列Pytorch-支持向量机(SVM)相关推荐

  1. 机器学习-白板推导系列(三十)-生成模型(Generative Model)

    机器学习-白板推导系列(三十)-生成模型(Generative Model) 30.1 生成模型的定义 前面所详细描述的模型以浅层的机器学习为主.本章将承上启下引出后面深度机器学习的部分.本小节,主要 ...

  2. 机器学习-白板推导系列笔记(十二)-变分推断(VI)

    此文章主要是结合哔站shuhuai008大佬的白板推导视频: VI变分推断_126min 全部笔记的汇总贴:机器学习-白板推导系列笔记 一.背景 对于概率模型 从频率派角度来看就会是一个优化问题 从贝 ...

  3. 机器学习-白板推导系列笔记(二十八)-BM

    此文章主要是结合哔站shuhuai008大佬的白板推导视频:玻尔兹曼机_147min 全部笔记的汇总贴:机器学习-白板推导系列笔记 参考花书20.1 一.介绍 玻尔兹曼机连接的每个节点都是离散的二值分 ...

  4. 机器学习-白板推导-系列(九)笔记:概率图模型: 贝叶斯网络/马尔可夫随机场/推断/道德图/因子图

    文章目录 0 笔记说明 1 背景介绍 1.1 概率公式 1.2 概率图简介 1.2.1 表示 1.2.2 推断 1.2.3 学习 1.2.4 决策 1.3 图 2 贝叶斯网络 2.1 条件独立性 2. ...

  5. 机器学习-白板推导系列笔记(十三)-MCMC

    此文章主要是结合哔站shuhuai008大佬的白板推导视频:MCMC_218min 全部笔记的汇总贴:机器学习-白板推导系列笔记 一.蒙特卡洛方法 蒙特卡洛方法(Monte Carlo Method) ...

  6. 机器学习-白板推导系列笔记(二十一)-RBM

    此文章主要是结合哔站shuhuai008大佬的白板推导视频:受限玻尔兹曼机_155min 全部笔记的汇总贴:机器学习-白板推导系列笔记 玻尔兹曼机介绍:白板推导系列笔记(二十八)-玻尔兹曼机 一.背景 ...

  7. 【白板推导系列笔记】降维-PCA-最大投影方差最小重构代价

    作者:shuhuai008 链接:[机器学习][白板推导系列][合集 1-33]_哔哩哔哩_bilibili PCA的核心就是对原始特征空间的重构(将一组可能线性相关的变量,通过正交变换变换成一组线性 ...

  8. 机器学习-白板推导-系列(五)笔记:降维(PCA/SVD/PCoA/PPCA)

    文章目录 0 笔记说明 1 背景 1.1 样本均值 1.2 样本协方差矩阵 2 主成分分析PCA 2.1 最大投影方差 2.2 最小重构距离 2.3 总结 3 SVD分解HX 4 主坐标分析PCoA ...

  9. 机器学习-白板推导-系列(十)笔记:EM算法

    文章目录 0 笔记说明 1 算法收敛性证明 2 公式导出 2.1 ELBO+KL Divergence 2.2 ELBO+Jensen Inequlity 2.3 最后的工作 3 从狭义EM到广义EM ...

  10. 机器学习-白板推导系列笔记(三十四)-MDP

    此文章主要是结合哔站shuhuai008大佬的白板推导视频:马尔科夫决策过程_107min 全部笔记的汇总贴:机器学习-白板推导系列笔记 一.背景介绍 Random Variable:XYX⊥YX\; ...

最新文章

  1. LeetCode 122. Best Time to Buy and Sell Stock II--贪心--Java,C++,Python解法
  2. python中一些实用而容易被忽视不常用的库
  3. EasyUI Window学习总结
  4. Flask 框架app = Flask(__name__) 解析
  5. PTA-6-1 利用指针找最大值 (10分)(C语言)
  6. memcache入门
  7. pat乙级相当于什么水平_英语四六级/专四/专八相当于美国人什么水平?
  8. 计算机web程序开发,基于WEB的计算机应用基础考试系统的开发与设计
  9. netty 5 心跳
  10. Mixly-呼吸灯及可调灯
  11. photoshop 大作业
  12. VUE提示Gradient has outdated direction syntax
  13. Smartbi的安装部署
  14. 只会PC端测试怎么行?智能手机ETT测试学习一下
  15. java 微信 推送_JAVA 微信消息模板推送
  16. 在html中让图片旋转180度,gif图片旋转教程:怎么把gif旋转90度/180度 附gif图片旋转软件...
  17. 为什么计算机没有无线网络,为什么没有无线路由器的计算机上没有宽带连接?...
  18. 自己动手编译交叉编译链
  19. 局部渐近稳定,全局渐进稳定,一致有界,一致最终有界
  20. h264 丢包花屏处理的一个想法

热门文章

  1. MSSQL数据库的一些长度限制
  2. C++多态的练习——编写一个计算器项目
  3. Django03-视图系统views
  4. mybatis3文档
  5. java当中的定时器的4种使用方式
  6. o'Reill的SVG精髓(第二版)学习笔记——第四章
  7. Restrictions
  8. JavaScript的语法规则
  9. [收藏]深入浅出的《网络socket编程指南》4
  10. C++编程语言中sizeof和strlen介绍