LIBSVM与LIBLINEAR(三)

2014-11-26

调节参数

LIBSVM和LIBLINEAR工具包都包含很多需要调节的参数,参数的调节既需要足够的耐心,也有着很多的技巧。当然,还需要对参数本身的意义和对模型的影响了如指掌。下面主要讨论一些对模型影响较大的参数

参数C

参数C是在LIBLINEAR和LIBSVM的求解中都要用到的一个参数。前面说到的各种模型,可以写成统一的形式:

 

argminwΩ(ϕ(w))+Ci=1l(yi,ϕ(w)Tϕ(xi))

 

其中右边的一项是模型的损失项,其大小表明了分类器对样本的拟合程度。而左边的一项,则是人为加上的损失,与训练样本无关,被称作正则化项(Regularizer),反映了对训练模型额外增加的一些约束。而参数C则负责调整两者之间的权重。C越大,则要求模型能够更好地拟合训练样本数据,反之,则要求模型更多的满足正则化

项的约束。以LIBLINEAR为例,下面先讨论LIBLINEAR下2norm的情况:

 

argminww22+Ci=1l(yi,wTxi)

 

之所以要增加正则化项,是因为在设计模型的时候,我们对于样本的质量以及模型的泛化能力没有充分的自信,认为在没有其他约束的情况下,训练得到的模型会因为过于迁就已有的样本数据而无法对新的数据达到同样的效果。在这个时候,就必须在模型中增加人类的一些经验知识。比如上面对ϕ(w)增加2norm的约束就是如此。如果上面公式中的损失函数对应一个回归问题,那么这个问题就被称作Ridge Regression,中文叫做脊回归或者岭回归。

我们可以站在不同的角度来理解2norm正则化项的意义。如果把学习分类函数中w看作是一个参数估计的问题,那么不带正则化项的目标函数对应的就是对w进行最大似然估计的问题。为了使w的估计更加接近真实的情况,我们可以根据经验对w制定一个先验分布。当我们假设w先验分布是一个多元高斯分布,且不同维度之间是没有关联的(即协方差矩阵非对角线元素为0),而每一个维度特征的方差为某一固定制,那么推导出来的最大后验概率就是上面的带正则化项的目标函数。而Cw先验分布的方差相关。C越大,就意味着正则化的效果偏弱,w的波动范围可以更大,先验的方差也更大;而C越小,则意味着正则化的效果更强,w的波动范围变小,先验的方差也变小。通过减小C的值,可以控制w的波动不至于过大,以免受一些数据的影响,造成模型的过拟合(overfitting)。 

另外也有一种更直观的解释,上面regularized形式的目标函数也可以根据KKT条件转为constraint形式,也就是:

 

argminws.t.i=1l(yi,wTxi)w22<s2

 

通过参数s限制w的大小,而sC也存在着一定正向相关的关系。因此,当C较小时,w的取值也被限制在的一个很小的范围内。下面的图给了一个非常直观的解释:

L2Norm

由于有了对w取值的限制,就出现了两种情况。第一种是当s不够大的时候,此时如果沿梯度下降的方向一直搜索,找到全局最优解,就已经找出圈外,不满足下面的约束项。这个时候,只能在满足约束的条件下找到尽量好的解。根据KKT条件,此时的最优解一定是划定范围的圆圈与目标函数等梯度线相切的位置,如上图左边所示。如果把梯度图看成一座山的等高线,那边最优解的位置一定是等高线中凸起的部分,类似于一座山上的山脊或者山岭,这也是脊(岭)回归的由来。另一种情况是当s足够大的时候,这个时候,在由s所划定的范围内已经能够达到全局最优解,这个时候,下面的约束项其实并没有起到作用,就如上图右边所示。

因此在调参过程中,如果数据量较少,或者我们对数据的质量信心不足,就应该减少C的大小,增加先验的重要性,反之则可以增加C的大小,让数据本身起更大的作用。而在优化过程中,C越大,需要搜索的w的范围也越大,计算的代价也会越高。而从前面的分析中可以看出,当C增加到一定程度后,模型已经能确保达到全局最优,此时继续增加C对提高算法的表现已经没有帮助。因此,在LIBLINEAR中,实际推荐的做法是将C的值从小向大来调,当C增加之后已经无法改变算法的效果时,说明C对模型已经没有影响,就没有必要继续调下去了。选择较小的C反而可以提高模型收敛的速度。

1norm的使用

在LIBLINEAR中,除了提供上面提到的2norm正则化项之外,还提供了1norm的选项。1norm一般写成w1,其实就是对向量w中的所有元素的绝对值进行求和。与2norm相比,1norm也具有对w本身大小的约束,使得w的某些维度值不至于过大而导致过拟合。这个特性在统计学上也称作收缩”shrinkage”。而此外,1norm还有另外一个非常有用的特征,即能够使学习到的w比较稀疏(sparse),也就是存在很多的0项,而且可以通过系数C控制0项的的个数。当C减小时,w的非0项就增多,当C无限小时,由于完全没有拟合损失的压力,w也可以变成全部是0了。

为什么1norm还有这样的功能呢?说来话长,下次可以专门再写博客讨论了。简单来说,是由1norm的特殊性质决定的。1norm所对应的绝对值函数是连续的,但并非处处可导,因为在0点存在特殊的情况,即左右导数实不相等的。因此可以认为定义sub_gradient来描述这种特殊情况的导数,这样的结果是在这个特殊点上,导数不是一个值,而是左右倒数中间的一个范围。由于在0点导数取值非常灵活,使得在模型求解的过程中,很容易在这样的点达到极值,也就会使得学习到的w尽量的稀疏。

基于1的线性回归模型也被叫做LASSO。采用这个惩罚项的基本动机是认为只有少数特征是与分类结果真正相关,而绝大多数特征是无关的。这一假设确实存在一定的道理,但是在实际分类准确度上,1norm正则化项对2norm项并没有绝对的优势,这是因为2norm虽然不能直接去除那些与分类结果无关的特征,但是模型学习的结果也会让这些特征的权重很低,所以他们能起到的影响不大。但是1norm的一个好处是可以作为一个特征选择的工具,从高维特征空间中只选取少数一些与分类结果最为相关的特征进行计算。这在处理大量高维数据或者实时计算问题是,还是非常有帮助的,可以大大减少存储,提高计算的效率。

Kernel相关参数

如果使用LIBSVM的话,参数调节的工作就会更复杂一些。首先是kernel的使用。一般来说rbf kernel是被鼓励优先使用的。如果使用rbf kernel效果都无法调到满意,那么采用poly或linear也无济于事。在一些特殊场景下,可以考虑自定义kernel,这在LIBSVM中也是支持的。

rbf的全称是Radial Basis Function,中文叫做径向基函数。而一般在SVM使用的rbf是Gaussian RBF,也就是我们一般所说的高斯核函数。给定两个点x1x2,Gaussian RBF定义为:

 

K(x1,x2)=exp(γx1x22)

 

可见,高斯核函数是对两点之间的欧氏距离进行了一定的变换,且变换受到参数γ的控制。应该怎样理解高斯核函数的意义与γ的作用的?

 

K(x1,x2)=exp(γx1x22)=exp(γ(x12+2xT1x2x22))=exp(γx12)exp(γx22)exp(2γxT1x2)=exp(γx12)exp(γx22)n=0(2γxT1x2)nn!

 

γ较小,或者说在极端情况趋向于0的时候,可以有n=0(2γxT1x2)nn!2γxT1x2,也就是n>1以后的项远小于n=1项。这个时候,rbf kernel的效果其实和linear kernel相差无几。

相反,当γ增大时,n>1以后的项也产生作用,其基本思想和poly kernel差不多,只是rbf直接把维度从有限维度的多项式上升到了无穷维的多项式而已。当γ无限增大时,可以看到,除非x1x220,否则K(x_1, x_2) 都会无限趋近于0。也就是说,当γ趋近于无穷大的时候,每一个数据点除了和其自身外,和其他点得距离都为0。在这种情况下,模型训练的结果只能是把所有点都作为支持向量,因此在训练数据上精度可以达到100%。这样的模型也可以看成KNN的特殊情况,此时的K等于1

上面分别讨论了问题的两个极端情况。当γ无限小的时候,rbf核SVM和线性SVM效果类似,因此模型的复杂度,或者说VC维较低,不容易过拟合。而当γ值无限增大时,所有点都变成支持向量,模型复杂多或者说VC维最高,也最容易过拟合。而一般情况下,γ取一个中间值,也就间距两者的意义,相比于线性模型,可以选择更多的支持向量,增加模型的复杂度与拟合能力。而相比于1-NN模型,也会适当降低模型的复杂度,避免过拟合的风险。此外,从上面的讨论也可以看出,通过参数调整,rbf核基本上可以达到与线性核以及poly核差不多的效果。所以,在不考虑计算效率的情况下,为了达到最优模型,只需要针对rbf模型进行调参就可以了。

上面在参数调整的讨论里,都假设参数C是固定的。但在实际SVM的调参过程中,Cγ是同时变化的,这进一步增加了调参的复杂性。关于两个变量之间的关系,也有很多理论上的分析与讨论,这里不过多进行讨论,可以参考文件:Asymptotic Behaviors of Support Vector Machines with Gaussian Kernel。

在实际的应用场景下,我们可以通过cross-validate的方法对参数进行遍历,选择最佳的参数组合。LIBSVM也提供了grid.py工具,用于SVM的调参。在一般的应用中,我们只需要设置参数的可变范围,然后在训练数据中对参数组合进行遍历,选择最优参数组合就可以了。

总结

最后简单做下总结参数与kernel的选择吧:

  • 线性模型选择,选择LIBLINEAR,主要调节参数C,从小到大调节,如果再增加C对结果改变不大时,就可以不用进行测试下去了,选择较小的C就可以了。
  • kernel选择,如果需要使用kernel,对于一般问题,优先使用rbf kernel。LIBSVM提供的多项式和tanh核函数,都存在一些局限性,一般来说,rbf是使用方便性和模型效果都比较稳定的核函数了。
  • LIBSVM参数调节。如果使用rbf核,需要同时调节参数C和参数γ,问题要更复杂一些,最好的办法是自动遍历参数进行参数选择,比如利用grid.py。
 

LIBSVM与LIBLINEAR(四)

2015-01-17

特征的预处理

一般而言,利用LIBSVM和LIBLINEAR训练分类器之前,会对数据的特征进行预处理。预处理有两类,一类是针对特征内在逻辑的处理,比如增加一些dummy变量,或者对特征的范围进行一些认为的调整。这样的特征构造和处理对于分类器的效果也有着非常重要的影响,尤其是线性分类器,由于本身判别能力偏弱,所以更依赖于人工的特征构造。当然,这一类的特征与处理往往与数据本身的理解有很大的关系,不同的业务与应用场景处理的方法网玩那个也不同,这里就不做过多讨论了。

另一类特征的预处理则更加通用,即统一特征的尺度。由于特征的采集方式不同,造成数据原始特征在不同维度往往会有较大的差别。比如对一个人的身体指标进行描述,身高如果单位是米的话,每个人的值都在1到2之间。而体重以千克为单位,每个人至少应该是两位数,或者三位数。如果直接使用这样的原始特征进行分类,一方面某些特征的权重会被人为加大,影响模型的准确性。另外一方面,由于某些维度的scale过大,也会造成优化中的一些效率问题,增加迭代收敛的次数。因此,在进行分类前,一般需要对特征进行归一化,将特征调成到统一尺度。

最常见的归一化方法就是针对特征的每一个维度进行归一化,使得不同的度量在尺度上达到统一。一般来说,scale后特征的值都落在区间[-1,+1]或[0,1]之间。在实际使用时,更加倾向于后者,因为特征稀疏后往往能够提高优化的效率。LIBSVM提供了svm-scale程序进行特征的自动归一化,以归一化到[0,1]为例,主要是根据公式:

 

x=(xxmin)/(xmaxxmin)

 

此外,还有一些地方需要特别注意:第一,训练数据和测试数据必须采用统一的归一化函数,保证数据的一致性,即xmaxxmin必须是一致的。第二,并不是所有场景都是用于按特征的归一化。比如文本分类的场景中,通常会对每一个instance进行归一化,或者采用一些更加复杂的归一化算法。

其他问题

除了以上列出的一些关键问题,还有很多琐碎的小点也值得注意,如分类结果的评估方法、不同语言的调用接口、结果的可视化等等,限于篇幅,这里就不详细介绍了。感兴趣的读者可以参考相关资料。

其他的工具

除LIBSVM和LIBLINEAR之外,还有一些工具包也能完成类似的功能,下面做一个简单地介绍。

  • SVMLight。与LIBSVM起名的工具包,但是我个人用的不多。数据的格式与LIBSVM相当,但是据说使用更少的资源。此外,SVMLight的扩展还支持排序学习与结构化SVM的训练,因此也有着大量的使用者。
  • SVMLin。专为线性SVM训练开发的工具包,之前有过介绍,另外还支持半监督SVM的训练。
  • LIBLINEAR SPARK版本。最近LIBLINEAR提供了Spark版本,保留了Liblinear的一些基本功能,能够处理更大规模的数据。

分了四个部分介绍了LIBSVM和LIBLINEAR,写到最后感觉有一些烂尾了,因为感觉越写越琐碎,以至于没有太多趣味了。后面的博客,还是希望能够集中在某一个问题,讨论的更加深入和透彻,这样写作起来也更容易坚持下去。