【问题标题】:Scikit-learn: Parallelize stochastic gradient descentScikit-learn:并行化随机梯度下降
【发布时间】:2014-01-29 21:11:03
【问题描述】:

我有一个相当大的训练矩阵(超过 10 亿行,每行两个特征)。有两个类(0 和 1)。 这对于单台机器来说太大了,但幸运的是我有大约 200 个 MPI 主机可供我使用。每个都是一个普通的双核工作站。

特征生成已经成功分发。

Multiprocessing scikit-learn 中的答案表明可以分发 SGDClassifier 的工作:

您可以跨核分布数据集,进行部分拟合,获取权重向量,对其进行平均,将它们分配给估计器,再次进行部分拟合。

当我对每个估算器第二次运行 partial_fit 时,我应该从哪里获得最终的聚合估算器?

我最好的猜测是再次平均系数和截距,并使用这些值进行估计。结果估计器给出的结果与使用 fit() 对整个数据构造的估计器不同。

详情

每个主机生成一个局部矩阵和一个局部向量。这是测试集的n行和对应的n个目标值。

每个主机都使用局部矩阵和局部向量来制作 SGDClassifier 并进行部分拟合。然后每个都将 coef 向量和截距发送到根。 Root 对这些进行平均并将它们发送回主机。主机执行另一个 partial_fit 并将 coef 向量和截距发送到 root。

Root 使用这些值构造一个新的估算器。

local_matrix = get_local_matrix()
local_vector = get_local_vector()

estimator = linear_model.SGDClassifier()
estimator.partial_fit(local_matrix, local_vector, [0,1])

comm.send((estimator.coef_,estimator.intersept_),dest=0,tag=rank)

average_coefs = None
avg_intercept = None

comm.bcast(0,root=0)
if rank > 0:
    comm.send( (estimator.coef_, estimator.intercept_ ), dest=0, tag=rank)
else:
    pairs = [comm.recv(source=r, tag=r) for r in range(1,size)]
    pairs.append( (estimator.coef_, estimator.intercept_) )
    average_coefs = np.average([ a[0] for a in pairs ],axis=0)
    avg_intercept = np.average( [ a[1][0] for a in pairs ] )

estimator.coef_ = comm.bcast(average_coefs,root=0)
estimator.intercept_ = np.array( [comm.bcast(avg_intercept,root=0)] )
estimator.partial_fit(metric_matrix, edges_exist,[0,1])

if rank > 0:
    comm.send( (estimator.coef_, estimator.intercept_ ), dest=0, tag=rank)
else:
    pairs = [comm.recv(source=r, tag=r) for r in range(1,size)]
    pairs.append( (estimator.coef_, estimator.intercept_) )
    average_coefs = np.average([ a[0] for a in pairs ],axis=0)
    avg_intercept = np.average( [ a[1][0] for a in pairs ] )

    estimator.coef_ = average_coefs
    estimator.intercept_ = np.array( [avg_intercept] )
    print("The estimator at rank 0 should now be working")

谢谢!

【问题讨论】:

    标签: python parallel-processing machine-learning mpi scikit-learn


    【解决方案1】:

    在具有 1e9 个样本和 2 个特征的数据集上训练线性模型很可能会欠拟合或浪费 CPU/IO 时间,以防数据实际上是线性可分的。不要浪费时间考虑用线性模型并行处理这样的问题:

    • 要么切换到更复杂的模型类别(例如,在适合内存的较小数据分区上训练随机森林并聚合它们)

    • 或者从你的数据集中选择随机子样本来增加和训练线性模型。测量持续测试的预测准确性,并在您看到收益递减时停止(可能在少数类的数千个样本之后)。

    【讨论】:

    • 普遍的共识似乎是对我的数据进行下采样。我想我只是把它复杂化了。谢谢。
    【解决方案2】:

    您遇到的情况是正常的和预期的。首先是使用 SGD 意味着您永远不会得到精确的结果。您将快速收敛到最佳解决方案(因为这是一个凸问题),然后在该区域附近徘徊以等待其余部分。单独使用整个数据集的不同运行每次都会产生略微不同的结果。

    我该从哪里获得最终的聚合估算器?

    理论上,您只需一遍又一遍地这样做,直到您对收敛感到满意为止。对于您正在做的事情完全没有必要。其他系统转而使用更复杂的方法(如 L-BFGS)来收敛到最终解决方案,因为它们在解决方案上有一个良好的“热启动”。但是,这不会让您在准确性方面获得任何显着提高(如果幸运的话,可能会获得一个完整的百分点) - 所以不要认为这是成败。考虑它是什么,微调。

    第二个事实是线性模型不能很好地并行化。尽管 vowpalwabbit 和其他一些库声称,您不会从并行训练线性模型中获得线性扩展。简单地平均中间结果是并行化这样一个系统的不好方法,遗憾的是,这与并行训练线性模型一样好。

    事实是,您只有 2 个功能。您应该能够仅使用较小的数据子集轻松训练更复杂的模型。 10 亿行对于 2 个功能来说是多余的。

    【讨论】:

    • 非常感谢您的详细解答。我显然是在不必要地过度工作。我将使用更小的子集。
    猜你喜欢
    • 2015-07-15
    • 2020-08-06
    • 2013-02-08
    • 2016-06-13
    • 2019-06-27
    • 1970-01-01
    • 2016-09-25
    • 2018-12-10
    • 2021-02-20
    相关资源
    最近更新 更多