CPU plus rapide que GPU en utilisant xgb et XGBclassifier
Je m'excuse d'avance car je suis débutant. J'essaie des tests GPU vs CPU avec XGBoost en utilisant xgb et XGBclassifier. Les résultats sont les suivants:
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
Je me demande pourquoi le CPU semble fonctionner à égalité sinon mieux que le GPU. Voici ma configuration :
- Python 3.6.1
- Système d'exploitation : Windows 10 64 bits
- GPU : NVIDIA RTX 2070 Super 8 Go vram (pilote mis à jour vers la dernière version)
- CUDA 10.1 installé
- Processeur i7 10700 2.9Ghz
- Exécution sur Jupyter Notebook
- Installation de la version nocturne de xgboost 1.2.0 via pip
** également essayé d'utiliser la version de xgboost installée à partir d'une roue binaire pré-construite en utilisant pip : même problème
Voici le code de test que j'utilise (tiré d' ici ):
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))
J'ai essayé d'incorporer une recherche de grille Sklearn pour voir si j'obtiendrais des vitesses plus rapides sur le GPU, mais cela a fini par être beaucoup plus lent que le 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}
J'utilise un ensemble de données avec 75k observations. Avez-vous une idée de la raison pour laquelle je n'obtiens pas d'accélération en utilisant le GPU ? L'ensemble de données est-il trop petit pour tirer parti de l'utilisation du GPU ?
Toute aide serait très appréciée. Merci beaucoup!
Réponses
Question interessante. Comme vous le notez, il y a quelques exemples de cela qui ont été notés sur Github et l'officiel xgboost site:
- https://github.com/dmlc/xgboost/issues/2819
- https://discuss.xgboost.ai/t/no-gpu-usage-when-using-gpu-hist/532
Il y en a aussi d'autres qui ont posté des questions similaires:
- Aucune accélération à l'aide de XGBClassifier avec prise en charge GPU
En regardant la documentation officiellexgboost , il y a une section complète sur le support GPU .
Il y a quelques points à vérifier. La documentation note que :
La construction d'arbres (formation) et la prédiction peuvent être accélérées avec des GPU compatibles CUDA.
1. Votre GPU CUDA est-il activé ?
Oui, c'est .
2. Utilisez-vous des paramètres qui peuvent être affectés par l'utilisation du GPU ?
Gardez à l'esprit que seuls certains paramètres bénéficient de l'utilisation d'un GPU. Ce sont:
Oui, vous l'êtes. La plupart d'entre eux sont inclus dans votre ensemble d'hyperparamètres, ce qui est une bonne chose.
{subsample, sampling_method, colsample_bytree, colsample_bylevel, max_bin, gamma, gpu_id, predictor, grow_policy, monotone_constraints, interaction_constraints, single_precision_histogram}
3. Configurez-vous les paramètres pour utiliser le support GPU ?
Si vous regardez la page Paramètres XGBoost , vous pouvez trouver des domaines supplémentaires qui peuvent vous aider à améliorer vos temps. Par exemple, updater
peut être défini sur grow_gpu_hist
, qui (notez que cela est sans objet puisque vous avez tree_method
défini, mais pour les notes):
grow_gpu_hist : agrandir l'arborescence avec le GPU.
Au bas de la page des paramètres, il y a des paramètres supplémentaires pour gpu_hist
activé, en particulier deterministic_histogram
(notez que c'est sans objet puisque la valeur par défaut est True
):
Construire un histogramme sur GPU de manière déterministe. La construction d'histogrammes n'est pas déterministe en raison de l'aspect non associatif de la sommation en virgule flottante. Nous utilisons une routine de pré-arrondi pour atténuer le problème, ce qui peut entraîner une précision légèrement inférieure. Définissez sur false pour le désactiver.
4. Les données
J'ai mené des expériences intéressantes avec certaines données. Comme je n'avais pas accès à vos données, j'ai utilisé celle sklearn
de make_classification, qui génère des données de manière assez robuste .
J'ai apporté quelques modifications à votre script mais je n'ai remarqué aucun changement : j'ai changé les hyperparamètres sur les exemples gpu vs cpu, j'ai exécuté ceci 100 fois et pris des résultats moyens, etc. Rien ne semblait me démarquer. J'ai rappelé que j'avais autrefois utilisé XGBoost
les capacités GPU vs CPU pour accélérer certaines analyses, cependant, je travaillais sur un ensemble de données beaucoup plus volumineux.
J'ai légèrement modifié votre script pour utiliser ces données, et j'ai également commencé à modifier le nombre de samples
et features
dans l'ensemble de données (via n_samples
et n_features
paramètres) pour observer les effets sur l'exécution. Il semble qu'un GPU améliore considérablement les temps de formation pour les données de grande dimension , mais ces données en masse avec de nombreux échantillons ne voient pas une amélioration considérable. Voir mon script ci-dessous:
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')
J'ai exécuté ceci en changeant chacun (échantillons, fonctionnalités) séparément et ensemble, sur les mêmes ensembles de données. Voir les résultats ci-dessous :
| 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 |
Pas de changement
Augmentation linéaire du nombre de fonctionnalités
Échantillons croissants linéairement
Échantillons à augmentation linéaire + fonctionnalités
Comme j'ai commencé à faire des recherches plus; c'est logique. Les GPU sont connus pour bien évoluer avec des données de grande dimension, et il serait logique que vous constatiez une amélioration du temps de formation si vos données étaient de grande dimension . Voir les exemples suivants :
- https://projecteuclid.org/download/pdfview_1/euclid.ss/1294167962
- Clustering Kmeans plus rapide sur des données de grande dimension avec prise en charge GPU
- https://link.springer.com/article/10.1007/s11063-014-9383-4
Bien que nous ne puissions pas dire avec certitude sans accès à vos données, il semblerait que les capacités matérielles d'un GPU permettent des augmentations significatives des performances lorsque vos données le prennent en charge, et il semble que ce ne soit pas le cas compte tenu de la taille et de la forme des données que vous ont.