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データサイエンスコミュニティは、XGboostがPySparkに実装されていることから間違いなく恩恵を受けるでしょう。理由は次のとおりです。

  • 一般的に、Pythonは2017年3月の時点で第3の言語であり、人気は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であるため、それほど重要ではないと思います。
  • 少なくとも、本番環境にPySparkを使用する3つのAIスタートアップを知っています。より一般的には、Pythonはデータサイエンティストにはるかに人気があり、求人市場で需要があります(
    http://r4stats.com/articles/popularity/)
    私の結論:PySparkに実装されたXGboostは、他のすべての実装の中でDataScienceに最大の影響を及ぼします。
    (PSが安定したら、Clouderaが実装していることを確認してください)

全てのコメント53件

@CodingCat PySparkコミュニティの大きさを知っていますか? ほとんどの人はScalaAPIを使用しています。 Pythonで多くのことを再実装する必要があるようです。間違っている場合は訂正してください。

PySparkは、データサイエンティストのコミュニティでかなり普及していると思います。つまり、ラピッドプロトタイピングなどのシナリオでは、データサイエンティストがpySparkを使用して大量のデータを分析する場合が多いと聞きました。

一方、本番レベルのシナリオのほとんどはScala APIに基づいています(大規模な本番環境でPySparkを使用しているケースは1つしかありません)

ええ、私は現在のpythonAPIがほとんどのプロトタイピングのニーズを処理できるはずだと感じています。 より多くのプロダクション対応のものが必要な場合、私は個人的にSparkをもっと気にします。 おそらく、人々が自分たちのニーズについて話し合うことができるように、ここで議論を残す必要があります。 それまでの間、統合のアプローチ/見積もり/ステップに関する詳細を提供していただければ幸いです。

コミュニティでの議論に気づきました

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

PySparkの開発は遅れているようです...ダウンストリームライブラリとして、私はPySpark統合に専念するためにhold onに投票します.....

ええ、あなたが遭遇した問題をデバッグするのも難しいです(少なくとも昨年私がそれを試していたとき)...

ロードマップ(#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データサイエンスコミュニティは、XGboostがPySparkに実装されていることから間違いなく恩恵を受けるでしょう。理由は次のとおりです。

  • 一般的に、Pythonは2017年3月の時点で第3の言語であり、人気は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であるため、それほど重要ではないと思います。
  • 少なくとも、本番環境にPySparkを使用する3つのAIスタートアップを知っています。より一般的には、Pythonはデータサイエンティストにはるかに人気があり、求人市場で需要があります(
    http://r4stats.com/articles/popularity/)
    私の結論:PySparkに実装されたXGboostは、他のすべての実装の中でDataScienceに最大の影響を及ぼします。
    (PSが安定したら、Clouderaが実装していることを確認してください)

PRを送ってください、あなたは費用を見つけるでしょう

何度もスレッドに戻らないようにするために、私は次の結論で議論を閉じます

  • 私は個人的に、PySparkを統合するためのこの取り組みを継続することに投票しません(今のところ)

  • 他の誰もがこれに貢献することを歓迎しますが、少なくとも次のことを考慮する必要があります。

    • 別のPythonパッケージを導入しないでください

    • 統合を実装する際の現在のPythonAPIとの下位互換性

    • 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は、XGBoostPySparkラッパーでコードスニペットを共有していただきありがとうございます。 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 、現在、Issue#3370でこれに適切に取り組んでおり、PR#3376が初期サポートを提供しています。

@haiy任意のデータセットの分類子に適合するコードのスニペットを見せて

@ 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'

環境:
Python 3.6
Spark 2.3
Scala 2.11

@ sagnik-rzt
わかりませんが、sparkクラスパスにdepsを含むxgboost-spark.jarを追加しますか?

@wpopielarskiねえ、私はそれをしていません。 そのjarファイルをどこで見つけることができるか考えていますか?

@ sagnik-rztこんにちは、ここからjarをダウンロードしてください。これは、公式のspark4j fatjarです。 。 申し訳ありませんが、私のjarファイルはMacに基づいて作成されていることがわかりましたてください。 そしてそれを$SPARK_HOME/jarsようにspark depsdirに入れます。

独自にビルドする必要があります:)、mavenとプロファイルassemblyを使用して、 jvm-packages/xgboost-spark/target程度でファットjarをビルドします。

@ sagnik-rztは何をするのかわかりませんが、OS用のfat jarをビルドするには、dmlc xgboost githubプロジェクトのクローンを作成し、jvm-packagesにcdして、 assembyプロファイルでmvnを実行します。 Gradleビルドファイルの書き方がよくわかりません。

さて、依存関係のあるファットjarを作成し、それを$ SPARK_HOME / jarにコピーして貼り付けました。
ただし、同じ例外が引き続き関係します。

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を使用して、-jarsスイッチにdepsを追加することをお勧めします

2018年6月29日午後02時30分GMT + 02:00 sagnik-RZT [email protected]

さて、依存関係のあるファットjarを作成し、それをコピーして貼り付けました
$ SPARK_HOME / jarsに。
ただし、同じ例外が引き続き関係します。

トレースバック(最後の最後の呼び出し):
ファイル "/home/sagnikb/PycharmProjects/xgboost/test_import.py"、21行目
clf = xgb(params)
__init__のファイル "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py"、48行目
self._java_obj = self._new_java_obj( "dmlc.xgboost4j.scala.spark.XGBoostEstimator"、self.uid、scalaMap)
_new_java_objのファイル "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py"、63行目
java_obj(* java_args)を返します
TypeError: '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. 通常のScalaXGBoostjarと依存関係をジョブに追加します。 (たとえば、 --jarsまたはspark.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")

ノート:

  • これはSpark2.2以降でのみ機能します
  • パイプラインとParamGridBuilderは一種のサポートがあり、通常のオブジェクトと同じように、変更されたパイプラインオブジェクトをfrom sparkxgb.pipeline import XGBoostPipeline,XGBoostPipelineModelします。
  • XGboost-0.72のエラーのためにnull値が正しく処理されるようにするには、float( "nan")ではなくfloat( "+ inf")を使用する必要があります。
  • トレーニングされていないモデルオブジェクトをロードバックすることはできません(#3035を参照)
  • このAPIは、pysparkサポートの完全リリースで変更されます。

@thesuperzapperjupyterノートブックのpysparkでこれをテストしようとしています。

私のシステム:
Python 3.6.1
xgboost 0.72
スパーク2.2.0
java 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

これはバグですか、それともいくつかの要件がありませんか?

@BogdanCojocarxgboostライブラリがないようです。

xgboostが正しく機能するには、これらの両方のjarファイルが必要です。

これらのMavenリンクから必要なjarファイルをダウンロードできます。

@thesuperzapperに感謝します。 正常に動作します。 pysparkへのこの統合で素晴らしい仕事をしました!

トレーニングされたモデルをPythonモジュールにロードするためのブースターに保存する方法に関する提案はありますか?

@ ericwang915通常、他のXGBoostライブラリと相互運用するモデルを取得するには、モデルオブジェクトで.booster.saveModel("XXX/XXX")メソッドを使用します。ここで、XXXはSparkドライバーのローカル(非HDFS)パスです。 他の保存方法を使用すると、エラーが発生します(#2480を参照)

ただし、そのバージョンのラッパーにsave関数を呼び出すメソッドを追加するのを忘れたので、時間があれば明日これを実行します。 (私はニュージーランドに住んでいます...だからタイムゾーン)

ありがとう。 ちなみに、トレーニング中は、サイレントが1に設定されていても、評価指標とブースティングラウンドを示すログはありません。

@thesuperzapperご指導ありがとう

@ccdtzccdtzは、0.8でSpark APIに大幅な変更が加えられたため、現在pysparkラッパーを再配線しています。終了すると、Spark ScalaAPIと同等の機能を持つことを目指しています。

最初のpysparkラッパーでネイティブブースターメソッドを公開しませんでしたが、Spark Scala APIを使用する場合は、 xgboost_model_object.nativeBooster.getFeatureScore(を呼び出して、通常どおりに使用できます。

pysparkのXGBoostが2回以上実行されると、一貫して失敗するのを見てきました。 同じコードで同じデータセットで実行しています。 1回目は成功しますが、2回目以降は失敗します。 Spark2.3でXGBoost0.72を使用しています。 ジョブを正常に実行するには、pysparkシェルを再起動する必要があります。

私はトレーニング目的で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ワーカー)、スパークエグゼキューター、コアなど。

-ニティーン

火、2018年9月4日には5:03でsagnik-RZT [email protected]書きました:

こんにちは@thesuperzapperhttps ://github.com/thesuperzapper
あなたが処方したものは、単一のワーカーノードで機能します。
ただし、複数を使用してpysparkxgboostを実行しようとすると
ワーカー、エグゼキュータはアイドル状態になり、しばらくするとシャットダウンします。
これはスタックトレースです。
'' '
トラッカーが開始されました。env= {DMLC_NUM_SERVER = 0、DMLC_TRACKER_URI = 172.16.1.5、
DMLC_TRACKER_PORT = 9093、DMLC_NUM_WORKER = 3} 2018-09-0408:52:55エラー
TaskSche dulerImpl:70-192.168.49.43でエグゼキュータ0が失われました:リモートRPC
クライアントの関連付けが解除されました。 コンテナがしきい値を超えているためか、
ネットワークの問題。 警告メッセージのドライバーログを確認します。2018-09-0408:52:55
エラー非同期ventQueue:91 -TaskFailedListenerへの投稿中に中断されました。
そのlistener.java.lang.InterruptedExceptionの削除:ExecutorLost中に
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ラッパーはXGboost0.72のみをサポートしているので、まったく機能することに驚いています。私たちはまだ0.8のものに取り組んでいます。

@thesuperzapper 、あなたが提供したバージョンに基づいて、xgboost0.80をサポートするためにいくつかの部分をやり直しました。
ただし、 py4j.protocol.Py4JError: ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier does not exist in the JVMエラーが発生します。 ここに完全な説明を提供しました。 見ていただけませんか?

すべてのコードはここに配置され

0.8で動作させるには、これまでに行ったよりもはるかに多くの変更が必要です。

私が0.8バージョンをプッシュしただけではない主な理由は、0.72のようにxgboost固有のパイプラインオブジェクトを作成したくないためです。pysparkxgboostオブジェクトを機能させる方法に取り組んでいます。デフォルトのパイプライン永続性を使用します。

@thesuperzapperは、0.72のコードを使用している間、私が使用されるXGBoostEstimator使用せずに直接あるオブジェクトXGBoostPipelineオブジェクト。 その間、トレーニング/フィッティングがクラスター上のワーカー全体に分散されていないことに気付きました。 ワーカー間での配布にXGBoostPipelineを使用する必要がありますか?

そうでない場合は、トレーニングが労働者全体に分散されない理由を知っていますか?

アップデート
XGBoostEstimatorXGBoostPipelineステージとして設定してトレーニングを試しましたが、問題は解決しません。 トレーニングは、他のpysparkでサポートされているモデルの場合とは異なり、クラスターで実行するとワーカー間で分散されません。

この振る舞いを観察しましたか? どうすればそれに取り組むことができますか?

私は主にXGBoost0.8のラッパーを再コーディングしましたが、作業クラスターはまだ2.2であるため、Dockerized Spark2.3クラスターはシャッフルロケーションの欠落の問題を取得せずにScalaXGBoost分散モデルをトレーニングすることさえできないため、分散モードで簡単にテストできません。

@ sagnik-rztやその他の人が経験している問題は、クラスター構成またはSpark-ScalaXGBoostのより深い問題に関連していると思います。

Spark-Scala XGBoostでモデルをトレーニングできますか?

@thesuperzapperに感謝しこのスタックオーバーフローの投稿を見つけたので、それらの提案を実装します。

また、準備ができたら、0.8バージョンを共有できますか? クラスタでの配布をテストできます。 それはspark2.3.1とpython3.5を持っています。

モデルを保存してロードした後、次のエラーが発生します

IllegalArgumentException:u '要件に失敗しました:メタデータの読み込みエラー:クラス名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 評価