svm的java实现
关于支持向量机这个东西,其实已经有很多相关的文章了,关于其原理也不是一两篇博客能概括的,包括线形可分时解的存在性、最优间隔分类器的问题转化、约束优化与无约束优化的转换、具体的无约束优化算法的选择、核函数的选择等。
我个人比较纠结于实现,即使已经有很优秀的开源实现比如libsvm,但还是自己从头到脚搞一次心里才踏实。网上关于svm的文章也似乎极少有实现的,大部分是使用libsvm等开源实现,对于我这种偏执狂是比较痛苦。而且很多文章都提到,理论上任何凸优化算法都可以求解,不过无一例外最后都用了smo,我倒是想试试别的方法,比如共轭梯度法之类的,反正实现也不难。于是,从二次规划的转化、手工运算解释解、程序建模设计、核心优化算法的实现(smo还没时间弄),以及一个简单的可视化实验界面,从端午前开始撸,到这周末总算是出来一个使自己心理上过得去的版本,还不包括软间隔(简单扩充下约束条件即可实现)及回归,因为底层的矩阵运算原本还想搞成wolframalpha那种带符号运算的,还想支持复矩阵的运算,因此效率也就成了屎。不过嘛,最后看到那些实验的图片时候,心里还是有点成就感的,毕竟作为一个大菜鸟,总算是做出了一个能简单应用的东西。
在这里太深入的原理就不解释了,主要过一遍比较关键的公式。
最优间隔分类的问题转化:
使用拉格朗日乘子法转换成无约束优化:
对w和b求偏导,代入以约去w和b:
由于这是鞍点,问题再转化成熟悉的最优化形式(约束条件又出来了。。):
问题与约束条件都只有变量alpha,理论上是可以用增广乘子法和罚函数什么的求解,罚函数公式:
由于之前已经写过一个简单的矩阵运算模板,加减乘、转置、lu分解、qr分解等都已经做成模板函数,想要不同的特性只需要实现出模板函数里面依赖的抽象函数就可以了,比如生成子类的实例、生成0、1及极小值的数据等。用熟了所以也就直接复用了,也可以直接用开源实现,质量方面有保证。
然后是一些最优化常用的运算,比如内积啦,二次值啦(quadratic,这个不知道该怎么说,就是x^T*A*x)等等,最优化基本上就是依赖这些运算,主要就是二次函数求梯度的时候,有了这些写起来比较简洁。
再下去就可以封装“标量函数”类了,一个函数无非就是两三个运算:求值、求梯度、求hessian矩阵,都是一个输入一个输出,如果不用牛顿法,hessian矩阵都不用管了。有了函数类,在求约束优化的时候会比较方便,把每个条件写成函数类(其实也就是初始化两个矩阵),然后组合成增广函数,比如上面的罚函数。
优化算法基础是线搜索(精确及不精确),然后是比较简单的几种无约束优化算法,最速下降、共轭梯度、bfgs,再上去就是约束优化算法比如ph算法、phr算法。
到svm的实现,主要就是提取训练集构造成二次函数矩阵,实现几个核函数。
代码写得不好,就不放出来了,放几张截图当个纪念,用了多项式核,线性及非线性都做了一些测试,如果训练数据的形式超出了核函数的“表达能力”,比如第2、3个图中的超平面,投影到2维是一个圆,这种情况如果核函数的幂次只有2,有可能比较难收敛,也就到了死循环,这种情况下用软间隔似乎可以解决,待验证。
收工,如果有人有兴趣,撸夫再补充一下比较完整的实现思路吧。