Xgboost: [DISCUSSION] Intégration avec PySpark

Créé le 25 oct. 2016  ·  53Commentaires  ·  Source: dmlc/xgboost

Je viens de remarquer qu'il y a des demandes d'intégration avec PySpark http://dmlc.ml/2016/03/14/xgboost4j-portable-distributed-xgboost-in-spark-flink-and-dataflow.html

J'ai également reçu des e-mails d'utilisateurs discutant du même sujet

Je voudrais initialiser une discussion ici pour savoir si/quand nous allons commencer ce travail

@tqchen @terrytangyuan

python

Commentaire le plus utile

La communauté @CodingCat @tqchen Data Science bénéficiera certainement de l'implémentation de XGboost dans PySpark, car :

  • En général, Python est le langage n°3 en mars 2017 avec 10,2 % de popularité (contre 1,8 % pour Scala)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group ;
  • En termes de performances PySpark vs Scala, je suppose que cela n'a pas beaucoup d'importance car c'est presque tout Scala sous le capot pour Spark, n'est-ce pas ?
  • Je connais, au moins, 3 startups d'IA qui utilisent PySpark pour la production et, plus généralement, Python est beaucoup plus populaire pour les Data Scientists et en demande sur le marché du travail (
    http://r4stats.com/articles/popularity/)
    Ma conclusion : XGboost implémenté dans PySpark aura le plus grand impact pour DataScience parmi toutes les autres implémentations.
    (PS une fois stable, assurez-vous que Cloudera l'implémente)

Tous les 53 commentaires

@CodingCat Savez-vous quelle est la taille de la communauté PySpark ? La plupart des gens utilisent simplement l'API Scala. Il semble que beaucoup de choses doivent être réimplémentées en Python - veuillez me corriger si je me trompe.

Je pense que PySpark est assez répandu dans la communauté des Data Scientists, c'est-à-dire dans le scénario de prototypage rapide, etc. J'ai entendu parler de nombreux cas où les data scientists utilisent pySpark pour analyser de gros volumes de données.

D'un autre côté, la plupart des scénarios de niveau production sont basés sur l'API Scala (je ne connais qu'un seul cas où les gens utilisent PySpark dans une production à grande échelle)

Oui, j'ai juste l'impression que l'API Python actuelle devrait être capable de gérer la plupart des besoins de prototypage. Personnellement, je me soucie davantage de Spark lorsque nous voulons plus de choses prêtes pour la production. Peut-être devrions-nous laisser la discussion ici pour que les gens puissent discuter de leurs besoins. En attendant, ce serait formidable si vous pouviez fournir des détails sur les approches/estimations/étapes de l'intégration.

Je viens de remarquer quelques discussions dans la communauté

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

il semble que le développement de PySpark soit à la traîne... en tant que bibliothèque en aval, je vote pour hold on à consacrer à l'intégration de PySpark.....

Oui, il est également difficile de déboguer les problèmes que vous avez rencontrés (du moins lorsque je l'ai essayé l'année dernière) ...

Dans la feuille de route (#873), il est indiqué que le python distribué a été implémenté. Cela signifie-t-il que xgboost peut s'exécuter sur un cluster hadoop avec python ? (Je ne veux pas dire pyspark)

oui, voir l'exemple posté dans le lien

quelle est la différence entre l'exécution de xgboost sur un cluster hadoop avec python et l'exécution de xgboost sur un cluster hadoop avec scala api ? Y a-t-il des différences de performances importantes ?
Je pense qu'il y a encore beaucoup de gens qui utilisent pyspark pour le modèle de production également.

@yiming-chen l'objectif de xgboost4j-spark est d'unifier l'ETL et la formation de modèles dans le même pipeline

la question se résume à quelle langue les utilisateurs utilisent-ils lors de l'ETL ? sur la base de mon observation et de mon expérience, 95% des utilisateurs construisent leur système ETL avec scala

@CodingCat Je ne sais pas d'où vous tenez votre statistique à 95%, mais PySpark est certainement largement utilisé dans mon expérience. Par exemple, nous essayons d'intégrer Airflow pour planifier le travail de notre pipeline et Python conviendrait dans cette situation.

@berch PySpark est largement utilisé par vous et vous allez vous intégrer au flux d'air... est-ce pertinent avec ce que j'ai dit ?

La communauté @CodingCat @tqchen Data Science bénéficiera certainement de l'implémentation de XGboost dans PySpark, car :

  • En général, Python est le langage n°3 en mars 2017 avec 10,2 % de popularité (contre 1,8 % pour Scala)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group ;
  • En termes de performances PySpark vs Scala, je suppose que cela n'a pas beaucoup d'importance car c'est presque tout Scala sous le capot pour Spark, n'est-ce pas ?
  • Je connais, au moins, 3 startups d'IA qui utilisent PySpark pour la production et, plus généralement, Python est beaucoup plus populaire pour les Data Scientists et en demande sur le marché du travail (
    http://r4stats.com/articles/popularity/)
    Ma conclusion : XGboost implémenté dans PySpark aura le plus grand impact pour DataScience parmi toutes les autres implémentations.
    (PS une fois stable, assurez-vous que Cloudera l'implémente)

n'hésitez pas à envoyer un PR, vous trouverez le coût

pour éviter de revenir sur le fil maintes et maintes fois, je clôturerai la discussion en concluant que

  • Je ne voterai personnellement pas pour continuer cet effort d'intégration de PySpark (pour l'instant)

  • toute autre personne est plus que bienvenue pour contribuer à ce sujet, cependant, nous devons au moins prendre en compte les éléments suivants :

    • ne pas introduire un autre paquet python

    • rétrocompatibilité avec l'API python actuelle lors de la mise en œuvre de l'intégration

    • gérer les fonctionnalités en retard du ML de pyspark

Nous ne pouvons donc pas utiliser pyspark pour charger le modèle XGBoost-spark ? @CodingCat

donc, en fait, scala XGBoost peut être enveloppé de manière moins douloureuse dans l'API PySpark JavaEstimator . J'ai joué un peu et j'ai un tel prototype :

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)

Je pense qu'il a encore besoin de travail, mais j'ai pu exécuter Xgboost dans PySpark avec.

Merci Wieslaw d'avoir partagé l'extrait de code sur le wrapper XGBoost PySpark. Pouvez-vous partager le code lors de l'appel de la classe XGBoost avec les paramètres appropriés ?

Merci

@wpopielarski c'est un travail formidable que vous avez fait. Pouvez-vous s'il vous plaît partager le code sur l'appel du XGBoost avec les paramètres nécessaires ? Ce serait d'une grande aide !

c'est quelque chose comme :

        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)

Je suis sur le point de faire un PR avec un support approprié de PySpark.

@thesuperzapper , c'est super !

Combien de temps pensez-vous qu'il faudrait pour le boucler? Partagez vos idées tout en progressant.

Merci!

salut, j'écris une version simple avec ParamGridBuilder au cas où quelqu'un serait intéressé, c'est vraiment facile de la personnaliser.

  • 1 créer un dossier de package mkdir -p ml/dmlc/xgboost4j/scala dans n'importe quel dossier PYTHONPATH valide.
  • 2 copier le code ci-dessous à 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 jouez-le comme un modèle pyspark normal !

@AakashBasuRZT @haiy , nous travaillons maintenant correctement sur ce problème dans le numéro 3370, avec le PR #3376 fournissant un support initial.

@haiy pourriez-vous me montrer un extrait de code qui correspond au classificateur sur un ensemble de données arbitraires ? J'ai suivi les points 1 et 2 que vous avez évoqués, mais je n'arrive pas à comprendre votre 3ème point.

@sagnik-rzt vérifie cet échantillon

@haiy j'essaie d'exécuter ceci :

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)

et il donne cette exception :

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'

Environnement:
Python 3.6
Étincelle 2.3
Scala 2.11

@sagnik-rzt
pas sûr, mais ajoutez-vous xgboost-spark.jar avec deps sur Spark classpath ?

@wpopielarski Hé non, je n'ai pas fait ça. Une idée où je peux trouver ce fichier jar ?

@sagnik-rzt salut, veuillez télécharger le pot ici , c'est le gros pot officiel de spark4j. . Désolé, je viens de découvrir que mon pot a été construit sur la base de mac, essayez simplement de le construire comme le suggère @wpopielarski . Et mettez-le dans le répertoire des deps d'étincelle, comme $SPARK_HOME/jars .

besoin de le construire vous-même :), avec maven et le profil assembly qui construit un gros pot en jvm-packages/xgboost-spark/target environ.

@sagnik-rzt pas sûr de ce que vous allez faire, mais pour créer un gros pot pour votre système d'exploitation, clonez simplement le projet dmlc xgboost github, cd vers jvm-packages et exécutez mvn avec le profil assemby . Je n'ai pas la moindre idée de la façon d'écrire un fichier de construction gradle.

Bon, j'ai construit un gros pot avec des dépendances, puis je l'ai copié-collé dans $ SPARK_HOME/jars.
Cependant, la même exception s'applique toujours :

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

désolé, mais vous l'exécutez sur un cluster, localement à partir d'un projet IDE ? Si vous êtes
en utilisant spark-submit, il est préférable d'ajouter deps au commutateur --jars

2018-06-29 14:30 GMT-02: sagnik-rzt [email protected] :

Bon alors j'ai construit un gros pot avec des dépendances puis je l'ai copié-collé
à $SPARK_HOME/pots.
Cependant, la même exception s'applique toujours :

Traceback (appel le plus récent en dernier) :
Fichier "/home/sagnikb/PycharmProjects/xgboost/test_import.py", ligne 21, dans
clf = xgb(params)
Fichier "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", ligne 48, dans __init__
self._java_obj = self._new_java_obj("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
Fichier "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", ligne 63, dans _new_java_obj
retourner java_obj(*java_args)
TypeError : l'objet 'JavaPackage' n'est pas appelable

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/dmlc/xgboost/issues/1698#issuecomment-401339910 , ou couper le son
le fil
https://github.com/notifications/unsubscribe-auth/ALEzS3JmKjO0AZ6JMzcixwCce0_3zRM0ks5uBh3ogaJpZM4KgAY_
.

Je travaille actuellement sur le rebasage de #3376 sur la nouvelle branche Spark. En attendant, quelques personnes ont demandé comment utiliser le code actuel sur XGBoost-0.72.

Voici un fichier zip avec le code pyspark pour XGBoost-0.72.
Télécharger : sparkxgb.zip

Tout ce que vous avez à faire est de :

  1. Ajoutez les jars et dépendances Scala XGBoost normaux à votre travail. (par exemple en utilisant --jars ou la configuration spark.jars ).
  2. Une fois le travail démarré, exécutez ceci en python : (ou n'importe quel emplacement local que chaque exécuteur peut voir)
sc.addPyFile("hdfs:///XXXX/XXXX/XXXX/sparkxgb.zip")
  1. Testez avec le code suivant. (En supposant que vous ayez déplacé sample_binary_classification_data.txt vers un endroit accessible, c'est normalement dans $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")

Noter:

  • Cela ne fonctionnera que pour Spark 2.2+
  • Les pipelines et ParamGridBuilder sont en quelque sorte pris en charge, utilisez l'objet pipeline modifié avec from sparkxgb.pipeline import XGBoostPipeline,XGBoostPipelineModel comme vous le feriez avec les objets normaux.
  • Vous devez utiliser float("+inf") pour les valeurs manquantes plutôt que float("nan") pour que les valeurs nulles soient traitées correctement en raison d'une erreur dans XGboost-0.72.
  • Vous ne pouvez pas recharger des objets de modèle non entraînés (voir #3035)
  • Cette API changera avec une version complète de la prise en charge de pyspark.

@thesuperzapper J'essaie de tester cela avec pyspark sur le cahier jupyter.

Mon système :
python 3.6.1
xgboost 0,72
étincelle 2.2.0
java 1.8
échelle 2.12

Lorsque j'essaie de charger XGBoostEstimator, j'obtiens :

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

Est-ce un bug ou ai-je raté certaines exigences ?

@BogdanCojocar Il semble que la bibliothèque xgboost vous manque.

Vous avez besoin de ces deux pots pour que xgboost fonctionne correctement :

Vous pouvez télécharger les pots requis à partir de ces liens maven.

Merci @thesuperzapper. Fonctionne bien. Excellent travail avec cette intégration à pyspark !

Une suggestion sur la façon d'enregistrer le modèle entraîné dans le booster pour le chargement dans le module python ?

@ericwang915 Généralement, pour obtenir un modèle qui interagit avec d'autres bibliothèques XGBoost, vous utiliserez la méthode .booster.saveModel("XXX/XXX") sur l'objet modèle, où XXX est un chemin local (non HDFS) sur le pilote Spark. Si vous utilisez une autre méthode d'enregistrement, vous obtenez une erreur (Voir : #2480)

Cependant, j'ai oublié d'ajouter une méthode pour appeler la fonction de sauvegarde dans cette version du wrapper, je le ferai demain si j'ai le temps. (Je vis en NZ... donc les fuseaux horaires)

Merci. Soit dit en passant, pendant le processus de formation, il n'y a pas de journal indiquant les métriques d'évaluation et le cycle de boost, même si le silence est défini sur 1.

@thesuperzapper merci pour les instructions. J'ai pu suivre vos instructions pour entraîner/enregistrer le modèle xgboost dans pyspark. Une idée sur la façon d'accéder à d'autres fonctions de modèle xgboost comme (scala) getFeatureScore () ?

@ccdtzccdtz actuellement, je recâble le wrapper pyspark puisque la version 0.8 a apporté des modifications massives à l'API Spark, une fois terminé, je vise à avoir la parité des fonctionnalités avec l'API Spark Scala.

Je n'ai pas exposé la méthode native booster dans mon wrapper pyspark initial, mais si vous utilisez l'API Spark Scala, vous pouvez appeler xgboost_model_object.nativeBooster.getFeatureScore( et l'utiliser comme d'habitude.

J'ai vu XGBoost sur pyspark échouer systématiquement s'il est exécuté 2 fois ou plus. Je l'exécute sur le même ensemble de données avec le même code. La première fois, cela réussit, mais la deuxième fois et par la suite, cela échoue. J'utilise XGBoost 0.72 sur Spark 2.3. Je dois redémarrer le shell pyspark pour exécuter à nouveau le travail avec succès.

J'utilise xgboost.trainWithDataFrame à des fins de formation.

Quelqu'un a-t-il déjà vu ce problème?

Salut @thesuperzapper
Ce que vous avez prescrit fonctionne pour moi sur un seul nœud de travail.
Cependant, lorsque j'essaie d'exécuter pyspark xgboost sur plusieurs utilisateurs (3 dans ce cas), les exécuteurs deviennent inactifs et s'arrêtent après un certain temps.
Voici le code que j'essaie d'exécuter sur le jeu de données Titanic (qui est un petit jeu de données) :

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)

Voici la trace de la pile :
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)

L'exécuteur est bloqué sur :
org.apache.spark.RDD.foreachPartition(RDD.scala:927) ml.dmlc.xgboost4j.scala.spark.XGBoost$$anonfun$trainDistributed$4$$anon$1.run(XGBoost.scala:348)

Environnement : Python 3.5.4, Spark Version 2.3.1, Xgboost 0.72

Pouvez-vous partager vos configurations xgboost et spark ? Combien
travailleurs (travailleurs xgboost), exécuteurs d'étincelles, noyaux, etc.

-Nitine

Le mardi 4 septembre 2018 à 5h03, sagnik-rzt [email protected] a écrit :

Salut @thesuperzapper https://github.com/thesuperzapper
Ce que vous avez prescrit fonctionne pour moi sur un seul nœud de travail.
Cependant, lorsque j'essaie d'exécuter pyspark xgboost sur un en utilisant plus d'un
travailleur, les exécuteurs testamentaires deviennent inactifs et s'arrêtent après un certain temps.
Voici la trace de la pile :
'''
Tracker démarré, avec 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 ERREUR
TaskSche dulerImpl:70 - Exécuteur perdu 0 sur 192.168.49.43 : RPC distant
client dissocié. Probablement en raison de conteneurs dépassant les seuils, ou
problèmes de réseau. Vérifiez les journaux du pilote pour les messages WARN.2018-09-04 08:52:55
ERREUR AsyncE ventQueue:91 - Interrompu lors de la publication sur TaskFailedListener.
Suppression de cette listener.java.lang.InterruptedException : ExecutorLost pendant
Formation XGBoost : ExecutorLostFailure (l'exécuteur 0 s'est arrêté en raison de l'un des
les tâches en cours) Raison : Client RPC distant dissocié. Probablement en raison de
conteneurs dépassant les seuils ou problèmes de réseau. Vérifiez les journaux du pilote pour
Messages d'AVERTISSEMENT. à
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)
sur org.apache.spark.util.ListenerBus$class.postToAll(ListenerBus.scala:91)
'''

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/dmlc/xgboost/issues/1698#issuecomment-418341557 , ou couper le son
le fil
https://github.com/notifications/unsubscribe-auth/AJY-XklxsZB_FE7ZoAarV_fqw8D3JqxWks5uXmwqgaJpZM4KgAY_
.

@sagnik-rzt Je suis surpris que cela fonctionne, car ce wrapper pyspark ne prend en charge que XGboost 0.72, nous travaillons toujours sur celui 0.8.

@thesuperzapper , en fonction de la version que vous avez fournie, j'ai refait certaines parties pour prendre en charge xgboost 0.80.
Cependant, je me retrouve avec une erreur py4j.protocol.Py4JError: ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier does not exist in the JVM . J'ai fourni une description complète ici . Pourriez-vous jeter un oeil?

Tous les codes sont placés ici .

Il y a beaucoup plus de changements nécessaires que vous n'en avez apportés pour le faire fonctionner avec 0.8.

La principale raison pour laquelle je ne viens pas de sortir une version 0.8, c'est parce que je ne veux vraiment pas créer un objet de pipeline spécifique à xgboost comme je l'ai dans la 0.72, je travaille sur un moyen, espérons-le, de faire fonctionner l'objet pyspark xgboost avec la persistance de pipeline par défaut.

@thesuperzapper , tout en utilisant les codes pour 0.72, j'ai utilisé l'objet XGBoostEstimator directement c'est-à-dire sans utiliser l'objet XGBoostPipeline . Et ce faisant, j'ai remarqué que la formation/l'adaptation n'est pas répartie entre les travailleurs du cluster. Est-il nécessaire d'utiliser le XGBoostPipeline pour la distribution entre les travailleurs ?

Si ce n'est pas le cas, savez-vous pourquoi la formation n'est pas répartie entre les travailleurs ?

Mettre à jour
J'ai essayé la formation en définissant XGBoostEstimator comme étape dans XGBoostPipeline mais le problème persiste. La formation n'est pas distribuée entre les travailleurs lorsque je l'exécute sur le cluster, contrairement aux autres modèles pris en charge par pyspark.

Avez-vous observé ce comportement ? Comment puis-je l'aborder?

J'ai principalement re-codé le wrapper pour XGBoost 0.8, mais comme mon cluster de travail est toujours sur 2.2, je ne peux pas le tester facilement en mode distribué, car mon cluster Dockerized Spark 2.3 ne peut même pas former les modèles distribués Scala XGBoost sans obtenir des problèmes de localisation aléatoire manquants .

Je pense que les problèmes rencontrés par @sagnik-rzt et d'autres sont liés à la configuration de votre cluster ou à un problème plus profond avec Spark-Scala XGBoost.

Êtes-vous capable d'entraîner un modèle dans Spark-Scala XGBoost ?

Merci @thesuperzapper , je pensais que les emplacements de ce post de stackoverflow donc je mettrai en œuvre ces suggestions.

Aussi, pourriez-vous partager votre version 0.8, si elle est prête ? Je peux tester la distribution sur mon cluster. Il a spark 2.3.1 et python 3.5.

après avoir enregistré le modèle et chargé l'erreur suivante

IllegalArgumentException : u'requirement a échoué : erreur de chargement des métadonnées : nom de classe attendu org.apache.spark.ml.Pipeline mais nom de classe trouvé org.apache.spark.ml.PipelineModel'

pouvez-vous s'il vous plaît aider avec cela. Merci

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)

J'ai essayé l'option suivante

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

Obtention de l'erreur suivante

Aucun module nommé ml.dmlc.xgboost4j.scala.spark

LIEN DE TÉLÉCHARGEMENT DE DÉVELOPPEMENT : sparkxgb.zip

Cette version fonctionnera avec XGBoost-0.8, mais veuillez ne pas l'utiliser pour autre chose que des tests ou contribuer à ce fil, car les choses vont changer.
(Notez également : j'ai supprimé tous les backports pour Spark 2.2, cela ne prend donc en charge que Spark 2.3)

Le principal problème que je connais avec cette version est que les modèles de classification ne se rechargent pas après avoir été enregistrés, ce qui donne l'erreur : TypeError: 'JavaPackage' object is not callable . Cependant, étrangement, XGBoostPipelineModel fonctionne très bien avec une étape de classification XGBoost. Cela m'amène à penser que c'est un problème de mon côté, quelqu'un peut-il vérifier si la lecture des modèles de classification fonctionne pour eux ?

Quoi qu'il en soit, j'essaie d' implémenter correctement XGBoostPipeline dédié, ce qui sera beaucoup plus facile à maintenir à long terme, donc le problème de lecture/écriture devrait devenir de toute façon hors de propos. (Cela pourrait également permettre à la persistance sur CrossValidator de fonctionner)

Cette page vous a été utile?
0 / 5 - 0 notes