LIBSVM与LIBLINEAR

来源:互联网 发布:unity3d遮罩shader 编辑:程序博客网 时间:2024/05/18 09:25

转载 http://orangeprince.info/2014/11/22/libsvm-liblinear/


LIBSVM与LIBLINEAR(一)


在过去的十几年里,支持向量机(Support Vector Machines)应该算得上是机器学习领域影响力最大的算法了。而在SVM算法的各种实现工具中,由国立台湾大学林智仁老师开发的工具包LIBSVM,又无疑是影响力最大的。2011年LIBSVM的系统介绍论文“LIBSVM: a library for support vector machines”发表在了期刊ACM TIST(ACM Transactions on Intelligent Systems and Technology)上。2011年的时候,这个期刊的影响因子还不到1,但到了2014年,它的影响因子居然达到了9.39,把TPAMI都甩出了一大截。这其中贡献最大的当然是关于LIBSVM的这篇论文,在google scholar上,这篇文章的引用量居然已经接近20000,着实吓人。仔细想来其实也并不奇怪,各种研究工作,只要涉及到分类,大部分都会用到SVM算法或者与SVM的算法进行对比,而此时LIBSVM往往是首选工具。其实不但是学术界,在工业界LIBSVM也有非常广泛的应用。这一方面得益于算法实现的稳定与高效,另一方面也是因为LIBSVM提供了丰富的接口与灵活的使用方式。一些非常有名的机器学习工具,如基于java的Weka和基于python的scikit-learn,其提供的SVM算法在底层也是基于LIBSVM的实现。

几年前参加过一个机器学习的学习班,主讲人是CMU的Eric Xing老师。在提问环节,大家都在讨论一些高深的理论问题,突然有一个女生举手提问主讲人如果要用SVM的话有什么工具推荐使用。这个问题在当时的场景似乎有点不合时宜,Eric Xing老师回答说他们CMU从来不用别人的库,所有的算法代码都是自己实现的云云。后来那次讲座上其他的东西我都不太记得了,印象最深的就变成了这个问答。现在想来,如果从算法学习角度,自己实现这些算法对于理论的理解和工程能力的提升都是大有好处。但是对于绝大部分人来说,自己动手实现的SVM算法在效率和扩展性上,还是会和LIBSVM的算法实现存在不小的差距,毕竟人家的程序是千锤百炼中产生的。如果单纯为了使用的话,一个大家都认可的好工具绝不失为一个很好地选择。但是,有一个好的工具并不等于我们可以对算法与实现一无所知而把所有的事情都交给工具。相反,如果我们能够很好地了解算法与实现中的一些背景知识,可以更好地使用这些工具。此外,LIBSVM与他的姊妹工具LIBLINEAR提供了丰富的优化与参数选项,通过选择适当的方法,也可以大大提高我们的工作效率。因此,下面总结一些在我之前的工作中遇到的一些与LIBSVM和LIBLINEAR相关的重要问题,希望能够为读者对这些工具的使用有所帮助。

LIBSVM与LIBLINEAR的关系

这是很多刚开始使用SVM的人容易弄混淆的问题。简单来说,LIBSVM是一套完整的SVM模型实现。用户可以在LIBSVM中使用核函数来训练非线性的分类器,当然也能使用更基础的线性SVM。而LIBLINEAR是一个针对线性分类场景而设计的工具包,除了支持线性SVM外,还支持线性的Logistic Regression等模型,但是无法通过定义核函数方式实现非线性的分类器。由于支持核函数的扩展,LIBSVM理论上具有比LIBLINEAR更强的分类能力,能够处理更为复杂的问题。但是,很多人因此就只使用LIBSVM,甚至最简单的线性分类器都是用LIBSVM来训练和预测,这也是不可取的。因为LIBLINEAR设计的初衷就是为了提高线性分类的效率,其优化算法与LIBSVM中的优化算法有着根本的区别。虽然在进行线性分类时LIBSVM和LIBLINEAR都可以达到类似的结果,但是LIBLINEAR无论是在训练上还是在预测上,都比LIBSVM高效得多。此外,受限于算法,LIBSVM往往在样本量过万之后速度就比较慢了,如果样本量再上升一个数量级,那么通常的机器已经无法处理了。但使用LIBLINEAR,则完全不需要有这方面的担忧,即便百万千万级别的数据,LIBLINEAR也可以轻松搞定,因为LIBLINEAR本身就是为了解决较大规模样本的模型训练而设计的。

虽然搞清楚了两者主要的区别,但我在刚刚接触这些工具时,一直很疑惑为什么两个紧密相关算法,却演化出两个彼此独立的工具包。而让我更加不解的是,LIBSVM早在2000年就已经发布了,而LIBLINEAR直到2007年才发布第一个版本。根据常识,应该是先有一个简单的工具,然后再逐渐完善,但是功能更加强大的LIBSVM却早于LIBLINEAR很久发布。要回答这个问题,还得从机器学习以及SVM的历史说起。

早期的机器学习分类算法可以追溯到Perception(感知机)。Perception的基本思想和Logistic Regression类似,只不过是用在线学习的方法训练出一个线性分类器。在UCI数据集 中可以看到很多80年代到90年代初期用于机器学习研究的数据。可以看出,这其中的很多问题都非常复杂,比如图像或者语音的识别。但是另一方面,受限于当时获取数据与计算存储能力的限制,这些数据集的规模通常非常的小,有的只有几千甚至几百个样本。对于这样相对复杂的问题,可以想到将特征直接用简单的线性分类器进行分类,肯定不会取得太好的效果。这个时候,机器学习领域一个里程碑Multi-Layer Neural Networks(多层神经网络)出现了。多层神经网络引入了Hidden Layer (隐含层),模型的表达能力大大增强,可以训练出各种复杂的分类器。然而神经网络也有一个致命的弱点,由于模型本身的局限性,非常容易过拟合,尤其是在训练样本量较少的情况下。而这时SVM应运而生,完美的解决了这个问题。一方面,SVM的目标函数是一个凸函数,可以保证得到问题的全局最优解,避免了神经网络优化频繁陷入局部最优的困扰。另一方面,SVM的背后有一套结构化风险最小化的理论,给定了训练样本和训练参数,是可以从理论上计算出模型在真实数据上误差的bounds。在SVM中,通过对参数的调节和样本量的选择,可以在模型方差与训练误差之间方便的做出权衡。此外,SVM可以定义不同的核函数来构造非线性分类器,可以得到与神经网络方法大体相当的分类能力,从而适应不同的问题。因此,在上个世纪末到这个是基础,SVM横扫了各种分类的应用场景,成为了当时最炙手可热的机器学习算法。

然而,SVM也存在局限性。首先,基于核函数的SVM求解相对比较复杂,需要存储一个稠密的样本间Kernel矩阵,当样本量很大时,存储量相当可观。而到目前为止,一直没有一个非常有效的并行SVM训练方法能够从根本上提升SVM模型的训练。在十几年前,样本量最多只是上万级别的时候,这个问题并不显得重要。但是在十多年后,随着互联网的爆炸式发展,随便一个模型的训练样本量都可能数以亿计,这时SVM在大数据训练上的不足就凸显无疑了。SVM之所以效果好,主要是得益于非线性核函数的引入。但是新的问题不断出现,而这些问题又涉及到的不同领域知识与业务场景,很多时候仅仅依靠常见的几种kernel函数并不能解决问题。但是SVM本身过分依赖于核函数,而核函数又存在着很多的限制,其灵活性当然不如人工的特征构造方法。另一方面,随着数据量的不断增加,即使这些样不能直接被标注用于模型的训练,但是可以很多机器学习方法可以从大量的样本中进行特征的自动学习。比如早年的流形学习,还有文本上的主题模型,图像上的稀疏编码与字典学习等。通过这些非线性的方法学习的样本特征,往往已经是样本的高层语义表达,有数据充足的情况下,只需要使用较为简单的线性分类器,就可以达到比较好的效果。这时的主要矛盾变成了分类器必须有能力处理足够大量的样本,而在方法上,可以是简单地现行方法。也就是在这个时候,LIBLINEAR应运而生。

在LIBSVM诞生的时代,SVM的核函数带来的非线性模型是SVM的主要优势之一,且当时的样本量还不是瓶颈。因此LIBSVM的整体框架都是针对训练Kernel SVM模型来训练的。但是如果只是需要训练一个线性的SVM模型,那么算法可以简单的多,也可以高效的多。因此LIBLINEAR在保持基本接口和调用方式一致的情况下,采用了新的训练算法,支持了线性SVM和Logistic Regression的训练。LIBSVM和LIBLINEAR的作者林智仁老师在后来的很多报告中,都在大力的推广LIBLINEAR,并且给出了很多实际的例子证明,人工构造特征+线性模型的方式可以达到甚至超过kernel SVM的表现,同时大大降低训练的时间和消耗的资源。

其实就在最近几年,情况又有了新的变化。人工构造特征+线性分类器的方式在很多问题上又遇到了瓶颈。与此同时,一方面可供使用数据量更大了,另一方面,计算机的计算能力又有了突飞猛进的增长。此时曾经被SVM狠狠压在地上的神经网络又重新焕发了生机。与SVM相比,神经网络模型的优势在于可以通过控制模型的层数和每一层函数的类型,设计出各种灵活的分类器。同时神经网络的优化算法比kernel SVM更适合并行化。当时影响神经网络发展的主要问题是计算资源的限制和样本量少引起的过拟合。但现在这两项限制都几乎不存在了。基于GPU的并行计算技术现在已经比较成熟,可以支持高速的并行计算。而造成过拟合的原因从根本上说,是因为训练样本的比真实样本数少的太多,不能够反应真实的数据情况。但是如果把我们拥有的所有样本都作为训练样本,其实机会已经就是真实的样本集了,因此过拟合的事实基础就不存在了。虽然神经网络在理论上还有缺陷,但是通过计算能力和数据的增加,这些缺陷已经不是问题。正是因为上面的原因,这些年机器学习的热点又重新回到了神经网络。

1995年,SVM的发明人Vapnik和他在Bell实验室的老大Larry Jackel打过两个赌,而见证人是当时也在Bell而最近因为Deep Learning而声名鹊起的Yann Lecun。赌局的具体内容见下图:bet-by-2000不管他们输赢与否,我们都能感觉到这门学科的变化之快。在神经网络大行其道的时候,很难想到半路杀出一个SVM将神经网络算法杀了一个体无完肤。而在SVM一统天下的时候,大部分人也不会相信神经网路居然还能最后等到逆袭的那一天。

仔细看每一次算法的革新,其实真正的推动力都是具体的问题需求与当时的技术条件。因此,脱离具体的应用场景去单纯比较算法的优劣并没有太多意义。对于使用者来说,最适合这个问题场景的算法就是最好的算法。具体到LIBSVM和LIBLINEAR,我尝试总结下面几个原则:

  • 凡是确定使用线性分类器的场景,一定使用LIBLINEAR而不是LIBSVM。
  • 如果样本量较大,比如达到10万以上的规模,这时LIBSVM已经很难处理了。如果线性分类器的效果实在不好,只能采用人工构造特征+LIBLINEAR的方式,或者采用其他的分类器,如神经网络,随机森林等。
  • 对于高维稀疏数据,典型的如文本的向量空间表示,一般都采用线性的分类器。
  • 对于样本量和维度都不算太大的问题,且没有对预测的效率有过分的需求,都可以用LIBSVM尝试一下kernel SVM的分类器,很多情况下用kernel SVM比直接用libear SVM还是能达到更高的精度。

LIBSVM与LIBLINEAR(二)



模型与优化

LIBSVM和LIBLINEAR都提供了多种不同的模型供使用者选择,不同的模型有各自适用的场景。下面分别介绍LIBSVM和LIBLINEAR所提供的各种模型。

LIBSVM

下面是LIBSVM帮助内容提供的介绍,给出了LIBSVM支持的5种模型。其中模型0和1对应的都是SVM的分类模型,2对应的是one-class分类器,也就是只需要标注一个标签,模型3和4对应的是SVM的回归模型。

1 -s svm_type : set type of SVM (default 0)2 0 -- C-SVC(multi-class classification)3 1 -- nu-SVC(multi-class classification)4 2 -- one-class SVM5 3 -- epsilon-SVR(regression)6 4 -- nu-SVR(regression)

首先来看最基础的C-SVC模型。SVM可以写成如下的优化目标函数(这里不详细介绍推导算法了):

argminw,b,ξ subjectto 12wTw+C∑i=1lξiyi(wT?(xi)?b)≥1?ξi,ξi≤0,i=1,…,l

当模型使用linear kernel,也就是?(x)=x时,上面的问题一个标准的二次凸优化问题,可以比较方便的对每一个变量进行求导。求解这样的问题是有很多快速的优化方法的,这些方法在LIBLINEAR中都有应用。但是如果是引入kernel的SVM,情况就大不一样了。因为很多时候我们既不能得到核函数的具体形式,又无法得到特征在核空间中新的表达。这个时候,之前用在线性SVM上的的求解思路就完全不work了。为了解决这个问题,就必须采用标准的SVM求解思路,首先把原问题转化为对偶问题,得到下面的目标函数(具体过程可以参考任何介绍SVM的资料):

argminα subjectto f(α)=12αTQα?eTα0≤αi≤C,i=1,…,l,yTα=0

通过对偶变化,上面的目标函数变成了一个关于变量α的二次型。很显然,上面目标函数中最重要的常亮是矩阵Q,既训练样本的Kernel Matrix,满足Qi.j=?(xi)T?(xj)。先看好的一方面,根据核函数的定义,能够保证Q是一个正定的矩阵。也就是说,上面的目标函数还是一个凸函数,优化收敛后能保证得到的解是全局最优解, 这也是SVM的重要优势之一。但是问题也随之而来,使用常用的核函数,只要任意给出两个向量,总是能够计算出一个非0的距离。这也就意味着矩阵Q将会是一个非常稠密的矩阵,如果训练样本足够多,那么矩阵Q的存储和计算将成为很大的问题,这也是SVM的优化算法中的最大挑战。

由于矩阵Q过大,所以想一次性优化整个α是比较困难的。所以常用的方法都是先把Q大卸八块,每次选择一部分的Q,然后update与这部分Q相关的α的值。这其中最著名的算法就是1998由John C. Platt提出的SMO算法,而LIBSVM的优化过程也是基于SMO算法进行的。SMO算法的每一步迭代都选择最小的优化单元,也就是固定其他的α,只挑选两个α的值进行优化。之所以不选择一个,是因为有yTα=0的约束,至少选择两个α的坐标才有可能进行更新。本文主要目的是介绍LIBSVM,所以就不详细讨论SMO的细节了。至于LIBSVM中的具体算法实现,在LIBSVM的官方论文中介绍的很详细,这里总结部分关键问题:

  • Working Set,也就是需要优化的α部分的选取
  • 迭代停止条件的设置
  • α的更新算法,也就是每一步子问题的求解方法
  • Shrinking,即移除一些已经满足条件的α,加快收敛速度
  • Cache,当Q矩阵过大时,需要对矩阵进行缓存。

上面的每个问题,处理起来都不简单。作为使用者,或许也没有必要深谙里面的所有细节。我觉得最需要认识的两个问题是:1) SVM的目标函数看起来好像是一个标准的优化问题,但实际求解却要复杂得多。为了提高求解的速度,既要做算法上的优化,也需要做工程上的改进。如果只是简简单单按照教科书的方法,甚至直接调用一些优化的工具包来实现的SVM算法,最多也就算个demo。要能够真正写一个高效稳定、能处理大规模数据的SVM工具还是非常不容易的。所以用LIBSVM还是比自己实现算法要简单靠谱不少。2)SVM的求解之所以要优化,就是因为这个问题本身计算和存储比较麻烦。所以虽然做了这么多的优化,整个算法求解的效率仍然较低。所以我们在使用时还要注意各种程序的细节,提高运行的效率。另外,样本量过大时,有时候为了充分利用数据,也不得不忍痛割爱,放弃kernel的使用。

除了标准的C-SVM,LIBSVM也提供了对其他一些SVM方法的支持。其中ν-SVM与C-SVM的算法与应用场景基本是相同的,唯一的区别是原本的参数C变成了参数ν。C-SVM中参数C调整范围在[0,+∞),而ν-SVM中与之对应的参数ν的调整范围变成了 (0,1]。这样的设置使得ν-SVM更具解释性,有时在参数设置上也能提供一定的方便。但ν-SVM与C-SVM并不存在本质上的差别,通过参数的调节,两者可以达到完全相同的效果。所以在使用LIBSVM处理分类问题是,选择上面任何一种方法都是OK的,只需要遵循自己的习惯就好了。

One-Class SVM也是LIBSVM所支持的一种分类方法。顾名思义,使用One Class时,只需要提供一类样本,算法会学习一个尽量小的超球面包裹所有的训练样本。One-Class SVM看起来很有诱惑力,因为我们经常会遇到有一类样本而需要学习分类器的情况。但事实上,一方面很多时候我们得到的正样本在采样过程中存在很大的偏差,导致学习出的One Class分类器不一定考虑到了所有正样本的情形;另一方面,大部分问题还是存在很多构造人工负样本的办法。根据我的经验,采用普通的SVM效果通常还是会好过One-Class SVM,而One-Class SVM在真实场景中的使用也并算不上多。因此在使用这个方法前也需要对问题进行更深入的研究。

最后,LIBSVM也支持基于SVM的回归模型,即SVR。与分类模型类似,SVR也分为C-SVR和ν-SVR。SVR的目标函数与SVM的分类模型稍有区别。由于回归问题预测值与目标值的偏差可大可小,因此SVR使用了两个slack variable用来刻画预测的误差边界。虽然存在这样的差别,但是两者的基本思路和优化算法与还是基本一致的。

在LIBSVM的实现中,上面五种模型,即C-SVM,ν-SVM,One-class SVM,C-SVR,ν-SVR,最终都可以转化为一个更通用的优化框架,然后用同样的策略进行求解,这也是LIBSVM所实现的主要功能。在实际使用中,最常用到的方法还是C-SVM,这是最传统的SVM分类模型。

LIBLINEAR

LIBLINEAR是在LIBSVM流行多年后才开发的,要解决的问题本质上也比LIBSVM更简单,其优势主要在于效率与scalablility。之所以存在这样的优势,是因为线性SVM的求解要比kernel SVM简单许多。

还从上面的对偶问题说起,之前SVM的求解很大程度上受到yTα=0的困扰,因此每次必须选择一组 α进行优化。如果对这一约束项追根述源,可以发现这一项是通过令模型的常数项b导数为0而得到的。而在线性模型中,我们可以通过一个简单地trick,令x=[x,1]和w=[w,b],这样,在模型中的常数项就不存在了。当然,这样的trick只能在线性模型中才适用。没有了上面的约束,优化的目标函数变成了:

argminα subjecttof(α)=12αTQα?eTα0≤αi≤C,i=1,…,l

这个时候,就可以每次只选择一个αi进行优化,每一轮遍历α的所有维度,多轮迭代,直至最后收敛。这样的优化算法叫做coordinate descent(坐标下降法)。利用线性函数的特殊性,直接根据α就可以计算出w的向量表示,于是大大提高了算法的效率。具体的优化算法可以参考文献 A Dual Coordinate Descent Method for Large-scale Linear SVM。

换一个看问题的角度,线性SVM的目标函数可以写成下面的形式:

argminw12wTw+C∑i=1l(max(0,1?yiwTxi))

进一步对问题进行抽象,可以把一类分类问题写成下面的形式:

argminwΩ(w)+C∑i=1l?(yi,wTxi)

其中的?作为误差函数,用来度量预测值与目标值的损失。在上面的线性SVM的情形中,有

?(yi,wTxi)=max(0,1?yiwTxi)

这里的?称为Hinge Loss。

又如在Logistic Regression中,loss function ?被定义为

?(yi,wTxi)=log(1+e?yiwTixi)

Ω一般被称为正则化项(Regularizer),最常使用的就是前面出现的?2-norm,写作wTw,也可以写作∥w∥22,即向量w中所有元素的平方和。除?2-norm之外,?1-norm也是经常使用regularizer,而且会带来一些特别的效果(后面会进行讨论)。大量的监督学习模型都可以写成loss function + regularizer的形式,而参数C则控制了两者在最终损失函数中所占的比重。不同loss function与regularizer的选取以及两者之间的平衡,是机器学习的最重要主题之一。

对于上面的问题,有很多成熟的算法可以进行模型的求解,比如最速梯度法,牛顿法等,对于样本量较大时,也可以采用随机梯度的方法进行训练。 一般来说,由于考虑了二阶导数,牛顿法本身的优化效率要高于只考虑一阶导数的最速梯度法。但由于牛顿法本身在计算量和收敛性上存在很多局限性,所以很少直接使用,而是在牛顿法思想基础上进行一定的改进。其中普遍使用的算法有BFGS和L-BFGS等。具体到liblinear软件包,作者采用的是Trust Region Newton (TRON) method对模型对传统牛顿法进行了改进,该方法被证明比L-BFGS训练更加高效。

LIBLINEAR中实现了基于TRON方法的L-2 SVM和Logistical Regression模型训练。其中的L2-loss SVM是标准SVM的变种,loss function变成了:

?(yi,wTxi)=(max(0,1?yiwTxi))2

从实际效果来说,L2-loss SVM与标准的L1-loss SVM并没有太大的区别。但是在计算上,前者的求导形式更加简单,便于梯度的计算与优化。LIBLINEAR并没有实现Trust Region Newton法的标准L1-loss SVM实现,一方面是因为直接对hinge loss求导需要分段讨论比较复杂,另一方面L2-loss SVM基本可以直接替代L1-loss SVM。不过在其他的一些软件包中,如SVMLIN中,则实现了L1-loss SVM的原问题求解,但使用的优化算法是L-BGFS而不是TRON。

总结

前面介绍了LIBSVM和LIBLINEAR的优化算法,下面简单总结一下不同算法的应用场景吧:

  • 所有线性问题都是用LIBLINEAR,而不要使用LIBSVM。
  • LIBSVM中的不同算法,如C-SVM和nu-SVM在模型和求解上并没有本质的区别,只是做了一个参数的变换,所以选择自己习惯的就好。
  • LIBLINEAR的优化算法主要分为两大类,即求解原问题(primal problem)和对偶问题(dual problem)。求解原问题使用的是TRON的优化算法,对偶问题使用的是Coordinate Descent优化算法。总的来说,两个算法的优化效率都较高,但还是有各自更加擅长的场景。对于样本量不大,但是维度特别高的场景,如文本分类,更适合对偶问题求解,因为由于样本量小,计算出来的Kernel Matrix也不大,后面的优化也比较方便。而如果求解原问题,则求导的过程中要频繁对高维的特征矩阵进行计算,如果特征比较稀疏的话,那么就会多做很多无意义的计算,影响优化的效率。相反,当样本数非常多,而特征维度不高时,如果采用求解对偶问题,则由于Kernel Matrix过大,求解并不方便。反倒是求解原问题更加容易。

多分类问题

LIBSVM和LIBLINEAR都支持多分类(Multi-class classification)问题。所谓多分类问题,就是说每一个样本的类别标签可以超过2个,但是最终预测的结果只能是一个类别。比如经典的手写数字识别问题,输入是一幅图像,最后输出的是0-9这十个数字中的某一个。

LIBSVM与LIBLINEAR但实现方式却完全不同。LIBSVM采取的one vs one的策略,也就是所有的分类两两之间都要训练一个分类器。这样一来,如果存在k个class,理论上就需要训练 k(k?1)/2个分类器。实际上,libsvm在这一步也进行了一定的优化,利用已有分类的关系,减少分类器的个数。尽管如此,LIBSVM在多分类问题上还是要多次训练分类器。但是,考虑到前面说的LIBSVM的优化方法,随着样本数量的增加,训练的复杂度会非线性的增加。而通过1VS1的策略,可以保证每一个子分类问题的样本量不至于太多,其实反倒是方便了整个模型的训练。

而LIBLINEAR则采取了另一种训练策略,即one vs all。每一个class对应一个分类器,副样本就是其他类别的所有样本。由于LIBLINEAR能够和需要处理的训练规模比LIBSVM大得多,因此这种方式要比one vs one更加高效。此外,LIBLINEAR还实现了基于Crammer and Singer方法的SVM多分类算法,在一个统一的目标函数中学习每一个class对应的分类器。

输出文件

一般来说,我们使用LIBLINEAR或者LIBSVM,可以直接调用系统的训练与预测函数,不需要直接去接触训练得到的模型文件。但有时候我们也可能需要在自己的平台实现预测的算法,这时候就不可避免的要对模型文件进行解析。

由于LIBLINEAR与LIBSVM的训练模型不同,因此他们对应的模型文件格式也不同。LIBLINEAR训练结果的格式相对简单,例如:

 1 solver_type L2R_L2LOSS_SVC_DUAL 2 nr_class 3 3 label 0 1 2  4 nr_feature 5 5 bias -1 6 w 7 -0.4021097293855418 0.1002472498884907 -0.1619908595357437 8 0.008699468444669581 0.2310109611908343 -0.2295723940247394 9 -0.6814324057724231 0.4263611607497726 -0.419071450508390610 -0.1505088594898125 0.2709227166451816 -0.192929469590578111 2.14656708009991 -0.007495770268046003 -0.1880325536062815

上面的solver_type表示求解算法,w以下表示求解得到的模型权重。其中每一列对应一个class的分类器,而每一行对应特征的一个维度。其中nr_class表示求解的个数,nr_feature表示特征的维度,bias表示模型的bias,可以人工设置权重。这里容易产生误解的是label这个字段,表示的是每一个用户训练文件中label对应w的列数。比如在上面的模型中,用户指定编号为0的分类器对应w的第一列。但是上面的对应关系并不是一定存在的,比如在二分类场景中,用将整样本标为1,负样本标为0,但在模型训练中,LIBLINEAR会按照自己的编号系统进行训练,因而有可能出现负样本在前,正样本在后的情形。这时候,就必须要根据label 1 0将LIBLIENAR内部的编号体系与真实的用户标签进行对应。当然,后来LIBLINEAR和LIBSVM做了一些优化,在二分类时,如果正负样本标签分别是-1+1,那么可以始终保证正样本出现在w的第一列。但是这个机制也不是完全靠谱,比如说在LIBLINEAR的spark实现代码中,就没有实现这个特性,曾经把我整的很惨。因此在这里还是需要十分注意。

LIBSVM的训练结果格式就更复杂一些,例如:

 1 kernel_type rbf 2 gamma 0.0769231 3 nr_class 3 4 total_sv 140 5 rho -1.04496 0.315784 1.03037 6 label 1 0 -1 7 nr_sv 2 2 1 8 SV 9 0 1 1:0.583333 2:-1 3:0.333333 4:-0.603774 5:1 6:-1 7:1 8:0.358779 9:-1 10:-0.483871 12:-1 13:110 0 0.6416468628860974 1:0.125 2:1 3:0.333333 4:-0.320755 5:-0.406393 6:1 7:1 8:0.0839695 9:1 10:-0.806452 12:-0.333333 13:0.511 0 1 1:0.333333 2:1 3:-1 4:-0.245283 5:-0.506849 6:-1 7:-1 8:0.129771 9:-1 10:-0.16129 12:0.333333 13:-112 0.2685466895842373 0 1:0.583333 2:1 3:1 4:-0.509434 5:-0.52968 6:-1 7:1 8:-0.114504 9:1 10:-0.16129 12:0.333333 13:113 0 1 1:0.208333 2:1 3:0.333333 4:-0.660377 5:-0.525114 6:-1 7:1 8:0.435115 9:-1 10:-0.193548 12:-0.333333 13:1

上面参数的意义都比较直接,需要注意的是SV后面就是训练出的模型参数,以支持向量的方式进行存储。nr_sv给出了每一个支持向量所对应的模型,比如“2 2 1”就表示前两行是标签为1类的支持向量,其后面两行是标签为0类的支持向量,最后一行是标签为-1类的支持向量。而具体每一行支持向量,在上面的模型中,由于存在三类,所以每一个支持向量有可能都会存在于两个分类器中,所以前两列的数分别对应了对剩下两个分类作为支持向量时候的α值,后面才是真正的支持向量。


0 0
原创粉丝点击