Hola, soy autor de Dask , una biblioteca para computación paralela y distribuida en Python. Tengo curiosidad por saber si hay interés dentro de esta comunidad para colaborar en la distribución de XGBoost en Dask, ya sea para capacitación paralela o para ETL.
Probablemente hay dos componentes de Dask que son relevantes para este proyecto:
¿Hay interés en colaborar aquí?
@mrocklin Pensé que Dask tiene integraciones con sklearn. ¿Le echaste un vistazo a nuestro envoltorio sklearn para ver si funciona con eso?
La integración significativa con un sistema distribuido generalmente debe realizarse a nivel de algoritmo en lugar de a nivel de biblioteca. Hay algunas formas en las que SKLearn y Dask pueden ayudarse mutuamente, sí, pero no son particularmente profundas.
El marco de datos Dask sería un buen comienzo. En nuestra base de código, tenemos una verificación para el marco de datos de pandas. Ahí podría ser donde el marco de datos dask encajaría como un comienzo.
Entonces, ¿qué sucede si alguien llega con un marco de datos dask de varios terabytes? ¿Simplemente lo convierte a Pandas y continúa? ¿O hay alguna manera de paralelizar XGBoost de forma inteligente en un clúster, apuntando a los diversos marcos de datos de pandas que componen un marco de datos dask?
¿Los usuarios pueden especificar el tamaño del lote? Me imagino que los usuarios pueden beneficiarse a través de shared_fit.
cc @tqchen que está más familiarizado con la parte distribuida del código.
La versión distribuida de xgboost se puede conectar a un lanzador de trabajos distribuidos, lo ideal es obtener la alimentación de la partición de datos en xgboost y luego continuar.
@mrocklin Creo que la parte más relevante es el módulo xgboost-spark y xgboost-flink, que incorpora xgboost en la función mapPartition de spark/flink. Supongo que habría algo similar en Dask.
El requisito del lado de xgboost es que XGBoost maneje la conexión entre procesos por rabit, y deberá iniciar un rastreador (que conecta cada trabajo) desde el lado del cliente.
consulte el código relevante en https://github.com/dmlc/xgboost/blob/master/jvm-packages/xgboost4j-spark/src/main/scala/ml/dmlc/xgboost4j/scala/spark/XGBoost.scala#L112
Rabit está diseñado para integrarse en otro sistema distribuido, por lo que creo que no sería demasiado difícil hacer el ajuste en el lado de Python.
Lanzar otros sistemas distribuidos desde Dask suele ser bastante factible. ¿Cómo se mueven los datos del sistema distribuido de alojamiento (spark/flink/dask) a xg-boost? ¿O es esto para entrenamiento distribuido en datos pequeños?
Más concretamente, espero construir un sistema de la siguiente manera:
¿Coincide esto con sus expectativas? ¿Es fácil para usted señalarme la API de Python relevante?
Sí, consulte la información relevante aquí https://github.com/dmlc/xgboost/blob/master/tests/distributed/ para la API de python.
Lo que deberá hacer adicionalmente es iniciar un rastreador de rabit en el lado del conductor (probablemente sea el lugar que conduce dask), esto se hace en el script dmlc-submit aquí https://github.com/dmlc/dmlc-core /árbol/maestro/rastreador/dmlc_tracker
OK, completando mi esquema de antes:
En el nodo controlador/programador iniciamos un rastreador de conejos
envs = {'DMLC_NUM_WORKER' : nworker,
'DMLC_NUM_SERVER' : nserver}
rabit = RabitTracker(hostIP=ip_address, nslave=num_workers)
envs.update(rabit.slave_envs())
rabit.start(args.num_workers) # manages connections in background thread
También puedo pasar por un proceso similar para iniciar un PSTracker
. ¿Debería estar en la misma máquina centralizada o debería estar en otro lugar dentro de la red? ¿Debería haber algunos de estos? ¿Debería ser configurable por el usuario?
Finalmente, hago que mi rastreador (¿y ptrackers?) se unan a la red rabit y bloqueen.
rabit.join() # join network
En los nodos de trabajo, necesito volcar estas variables de entorno (que moveré a través de los canales de escritorio normales) en el entorno local. Entonces solo llamar a xgboost.rabit.init()
debería ser suficiente
import os
os.environ.update(envs)
xgboost.rabit.init()
Mirando el código de Rabit, parece que las variables de entorno son la única forma de proporcionar esta información. ¿Puedes verificar esto? ¿Hay alguna manera de proporcionar información de host/puerto de rastreador como entradas directas?
Luego convierto mis arreglos numpy / marcos de datos pandas / arreglos dispersos scipy en objetos DMatrix, esto parece relativamente sencillo. Sin embargo, es probable que tenga varios lotes de datos por trabajador. ¿Existe una forma limpia de llamar al tren varias veces con más datos a medida que estén disponibles? Me preocupan los comentarios en estas líneas:
# Run training, all the features in training API is available.
# Currently, this script only support calling train once for fault recovery purpose.
bst = xgb.train(param, dtrain, num_round, watchlist, early_stopping_rounds=2)
¿Tenemos que esperar a que lleguen todos los datos antes de empezar a entrenar?
Suponiendo que tengo todo lo anterior correcto, ¿existe un ejemplo de capacitación distribuida estándar que la gente use para la demostración?
No es necesario iniciar pstracker.
Tuve algo de tiempo para jugar con esto esta mañana. Resultados aquí: https://github.com/mrocklin/dask-xgboost
Hasta ahora, solo maneja el aprendizaje distribuido de un solo conjunto de datos en memoria. Surgieron algunas preguntas:
rabit.init
? ¿Cuál es exactamente la forma esperada de las entradas de rabit.init
? Pasar el resultado de slave_envs()
a rabit.init obviamente no funcionará porque espera una lista. ¿Deberíamos convertir cada nombre clave a --key
, tal vez eliminando el prefijo DMLC
y convirtiéndolo a minúsculas?rabit.init(['DMLC_KEY1=VALUE1', 'DMLC_KEY2=VALUE2']
Dos preguntas más en general sobre cómo se usa esto (no tengo experiencia con XGBoost y solo un poco de experiencia con el aprendizaje automático, perdone mi ignorancia).
¿Qué caso de uso es más común?
Cada trabajo debe funcionar en una partición diferente de datos (por filas), NO deben mirar los mismos datos de entrada.
Esto normalmente corresponde a la operación mapPartition en marcos como spark/flink
Digamos que mi conjunto de datos tiene 8 filas, 4 columnas, si comenzamos con dos trabajadores
Bien, lo que hay ahora está un poco más limpio. Sería bueno si tuviéramos alguna capacidad para consumir los resultados a medida que se generaron en cada trabajador, pero por ahora lo hemos solucionado. Aquí está la solución actual:
Esta solución parece ser manejable, pero no es ideal. Sería conveniente que xgboost-python pudiera aceptar los resultados tal como llegaron. Sin embargo, creo que lo siguiente que debe hacer es probarlo en la práctica.
Voy a buscar en Internet ejemplos. Si alguien tiene un problema artificial que puedo generar fácilmente con la API numpy o pandas, sería bienvenido. Hasta entonces, aquí hay un ejemplo trivial en mi computadora portátil con datos aleatorios:
In [1]: import dask.dataframe as dd
In [2]: df = dd.demo.make_timeseries('2000', '2001', {'x': float, 'y': float, 'z': int}, freq='1s', partition_freq=
...: '1D') # some random time series data
In [3]: df.head()
Out[3]:
x y z
2000-01-01 00:00:00 0.778864 0.824796 977
2000-01-01 00:00:01 -0.019888 -0.173454 1023
2000-01-01 00:00:02 0.552826 0.051995 1083
2000-01-01 00:00:03 -0.761811 0.780124 959
2000-01-01 00:00:04 -0.643525 0.679375 980
In [4]: labels = df.z > 1000
In [5]: del df['z']
In [6]: df.head()
Out[6]:
x y
2000-01-01 00:00:00 0.778864 0.824796
2000-01-01 00:00:01 -0.019888 -0.173454
2000-01-01 00:00:02 0.552826 0.051995
2000-01-01 00:00:03 -0.761811 0.780124
2000-01-01 00:00:04 -0.643525 0.679375
In [7]: labels.head()
Out[7]:
2000-01-01 00:00:00 False
2000-01-01 00:00:01 True
2000-01-01 00:00:02 True
2000-01-01 00:00:03 False
2000-01-01 00:00:04 False
Name: z, dtype: bool
In [8]: from dask.distributed import Client
In [9]: c = Client() # creates a local "cluster" on my laptop
In [10]: from dask_xgboost import train
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
In [11]: param = {'max_depth': 2, 'eta': 1, 'silent': 1, 'objective': 'binary:logistic'} # taken from example
In [12]: bst = train(c, param, df, labels)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
[14:46:20] Tree method is automatically selected to be 'approx' for faster speed. to use old behavior(exact greedy algorithm on single machine), set tree_method to 'exact'
In [13]: bst
Out[13]: <xgboost.core.Booster at 0x7fbaacfd17b8>
El código relevante está aquí si alguien quiere echar un vistazo: https://github.com/mrocklin/dask-xgboost/blob/master/dask_xgboost/core.py
Como dije, soy nuevo en XGBoost, así que probablemente me esté perdiendo cosas.
un ejemplo típico de juguete para probar está en https://github.com/dmlc/xgboost/tree/master/demo/data
Sin embargo, está en formato libsvm y necesita un poco de análisis para convertirlo en numpy
¿Algo más grande (para lo cual realmente necesitarías un clúster)? ¿O hay una forma estándar de generar un conjunto de datos de tamaño arbitrario?
O, tal vez, una mejor pregunta es: "¿Qué le gustaría ver aquí a usted (oa cualquier otra persona que lea este número)?"
Edificio predecir ahora. Si vuelvo a mover el modelo a un trabajador (pasando por el proceso de encurtido/desencurtido) y luego llamo a bst.predict
en algunos datos, obtengo el siguiente error:
Doing rabit call after Finalize
Mi suposición era que, en este punto, el modelo es autónomo y ya no necesita usar rabit. Parece funcionar bien en la máquina cliente. ¿Alguna idea de por qué podría recibir este error al llamar a predict
?
Una parte de la predicción todavía usa rabit, principalmente porque el predictor todavía usa el alumno con algunas rutinas de inicialización que se comparten con el entrenamiento. Eventualmente, esto debería arreglarse, pero este es el caso por ahora.
Creo que mientras funcione bien para el conjunto de datos común, es un punto de partida interesante.
De todos modos, hay razones para usar un clúster para datos medianos (facilidad de programación en entorno de clúster), algunos de los usuarios de pyspark podrían estar interesados en probarlo si lo publicitamos un poco
Probar el conjunto de datos que realmente importa fue difícil, por ejemplo (pruebe 1 conjunto de datos con mil millones de filas). Kaggle podría tener un gran conjunto de datos que podría ser relevante, alrededor de 10 millones.
Este repositorio muestra experimentos contra el conjunto de datos de las aerolíneas, que creo que está en decenas de millones de filas y decenas de columnas (¿miles después de una codificación en caliente?) Para su punto de referencia, parece que tomaron una muestra de 100k filas y generaron artificialmente conjuntos de datos más grandes de esta muestra. Presumiblemente, podríamos escalar esto si fuera necesario.
Aquí hay un ejemplo que usa estos datos con pandas y xgboost en un solo núcleo. Cualquier recomendación sobre la preparación de datos, los parámetros o cómo hacerlo correctamente sería bienvenida.
In [1]: import pandas as pd
In [2]: df = pd.read_csv('train-0.1m.csv')
In [3]: df.head()
Out[3]:
Month DayofMonth DayOfWeek DepTime UniqueCarrier Origin Dest Distance \
0 c-8 c-21 c-7 1934 AA ATL DFW 732
1 c-4 c-20 c-3 1548 US PIT MCO 834
2 c-9 c-2 c-5 1422 XE RDU CLE 416
3 c-11 c-25 c-6 1015 OO DEN MEM 872
4 c-10 c-7 c-6 1828 WN MDW OMA 423
dep_delayed_15min
0 N
1 N
2 N
3 N
4 Y
In [4]: labels = df.dep_delayed_15min == 'Y'
In [5]: del df['dep_delayed_15min']
In [6]: df = pd.get_dummies(df)
In [7]: len(df.columns)
Out[7]: 652
In [8]: import xgboost as xgb
/home/mrocklin/Software/anaconda/lib/python3.5/site-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
"This module will be removed in 0.20.", DeprecationWarning)
In [9]: dtrain = xgb.DMatrix(df, label=labels)
In [10]: param = {} # Are there better choices for parameters? I could use help here
In [11]: bst = xgb.train(param, dtrain) # or other parameters here?
[17:50:28] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 124 extra nodes, 0 pruned nodes, max_depth=6
[17:50:30] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[17:50:32] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[17:50:33] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 116 extra nodes, 0 pruned nodes, max_depth=6
[17:50:35] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 112 extra nodes, 0 pruned nodes, max_depth=6
[17:50:36] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 114 extra nodes, 0 pruned nodes, max_depth=6
[17:50:38] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 106 extra nodes, 0 pruned nodes, max_depth=6
[17:50:39] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 116 extra nodes, 0 pruned nodes, max_depth=6
[17:50:41] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 104 extra nodes, 0 pruned nodes, max_depth=6
[17:50:43] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 100 extra nodes, 0 pruned nodes, max_depth=6
In [12]: test = pd.read_csv('test.csv')
In [13]: test.head()
Out[13]:
Month DayofMonth DayOfWeek DepTime UniqueCarrier Origin Dest Distance \
0 c-7 c-25 c-3 615 YV MRY PHX 598
1 c-4 c-17 c-2 739 WN LAS HOU 1235
2 c-12 c-2 c-7 651 MQ GSP ORD 577
3 c-3 c-25 c-7 1614 WN BWI MHT 377
4 c-6 c-6 c-3 1505 UA ORD STL 258
dep_delayed_15min
0 N
1 N
2 N
3 N
4 Y
In [14]: test_labels = test.dep_delayed_15min == 'Y'
In [16]: del test['dep_delayed_15min']
In [17]: test = pd.get_dummies(test)
In [18]: len(test.columns) # oops, looks like the columns don't match up
Out[18]: 670
In [19]: dtest = xgb.DMatrix(test)
In [20]: predictions = bst.predict(dtest) # this fails because of mismatched columns
De todos modos, aquí hay una opción. El conjunto de datos de las aerolíneas parece bien conocido y puede ser inconvenientemente grande en la práctica. Sin embargo, una vez más, el aprendizaje automático no es mi especialidad, por lo que no sé si esto es apropiado o no.
cc @TomAugspurger , que parece el tipo de persona que podría tener pensamientos sobre esto.
Con respecto a Dask y predecir, siempre puedo configurar rabit nuevamente. Sin embargo, esto se siente un poco sucio porque obliga a la evaluación en lugar de mantener las cosas perezosas. Pero este no es un bloqueador serio para usar.
Me encontré con algunos problemas con predict. Dos preguntas:
Booster.predict
varias veces dentro de la misma sesión de rabit?rabit.init
, Booster.predict
y rabit.finalize
en subprocesos separados?Actualmente, creo un nuevo rastreador y llamo a rabit.init
en el hilo principal del trabajador. Esto funciona bien. Sin embargo, cuando llamo a Booster.predict
en subprocesos de trabajo (cada trabajador de dask mantiene un grupo de subprocesos para el cálculo) obtengo errores como Doing rabit call after Finalize
. ¿Alguna recomendación?
Una parte de la predicción todavía usa rabit, principalmente porque el predictor todavía usa el alumno con algunas rutinas de inicialización que se comparten con el entrenamiento. Eventualmente, esto debería arreglarse, pero este es el caso por ahora.
Tengo curiosidad sobre esto. Después de serializar, transferir y deserializar el modelo entrenado de un trabajador a mi máquina cliente, parece funcionar bien con datos normales aunque no haya una red rabit. Parece que un modelo entrenado con Rabit se puede usar para predecir datos sin rabit. Esto también parece que sería necesario en la producción. ¿Puede decir más sobre las limitaciones de usar un modelo entrenado en conejos aquí?
Ejemplo de conjunto de datos/problema
Suponiendo que tengo todo lo anterior correcto, ¿existe un ejemplo de capacitación distribuida estándar que la gente use para la demostración?
Sería bueno reproducir los resultados de este experimento:
https://github.com/Microsoft/LightGBM/wiki/Experiments#parallel -experimento
con la nueva opción binning + hist rápido de XGBoost (#1950), debería ser posible obtener resultados similares.
un ejemplo típico de juguete para probar está en https://github.com/dmlc/xgboost/tree/master/demo/data
Sin embargo, está en formato libsvm y necesita un poco de análisis para convertirlo en numpy
Puede que le interese este PR en sklearn: https://github.com/scikit-learn/scikit-learn/pull/935
@mrocklin No hay restricciones para reutilizar el modelo. Por lo tanto, el modelo entrenado en versión distribuida se puede usar en versión en serie. Es solo que la limitación actual del predictor (cuando se compila con rabit) tiene una función mixta con la función de entrenamiento (por lo que sucedió la llamada rabit).
Ahora que lo dices, creo que podríamos tener una solución para el problema. Simplemente haga un rabit.init
(sin pasar nada, y haga que el predictor piense que es el único trabajador) antes de que la predicción resuelva el problema
Si. Efectivamente eso resuelve el problema. dask-xgboost ahora admite predicción: https://github.com/mrocklin/dask-xgboost/commit/827a03d96977cda8d104899c9f42f52dac446165
¡Gracias por la solución @tqchen !
Aquí hay un flujo de trabajo con dask.dataframe y xgboost en una pequeña muestra del conjunto de datos de aerolíneas en mi computadora portátil local. ¿Esto les parece bien a todos? ¿Hay elementos API de XGBoost que me faltan aquí?
In [1]: import dask.dataframe as dd
In [2]: import dask_xgboost as dxgb
In [3]: df = dd.read_csv('train-0.1m.csv')
In [4]: df.head()
Out[4]:
Month DayofMonth DayOfWeek DepTime UniqueCarrier Origin Dest Distance \
0 c-8 c-21 c-7 1934 AA ATL DFW 732
1 c-4 c-20 c-3 1548 US PIT MCO 834
2 c-9 c-2 c-5 1422 XE RDU CLE 416
3 c-11 c-25 c-6 1015 OO DEN MEM 872
4 c-10 c-7 c-6 1828 WN MDW OMA 423
dep_delayed_15min
0 N
1 N
2 N
3 N
4 Y
In [5]: labels = df.dep_delayed_15min == 'Y'
In [6]: del df['dep_delayed_15min']
In [7]: df = df.categorize()
In [8]: df = dd.get_dummies(df)
In [9]: data_train, data_test = df.random_split([0.9, 0.1], random_state=123)
In [10]: labels_train, labels_test = labels.random_split([0.9, 0.1], random_state=123)
In [11]: from dask.distributed import Client
In [12]: client = Client() # in a large-data situation I probably should have done this before calling categorize above (which requires computation)
In [13]: param = {} # Are there better choices for parameters?
In [14]: bst = dxgb.train(client, {}, data_train, labels_train)
[14:00:46] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:48] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:50] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 122 extra nodes, 0 pruned nodes, max_depth=6
[14:00:53] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:00:55] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 120 extra nodes, 0 pruned nodes, max_depth=6
[14:00:57] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 114 extra nodes, 0 pruned nodes, max_depth=6
[14:00:59] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:01:01] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 118 extra nodes, 0 pruned nodes, max_depth=6
[14:01:04] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 94 extra nodes, 0 pruned nodes, max_depth=6
[14:01:06] src/tree/updater_prune.cc:74: tree pruning end, 1 roots, 102 extra nodes, 0 pruned nodes, max_depth=6
In [15]: bst
Out[15]: <xgboost.core.Booster at 0x7f689803af60>
In [16]: predictions = dxgb.predict(client, bst, data_test)
In [17]: predictions
Out[17]:
Dask Series Structure:
npartitions=1
None float32
None ...
Name: predictions, dtype: float32
Dask Name: _predict_part, 9 tasks
Mi objetivo a corto plazo es escribir una breve publicación de blog sobre esto para que, con suerte, llegue alguien más con más experiencia con XGBoost y con más tiempo que adopte este proyecto y lo impulse. (Yo, como todos los demás aquí, estoy trabajando en algunos otros proyectos como este al mismo tiempo).
Soy partidario del conjunto de datos de las aerolíneas solo porque ya lo tengo en un depósito S3. Sin embargo, estoy de acuerdo en que el conjunto de datos de Criteo sería una mejor demostración a escala.
Todavía no estoy seguro de qué parámetros usar o cómo juzgar el resultado. Para los parámetros, puedo usar el experimento de @szilard aquí . ¿Hay una buena manera de juzgar las predicciones? Por ejemplo, ¿estamos buscando predictions > 0.5
para que coincida con labels_test
?
Quizás la forma más común de evaluar el rendimiento predictivo para la clasificación binaria (especialmente en entornos de investigación o competencia) es usar el área bajo la curva ROC (AUC), aunque en las aplicaciones del mundo real se deben usar métricas que estén alineadas con los valores "comerciales". producido mediante el uso de los modelos.
Por ejemplo, ¿buscamos predicciones > 0,5 para que coincidan con las etiquetas_prueba?
Si. Si toma la media de eso en el conjunto de prueba, esta es la precisión de la prueba. Pero es probable que el conjunto de datos esté desequilibrado (mucha más ausencia de clics que clics). En ese caso, la puntuación ROC AUC es una mejor métrica.
from sklearn.metrics import roc_auc_score
print(roc_auc_score(labels_test, predictions))
suponiendo que predictions
es una matriz 1D de probabilidades positivas estimadas por el modelo para cada fila del conjunto de prueba.
@mrocklin Una pregunta de seguimiento, ¿dask permite trabajos de trabajadores de subprocesos múltiples? Sé que esto no es muy relevante para Python debido a GIL. Pero xgboost puede permitir la capacitación de subprocesos múltiples por trabajador mientras aún se coordinan entre sí de forma distribuida. Siempre debemos configurar los argumentos nthread de xgboost para que sean el número de núcleos de trabajo de ese trabajador
La respuesta corta es "sí". La mayor parte del uso de Dask es con proyectos como NumPy, Pandas, SKLearn y otros que en su mayoría son solo código C y Fortran, envueltos con Python. El GIL no afecta a estas bibliotecas. Algunas personas usan Dask para aplicaciones similares a PySpark RDD (consulte dask.bag ) y se verán afectadas. Aunque este grupo es minoritario.
Entonces sí, Dask permite tareas de subprocesos múltiples. ¿Cómo le decimos a XGBoost que use múltiples subprocesos? En mis experimentos hasta ahora, veo un alto uso de la CPU sin cambiar ningún parámetro, ¿así que tal vez todo funcione bien de manera predeterminada?
XGBoost usa subprocesos múltiples de forma predeterminada y utilizará todos los subprocesos de CPU disponibles en la máquina (en lugar de en ese trabajador) si nthread no está configurado. Esto puede crear una condición de carrera cuando se asignan varios trabajadores a la misma máquina.
Por lo tanto, siempre es bueno establecer el parámetro nthread en la cantidad máxima de núcleos que el trabajador puede usar. Por lo general, una buena práctica es usar alrededor de 4 subprocesos por trabajador.
Claro, debe lograrse en
https://github.com/mrocklin/dask-xgboost/commit/c22d066b67c78710d5ad99b8620edc55182adc8f
El lunes 20 de febrero de 2017 a las 6:31 p. m., Tianqi Chen [email protected]
escribió:
XGBoost utiliza subprocesos múltiples de forma predeterminada y utilizará toda la CPU disponible
subprocesos en la máquina (en lugar de en ese trabajador) si nthread no está configurado.
Esto puede crear una condición de carrera cuando se asignan varios trabajadores al mismo
máquina.Por lo tanto, siempre es bueno establecer el parámetro nthread en el número máximo de
núcleos que el trabajador permitió usar. Por lo general, una buena práctica es usar alrededor de, por ejemplo,
4 hilos por trabajador—
Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/dmlc/xgboost/issues/2032#issuecomment-281205747 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AASszPELRoeIvqEzyJhkKumIs-vd0PHiks5reiJngaJpZM4L_PXa
.
Cuaderno: https://gist.github.com/19c89d78e34437e061876a9872f4d2df
Screencast corto (seis minutos): https://youtu.be/Cc4E-PdDSro
La retroalimentación crítica es muy bienvenida. Nuevamente, perdonen mi ignorancia en este campo.
@mrocklin gran demostración! Creo que el rendimiento del tiempo de ejecución (y posiblemente el uso de la memoria) podría mejorarse mucho usando 'tree_method': 'hist', 'grow_policy': 'lossguide'
en el dictado de parámetros.
Gracias @ogrisel. Con esos parámetros el tiempo de entrenamiento pasa de seis minutos a un minuto. Sin embargo, el uso de la memoria parece permanecer casi igual.
Bien, volviendo a esto. ¿Hay alguna operación de XGBoost además de entrenar y predecir que deberíamos implementar?
@tqchen o @ogrisel si alguno de ustedes tiene tiempo para revisar la implementación en https://github.com/mrocklin/dask-xgboost/blob/master/dask_xgboost/core.py Se lo agradecería. Sin embargo, entiendo que mirar a través de una base de código extranjera no siempre ocupa un lugar destacado en las listas de prioridades.
Si todo está bien, agregaré un poco más al LÉAME, publicaré en PyPI y luego probablemente podamos cerrar este problema.
Creo que solo entrenar y predecir necesitan ser distribuidos. No es necesario distribuir otras cosas, ya que no responden en el conjunto de datos.
Empujé dask-xgboost a PyPI y lo moví a https://github.com/dask/dask-xgboost
Gracias @tqchen y @ogrisel por su ayuda aquí. La colaboración hizo esto relativamente fácil.
Estaría feliz de ayudar a las personas si quisieran ejecutar puntos de referencia. Hasta entonces, cerrando.
Comentario más útil
Cuaderno: https://gist.github.com/19c89d78e34437e061876a9872f4d2df
Screencast corto (seis minutos): https://youtu.be/Cc4E-PdDSro
La retroalimentación crítica es muy bienvenida. Nuevamente, perdonen mi ignorancia en este campo.