system: [SYSTEM]

user: 2. 分布式支持向量机 2.1. 支持向量机 支持向量机(Support Vector Machine， SVM)是Cortes和Vapnik在1995年正式发表的一种基于统计学习的机器学习算法，凭借其在文本分类任务中的出色性能成为了机器学习的主流技术。如今经过多年研究发展，支持向量机思想已经涉及分类、回归等多个领域，实现了线性、非线性以及分布式等多种支持向量机算法应用。 在给定的训练样本集后，简单二分类学习的最基本思想就是基于给定的训练样本空间中找到一个超平面，可以将不同类别的样本划分开来。其中距离超平面最近的几个训练样本点即为“支持向量”(support vector)，两个异类支持向量到超平面的距离之和即为“间隔”，具有最大间隔的超平面划分就是鲁棒性最高，泛化能力最强的最优划分。由此可推导出支持向量机的基本型及其本质就是如何高效求解一个凸二次规划问题，如公式(1)所示，其中公式中出现的 ω 为超平面的法向量，b为超平面的位移项， ( x i ， y i ) 为样本点。 min ω ， b 1 2 ‖ ω ‖ 2 s .t .     y i ( ω T x i + b ) ≥ 1 ，   i = 1 ， 2 ， ⋯ ， m (1) 对于求解一个凸二次规划问题有两种常用的方法，可以直接利用成熟的优化计算包求解，也可以引入拉格朗日乘子法，添加拉格朗日乘子 α i ≥ 0 ，得到比原问题更容易求解的对偶问题，如公式(2)所示： max α ∑ i = 1 m α i − 1 2 ∑ i = 1 m ∑ j = 1 m α i α j y i y j x i T x j s .t .     ∑ i = 1 m α i y i = 0 ，   α i ≥ 0 ，   i = 1 ， 2 ， ⋯ ， m (2) 最后通过SMO等方法高效地求解二次规划问题，得到判别模型，如公式(3)所示： f ( x ) = ω T x + b = ∑ i = 1 m α i y i x i T x + b (3) 在求解过程中我们不难发现所谓支持向量机，即是最终模型仅与支持向量有关，此种分类器的关键是如何找到合适的支持向量构建解模型，其复杂度也主要和支持向量的数目有关，这样可以帮助我们抓住关键样本，提出冗余属性，一定程度上避免了维数暴增难题，具有更好的鲁棒性。 在现实任务中，原始样本并非都是理想的线性可分形式，若在原始样本空间中，不存在一个能正确划分两类样本的超平面时，则需要引入核函数，借助核技巧，将样本从原始空间映射到一个更高维的特征空间，使得样本在这个新的特征空间内线性可分。同时在现实任务中，完全的线性可分太过理想，我们需要允许支持向量机在一些样本上有一定的容错率，可以出错，由此引入了“软间隔”的思想，加入了损失函数，即为常用的“软间隔支持向量机”。 支持向量机的最基本思想就是寻找到一个合适的超平面分割不同类别的数据，显然这是一个典型的解决二分类问题的思路。但在现实任务应用问题中，仅仅解决二分类问题是不够的，所以需要构建出适合的多类分类器。目前常用的解决方案主要从修改优化求解问题或者通过多个二分类器合并的思路实现了以下几种： (1) 修改目标函数，把多个分类超平面的求解问题融合到一个最优化求解问题中。 (2) 针对K类问题，训练K个二分类器，每个分类器将把某一类归为一类，其它不属于该类的样本划为另一类，最终分类结果考虑K个分类器的分类函数值，选择其中最大的那一类为分类结果。 (3) 针对K类问题，选取任意两个类别的样本，从中设计一个二分类器，由此可得到 k ( k − 1 ) / 2 个二分类器。每当分类未知样本时，考虑所有分类器的结果，选择其中出现最多的一个类别作为最终的分类结果。由台湾大学林智仁教授等开发设计的经典支持向量机算法包LibSVM [ 7 ] 中的多分类解决方案就是依据这种方式实现的。 (4) 针对K类问题，参考决策数的多分类思想，先把所有类别划分成两个子类，由此训练得到一个二分类器作为一个分枝节点，而后分别把两个子类的每一类内部再进一步划分为两个子类，再训练，如此迭代循环，直到最后得到原始K类问题中的一个独立类别为止，该类即为最终分类结果。 2.2. Spark-MLlib SVM的分布式实现分析 MLlib是Spark为了用户更加便捷地使用机器学习算法解决问题，而提供的机器学习拓展库(machine learning library)。用户可以利用拓展库中封装的部分经典算法，同时可以依据自己的需求做出相关更改，具有较强的兼容性和可拓展性，大大简化了机器学习在分布式环境下的移植工作。 对于Spark2.2.0系统中Spark-MLlib中封装的支持向量机算法，主要实现了随机梯度下降的线性二分类的支持向量机 [ 8 ]，遵从线性二分类的最基本思路，寻找最优化划分超平面，即寻找最优的支持向量。目标函数为： y = ω T x + b ， ω 为超平面法向量，b为超平面的位移项。考虑实际问题难以做到线性可分，需要一定的容错率，因此采用软间隔方式，引入损失函数，采用的是hinge损失函数： l hinge ( z ) = max ( 0 ， 1 − z ) 。在引入损失函数后可以添加正则化项，利用正则化方法防止模型过拟合，提高泛化能力。显然可以引入松弛变量 ξ i ，依此把待优化的二次规划问题重写为公式(4)： min ω ， b ， ξ 1 2 ‖ ω ‖ 2 + C ∑ i = 1 m ξ i s .t .     y i ( ω T x i + b ) ≥ 1 − ξ i ，   ξ i ≥ 0 ，   i = 1 ， 2 ， ⋯ ， m (4) 同样可以引入拉格朗日乘子，将上面的公式转化为对偶问题再求解。在求解过程中，我们需要求解合适的参数 ω ，使得损失函数取值最小化，即要求在最大化间隔的同时，不满足约束的错误样本应该尽可能的少，这也被称为最优化的过程。最优化问题中最常采用的方法就是随机梯度下降优化方式。Spark-MLlib也采用这种方式实现了随机梯度下降的线性支持向量机，即继承了Generalized Linear Algorithm的SVMWithSGD类，该类中定义了训练支持向量机分类模型的train()方法，是创建线性支持向量机模型的入口。Train()方法将会创建SVMWithSGD对象，并使用run()方法调用optimitor：Gradient Descent (gradient， updater)优化得到模型的权值参数weights，并调用create Model (weights)方法创建一个SVMModel，最后把SVMModel作为返回结果输出。 其中GradientDescent即为随机梯度下降算法封装的求解器，通过其下的成员方法runMiniBatchSGD实现模型参数的迭代运算，在运算过程中也通过集群下模型参数的共享同步和先求解分区上的梯度值再聚合求总梯度值的两方面计算方式体现分布式运算的思想。SVMWithSGD的类图关系如图1所示。 图1. SVMWithSGD类图 仅从Spark-MLlib的开源代码中看，程序执行的都是基于弹性分布式数据集(Resilient Distributed Datasets， RDD)的操作。这是因为Spark-MLlib使用RDD抽象了所需要的分布式计算，将其转化为RDD上的转换(Transform)和动作(Action)等操作。RDD DAG是用来描述RDD之间的依赖关系，Spark依照此依赖关系利用DAG划分成不同的Stage，Stage间依据依赖关系先后执行。但每个Stage都会将对应的Task任务提交给Executor，如此在一个Stage进行运算时Executor便可以并行计算Task任务。以Spark中wordCount为例，其在集群上分布式计算的流程示意图如图2和图3所示。 图2. wordCount分布式计算流程 图3. Spark分布式计算 使用Spark-MLlib中的分布式线性支持向量机和台湾大学林智仁教授开发的LibSVM工具包实现的单机支持向量机算法做简单的对比实验可以发现，分布式支持向量机在数据量较少时并不能体现出相比于单机的明显优势，但当数据集规模巨大超过十万数量级时，分布式支持向量机算法将在时间开销上大大优于单机支持向量机算法。正如文献 [ 9 ] 中记录的实验，实验数据采用来自UCI/Covtype的数据集covtype，数据行数达到581，012条，特征数共54个 1 。分别使用LibSVM实现的单机线性支持向量机分类算法和Spark-MLlib实现的分布式线性支持向量机分类算法对该数据集进行训练分类测试，最终实验结构表明：在面对数据行数达到万条记录，特征数达到百位计数的同一份数据集，训练迭代次数都选用20次。此时分布式支持向量机算法和单机下LibSVM分类的准确率相差不大，但相比在时间效率上，分布式支持向量机算法有着明显的优势，如表1所示。 Table 1 Experimental comparison result covtype 准确率 执行时间(s) Spark-MLlib 61.18% 96 LibSVM 77.12% 54320 表1. 实验对比结果