ЦП быстрее графического процессора с использованием xgb и XGBclassifier
Заранее прошу прощения, так как я новичок. Я пробую тесты GPU против CPU с XGBoost, используя xgb и XGBclassifier. Результаты приведены ниже:
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
Мне интересно, почему CPU работает наравне, если не лучше, чем GPU. Это моя установка:
- Python 3.6.1
- ОС: Windows 10 64-битная
- Графический процессор: NVIDIA RTX 2070 Super 8gb vram (драйвер обновлен до последней версии)
- CUDA 10.1 установлен
- Процессор i7 10700 2,9 ГГц
- Запуск на Jupyter Notebook
- Установил ночную сборку xgboost 1.2.0 через pip
** также пытался использовать версию xgboost, установленную из предварительно созданного двоичного колеса, используя pip: та же проблема
Вот тестовый код, который я использую (взят отсюда ):
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))
Я попытался включить поиск по сетке Sklearn, чтобы увидеть, смогу ли я получить более высокие скорости на графическом процессоре, но в итоге он оказался намного медленнее, чем процессор:
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}
Я использую набор данных с 75 тыс. Наблюдений. Есть идеи, почему я не получаю ускорения от использования графического процессора? Набор данных слишком мал, чтобы получить выгоду от использования графического процессора?
Любая помощь приветствуется. Большое спасибо!
Ответы
Интересный вопрос. Как вы заметили, есть несколько примеров этого, которые были отмечены на Github и официальном сайте xgboost site:
- https://github.com/dmlc/xgboost/issues/2819
- https://discuss.xgboost.ai/t/no-gpu-usage-when-using-gpu-hist/532
Есть и другие, кто разместил похожие вопросы:
- Нет ускорения с помощью XGBClassifier с поддержкой графического процессора
Глядя на официальной xgboostдокументации , есть обширный раздел о поддержке GPU .
Есть несколько вещей, которые нужно проверить. В документации отмечается, что:
Построение дерева (обучение) и прогнозирование можно ускорить с помощью графических процессоров с поддержкой CUDA.
1. Включен ли ваш GPU CUDA?
Да, это так .
2. Используете ли вы параметры, на которые может повлиять использование графического процессора?
Имейте в виду, что от использования графического процессора выигрывают только определенные параметры. Это:
Да, вы. Большинство из них включены в ваш набор гиперпараметров, и это хорошо.
{subsample, sampling_method, colsample_bytree, colsample_bylevel, max_bin, gamma, gpu_id, predictor, grow_policy, monotone_constraints, interaction_constraints, single_precision_histogram}
3. Вы настраиваете параметры для использования поддержки GPU?
Если вы посмотрите на страницу параметров XGBoost , вы можете найти дополнительные области, которые могут помочь улучшить ваше время. Например, updater
может быть установлено grow_gpu_hist
, что (обратите внимание, что это спорный вопрос , так как вы tree_method
установите, но для заметок):
grow_gpu_hist: вырастить дерево с помощью графического процессора.
Внизу страницы параметров есть дополнительные параметры для gpu_hist
включения, в частности deterministic_histogram
(обратите внимание, это спорный вопрос, поскольку по умолчанию это значение True
):
Построение гистограммы на GPU детерминировано. Построение гистограммы не является детерминированным из-за неассоциативного аспекта суммирования с плавающей запятой. Мы используем процедуру предварительного округления, чтобы устранить проблему, которая может немного снизить точность. Установите значение false, чтобы отключить его.
4. Данные
Я провел несколько интересных экспериментов с некоторыми данными. Поскольку у меня не было доступа к вашим данным, я использовал sklearn
's make_classification, который генерирует данные довольно надежным способом .
Я внес несколько изменений в ваш скрипт, но не заметил никаких изменений: я изменил гиперпараметры в примерах GPU и CPU, я выполнил это 100 раз и получил средние результаты и т. Д. Мне казалось, что ничто не выделяется. Я вспомнил, что однажды я использовал возможности XGBoost
GPU и CPU для ускорения некоторой аналитики, однако я работал над гораздо большим набором данных.
Я слегка отредактированный сценарий , чтобы использовать эти данные, а также стали изменения количества samples
и features
в наборе данных ( с помощью n_samples
и n_features
параметров) , чтобы наблюдать влияние на время выполнения. Похоже, что графический процессор значительно сократит время обучения для многомерных данных , но для массивных данных с большим количеством выборок не наблюдается значительного улучшения. Смотрите мой сценарий ниже:
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')
Я выполнил это изменение каждого (образцы, функции) отдельно и вместе на одних и тех же наборах данных. См. Результаты ниже:
| 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 |
Без изменений

Линейно возрастающее количество признаков

Линейно возрастающие образцы

Линейно возрастающие образцы + особенности

Когда я начал больше исследовать; это имеет смысл. Известно, что графические процессоры хорошо масштабируются с многомерными данными, и было бы логично, что вы бы заметили улучшение времени обучения, если бы ваши данные были многомерными . См. Следующие примеры:
- https://projecteuclid.org/download/pdfview_1/euclid.ss/1294167962
- Более быстрая кластеризация Kmeans для многомерных данных с поддержкой графического процессора
- https://link.springer.com/article/10.1007/s11063-014-9383-4
Хотя мы не можем сказать наверняка без доступа к вашим данным, может показаться, что аппаратные возможности графического процессора позволяют значительно повысить производительность, когда ваши данные поддерживают его, и похоже, что это может быть не так, учитывая размер и форму данных, которые вы имеют.