Xgboost: [讨论] 与 PySpark 的集成

创建于 2016-10-25  ·  53评论  ·  资料来源: dmlc/xgboost

我刚刚注意到有一些与 PySpark 集成的请求http://dmlc.ml/2016/03/14/xgboost4j-portable-distributed-xgboost-in-spark-flink-and-dataflow.html

我还收到了一些来自讨论同一主题的用户的电子邮件

我想在这里开始讨论我们是否/何时开始这项工作

@tqchen @terrytangyuan

python

最有用的评论

@CodingCat @tqchen数据科学社区肯定会受益于在 PySpark 中实施的 XGboost,因为:

  • 总的来说,截至 2017 年 3 月,Python 是排名第三的语言,流行度为 10.2%(而 Scala 为 1.8%)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group;
  • 就性能而言,PySpark 与 Scala 的比较,我认为这并不重要,因为 Spark 的幕后几乎都是 Scala,对吧?
  • 我知道,至少有 3 家 AI 初创公司使用 PySpark 进行生产,更一般地说,Python 在数据科学家和就业市场上更受欢迎(
    http://r4stats.com/articles/popularity/)
    我的结论是:在 PySpark 中实施的 XGboost 对数据科学的影响最大。
    (PS一旦稳定,请确保Cloudera实现它)

所有53条评论

@CodingCat你知道 PySpark 社区有多大吗? 大多数人只使用 Scala API。 似乎很多东西需要在 Python 中重新实现——如果我错了,请纠正我。

我认为 PySpark 在数据科学家社区中非常流行,这意味着在快速原型设计等场景中。我听说过很多数据科学家使用 pySpark 分析大量数据的案例。

另一方面,大部分生产级场景都是基于Scala API的(我只知道一个案例,人们在大规模生产中使用PySpark)

是的,我只是觉得当前的 python API 应该能够处理大多数原型设计需求。 当我们想要更多生产就绪的东西时,我个人更关心 Spark。 也许我们应该把讨论留在这里,这样人们就可以讨论他们的需求。 同时,如果您能提供一些有关集成方法/估计/步骤的详细信息,那就太好了。

刚刚注意到社区中的一些讨论

http://apache-spark-developers-list.1001551.n3.nabble.com/Blocked-PySpark-changes-td19712.html

看来PySpark的发展有点落后了...作为下游库,我投给hold on ,致力于PySpark的整合.....

是的,调试您遇到的任何问题也很困难(至少在我去年尝试时)...

在路线图 (#873) 中,它说分布式 python 已经实现。 是不是意味着 xgboost 可以运行在带有 python 的 hadoop 集群上? (我不是说 pyspark)

是的,请参阅链接中发布的示例

使用python在hadoop集群上运行xgboost与使用scala api在hadoop集群上运行xgboost有什么区别?是否存在重大性能差异?
我认为仍然有很多人将 pyspark 用于生产模型。

@yiming-chen xgboost4j-spark 的目标是在同一管道中统一 ETL 和模型训练

问题归结为用户在进行 ETL 时使用什么语言? 根据我的观察和经验,95% 的用户正在使用 scala 构建他们的 ETL 系统

@CodingCat我不知道你从哪里得到 95% 的统计数据,但 PySpark 在我的经验中绝对被广泛使用。 例如,我们正在尝试集成 Airflow 来为我们的管道安排作业,而 Python 将适用于这种情况。

@berch PySpark 被您广泛使用,您将与气流集成……这与我所说的有关吗?

@CodingCat @tqchen数据科学社区肯定会受益于在 PySpark 中实施的 XGboost,因为:

  • 总的来说,截至 2017 年 3 月,Python 是排名第三的语言,流行度为 10.2%(而 Scala 为 1.8%)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group;
  • 就性能而言,PySpark 与 Scala 的比较,我认为这并不重要,因为 Spark 的幕后几乎都是 Scala,对吧?
  • 我知道,至少有 3 家 AI 初创公司使用 PySpark 进行生产,更一般地说,Python 在数据科学家和就业市场上更受欢迎(
    http://r4stats.com/articles/popularity/)
    我的结论是:在 PySpark 中实施的 XGboost 对数据科学的影响最大。
    (PS一旦稳定,请确保Cloudera实现它)

随意发送公关,你会发现成本

为了避免一次又一次地回到线程,我将结束讨论的结论是

  • 我个人不会投票支持继续整合 PySpark(目前)

  • 非常欢迎任何其他人为此做出贡献,但是,我们至少需要考虑以下事项:

    • 不要引入另一个python包

    • 实现集成时向后兼容当前的python API

    • 处理 pyspark ML 的滞后特性

所以我们不能使用pyspark来加载XGBoost-spark模型? @CodingCat

因此,实际上 scala XGBoost可以更轻松地包裹在 PySpark JavaEstimator API 中。 我玩了一点,有这样的原型:

from pyspark.ml.wrapper import JavaEstimator, JavaModel
from pyspark.ml.param.shared import *
from pyspark.ml.util import *
from pyspark.context import SparkContext

class XGBoost(JavaEstimator, JavaMLWritable, JavaMLReadable, HasRegParam, HasElasticNetParam):

    def __init__(self, paramMap = {}):
        super(XGBoost, self).__init__()
        scalaMap = SparkContext._active_spark_context._jvm.PythonUtils.toScalaMap(paramMap)
        self._java_obj = self._new_java_obj(
            "ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
        self._defaultParamMap = paramMap
        self._paramMap = paramMap

    def setParams(self, paramMap = {}):
        return self._set(paramMap)

    def _create_model(self, javaTrainingData):
        return JavaModel(javaTrainingData)

我认为它仍然需要一些工作,但我能够用它在 PySpark 中运行Xgboost

Wieslaw 感谢您分享有关 XGBoost PySpark 包装器的代码片段。您能否分享有关使用适当参数调用 XGBoost 类的代码?

谢谢

@wpopielarski你做的真是太棒了。 您能否分享有关使用所需参数调用 XGBoost 的代码? 那将是一个很大的帮助!

这类似于:

        from app.xgboost import XGBoost
        xgboost_params = {
            "eta"  : 0.023,
            "max_depth" : 10,
            "min_child_weight" : 0.3,
            "subsample" : 0.7,
            "colsample_bytree" : 0.82,
            "colsample_bylevel" : 0.9,
            "base_score" : base_score,
            "eval_metric" : "auc",
            "seed" : 49,
            "silent" : 1,
            "objective" : "binary:logistic",
            "round" : 10,
            "nWorkers" : 2,
            "useExternalMemory" : True
        }
        xgboost_estimator = XGBoost.XGBoost(xgboost_params)
...
        model = xgboost_estimator.fit(data)

我即将通过适当的 PySpark 支持进行 PR。

@thesuperzapper ,太棒了!

你认为需要多长时间才能完成? 在进步的同时分享见解。

谢谢!

嗨,我用ParamGridBuilder写了一个简单的版本,以防有人感兴趣,定制它真的很容易。

  • 1 在任何有效的 PYTHONPATH 目录中创建一个包目录mkdir -p ml/dmlc/xgboost4j/scala
  • 2 将下面的代码复制到ml/dmlc/xgboost4j/scala/spark.py
from pyspark.ml.classification import JavaClassificationModel, JavaMLWritable, JavaMLReadable, TypeConverters, Param, \
    Params, HasFeaturesCol, HasLabelCol, HasPredictionCol, HasRawPredictionCol, SparkContext
from pyspark.ml.wrapper import JavaModel, JavaWrapper, JavaEstimator


class XGBParams(Params):
    '''

    '''
    eta = Param(Params._dummy(), "eta",
                "step size shrinkage used in update to prevents overfitting. After each boosting step, we can directly get the weights of new features. and eta actually shrinks the feature weights to make the boosting process more conservative",
                typeConverter=TypeConverters.toFloat)
    max_depth = Param(Params._dummy(), "max_depth",
                      "maximum depth of a tree, increase this value will make the model more complex / likely to be overfitting. 0 indicates no limit, limit is required for depth-wise grow policy.range: [0,∞]",
                      typeConverter=TypeConverters.toInt)
    min_child_weight = Param(Params._dummy(), "min_child_weight",
                             "minimum sum of instance weight (hessian) needed in a child. If the tree partition step results in a leaf node with the sum of instance weight less than min_child_weight, then the building process will give up further partitioning. In linear regression mode, this simply corresponds to minimum number of instances needed to be in each node. The larger, the more conservative the algorithm will berange: [0,∞]",
                             typeConverter=TypeConverters.toFloat)
    max_delta_step = Param(Params._dummy(), "max_delta_step",
                           "Maximum delta step we allow each tree’s weight estimation to be. If the value is set to 0, it means there is no constraint. If it is set to a positive value, it can help making the update step more conservative. Usually this parameter is not needed, but it might help in logistic regression when class is extremely imbalanced. Set it to value of 1-10 might help control the update.",
                           typeConverter=TypeConverters.toInt)
    subsample = Param(Params._dummy(), "subsample",
                      "subsample ratio of the training instance. Setting it to 0.5 means that XGBoost randomly collected half of the data instances to grow trees and this will prevent overfitting.",
                      typeConverter=TypeConverters.toFloat)
    colsample_bytree = Param(Params._dummy(), "colsample_bytree",
                             "subsample ratio of columns when constructing each tree",
                             typeConverter=TypeConverters.toFloat)
    colsample_bylevel = Param(Params._dummy(), "colsample_bylevel",
                              "subsample ratio of columns for each split, in each level.",
                              typeConverter=TypeConverters.toFloat)
    max_leaves = Param(Params._dummy(), "max_leaves",
                       "Maximum number of nodes to be added. Only relevant for the ‘lossguide’ grow policy.",
                       typeConverter=TypeConverters.toInt)

    def __init__(self):
        super(XGBParams, self).__init__()

class XGBoostClassifier(JavaEstimator, JavaMLWritable, JavaMLReadable, XGBParams,
                        HasFeaturesCol, HasLabelCol, HasPredictionCol, HasRawPredictionCol):
    def __init__(self, paramMap={}):
        super(XGBoostClassifier, self).__init__()
        scalaMap = SparkContext._active_spark_context._jvm.PythonUtils.toScalaMap(paramMap)
        self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
        self._defaultParamMap = paramMap
        self._paramMap = paramMap

    def setParams(self, paramMap={}):
        return self._set(paramMap)

    def _create_model(self, java_model):
        return XGBoostClassificationModel(java_model)


class XGBoostClassificationModel(JavaModel, JavaClassificationModel, JavaMLWritable, JavaMLReadable):

    def getBooster(self):
        return self._call_java("booster")

    def saveBooster(self, save_path):
        jxgb = JavaWrapper(self.getBooster())
        jxgb._call_java("saveModel", save_path)
  • 3 把它当作普通的pyspark模型来玩!

@AakashBasuRZT @haiy ,我们现在正在问题 #3370 中正确处理此问题,PR #3376 提供初步支持。

@haiy你能告诉我一段适合某个任意数据集的分类器的代码吗? 我遵循了您概述的第 1 点和第 2 点,但我无法理解您的第 3 点。

@sagnik-rzt 检查这个样本

@haiy我正在尝试运行这个:

import pyspark
import pandas as pd
from dmlc.xgboost4j.scala.spark import XGBoostClassifier
from sklearn.utils import shuffle

sc = pyspark.SparkContext('local[2]')
spark = pyspark.sql.SparkSession(sc)
df = pd.DataFrame({'x1': range(10), 'x2': [10] * 10, 'y': shuffle([0 for i in range(5)] + [1 for i in range(5)])})
sdf = spark.createDataFrame(df)
X = sdf.select(['x1', 'x2'])
Y = sdf.select(['y'])
print(X.show(5))

params = {'objective' :'binary:logistic', 'n_estimators' : 10, 'max_depth' : 3, 'learning_rate' : 0.033}
xgb_model = XGBoostClassifier(params)

它给出了这个例外:

Traceback (most recent call last):
  File "/home/sagnikb/PycharmProjects/auto_ML/pyspark_xgboost.py", line 20, in <module>
    xgb_model = XGBoostClassifier(params)
  File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 47, in __init__
    self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
  File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
    return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable

Error in sys.excepthook:
Traceback (most recent call last):
  File "/home/sagnikb/PycharmProjects/auto_ML/pyspark_xgboost.py", line 20, in <module>
    xgb_model = XGBoostClassifier(params)
  File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 47, in __init__
    self._java_obj = self._new_java_obj("ml.dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
  File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
    return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable
Exception ignored in: <bound method JavaParams.__del__ of XGBoostClassifier_4f9eb5d1388e9e1424a4>
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 105, in __del__
    SparkContext._active_spark_context._gateway.detach(self._java_obj)
  File "/usr/local/lib/python3.6/dist-packages/py4j/java_gateway.py", line 1897, in detach
    java_object._detach()
AttributeError: 'NoneType' object has no attribute '_detach'

环境:
蟒蛇 3.6
火花2.3
斯卡拉 2.11

@sagnik-rzt
不确定,但是您是否在 spark 类路径上添加了带有 deps 的 xgboost-spark.jar?

@wpopielarski嘿,不,我没有这样做。 知道在哪里可以找到那个 jar 文件吗?

@sagnik-rzt 嗨,请在这里下载 jar,它是官方的 spark4j fat jar。 . 抱歉,我刚刚发现我的 jar 是基于 mac 构建的,请尝试按照@wpopielarski 的建议构建它。 并将其放在 spark deps 目录中,例如$SPARK_HOME/jars

需要自己构建它:),使用 maven 和配置文件assembly ,它在jvm-packages/xgboost-spark/target左右构建胖罐。

@sagnik-rzt 不确定你要做什么,但要为你的操作系统构建胖 jar 只需克隆 dmlc xgboost github 项目,cd 到 jvm-packages 并使用assemby配置文件运行 mvn。 我对如何编写 gradle 构建文件一无所知。

好的,所以我已经构建了一个带有依赖项的胖 jar,然后将其复制粘贴到 $SPARK_HOME/jars。
但是,同样的例外仍然适用:

Traceback (most recent call last):
  File "/home/sagnikb/PycharmProjects/xgboost/test_import.py", line 21, in <module>
    clf = xgb(params)
  File "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", line 48, in __init__
    self._java_obj = self._new_java_obj("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
  File "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", line 63, in _new_java_obj
    return java_obj(*java_args)
TypeError: 'JavaPackage' object is not callable

抱歉,您是在集群上从某个 IDE 项目本地运行它的吗? 如果你是
使用 spark-submit 最好将 deps 添加到 --jars 开关

2018-06-29 14:30 GMT+02:00 sagnik-rzt通知@github.com:

好的,所以我已经构建了一个带有依赖项的胖 jar,然后复制粘贴它
到 $SPARK_HOME/jars。
但是,同样的例外仍然适用:

回溯(最近一次调用最后一次):
文件“/home/sagnikb/PycharmProjects/xgboost/test_import.py”,第 21 行,在
clf = xgb(参数)
文件“/usr/lib/ml/dmlc/xgboost4j/scala/spark.py”,第 48 行,在 __init__ 中
self._java_obj = self._new_java_obj("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
文件“/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py”,第 63 行,在 _new_java_obj 中
返回 java_obj(*java_args)
类型错误:“JavaPackage”对象不可调用


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/dmlc/xgboost/issues/1698#issuecomment-401339910或静音
线程
https://github.com/notifications/unsubscribe-auth/ALEzS3JmKjO0AZ6JMzcixwCce0_3zRM0ks5uBh3ogaJpZM4KgAY_
.

我目前正在将#3376 重新绑定到新的 spark 分支,同时,一些人询问如何在 XGBoost-0.72 上使用当前代码。

这是一个带有 XGBoost-0.72 pyspark 代码的 zip 文件。
下载: sparkxgb.zip

您需要做的就是:

  1. 将普通的 Scala XGBoost jars 和依赖项添加到您的作业中。 (例如使用--jarsspark.jars配置)。
  2. 作业开始后,在 python 中运行:(或每个执行者可以看到的任何本地位置)
sc.addPyFile("hdfs:///XXXX/XXXX/XXXX/sparkxgb.zip")
  1. 使用以下代码进行测试。 (假设您已将sample_binary_classification_data.txt到可到达的位置,它通常在$SPARK_HOME/data/mllib/sample_binary_classification_data.txt
from sparkxgb import XGBoostEstimator

# Load Data
dataPath = "sample_binary_classification_data.txt"
dataDF = spark.read.format("libsvm").load(dataPath)

# Split into Train/Test
trainDF, testDF = dataDF.randomSplit([0.8, 0.2], seed=1000)

# Define and train model
xgboost = XGBoostEstimator(
    # General Params
    nworkers=1, nthread=1, checkpointInterval=-1, checkpoint_path="",
    use_external_memory=False, silent=0, missing=float("nan"),

    # Column Params
    featuresCol="features", labelCol="label", predictionCol="prediction", 
    weightCol="weight", baseMarginCol="baseMargin", 

    # Booster Params
    booster="gbtree", base_score=0.5, objective="binary:logistic", eval_metric="error", 
    num_class=2, num_round=2, seed=None,

    # Tree Booster Params
    eta=0.3, gamma=0.0, max_depth=6, min_child_weight=1.0, max_delta_step=0.0, subsample=1.0,
    colsample_bytree=1.0, colsample_bylevel=1.0, reg_lambda=0.0, alpha=0.0, tree_method="auto",
    sketch_eps=0.03, scale_pos_weight=1.0, grow_policy='depthwise', max_bin=256,

    # Dart Booster Params
    sample_type="uniform", normalize_type="tree", rate_drop=0.0, skip_drop=0.0,

    # Linear Booster Params
    lambda_bias=0.0
)
xgboost_model = xgboost.fit(trainDF)

# Transform test set
xgboost_model.transform(testDF).show()

# Write model/classifier
xgboost.write().overwrite().save("xgboost_class_test")
xgboost_model.write().overwrite().save("xgboost_class_test.model")

笔记:

  • 这仅适用于 Spark 2.2+
  • 管道和 ParamGridBuilder 是受支持的,使用带有from sparkxgb.pipeline import XGBoostPipeline,XGBoostPipelineModel的修改后的管道对象,就像使用普通对象一样。
  • 由于 XGboost-0.72 中的错误,您必须对缺失值使用 float("+inf") 而不是 float("nan") 来正确处理空值。
  • 你不能加载未经训练的模型对象,(见#3035)
  • 这个 API 将随着 pyspark 支持的完整版本而改变。

@thesuperzapper我试图在 jupyter 笔记本上用 pyspark 测试这个。

我的系统:
蟒蛇 3.6.1
xgboost 0.72
火花 2.2.0
爪哇1.8
Scala 2.12

当我尝试加载 XGBoostEstimator 时,我得到:

Exception in thread "Thread-19" java.lang.NoClassDefFoundError: ml/dmlc/xgboost4j/scala/EvalTrait
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.privateGetPublicMethods(Class.java:2902)
    at java.lang.Class.getMethods(Class.java:1615)
    at py4j.reflection.ReflectionEngine.getMethodsByNameAndLength(ReflectionEngine.java:345)
    at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:305)
    at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:326)
    at py4j.Gateway.invoke(Gateway.java:272)
    at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
    at py4j.commands.CallCommand.execute(CallCommand.java:79)
    at py4j.GatewayConnection.run(GatewayConnection.java:214)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: ml.dmlc.xgboost4j.scala.EvalTrait
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 12 more

这是一个错误还是我错过了一些要求?

@BogdanCojocar似乎您缺少 xgboost 库。

你需要这两个 jars 才能让 xgboost 正常工作:

您可以从这些 Maven 链接下载所需的 jar。

谢谢@thesuperzapper。 工作正常。 与 pyspark 的这种集成做得很好!

关于如何将经过训练的模型保存到 booster 以加载到 python 模块中的任何建议?

@ericwang915通常要获得与其他 XGBoost 库互操作的模型,您可以在模型对象上使用.booster.saveModel("XXX/XXX")方法,其中 XXX 是 Spark 驱动程序上的本地(非 HDFS)路径。 如果您使用其他保存方法,则会出现错误(请参阅:#2480)

但是,我忘了在那个版本的包装器中添加一个调用 save 函数的方法,如果我有时间,明天我会这样做。 (我住在新西兰......所以时区)

谢谢你。 顺便说一下,在训练过程中,即使静音设置为 1,也没有显示评估指标和提升轮次的日志。

@thesuperzapper感谢您的指导。我能够按照您的说明在 pyspark 中训练/保存 xgboost 模型。关于如何访问其他 xgboost 模型函数如 (scala)getFeatureScore() 的任何想法?

@ccdtzccdtz目前我正在重新连接 pyspark 包装器,因为 0.8 对 Spark API 进行了大量更改,完成后,我的目标是使功能与 Spark Scala API 相同。

我没有在我最初的 pyspark 包装器中公开原生 booster 方法,但是如果你使用 Spark Scala API,你可以调用xgboost_model_object.nativeBooster.getFeatureScore(并像往常一样使用它。

我已经看到 pyspark 上的 XGBoost 在运行 2 次或更多次时始终失败。 我使用相同的代码在相同的数据集上运行它。 第一次成功,但第二次和随后失败。 我在 Spark 2.3 上使用 XGBoost 0.72。 我必须重新启动 pyspark shell 才能再次成功运行该作业。

我使用 xgboost.trainWithDataFrame 进行培训。

有没有人看到这个问题?

嗨@thesuperzapper
您规定的内容在单个工作节点上对我有用。
但是,当我尝试在使用多个工作程序(在本例中为 3 个)上运行 pyspark xgboost 时,执行程序会在一段时间后空闲并关闭。
这是我试图在 Titanic 数据集(这是一个小数据集)上运行的代码:

from pyspark.sql.session import SparkSession
from pyspark.sql.types import *
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.sql.functions import col

spark = SparkSession\
        .builder\
        .appName("PySpark XGBOOST Titanic")\
        .getOrCreate()

#spark.sparkContext.addPyFile("../sparkxgb.zip")

from automl.sparkxgb import XGBoostEstimator

schema = StructType(
  [StructField("PassengerId", DoubleType()),
    StructField("Survival", DoubleType()),
    StructField("Pclass", DoubleType()),
    StructField("Name", StringType()),
    StructField("Sex", StringType()),
    StructField("Age", DoubleType()),
    StructField("SibSp", DoubleType()),
    StructField("Parch", DoubleType()),
    StructField("Ticket", StringType()),
    StructField("Fare", DoubleType()),
    StructField("Cabin", StringType()),
    StructField("Embarked", StringType())
  ])

df_raw = spark\
  .read\
  .option("header", "true")\
  .schema(schema)\
  .csv("titanic.csv")


df = df_raw.na.fill(0)

sexIndexer = StringIndexer() \
    .setInputCol("Sex") \
    .setOutputCol("SexIndex") \
    .setHandleInvalid("keep")

cabinIndexer = StringIndexer() \
    .setInputCol("Cabin") \
    .setOutputCol("CabinIndex") \
    .setHandleInvalid("keep")

embarkedIndexer = StringIndexer() \
    .setInputCol("Embarked") \
    .setOutputCol("EmbarkedIndex") \
    .setHandleInvalid("keep")

vectorAssembler  = VectorAssembler()\
  .setInputCols(["Pclass", "SexIndex", "Age", "SibSp", "Parch", "Fare", "CabinIndex", "EmbarkedIndex"])\
  .setOutputCol("features")

xgboost = XGBoostEstimator(nworkers=2,
    featuresCol="features",
    labelCol="Survival",
    predictionCol="prediction"
)

pipeline = Pipeline().setStages([sexIndexer, cabinIndexer, embarkedIndexer, vectorAssembler, xgboost])
trainDF, testDF = df.randomSplit([0.8, 0.2], seed=24)

model  =pipeline.fit(trainDF)
print(trainDF.schema)

这是堆栈跟踪:
Tracker started, with env={DMLC_NUM_SERVER=0, DMLC_TRACKER_URI=172.16.1.5, DMLC_TRACKER_PORT=9093, DMLC_NUM_WORKER=3}2018-09-04 08:52:55 ERROR TaskSchedulerImpl:70 - Lost executor 0 on 192.168.49.43: Remote RPC client disassociated. Likely due to containers exceeding thresholds, or network issues. Check driver logs for WARN messages.2018-09-04 08:52:55 ERROR AsyncEventQueue:91 - Interrupted while posting to TaskFailedListener. Removing that listener.java.lang.InterruptedException: ExecutorLost during XGBoost Training: ExecutorLostFailure (executor 0 exited caused by one of the running tasks) Reason: Remote RPC client disassociated. Likely due to containers exceeding thresholds, or network issues. Check driver logs for WARN messages. at org.apache.spark.TaskFailedListener.onTaskEnd(SparkParallelismTracker.scala:116) at org.apache.spark.scheduler.SparkListenerBus$class.doPostEvent(SparkListenerBus.scala:45) at org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37) at org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37) at org.apache.spark.util.ListenerBus$class.postToAll(ListenerBus.scala:91)

执行者卡在:
org.apache.spark.RDD.foreachPartition(RDD.scala:927) ml.dmlc.xgboost4j.scala.spark.XGBoost$$anonfun$trainDistributed$4$$anon$1.run(XGBoost.scala:348)

环境:Python 3.5.4、Spark 2.3.1、Xgboost 0.72

你能分享你的 xgboost 和 spark 配置吗? 多少
工人(xgboost 工人),火花执行器,核心等。

-Nitin

在星期二,2018年9月4日在上午05时03分sagnik-RZT [email protected]写道:

@thesuperzapper https://github.com/thesuperzapper
您规定的内容在单个工作节点上对我有用。
但是,当我尝试在使用多个时运行 pyspark xgboost 时
worker,executors 空闲并在一段时间后关闭。
这是堆栈跟踪:
'''
跟踪器启动,env={DMLC_NUM_SERVER=0, DMLC_TRACKER_URI=172.16.1.5,
DMLC_TRACKER_PORT=9093, DMLC_NUM_WORKER=3}2018-09-04 08:52:55 错误
TaskSche dulerImpl:70 - 192.168.49.43 上丢失的执行程序 0:远程 RPC
客户端解除关联。 可能是由于容器超过阈值,或
网络问题。 检查驱动程序日志中的警告消息。2018-09-04 08:52:55
错误 AsyncE ventQueue:91 - 发布到 TaskFailedListener 时中断。
删除那个 listener.java.lang.InterruptedException: ExecutorLost during
XGBoost 训练:ExecutorLostFailure(执行程序 0 由以下原因之一退出)
正在运行的任务)原因:远程 RPC 客户端断开关联。 可能是由于
容器超过阈值或网络问题。 检查驱动程序日志
警告消息。 在
org.apache.spark.TaskFailedListener.onTaskEnd(SparkParallelismTracker.scala:116)

org.apache.spark.scheduler.SparkListenerBus$class.doPostEvent(SparkListenerBus.scala:45)

org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37)

org.apache.spark.scheduler.AsyncEventQueue.doPostEvent(AsyncEventQueue.scala:37)
在 org.apache.spark.util.ListenerBus$class.postToAll(ListenerBus.scala:91)
'''


您收到此消息是因为您发表了评论。
直接回复本邮件,在GitHub上查看
https://github.com/dmlc/xgboost/issues/1698#issuecomment-418341557或静音
线程
https://github.com/notifications/unsubscribe-auth/AJY-XklxsZB_FE7ZoAarV_fqw8D3JqxWks5uXmwqgaJpZM4KgAY_
.

@sagnik-rzt 我很惊讶它竟然有效,因为那个 pyspark 包装器只支持 XGboost 0.72,我们仍在开发 0.8 版本。

@thesuperzapper ,根据您提供的版本,我重做了一些部分以支持 xgboost 0.80。
但是,我最终遇到了py4j.protocol.Py4JError: ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier does not exist in the JVM错误。 我在这里提供了完整的描述。 你能看看吗?

所有代码都放在这里

要使其与 0.8 一起使用,需要进行的更改比您所做的要多得多。

我没有推出 0.8 版本的主要原因是因为我真的不想像 0.72 中那样制作 xgboost 特定的管道对象,我正在研究一种希望让 pyspark xgboost 对象工作的方法使用默认的管道持久性。

@thesuperzapper ,在使用 0.72 的代码时,我直接使用了XGBoostEstimator对象,没有使用XGBoostPipeline对象。 在这样做的同时,我注意到训练/拟合并没有分布在集群上的工作人员之间。 是否有必要使用XGBoostPipeline在工人之间进行分配?

如果不是这种情况,您知道为什么培训没有分配给工人吗?

更新
我试图通过设置培训XGBoostEstimator在作为舞台XGBoostPipeline ,但问题仍然存在。 当我在集群上运行它时,训练不会在工作人员之间分布,而它适用于其他 pyspark 支持的模型。

你观察过这种行为吗? 我该如何解决?

我主要为 XGBoost 0.8 重新编码了包装器,但由于我的工作集群仍在 2.2 上,我无法在分布式模式下轻松测试它,因为我的 Dockerized Spark 2.3 集群甚至无法训练 Scala XGBoost 分布式模型而不会出现 shuffle location 丢失问题.

我认为@sagnik-rzt 和其他人遇到的问题与您的集群配置或 Spark-Scala XGBoost 的一些更深层次的问题有关。

你能在 Spark-Scala XGBoost 中训练模型吗?

感谢@thesuperzapper ,我认为 shuffle 位置是在内部处理的,也就是说,它将独立于集群配置进行处理。 但是我发现了这个stackoverflow 帖子,因此将实施这些建议。

另外,如果准备好了,您可以分享您的 0.8 版本吗? 我可以测试我的集群上的分布。 它有 spark 2.3.1 和 python 3.5。

保存模型并加载后出现以下错误

IllegalArgumentException: u'requirement failed: Error loading metadata: Expected class name org.apache.spark.ml.Pipeline 但找到类名 org.apache.spark.ml.PipelineModel'

你能帮帮忙吗? 谢谢

import pyspark
from pyspark.sql.session import SparkSession
from pyspark.sql.types import *
from pyspark.ml.feature import StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.sql.functions import col

spark.sparkContext.addPyFile("sparkxgb.zip")
from sparkxgb import XGBoostEstimator
schema = StructType(
  [StructField("PassengerId", DoubleType()),
    StructField("Survival", DoubleType()),
    StructField("Pclass", DoubleType()),
    StructField("Name", StringType()),
    StructField("Sex", StringType()),
    StructField("Age", DoubleType()),
    StructField("SibSp", DoubleType()),
    StructField("Parch", DoubleType()),
    StructField("Ticket", StringType()),
    StructField("Fare", DoubleType()),
    StructField("Cabin", StringType()),
    StructField("Embarked", StringType())
  ])

df_raw = spark\
  .read\
  .option("header", "true")\
  .schema(schema)\
  .csv("train.csv")

 df = df_raw.na.fill(0)

 sexIndexer = StringIndexer()\
  .setInputCol("Sex")\
  .setOutputCol("SexIndex")\
  .setHandleInvalid("keep")

cabinIndexer = StringIndexer()\
  .setInputCol("Cabin")\
  .setOutputCol("CabinIndex")\
  .setHandleInvalid("keep")

embarkedIndexer = StringIndexer()\
  .setInputCol("Embarked")\
  .setOutputCol("EmbarkedIndex")\
  .setHandleInvalid("keep")

vectorAssembler = VectorAssembler()\
  .setInputCols(["Pclass", "SexIndex", "Age", "SibSp", "Parch", "Fare", "CabinIndex", "EmbarkedIndex"])\
  .setOutputCol("features")
xgboost = XGBoostEstimator(
    featuresCol="features", 
    labelCol="Survival", 
    predictionCol="prediction"
)

pipeline = Pipeline().setStages([sexIndexer, cabinIndexer, embarkedIndexer, vectorAssembler, xgboost])
model = pipeline.fit(df)
model.transform(df).select(col("PassengerId"), col("prediction")).show()

model.save("model_xgboost")
loadedModel = Pipeline.load("model_xgboost")


IllegalArgumentException: u'requirement failed: Error loading metadata: Expected class name org.apache.spark.ml.Pipeline but found class name org.apache.spark.ml.PipelineModel'


#predict2 = loadedModel.transform(df)

尝试了以下选项

from pyspark.ml import PipelineModel
#model.save("model_xgboost")
loadedModel = PipelineModel.load("model_xgboost")

得到以下错误

没有名为 ml.dmlc.xgboost4j.scala.spark 的模块

开发下载链接: sparkxgb.zip

此版本将与 XGBoost-0.8 一起使用,但请不要将其用于测试或为该线程做出贡献以外的任何其他用途,因为内容会发生变化。
(另请注意:我已经删除了 Spark 2.2 的所有向后移植,所以这只支持 Spark 2.3)

我知道该版本的主要问题是分类模型在保存后不会重新加载,并给出错误: TypeError: 'JavaPackage' object is not callable 。 然而,奇怪的是 XGBoostPipelineModel 在 XGBoost 分类阶段工作得很好。 这让我认为这是我的问题,有人可以验证阅读分类模型是否适合他们吗?

无论如何,我正在尝试正确实现DefaultParamsWritable ,这将消除对专用XGBoostPipeline ,这将更容易长期维护,因此无论如何读/写问题都应该变得无关紧要。 (这也可能允许 CrossValidator 的持久性工作)

此页面是否有帮助?
0 / 5 - 0 等级