首页 » 网站建设 » phplibsvm技巧_干货 若何进修SVM支持向量机以及改进实现SVM算法轨范

phplibsvm技巧_干货 若何进修SVM支持向量机以及改进实现SVM算法轨范

访客 2024-11-19 0

扫一扫用手机浏览

文章目录 [+]

韦易笑知乎网址:

https://www.zhihu.com/people/skywind3000/activities

phplibsvm技巧_干货  若何进修SVM支持向量机以及改进实现SVM算法轨范

知乎问题:

phplibsvm技巧_干货  若何进修SVM支持向量机以及改进实现SVM算法轨范
(图片来自网络侵删)

https://www.zhihu.com/question/31211585/answer/640501555

以下为正文:

学习 SVM 的最好方法是实现一个 SVM,可讲理论的很多,讲实现的太少了。

假设你已经读懂了 SVM 的事理,并理解公式怎么推导出来的,比如到这里:

SVM 的问题就变成:求解一系列知足约束的 alpha 值,使得上面那个函数可以取到最小值。
然后记录下这些非零的 alpha 值和对应样本中的 x 值和 y 值,就完成学习了,然后预测的时候用:

上面的公式打算出 f(x) ,如果返回值 > 0 那么是 +1 种别,否则是 -1 种别,先把这一步怎么来的,为什么这么来找篇文章读懂,不然你会做的一头雾水。

那么剩下的 SVM 实现问题便是如何求解这个函数的极值。
方法有很多,我们先找个出发点,比如 Platt 的SMO 算法(https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-98-14.pdf),它后面有伪代码描述怎么快速求解 SVM 的各个系数。

第一步:实现传统的 SMO 算法

现在大部分的 SVM 开源实现,源头都是 platt 的 smo 算法,读完他的文章和推导,然后照着伪代码写就行了,核心代码没几行:

target = desired output vector

point = training point matrix

procedure takeStep(i1,i2)

if (i1 == i2) return 0

alph1 = Lagrange multiplier for i1

y1 = target[i1]

E1 = SVM output on point[i1] – y1 (check in error cache)

s = y1y2

Compute L, H via equations (13) and (14)

if (L == H)

return 0

k11 = kernel(point[i1],point[i1])

k12 = kernel(point[i1],point[i2])

k22 = kernel(point[i2],point[i2])

eta = k11+k22-2k12

if (eta > 0)

{

a2 = alph2 + y2(E1-E2)/eta

if (a2 < L) a2 = L

else if (a2 > H) a2 = H

}

else

{

Lobj = objective function at a2=L

Hobj = objective function at a2=H

if (Lobj < Hobj-eps)

a2 = L

else if (Lobj > Hobj+eps)

a2 = H

else

a2 = alph2

}

if (|a2-alph2| < eps(a2+alph2+eps))

return 0

a1 = alph1+s(alph2-a2)

Update threshold to reflect change in Lagrange multipliers

Update weight vector to reflect change in a1 & a2, if SVM is linear

Update error cache using new Lagrange multipliers

Store a1 in the alpha array

Store a2 in the alpha array

return 1

endprocedure

核心代码很紧凑,便是给定两个 ai, aj,然后迭代出新的 ai, aj 出来,还有一层循环会一直的选择最须要被优化的系数 ai, aj,然后调用这个函数。
如何更新权重和 b 变量(threshold)文章里面都有说,再多调试一下,可以用 python 先调试,再换成 C/C++,担保得到一个精确可用的 SVM 程序,这是后面的根本。

第二步:实现核函数缓存

不雅观察下上面的伪代码,开销最大的便是打算核函数 K(xi, xj),有些打算又反复用到,一个 100 个样本的数据集求解,假设统共要调用核函数 20 万次,但是 xi, xj 的组和只有 100x100=1 万种,有缓存的话你的效率可以提升 20 倍。

样本太大时,如果你想存储所有核函数的组和,须要 NN sizeof(double) 的空间,如果演习集有 10 万个样本,那么须要 76 GB 的内存,显然是不可能实现的,以是核函数缓存是一个有限空间的 LRU 缓存,SVM 的 SMO 求解过程中实在会反复用到特定的几个有限的核函数求解,以是命中率不用担心。

有了这个核函数缓存,你的 SVM 求解程序能瞬间快几十倍。

第三步:优化偏差值求解

把稳看上面的伪代码,里面须要打算一个估计值和真实值的偏差 Ei 和 Ej,他们的求解方法是:

E(i) = f(xi) - yi

这便是目前为止 SMO 这段为代码里代价最高的函数,由于回顾下上面的公式,打算一遍 f(x) 须要 for 循环做乘法加法。

platt 的文章建议是做一个 E 函数的缓存,方便后面选择 i, j 时比较,我看到很多入门版本 SVM 实现都是这么做。
实在这是有问题的,后面我们会说到。
最好的办法是定义一个 g(x) 令其即是:

也便是 f(x) 公式除了 b 以外前面的最费时的打算,那么我们随时可以打算偏差:

E(j) = g(xj) + b - yj

以是最好的办法是对 g(x) 进行缓存,platt 的方法里由于所有 alpha 值初始化成了 0,以是 g(x) 一开始就可以全部设置成 0,轻微不雅观察一下 g(x) 的公式,你就会创造,由于去掉了 b 的滋扰,而每次 SMO 迭代更新 ai, aj 参数时,这两个值都是线性变革的,以是我们可以给 g(x) 求关于 a 的偏导,假设 ai,aj 变革了步长 delta,那么所有样本对应的 g(x) 加上 delta 乘以针对 ai, aj 的偏导数就行了,详细代码类似:

double Kik = kernel(i, k);

double Kjk = kernel(j, k);

G[k] += delta_alpha_i Kik y[i] + delta_alpha_j Kjk y[j];

把这段代码放在 takeStep 后面,每次成功更新一对 ai, aj 往后,更新所有样本对应的 g(x) 缓存,这样通过每次迭代更新 g(x) 避免了大量的重复打算。

这实在是很直白的一种优化办法,我查了一下,有人专门发论文就讲了个类似的方法。

第四步:实现冷热数据分离

Platt 的文章里也证明过一旦某个 alpha 出于边界(0 或者 C)的时候,就很不随意马虎变动,而且伪代码也是优先在事情集里探求 > 0 and < C 的 alpha 值进行优化,找不到了,再对事情集整体的 alpha 值进行迭代。

那么我们势必就可以把事情集分成两个部分,热数据在前(大于 0 小于 C 的 alpha 值),冷数据在后(小于即是 0 或者大于即是 C 的 alpha)。

随着迭代加深,会创造大部分时候只须要在热数据里求解,并且热数据的大小会逐步一直的紧缩,以是区分了冷热往后 SVM 大部分都在针对有限的热数据迭代,偶尔弗成了,再全部迭代一次,然后又回到冷热迭代,性能又能提高不少。

第五步:支持 Ensemble

大家都知道,通过 Ensemble 可以让多个不同的弱模型组和成一个强模型,而传统 SVM 实现并不能适应一些类似 AdaBoost 的集成方法,以是我们须要做一些改动。
可以让表面针对某一个分类传入一个“权重”过来,改动 SVM 的识别结果。

最传统的修正办法便是将不等式约束 C 分为 Cp 和 Cn 两个针对 +1 分类的 C 及针对 -1 分类的 C。
修正办法是直接用原始的 C 乘以各自分类的权重,得到 Cp 和 Cn,然后迭代时,不同的样本根据它的 y 值符号,用不同的 C 值带入打算。

这样 SVM 就能用各种集成方法同其他模型一起组成更为强大精准的模型了。

实现到这一步你就得到了功能上和性能上同 libsvm 类似的东西,接下来我们连续优化。

第六步:连续优化核函数打算

核函数缓存非常花费内存,libsvm 数学上已经没得挑了,但是工程方面还有很大改进余地,比如它的核缓存实现。

由于标准 SVM 核函数用的是两个高维矢量的内积,根据内积的几个条件,SVM 的核函数又是一个正定核,即 K(xi, xj) = K(xj, xi),那么我们同样的内存还能再多存一倍的核函数,性能又能有所提升。

针对核函数的打算和存储有很多优化办法,比如有人对 NxN 的核函数矩阵进行采样,只打算有限的几个核函数,然后通过插值的办法求解出中间的值。
还有人用 float 存储核函数值,又降落了一倍空间需求。

第七步:支持稀疏向量和非稀疏向量

对付高维样本,比如笔墨这些,可能有上千维,每个样本的非零特色可能就那么几个,以是稀疏向量会比较高效,libsvm 也是用的稀疏向量。

但是还有很多时候样本是密集向量,比如一共 200 个特色,大部分样本都有 100个以上的非零特色,用稀疏向量存储的话就非常低效了,openCV 的 SVM 实现就是非稀疏向量。

非稀疏向量直接是用数组保存样本每个特色的值,在工程方面就有很多优化办法了,比如用的最多的求核函数的时候,直接上 SIMD 指令或者 CUDA,就能得到更好的打算性能。

以是最好的办法是同时支持稀疏和非稀疏,兼顾韶光和空间效率,对不同的数据选择最适宜的办法。

第八步:针对线性核进行优化

传统的 SMO 方法,是 SVM 的通用求解方法,然而针对线性核,便是:

K(xi, xj) = xi . xj

还有很多更高效的求解思路,比如 Pegasos 算法就用了一种类似随机梯度低落的方法,快速求 SVM 的解权重 w,如果你的样本适宜线性核,利用一些针对性的非 SMO 算法可以极大的优化 SVM 求解,并且能处理更加弘大的数据集,LIBLINEAR 便是做这件事情的。

同时这类算法也适宜 online 演习和并行演习,可以逐步更新增量演习新的样本,还可以用到多核和分布式打算来演习模型,这是 SMO 算法做不到的地方。

但是如果碰到非线性核,权重 w 处于高维核空间里(有可能无限维),你没法梯度低落迭代 w,并且 pegasos 的 pdf 里面也没有提到如何用到非线性核上,LIBLINEAR 也没有办法处理非线性核。

或许哪天出个数学家又找到一种更好的方法,可以用类似 pegasos 的办法求解非线性核,那么 SVM 就能有比较大的进展了。

后话

上面八条,你如果实现前三条,基本就能深入理解 SVM 的事理了,如果实现一大半,就可以得到一个类似 libsvm 的东西,全部实现,你就能得到一个比 libsvm 更好用的 SVM 库了。

上面便是如何实现一个相对成熟的 SVM 模型的思路,以及配套优化方法,再今后还有兴趣,可以接其实现支持向量回归,也是一个很有用的东西。

点击阅读原文,加入 PyTorch 技能互换小组,与同行切磋互换

标签:

相关文章

介绍皮肤设置,如何打造理想肌肤状态

随着科技的发展和人们对美的追求,皮肤设置已成为美容护肤的重要一环。如何根据皮肤类型、肤质、年龄等因素进行合理设置,已成为众多爱美人...

网站建设 2025-01-03 阅读3 评论0

介绍盖章制作,传承文化,彰显权威

自古以来,盖章在我国文化中具有重要的地位。从古代的官印、私印到现代的公章、合同章,盖章已成为一种独特的文化符号,承载着丰富的历史内...

网站建设 2025-01-03 阅读4 评论0

介绍监控破坏,技术手段与法律风险并存

随着科技的飞速发展,监控设备已遍布大街小巷,成为维护社会治安的重要手段。一些不法分子为了逃避法律制裁,开始研究如何破坏监控设备。本...

网站建设 2025-01-03 阅读1 评论0

介绍登录不上之谜,技术故障还是人为疏忽

随着互联网的普及,登录已成为人们日常生活中不可或缺的一部分。在享受便捷的登录不上这一问题也困扰着许多用户。本文将深入剖析登录不上之...

网站建设 2025-01-03 阅读1 评论0

介绍电脑键盘调出方法,让操作更高效

随着科技的发展,电脑已经成为了我们日常生活中不可或缺的工具。而电脑键盘,作为电脑输入设备,更是我们与电脑进行交流的桥梁。你是否知道...

网站建设 2025-01-03 阅读1 评论0

介绍磁力链,高效便捷的文件下载利器

在互联网高速发展的今天,文件下载已成为日常生活中不可或缺的一部分。而磁力链作为一种新型的文件下载方式,凭借其高效、便捷的特点,受到...

网站建设 2025-01-03 阅读1 评论0