CPU más rápido que GPU usando xgb y XGBclassifier
Pido disculpas de antemano ya que soy un principiante. Estoy probando pruebas GPU vs CPU con XGBoost usando xgb y XGBclassifier. Los resultados son los siguientes:
passed time with xgb (gpu): 0.390s
passed time with XGBClassifier (gpu): 0.465s
passed time with xgb (cpu): 0.412s
passed time with XGBClassifier (cpu): 0.421s
Me pregunto por qué la CPU parece funcionar a la par, si no mejor, que la GPU. Esta es mi configuración:
- Pitón 3.6.1
- Sistema operativo: Windows 10 de 64 bits
- GPU: NVIDIA RTX 2070 Super 8 gb vram (controlador actualizado a la última versión)
- CUDA 10.1 instalado
- Procesador i7 10700 2,9 GHz
- Ejecución en Jupyter Notebook
- Instalé la compilación nocturna de xgboost 1.2.0 a través de pip
** también intenté usar la versión de xgboost instalada desde una rueda binaria preconstruida usando pip: el mismo problema
Aquí está el código de prueba que estoy usando (tomado de aquí ):
param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'eta':0.5, 'min_child_weight':1,
'tree_method':'gpu_hist'
}
num_round = 100
dtrain = xgb.DMatrix(X_train2, y_train)
tic = time.time()
model = xgb.train(param, dtrain, num_round)
print('passed time with xgb (gpu): %.3fs'%(time.time()-tic))
xgb_param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'learning_rate':0.5, 'min_child_weight':1,
'tree_method':'gpu_hist'}
model = xgb.XGBClassifier(**xgb_param)
tic = time.time()
model.fit(X_train2, y_train)
print('passed time with XGBClassifier (gpu): %.3fs'%(time.time()-tic))
param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'eta':0.5, 'min_child_weight':1,
'tree_method':'hist'}
num_round = 100
dtrain = xgb.DMatrix(X_train2, y_train)
tic = time.time()
model = xgb.train(param, dtrain, num_round)
print('passed time with xgb (cpu): %.3fs'%(time.time()-tic))
xgb_param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'learning_rate':0.5, 'min_child_weight':1,
'tree_method':'hist'}
model = xgb.XGBClassifier(**xgb_param)
tic = time.time()
model.fit(X_train2, y_train)
print('passed time with XGBClassifier (cpu): %.3fs'%(time.time()-tic))
Intenté incorporar una búsqueda de cuadrícula de Sklearn para ver si obtenía velocidades más rápidas en la GPU, pero terminó siendo mucho más lenta que la CPU:
passed time with XGBClassifier (gpu): 2457.510s
Best parameter (CV score=0.490):
{'xgbclass__alpha': 100, 'xgbclass__eta': 0.01, 'xgbclass__gamma': 0.2, 'xgbclass__max_depth': 5, 'xgbclass__n_estimators': 100}
passed time with XGBClassifier (cpu): 383.662s
Best parameter (CV score=0.487):
{'xgbclass__alpha': 100, 'xgbclass__eta': 0.1, 'xgbclass__gamma': 0.2, 'xgbclass__max_depth': 2, 'xgbclass__n_estimators': 20}
Estoy usando un conjunto de datos con 75k observaciones. ¿Alguna idea de por qué no obtengo una aceleración al usar GPU? ¿Es el conjunto de datos demasiado pequeño para obtener las ganancias del uso de la GPU?
Cualquier ayuda sería muy apreciada. ¡Muchos gracias!
Respuestas
Interesante pregunta. Como usted nota, hay algunos ejemplos de esto que se han observado en Github y el oficial xgboost site:
- https://github.com/dmlc/xgboost/issues/2819
- https://discuss.xgboost.ai/t/no-gpu-usage-when-using-gpu-hist/532
También hay otros que han publicado preguntas similares:
- Sin aceleración usando XGBClassifier con soporte GPU
En cuanto a la documentación oficialxgboost , hay una sección extensa sobre el soporte de GPU .
Hay algunas cosas que comprobar. La documentación señala que:
La construcción de árboles (entrenamiento) y la predicción se pueden acelerar con GPU compatibles con CUDA.
1. ¿Está habilitada su GPU CUDA?
Sí, lo es .
2. ¿Está utilizando parámetros que pueden verse afectados por el uso de la GPU?
Tenga en cuenta que solo ciertos parámetros se benefician del uso de una GPU. Esos son:
Sí es usted. La mayoría de estos están incluidos en su conjunto de hiperparámetros, lo cual es bueno.
{subsample, sampling_method, colsample_bytree, colsample_bylevel, max_bin, gamma, gpu_id, predictor, grow_policy, monotone_constraints, interaction_constraints, single_precision_histogram}
3. ¿Estás configurando parámetros para usar la compatibilidad con GPU?
Si observa la página de parámetros de XGBoost , puede encontrar áreas adicionales que pueden ayudarlo a mejorar sus tiempos. Por ejemplo, updater
se puede establecer en grow_gpu_hist
, que (nota, esto es discutible ya que lo ha tree_method
establecido, pero para notas):
grow_gpu_hist: árbol de crecimiento con GPU.
En la parte inferior de la página de parámetros, hay parámetros adicionales para gpu_hist
habilitar, específicamente deterministic_histogram
(tenga en cuenta que esto es discutible ya que el valor predeterminado es True
):
Cree un histograma en la GPU de manera determinista. La construcción de histogramas no es determinista debido al aspecto no asociativo de la suma de puntos flotantes. Empleamos una rutina de redondeo previo para mitigar el problema, lo que puede conducir a una precisión ligeramente inferior. Establézcalo en falso para deshabilitarlo.
4. Los datos
Hice algunos experimentos interesantes con algunos datos. Como no tenía acceso a sus datos, usé sklearn
's make_classification, que genera datos de una manera bastante robusta .
Hice algunos cambios en su secuencia de comandos, pero no noté ningún cambio: cambié los hiperparámetros en los ejemplos de gpu vs cpu, ejecuté esto 100 veces y obtuve resultados promedio, etc. Nada me pareció destacar. Recordé que una vez usé XGBoost
las capacidades de GPU frente a CPU para acelerar algunos análisis, sin embargo, estaba trabajando en un conjunto de datos mucho más grande.
Edité ligeramente su secuencia de comandos para usar estos datos, y también comencé a cambiar el número de samples
y features
en el conjunto de datos (vía n_samples
y n_features
parámetros) para observar los efectos en el tiempo de ejecución. Parece como si una GPU mejorara significativamente los tiempos de entrenamiento para datos de alta dimensión , pero esos datos masivos con muchas muestras no ven una gran mejora. Vea mi guión a continuación:
import xgboost as xgb, numpy, time
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
xgb_gpu = []
xgbclassifier_gpu = []
xgb_cpu = []
xgbclassifier_cpu = []
n_samples = 75000
n_features = 500
for i in range(len(10)):
n_samples += 10000
n_features += 300
# Make my own data since I do not have the data from the SO question
X_train2, y_train = make_classification(n_samples=n_samples, n_features=n_features*0.9, n_informative=n_features*0.1,
n_redundant=100, flip_y=0.10, random_state=8)
# Keep script from OP intact
param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'eta':0.5, 'min_child_weight':1,
'tree_method':'gpu_hist', 'gpu_id': 0
}
num_round = 100
dtrain = xgb.DMatrix(X_train2, y_train)
tic = time.time()
model = xgb.train(param, dtrain, num_round)
print('passed time with xgb (gpu): %.3fs'%(time.time()-tic))
xgb_gpu.append(time.time()-tic)
xgb_param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'learning_rate':0.5, 'min_child_weight':1,
'tree_method':'gpu_hist', 'gpu_id':0}
model = xgb.XGBClassifier(**xgb_param)
tic = time.time()
model.fit(X_train2, y_train)
print('passed time with XGBClassifier (gpu): %.3fs'%(time.time()-tic))
xgbclassifier_gpu.append(time.time()-tic)
param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'eta':0.5, 'min_child_weight':1,
'tree_method':'hist'}
num_round = 100
dtrain = xgb.DMatrix(X_train2, y_train)
tic = time.time()
model = xgb.train(param, dtrain, num_round)
print('passed time with xgb (cpu): %.3fs'%(time.time()-tic))
xgb_cpu.append(time.time()-tic)
xgb_param = {'max_depth':5, 'objective':'binary:logistic', 'subsample':0.8,
'colsample_bytree':0.8, 'learning_rate':0.5, 'min_child_weight':1,
'tree_method':'hist'}
model = xgb.XGBClassifier(**xgb_param)
tic = time.time()
model.fit(X_train2, y_train)
print('passed time with XGBClassifier (cpu): %.3fs'%(time.time()-tic))
xgbclassifier_cpu.append(time.time()-tic)
import pandas as pd
df = pd.DataFrame({'XGB GPU': xgb_gpu, 'XGBClassifier GPU': xgbclassifier_gpu, 'XGB CPU': xgb_cpu, 'XGBClassifier CPU': xgbclassifier_cpu})
#df.to_csv('both_results.csv')
Ejecuté esto cambiando cada uno (muestras, características) por separado y juntos, en los mismos conjuntos de datos. Vea los resultados a continuación:
| Interval | XGB GPU | XGBClassifier GPU | XGB CPU | XGBClassifier CPU | Metric |
|:--------:|:--------:|:-----------------:|:--------:|:-----------------:|:----------------:|
| 0 | 11.3801 | 12.00785 | 15.20124 | 15.48131 | Changed Features |
| 1 | 15.67674 | 16.85668 | 20.63819 | 22.12265 | Changed Features |
| 2 | 18.76029 | 20.39844 | 33.23108 | 32.29926 | Changed Features |
| 3 | 23.147 | 24.91953 | 47.65588 | 44.76052 | Changed Features |
| 4 | 27.42542 | 29.48186 | 50.76428 | 55.88155 | Changed Features |
| 5 | 30.78596 | 33.03594 | 71.4733 | 67.24275 | Changed Features |
| 6 | 35.03331 | 37.74951 | 77.68997 | 75.61216 | Changed Features |
| 7 | 39.13849 | 42.17049 | 82.95307 | 85.83364 | Changed Features |
| 8 | 42.55439 | 45.90751 | 92.33368 | 96.72809 | Changed Features |
| 9 | 46.89023 | 50.57919 | 105.8298 | 107.3893 | Changed Features |
| 0 | 7.013227 | 7.303488 | 6.998254 | 9.733574 | No Changes |
| 1 | 6.757523 | 7.302388 | 5.714839 | 6.805287 | No Changes |
| 2 | 6.753428 | 7.291906 | 5.899611 | 6.603533 | No Changes |
| 3 | 6.749848 | 7.293555 | 6.005773 | 6.486256 | No Changes |
| 4 | 6.755352 | 7.297607 | 5.982163 | 8.280619 | No Changes |
| 5 | 6.756498 | 7.335412 | 6.321188 | 7.900422 | No Changes |
| 6 | 6.792402 | 7.332112 | 6.17904 | 6.443676 | No Changes |
| 7 | 6.786584 | 7.311666 | 7.093638 | 7.811417 | No Changes |
| 8 | 6.7851 | 7.30604 | 5.574762 | 6.045969 | No Changes |
| 9 | 6.789152 | 7.309363 | 5.751018 | 6.213471 | No Changes |
| 0 | 7.696765 | 8.03615 | 6.175457 | 6.764809 | Changed Samples |
| 1 | 7.914885 | 8.646722 | 6.997217 | 7.598789 | Changed Samples |
| 2 | 8.489555 | 9.2526 | 6.899783 | 7.202334 | Changed Samples |
| 3 | 9.197605 | 10.02934 | 7.511708 | 7.724675 | Changed Samples |
| 4 | 9.73642 | 10.64056 | 7.918493 | 8.982463 | Changed Samples |
| 5 | 10.34522 | 11.31103 | 8.524865 | 9.403711 | Changed Samples |
| 6 | 10.94025 | 11.98357 | 8.697257 | 9.49277 | Changed Samples |
| 7 | 11.80717 | 12.93195 | 8.734307 | 10.79595 | Changed Samples |
| 8 | 12.18282 | 13.38646 | 9.175231 | 10.33532 | Changed Samples |
| 9 | 13.05499 | 14.33106 | 11.04398 | 10.50722 | Changed Samples |
| 0 | 12.43683 | 13.19787 | 12.80741 | 13.86206 | Changed Both |
| 1 | 18.59139 | 20.01569 | 25.61141 | 35.37391 | Changed Both |
| 2 | 24.37475 | 26.44214 | 40.86238 | 42.79259 | Changed Both |
| 3 | 31.96762 | 34.75215 | 68.869 | 59.97797 | Changed Both |
| 4 | 41.26578 | 44.70537 | 83.84672 | 94.62811 | Changed Both |
| 5 | 49.82583 | 54.06252 | 109.197 | 108.0314 | Changed Both |
| 6 | 59.36528 | 64.60577 | 131.1234 | 140.6352 | Changed Both |
| 7 | 71.44678 | 77.71752 | 156.1914 | 161.4897 | Changed Both |
| 8 | 81.79306 | 90.56132 | 196.0033 | 193.4111 | Changed Both |
| 9 | 94.71505 | 104.8044 | 215.0758 | 224.6175 | Changed Both |
Ningún cambio

Recuento de características que aumenta linealmente

Muestras linealmente crecientes

Muestras + funciones linealmente crecientes

A medida que comencé a investigar más; Esto tiene sentido. Se sabe que las GPU escalan bien con datos de gran dimensión, y tendría sentido que notara una mejora en el tiempo de entrenamiento si sus datos fueran de gran dimensión . Vea los siguientes ejemplos:
- https://projecteuclid.org/download/pdfview_1/euclid.ss/1294167962
- Agrupación de Kmeans más rápida en datos de alta dimensión con compatibilidad con GPU
- https://link.springer.com/article/10.1007/s11063-014-9383-4
Aunque no podemos asegurarlo sin acceso a sus datos, parecería que las capacidades de hardware de una GPU permiten aumentos significativos en el rendimiento cuando sus datos lo admiten, y parece que ese podría no ser el caso dado el tamaño y la forma de los datos que necesita. tener.