Python Spark ML梯度增强树不使用所有节点

Python Spark ML梯度增强树不使用所有节点,python,apache-spark,pyspark,apache-spark-ml,Python,Apache Spark,Pyspark,Apache Spark Ml,我正在使用inpyspark在AWS EMR集群上训练一个数据帧上的二进制分类模型,该数据帧具有约400k行和约9k列。我将其与当前的解决方案进行比较,目前的解决方案是在一个巨大的EC2上运行XGBoost,该EC2可以容纳内存中的整个数据帧 我希望我能在Spark中更快地训练(并获得新的观察结果),因为它是分布式/并行的。然而,当观察我的集群(通过ganglia)时,我看到只有3-4个节点有活动的CPU,而其余的节点只是坐在那里。实际上,从外观上看,它可能只使用一个节点进行实际训练 我在文档中

我正在使用in
pyspark
在AWS EMR集群上训练一个数据帧上的二进制分类模型,该数据帧具有约400k行和约9k列。我将其与当前的解决方案进行比较,目前的解决方案是在一个巨大的EC2上运行XGBoost,该EC2可以容纳内存中的整个数据帧

我希望我能在Spark中更快地训练(并获得新的观察结果),因为它是分布式/并行的。然而,当观察我的集群(通过ganglia)时,我看到只有3-4个节点有活动的CPU,而其余的节点只是坐在那里。实际上,从外观上看,它可能只使用一个节点进行实际训练

我在文档中似乎找不到任何关于节点限制或分区的信息,也找不到任何与发生这种情况的原因相关的信息。也许我只是误解了算法的实现,但我认为它的实现方式可以使训练并行化,以利用Spark的EMR/集群特性。如果不是,那么这种方式与在单个EC2上的内存中进行比较有什么优势吗?我想您不必将数据加载到内存中,但这并不是什么优势

这是我的一些代码样本。谢谢你的建议

import pyspark
from pyspark.sql import SparkSession
from pyspark.sql.functions import udf
from pyspark.sql.types import DoubleType
from pyspark.ml.classification import GBTClassifier
from pyspark.ml.evaluation import BinaryClassificationEvaluator

# Start Spark context:
sc = pyspark.SparkContext()
sqlContext = SparkSession.builder.enableHiveSupport().getOrCreate()

# load data
df = sqlContext.sql('SELECT label, features FROM full_table WHERE train = 1')
df.cache()
print("training data loaded: {} rows".format(df.count()))

test_df = sqlContext.sql('SELECT label, features FROM full_table WHERE train = 0')
test_df.cache()
print("test data loaded: {} rows".format(test_df.count()))


#Create evaluator
evaluator = BinaryClassificationEvaluator()
evaluator.setRawPredictionCol('prob')
evaluator.setLabelCol('label')

# train model
gbt = GBTClassifier(maxIter=100, 
                    maxDepth=3, 
                    stepSize=0.1,
                    labelCol="label", 
                    seed=42)

model = gbt.fit(df)


# get predictions
gbt_preds = model.transform(test_df)
gbt_preds.show(10)


# evaluate predictions
getprob=udf(lambda v:float(v[1]),DoubleType())
preds = gbt_preds.withColumn('prob', getprob('probability'))\
        .drop('features', 'rawPrediction', 'probability', 'prediction')
preds.show(10)

auc = evaluator.evaluate(preds)
auc

旁注:我使用的表已经矢量化了。该模型使用此代码运行,运行速度很慢(训练时间约为10-15分钟),并且只使用3-4个(或者可能只使用其中一个)内核。

感谢上面的澄清评论

Spark的实现没有必要比XGBoost更快。事实上,我期待你看到的

最大的因素是XGBoost的设计和编写特别考虑了渐变增强树。另一方面,Spark更具通用性,而且很可能没有XGBoost所具有的那种优化。有关XGBoost和scikit learn实现分类器算法之间的差异,请参阅。如果您想真正深入了解细节,可以阅读本文,甚至可以阅读XGBoost和Spark实现背后的代码

记住,XGBoost也是并行/分布式的。它只是在同一台机器上使用多个线程。Spark帮助您在数据不适合单个计算机时运行算法

我能想到的其他几点是A)Spark确实有一个不平凡的启动时间。不同机器之间的通信也会增加。(b)XGBOOST是C++编写的,一般用于数值计算。 至于Spark为什么只使用3-4个内核,这取决于您的数据集大小、数据集在节点上的分布方式、Spark启动的执行器数量、哪个阶段占用的时间最多、内存配置等。您可以使用Spark UI尝试了解发生了什么。如果不查看数据集,很难说为什么会发生这种情况

希望有帮助


编辑:我刚刚找到了一个很好的答案,比较了一个简单的Spark应用程序和一个独立的java应用程序的执行时间。同样的原则也适用于此,事实上,由于XGBoost经过了高度优化,所以更适用于此。

所以您使用的是EMR,对吗?您是否使用
spark submit
提交作业?如果是这样的话,你能发布你用来提交作业的整个命令吗?是的,我只是使用
spark submit spark\u gbt.py
(其中
spark\u gbt.py
是上面脚本的名称)从命令行ssh'd发布到主节点。您是否想知道群集上的任何特定设置?我不是自己设置的,但如果你认为这是相关的,我当然可以找到它们。我会说,我在同一集群上运行的其他pyspark作业使用所有节点。我试图弄清楚您是使用本地模式还是实际使用分布式模式。据我所知,如果您没有指定
--master warn
,那么它将在EMR上以本地模式运行。我还注意到另一件事——您没有在代码中缓存任何数据。在运行算法之前,您应该运行
df.cache()
,甚至可能运行
df.count()
来初始化缓存。它正在运行分布式模式。我用
--master warn
再次检查,结果是一样的。我还添加了
df.cache()
df.count()
行,没有任何更改。(请参见上面的编辑以了解位置。)我想,更清楚地说,我的问题是:其他人在Spark ML中训练模型时是否也看到同样的行为?这非常有用。非常感谢。我隐约想到了这些权衡,但得到确认是件好事。我的问题仍然是:其他人也看到同样的事情吗?我在使用
LogisticRegression
分类器时也看到了它。正如您所说,XGBoost是跨核心并行的,所以您可能认为Spark至少会尝试跨节点并行以竞争。我用1400万行再次尝试了这个方法,花了一个多小时,但仍然只使用了一个节点(不是主节点)进行训练。在训练ML模型时,我唯一需要检查Spark UI的时间是运行一个渐变增强的树模型-与您在原始帖子中看到的一样。我记得有很多节点在工作——它肯定多于1个,而少于集群中的节点总数。它没有打扰我,因为集群相当大——25-30个节点。更新:我仍然无法让它使用多个节点进行训练,但如果我多线程执行几个不同的
spark submit
命令,那么它将向每个节点发送一个模型训练作业。这只会有帮助,因为我实际上每次都要训练20个这样的模型(类似于迷你网格搜索)。我仍然好奇是否有人知道Spark ML培训是否应该分发,但据我所知不是。谢谢你的帮助。