Xgboost: [DISCUSIÓN] Integración con PySpark

Creado en 25 oct. 2016  ·  53Comentarios  ·  Fuente: dmlc/xgboost

Acabo de notar que hay algunas solicitudes de integración con PySpark http://dmlc.ml/2016/03/14/xgboost4j-portable-distributed-xgboost-in-spark-flink-and-dataflow.html

También recibí algunos correos electrónicos de los usuarios discutiendo el mismo tema.

Me gustaría iniciar una discusión aquí sobre si / cuándo comenzaremos este trabajo

@tqchen @terrytangyuan

python

Comentario más útil

@CodingCat @tqchen La comunidad de ciencia de datos definitivamente se beneficiará de la implementación de XGboost en PySpark, porque:

  • En general, Python es el idioma n. ° 3 a marzo de 2017 con un 10,2% de popularidad (frente al 1,8% de Scala)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group;
  • En términos de rendimiento PySpark vs Scala, supongo que no importa tanto porque es casi todo Scala bajo el capó para Spark, ¿verdad?
  • Conozco, al menos, 3 empresas emergentes de IA que utilizan PySpark para la producción y, de manera más general, Python es mucho más popular para los científicos de datos y tiene más demanda en el mercado laboral (
    http://r4stats.com/articles/popularity/)
    Mi conclusión: XGboost implementado en PySpark tendrá el mayor impacto para DataScience entre todas las demás implementaciones.
    (PD una vez estable, asegúrese, Cloudera lo implementa)

Todos 53 comentarios

@CodingCat ¿Sabes cuán grande es la comunidad PySpark? La mayoría de la gente solo usa la API de Scala. Parece que es necesario volver a implementar muchas cosas en Python; corríjame si me equivoco.

Creo que PySpark es bastante frecuente en la comunidad de científicos de datos, es decir, en el escenario de creación rápida de prototipos, etc. Escuché de muchos casos en los que los científicos de datos usan pySpark para analizar grandes volúmenes de datos.

Por otro lado, la mayoría de los escenarios a nivel de producción se basan en la API de Scala (solo conozco un caso en el que las personas están usando PySpark en una producción a gran escala)

Sí, siento que la API de Python actual debería poder manejar la mayoría de las necesidades de creación de prototipos. Personalmente, me preocupo más por Spark cuando queremos más cosas listas para producción. Quizás deberíamos dejar la discusión aquí para que la gente pueda discutir sus necesidades. Mientras tanto, sería fantástico si pudiera proporcionar algunos detalles sobre enfoques / estimaciones / pasos para la integración.

acabo de notar algunas discusiones en la comunidad

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

parece que el desarrollo de PySpark se está quedando atrás ... como la biblioteca descendente, voto a hold on para dedicarlo a la integración de PySpark .....

Sí, también es difícil depurar cualquier problema que haya encontrado (al menos cuando lo intenté el año pasado) ...

En la hoja de ruta (# 873), dijo que se implementó Python distribuido. ¿Significa que xgboost puede ejecutarse en un clúster hadoop con python? (No me refiero a pyspark)

sí, vea el ejemplo publicado en el enlace

¿Cuál es la diferencia entre ejecutar xgboost en el clúster hadoop con python y ejecutar xgboost en el clúster hadoop con scala api? ¿Existen diferencias importantes en el rendimiento?
Creo que todavía hay mucha gente que usa pyspark para el modelo de producción.

@ yiming-chen el objetivo de xgboost4j-spark es unificar ETL y el entrenamiento de modelos en la misma canalización

la pregunta se reduce a ¿qué idioma usan los usuarios al hacer ETL? Según mi observación y experiencia, el 95% de los usuarios están construyendo su sistema ETL con scala.

@CodingCat No sé de dónde

@berch PySpark es ampliamente utilizado por usted y lo integrará con el flujo de aire ... ¿es relevante con lo que dije?

@CodingCat @tqchen La comunidad de ciencia de datos definitivamente se beneficiará de la implementación de XGboost en PySpark, porque:

  • En general, Python es el idioma n. ° 3 a marzo de 2017 con un 10,2% de popularidad (frente al 1,8% de Scala)
    http://redmonk.com/sogrady/2017/03/17/language-rankings-1-17/
    https://jobsquery.it/stats/language/group;
  • En términos de rendimiento PySpark vs Scala, supongo que no importa tanto porque es casi todo Scala bajo el capó para Spark, ¿verdad?
  • Conozco, al menos, 3 empresas emergentes de IA que utilizan PySpark para la producción y, de manera más general, Python es mucho más popular para los científicos de datos y tiene más demanda en el mercado laboral (
    http://r4stats.com/articles/popularity/)
    Mi conclusión: XGboost implementado en PySpark tendrá el mayor impacto para DataScience entre todas las demás implementaciones.
    (PD una vez estable, asegúrese, Cloudera lo implementa)

no dude en enviar un PR, encontrará el costo

Para evitar volver al hilo una y otra vez, cerraré la discusión con la conclusión de que

  • Personalmente, no votaré para continuar con este esfuerzo para integrar PySpark (por ahora)

  • cualquier otra persona es más que bienvenida para contribuir en esto, sin embargo, debemos al menos considerar las siguientes cosas:

    • no introduzca otro paquete de Python

    • compatibilidad con versiones anteriores de la API de Python actual cuando se implementa la integración

    • manejar las características rezagadas del ML de pyspark

¿Entonces no podemos usar pyspark para cargar el modelo XGBoost-spark? @CodingCat

entonces, en realidad scala XGBoost puede ser envuelto de manera más menos dolorosa en PySpark JavaEstimator API. Jugué un poco y tengo ese prototipo:

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)

Creo que todavía necesita algo de trabajo, pero pude ejecutar Xgboost en PySpark con él.

Wieslaw agradece por compartir el fragmento de código en el contenedor XGBoost PySpark. ¿Puede compartir el código al invocar la clase XGBoost con los parámetros apropiados?

Gracias

@wpopielarski , es un trabajo increíble que hiciste. ¿Puede compartir el código al invocar XGBoost con los parámetros necesarios? ¡Eso sería de gran ayuda!

esto es algo como:

        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)

Me estoy acercando a hacer un PR con el soporte adecuado de PySpark.

@thesuperzapper , ¡eso es genial!

¿Cuánto tiempo crees que tomaría terminarlo? Comparta ideas mientras progresa.

¡Gracias!

hola, escribo una versión simple con ParamGridBuilder en caso de que alguien esté interesado, es muy fácil de personalizar.

  • 1 cree un directorio de paquete mkdir -p ml/dmlc/xgboost4j/scala en cualquier directorio PYTHONPATH válido.
  • 2 copie el código de abajo a 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 ¡juega como un modelo normal de pyspark!

@AakashBasuRZT @haiy , ahora estamos trabajando en esto correctamente en el número 3370, con PR # 3376 proporcionando soporte inicial.

@haiy, ¿ podría mostrarme un fragmento de código que se ajuste al clasificador en algún conjunto de datos arbitrario? He seguido los puntos 1 y 2 que ha descrito, pero no puedo comprender su tercer punto.

@ sagnik-rzt revisa esta muestra

@haiy estoy tratando de ejecutar esto:

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)

y está dando esta excepción:

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'

Ambiente:
Python 3.6
Spark 2.3
Scala 2.11

@ sagnik-rzt
no estoy seguro, pero ¿agrega xgboost-spark.jar con deps en spark classpath?

@wpopielarski Oye, no, no he hecho eso. ¿Alguna idea de dónde puedo encontrar ese archivo jar?

@ sagnik-rzt hola, descargue el frasco aquí , es el frasco gordo oficial de spark4j. . Lo siento, acabo de descubrir que mi jar se creó en base a mac, solo intente construirlo como sugiere @wpopielarski . Y póngalo en el directorio Spark deps, como $SPARK_HOME/jars .

necesita construirlo por su cuenta :), con maven y el perfil assembly que construye fat jar en jvm-packages/xgboost-spark/target o menos.

@ sagnik-rzt no estoy seguro de lo que vas a hacer, pero para construir fat jar para tu sistema operativo simplemente clona dmlc xgboost github project, cd to jvm-packages y ejecuta mvn con assemby profile. No tengo la menor idea de cómo escribir un archivo de compilación de Gradle.

Bien, he construido un frasco gordo con dependencias y luego lo he copiado y pegado en $ SPARK_HOME / jars.
Sin embargo, la misma excepción sigue vigente:

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

lo siento, pero ¿lo ejecuta en un clúster, localmente desde algún proyecto IDE? Si usted es
usando spark-submit es mejor agregar deps a --jars switch

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

Bien, he construido un frasco gordo con dependencias y luego lo he copiado y pegado
a $ SPARK_HOME / jars.
Sin embargo, la misma excepción sigue vigente:

Rastreo (llamadas recientes más última):
Archivo "/home/sagnikb/PycharmProjects/xgboost/test_import.py", línea 21, en
clf = xgb (params)
Archivo "/usr/lib/ml/dmlc/xgboost4j/scala/spark.py", línea 48, en __init__
self._java_obj = self._new_java_obj ("dmlc.xgboost4j.scala.spark.XGBoostEstimator", self.uid, scalaMap)
Archivo "/usr/local/lib/python3.6/dist-packages/pyspark/ml/wrapper.py", línea 63, en _new_java_obj
return java_obj (* java_args)
TypeError: el objeto 'JavaPackage' no es invocable

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/dmlc/xgboost/issues/1698#issuecomment-401339910 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/ALEzS3JmKjO0AZ6JMzcixwCce0_3zRM0ks5uBh3ogaJpZM4KgAY_
.

Actualmente estoy trabajando en cambiar la base del número 3376 a la nueva rama Spark. Mientras tanto, algunas personas han preguntado cómo usar el código actual en XGBoost-0.72.

Aquí hay un archivo zip con el código pyspark para XGBoost-0.72.
Descargar: sparkxgb.zip

Todo lo que necesitas hacer es:

  1. Agregue los archivos jar y las dependencias normales de Scala XGBoost a su trabajo. (por ejemplo, usando --jars o la configuración spark.jars ).
  2. Una vez que el trabajo ha comenzado, ejecute esto en Python: (O cualquier ubicación local que todos los ejecutores puedan ver)
sc.addPyFile("hdfs:///XXXX/XXXX/XXXX/sparkxgb.zip")
  1. Prueba con el siguiente código. (Suponiendo que haya movido sample_binary_classification_data.txt a una ubicación accesible, normalmente está en $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")

Nota:

  • Esto solo funcionará para Spark 2.2+
  • Pipelines y ParamGridBuilder son compatibles, use el objeto de canalización modificado con from sparkxgb.pipeline import XGBoostPipeline,XGBoostPipelineModel como lo haría con los objetos normales.
  • Debe usar float ("+ inf") para los valores perdidos en lugar de float ("nan") para que los valores nulos se traten correctamente debido a un error en XGboost-0.72.
  • No puede volver a cargar objetos de modelo no entrenados (consulte el n. ° 3035)
  • Esta API cambiará con una versión completa del soporte de pyspark.

@thesuperzapper Estoy tratando de probar esto con pyspark en el cuaderno jupyter.

Mi sistema:
pitón 3.6.1
xgboost 0,72
chispa 2.2.0
java 1.8
scala 2.12

Cuando intento cargar el XGBoostEstimator obtengo:

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

¿Es esto un error o me faltan algunos requisitos?

@BogdanCojocar Parece que te falta la biblioteca xgboost.

Necesita estos dos frascos para que xgboost funcione correctamente:

Puede descargar los frascos necesarios desde esos enlaces de Maven.

Gracias @thesuperzapper. Funciona bien. ¡Buen trabajo con esta integración a pyspark!

¿Alguna sugerencia sobre cómo guardar el modelo entrenado en un refuerzo para cargarlo en el módulo de Python?

@ ericwang915 Normalmente, para obtener un modelo que interactúe con otras bibliotecas XGBoost, usaría el método .booster.saveModel("XXX/XXX") en el objeto del modelo, donde XXX es una ruta local (no HDFS) en el controlador Spark. Si usa otro método de guardado, obtiene un error (Ver: # 2480)

Sin embargo, olvidé agregar un método para llamar a la función de guardar en esa versión del contenedor, haré esto mañana si tengo tiempo. (Vivo en Nueva Zelanda ... entonces zonas horarias)

Gracias. Por cierto, durante el proceso de entrenamiento, no hay un registro que muestre las métricas de evaluación y la ronda de impulso aunque el silencio esté configurado como 1.

@thesuperzapper gracias por la instrucción. Pude seguir sus instrucciones para entrenar / guardar el modelo xgboost en pyspark. ¿Alguna idea sobre cómo acceder a otra función del modelo xgboost como (scala) getFeatureScore ()?

@ccdtzccdtz actualmente estoy recableando el contenedor pyspark ya que 0.8 tuvo cambios masivos en la API de Spark, cuando termine, mi objetivo es tener paridad de características con la API de Spark Scala.

No expuse el método de refuerzo nativo en mi envoltorio pyspark inicial, pero si usa la API Spark Scala, puede llamar a xgboost_model_object.nativeBooster.getFeatureScore( y usarlo como de costumbre.

He visto que XGBoost en pyspark falla constantemente si se ejecuta 2 o más veces. Lo estoy ejecutando en el mismo conjunto de datos con el mismo código. La primera vez tiene éxito, pero la segunda y posteriormente fracasa. Estoy usando XGBoost 0.72 en Spark 2.3. Tengo que reiniciar el shell pyspark para ejecutar el trabajo correctamente nuevamente.

Utilizo xgboost.trainWithDataFrame con fines de entrenamiento.

¿Alguien ha visto este problema?

Hola @thesuperzapper
Lo que prescribiste funciona para mí en un solo nodo trabajador.
Sin embargo, cuando intento ejecutar pyspark xgboost en un uso de más de un trabajador (3 en este caso), los ejecutores quedan inactivos y se apagan después de un tiempo.
Este es el código que intento ejecutar en el conjunto de datos del Titanic (que es un conjunto de datos pequeño):

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)

Este es el seguimiento de la pila:
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)

El ejecutor está atascado en:
org.apache.spark.RDD.foreachPartition(RDD.scala:927) ml.dmlc.xgboost4j.scala.spark.XGBoost$$anonfun$trainDistributed$4$$anon$1.run(XGBoost.scala:348)

Entorno: Python 3.5.4, Spark versión 2.3.1, Xgboost 0.72

¿Puedes compartir tus configuraciones de xgboost y spark? Cuántos
trabajadores (trabajadores xgboost), ejecutores de chispas, núcleos, etc.

-Nitina

El martes 4 de septiembre de 2018 a las 5:03 a.m. sagnik-rzt [email protected] escribió:

Hola @thesuperzapper https://github.com/thesuperzapper
Lo que prescribiste funciona para mí en un solo nodo trabajador.
Sin embargo, cuando trato de ejecutar pyspark xgboost en un uso de más de uno
trabajador, los ejecutores quedan inactivos y se apagan después de un tiempo.
Este es el seguimiento de la pila:
'' '
El rastreador se inició, con 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
TaskSche dulerImpl: 70 - Ejecutor perdido 0 en 192.168.49.43: RPC remoto
cliente disociado. Probablemente debido a que los contenedores exceden los umbrales, o
problemas de red. Compruebe los registros del controlador para ver si hay mensajes WARN. 2018-09-04 08:52:55
ERROR AsyncE ventQueue: 91 - Se interrumpió al publicar en TaskFailedListener.
Eliminando ese listener.java.lang.InterruptedException: ExecutorLost durante
Entrenamiento de XGBoost: ExecutorLostFailure (ejecutor 0 salió debido a uno de
las tareas en ejecución) Motivo: Cliente RPC remoto desasociado. Probablemente debido a
contenedores que superan los umbrales o problemas de red. Compruebe los registros del conductor para
Mensajes de ADVERTENCIA. en
org.apache.spark.TaskFailedListener.onTaskEnd (SparkParallelismTracker.scala: 116)
en
org.apache.spark.scheduler.SparkListenerBus $ class.doPostEvent (SparkListenerBus.scala: 45)
en
org.apache.spark.scheduler.AsyncEventQueue.doPostEvent (AsyncEventQueue.scala: 37)
en
org.apache.spark.scheduler.AsyncEventQueue.doPostEvent (AsyncEventQueue.scala: 37)
en org.apache.spark.util.ListenerBus $ class.postToAll (ListenerBus.scala: 91)
'' '

-
Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/dmlc/xgboost/issues/1698#issuecomment-418341557 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AJY-XklxsZB_FE7ZoAarV_fqw8D3JqxWks5uXmwqgaJpZM4KgAY_
.

@ sagnik-rzt Me sorprende que funcione, ya que ese contenedor pyspark solo admite XGboost 0.72, todavía estamos trabajando en el 0.8.

@thesuperzapper , según la versión que proporcionó, rehice algunas partes para admitir xgboost 0.80.
Sin embargo, estoy terminando con un error py4j.protocol.Py4JError: ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier does not exist in the JVM . He proporcionado una descripción completa aquí . ¿Podrías echar un vistazo?

Todos los códigos se colocan aquí .

Se necesitan muchos más cambios de los que ha realizado para que funcione con 0.8.

La razón principal por la que no acabo de sacar una versión 0.8 es porque realmente no quiero hacer un objeto de canalización específico de xgboost como el que tengo en el 0.72, estoy trabajando en una manera de que, con suerte, el objeto pyspark xgboost funcione con la persistencia de canalización predeterminada.

@thesuperzapper , mientras usaba los códigos para 0.72, usé el objeto XGBoostEstimator directamente, es decir, sin usar el objeto XGBoostPipeline . Y mientras lo hacía, noté que la capacitación / adaptación no se distribuye entre los trabajadores del clúster. ¿Es necesario utilizar XGBoostPipeline para la distribución entre los trabajadores?

Si ese no es el caso, ¿sabe por qué la capacitación no se distribuye entre los trabajadores?

Actualizar
Probé el entrenamiento configurando XGBoostEstimator como etapa en XGBoostPipeline pero el problema persiste. La capacitación no se distribuye entre los trabajadores cuando la ejecuto en el clúster, mientras que lo hace con otros modelos compatibles con pyspark.

¿Ha observado este comportamiento? ¿Cómo lo abordo?

En su mayoría, he vuelto a codificar el contenedor para XGBoost 0.8, pero como mi clúster de trabajo todavía está en 2.2, no puedo probarlo fácilmente en modo distribuido, ya que mi clúster Dockerized Spark 2.3 ni siquiera puede entrenar modelos distribuidos de Scala XGBoost sin tener problemas de ubicación aleatoria. .

Creo que los problemas que están experimentando @ sagnik-rzt y otros están relacionados con la configuración de su clúster o algún problema más profundo con Spark-Scala XGBoost.

¿Puede entrenar un modelo en Spark-Scala XGBoost?

Gracias @thesuperzapper , pensé que las ubicaciones de reproducción aleatoria se manejaban internamente, es decir, se ocuparía de ellas independientemente de la configuración del clúster. Pero encontré esta publicación de stackoverflow, así que implementaré esas sugerencias.

Además, ¿podría compartir su versión 0.8, si está lista? Puedo probar la distribución en mi clúster. Tiene Spark 2.3.1 y Python 3.5.

después de guardar el modelo y cargar obteniendo el siguiente error

IllegalArgumentException: error en el requisito u: Error al cargar metadatos: nombre de clase esperado org.apache.spark.ml.Pipeline pero se encontró el nombre de clase org.apache.spark.ml.PipelineModel '

¿Podrías ayudarme con esto? Gracias

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)

Probé la siguiente opción

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

Obteniendo el siguiente error

Ningún módulo llamado ml.dmlc.xgboost4j.scala.spark

ENLACE DE DESCARGA DE DESARROLLO : sparkxgb.zip

Esta versión funcionará con XGBoost-0.8, pero no la use para nada más que probar o contribuir a este hilo, ya que las cosas cambiarán.
(También tenga en cuenta: he eliminado todos los puertos posteriores para Spark 2.2, por lo que solo es compatible con Spark 2.3)

El problema principal que conozco con esa versión es que los modelos de clasificación no se cargan nuevamente después de ser guardados, dando el error: TypeError: 'JavaPackage' object is not callable . Sin embargo, extrañamente XGBoostPipelineModel funciona bien con una etapa de clasificación XGBoost. Esto me lleva a pensar que es un problema de mi parte, ¿alguien puede verificar si la lectura de modelos de clasificación funciona para ellos?

Independientemente, estoy intentando implementar DefaultParamsWritable correctamente, lo que eliminaría la necesidad del XGBoostPipeline dedicado, que será mucho más fácil de mantener a largo plazo, por lo que el problema de lectura / escritura debería volverse irrelevante de todos modos. (Esto también podría permitir que funcione la persistencia en CrossValidator)

¿Fue útil esta página
0 / 5 - 0 calificaciones