优化器LBFGS OWLQN实现

时间:2016-08-01 15:14:36

标签: apache-spark apache-spark-mllib apache-spark-ml

我正在寻找有关在Spark 1.6 ML库中实现并行LBFGS和OWLQN算法的文档。

我找到了1.6:http://spark.apache.org/docs/1.6.1/ml-advanced.html的这个页面,但没有关于并行化的内容

对于2.0:http://spark.apache.org/docs/2.0.0/ml-advanced.html但仍然没有关于并行化

最后,我阅读了代码[link1]。方法

def train(dataset: DataFrame): LogisticRegressionModel

似乎使用Breeze优化模型,但我找不到调用spark函数的位置(map,flatMap,reduce,...)。

在代码[link2]中,map用于计算减少到计算梯度的子梯度。

由于

1 个答案:

答案 0 :(得分:2)

简而言之,Spark使用Breeze LBFGS和OWLQN优化算法,并为每个算法提供一种计算每次迭代时成本函数梯度的方法。

例如,Spark的LogisticRegression类使用了LogisticCostFun类来扩展Breeze的DiffFunction特性。此cost函数类实现具有签名的calculate抽象方法:

override def calculate(coefficients: BDV[Double]): (Double, BDV[Double])

计算方法使用LogisticAggregator类,这是完成实际工作的地方。聚合类定义了两个重要的方法:

def add(instance: Instance): this.type // the gradient update equation is hard-coded here
def merge(other: LogisticAggregator): this.type // just adds other's gradient to the current gradient

add方法定义了一种在添加单个数据点后更新渐变的方法,并且merge方法定义了一种组合两个单独聚合器的方法。此类发送到执行程序,用于聚合每个数据分区,然后用于将所有分区聚合器组合到单个聚合器中。最终聚合器实例保存当前迭代的累积梯度,并用于更新驱动程序节点上的系数。此过程由treeAggregate类中对LogisticCostFun的调用控制:

val logisticAggregator = {
  val seqOp = (c: LogisticAggregator, instance: Instance) => c.add(instance)
  val combOp = (c1: LogisticAggregator, c2: LogisticAggregator) => c1.merge(c2)

  instances.treeAggregate(
    new LogisticAggregator(coeffs, numClasses, fitIntercept, featuresStd, featuresMean)
  )(seqOp, combOp)
}

你可以更简单地想一想:Breeze实现了几种不同的优化方法(例如LBFGS,OWLQN),只需要告诉优化方法如何计算梯度。 Spark告诉Breeze算法如何通过LogisticCostFun类计算渐变。 LogisticCostFun只是说将LogisticAggregator实例发送到每个分区,收集渐变更新,然后将它们发送回驱动程序。