Три подхода к ускорению обучения XGBoost-моделей
- пятница, 13 мая 2022 г. в 00:35:00
Фреймворк XGBoost (Extreme Gradient Boosting, экстремальный градиентный бустинг) — это эффективная опенсорсная реализация алгоритма градиентного бустинга. Этот фреймворк отличается высокой скоростью работы, а модели, построенные на его основе, обладают хорошей производительностью. Поэтому он пользуется популярностью при решении задач классификации и регрессии с использованием табличных наборов данных. Но процесс обучения XGBoost-моделей может занять много времени.
В предыдущем материале мы говорили о плюсах и минусах различных подходов к ускорению обучения XGBoost-моделей. Ознакомившись с тем материалом, вы сможете получить общее представление об этих подходах. В этой статье мы рассмотрим три различных подхода к уменьшению времени обучения XGBoost-классификатора. Здесь вы найдёте примеры кода, что позволит вам самостоятельно испытать то, о чём мы будем говорить. А именно, речь пойдёт о трёх методах ускорения обучения XGBoost-моделей:
Применение деревьев (с использованием параметра tree_method="gpu_hist"
).
Облачное обучение моделей.
Распределённое обучение XGBoost-моделей с использованием xgboost_ray.
Прежде чем перейти к нашей основной теме — создадим XGBoost-модель, импортировав функцию make_classification
из библиотеки scikit-learn
. Это позволит нам создать синтетический набор данных. Затем мы определим XGBoost-классификатор, который будем обучать на этом наборе данных.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from xgboost import XGBClassifier
# определение набора данных
X, y = make_classification(
n_samples=100000,
n_features=1000,
n_informative=50,
n_redundant=0,
random_state=1)
# разбиение набора данных на обучающую и тестовую выборки
print(X.shape, y.shape)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.50, random_state=1)
# определение модели
model = XGBClassifier()
С помощью этого кода создан XGBoost-классификатор, готовый к тому, чтобы его обучили. Поговорим теперь о том, как его обучить с использованием трёх вышеупомянутых подходов.
Параметр XGBoost-классификатора tree_method
указывает фреймворку на то, что ему нужно воспользоваться реализацией алгоритма градиентного бустинга, базовой моделью которого является дерево. По умолчанию значением этого параметра является approx
, но этот алгоритм использования деревьев не даёт наилучшего уровня производительности. Переключение на алгоритм hist
позволяет улучшить производительность. Но, из-за того, что оба эти алгоритма используют процессор (CPU), ни один из них не способен выйти на по-настоящему высокий уровень производительности.
Выбирая алгоритм gpu_hist
, как показано в следующем примере кода, мы получаем возможность обучать XGBoost-модели на видеокарте (GPU). Нам интересен именно этот подход, так как обучение моделей на GPU, в сравнении с обучением их на CPU, способно сэкономить немало времени.
Обратите внимание на то, что при применении моделей, использующих деревья, можно указать максимальную глубину роста дерева. Дерево, расположенное в левой части следующей схемы, имеет глубину, равную 2. А глубина дерева, находящегося справа, равна 3.
По умолчанию максимальная глубина дерева — 6. Более глубокие деревья могут лучше моделировать сложные взаимодействия между признаками, но если они оказываются слишком глубокими — это может привести к переобучению модели. Применение более глубоких деревьев, кроме того, означает, что на обучение модели понадобится больше времени. Есть и многие другие гиперпараметры, которые управляют процессом обучения. Подбор наилучшего набора гиперпараметров для конкретной задачи стоит автоматизировать с помощью специализированного инструмента вроде HyperOpt, Optuna или Ray Tune.
# определение наборов данных для оценки итераций
evalset = [(X_train, y_train), (X_test, y_test)]
#################
model = XGBClassifier(
learning_rate=0.02,
n_estimators=10,
objective="binary:logistic",
nthread=3,
tree_method="gpu_hist" # благодаря этому задействуется GPU.
)
import time
print('Lets GO!')
start = time.ctime()
# обучение модели
model.fit(X_train, y_train, eval_metric='logloss', eval_set=evalset)
end = time.ctime()
print('all done!')
print('started', start)
print('finished', end)
Ниже показана кривая обучения XGBoost-модели с использованием GPU. Там же приведено сравнение времени обучения модели на CPU (hist
) и GPU (gpu_hist
).
Видно, что при обучении XGBoost-модели на большом наборе данных с параметром tree_method="gpu_hist"
скорость обучения значительно возрастает. А именно, время, затрачиваемое на обучение модели с применением CPU (hist
), составляет 41 секунду. Применение GPU (gpu_hist
) позволяет сократить это время до 23 секунд.
Использование параметра tree_method
, подбор подходящего значения для него, это — идеальный подход к ускорению обучения XGBoost моделей с применением локальных GPU. Но другие подходы к ускорению обучения таких моделей могут оказаться эффективнее. Один из них заключается в использовании облачных ресурсов. Облачные платформы позволяют работать с гораздо более мощными GPU, чем те, которые обычно устанавливают в рабочие компьютеры. Кроме того, таких GPU может быть больше, чем имеется в локальном окружении. Правда, за всё это придётся платить.
Облачные GPU-провайдеры не предоставляют свои услуги бесплатно. Но среди предлагаемых ими тарифных планов можно подобрать именно то, что нужно. Например — такой, когда оплачивается лишь фактическое время использования оборудования. Это позволяет пользователю отключать используемые инстансы виртуальных или физических машин, применяемые для обучения модели. В результате платить приходится только за время реального использования ресурсов.
XGBoost-модель, используемая в этой статье, обучается с использованием инстансов AWS EC2. Мы фиксируем время, которое тратится на обучение. Этот процесс довольно-таки прост. Ниже приведён пошаговый план обучения XGBoost-моделей на инстансах AWS EC2:
Регистрация учётной записи AWS (если нужно).
Запуск инстанса AWS.
Вход в инстанс и запуск кода.
Обучение XGBoost-модели.
Остановка инстанса AWS.
Для того чтобы облегчить себе жизнь — после входа в система выберите Amazon Machine Image (AMI) для запуска виртуальной машины с помощью EC2. Именно на этой виртуальной машине и можно будет произвести обучение XGBoost-модели.
Для того чтобы узнать подробности об инстансах EC2 — обратитесь к этому материалу, посвящённому обучению XGBoost-моделей в облачной среде AWS.
После того, как инстанс будет готов к работе, там можно запустить тот же код, который мы уже рассматривали. В частности, речь идёт об обучении модели, созданной с параметром tree_method="gpu_hist"
. Если вы сравните время облачного и локального обучения модели, то окажется, что в облачной среде модели обучаются быстрее.
Мы уже разобрались с тем, что скорость обучения XGBoost-моделей на больших наборах данных в локальном окружении можно увеличить, прибегнув к XGBoost-деревьям, задействующим GPU. Дальнейшего роста скорости можно добиться, воспользовавшись облачными решениями наподобие AWS или Google Cloud. В дополнение к этим двум возможностям в нашем распоряжении имеется и ещё одна, при этом — самая интересная. Это — распределённое обучение XGBoost-моделей с использованием фреймворка Ray. Для краткости этот метод обучения моделей мы будем называть XGBoost-Ray.
Метод XGBoost-Ray предусматривает использование Python-библиотеки, позволяющей организовать распределённое обучение XGBoost-моделей. Эта библиотека основана на фреймворке для распределённых вычислений Ray. Применение XGBoost-Ray позволяет без особого труда перенести вычислительную нагрузку, связанную с обучением, на ресурсы кластера, состоящего из сотен узлов. Этот метод, кроме того, даёт нам различные дополнительные возможности, в частности, обеспечивает отказоустойчивость, масштабирование обучения, интеграцию с Ray Tune для оптимизации гиперпараметров.
Стандартная реализация XGBoost рассчитана на использование одного GPU или CPU на одном компьютере. Для того чтобы воспользоваться дополнительными вычислительными ресурсами, необходимо прибегнуть к механизму распределённого обучения наподобие XGBoost-Ray. А если наборы данных, с которыми вы работаете, очень велики и не помещаются в памяти отдельного компьютера, то вам просто необходимо прибегнуть к распределённому обучению.
Вот схема организации распределённого обучения с применением XGBoost-Ray, когда задействованы несколько узлов с несколькими GPU.
XGBoost-Ray, для организации обучения, создаёт агенты обучения для всего кластера. Потом каждый из агентов обучается на отдельном фрагменте данных. Это называется обучением с параллелизмом по данным. Агенты объединяют результаты вычисления градиентов с помощью операции AllReduce
, основанной на древовидной структуре.
Поговорим о том, что надо сделать для обучения XGBoost-модели с помощью Ray. Начнём с кода, который мы уже рассматривали. Импортируем в него зависимости xgboost_ray
, такие, как train
и RayParams
.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# определение набора данных
X, y = make_classification(
n_samples=100000,
n_features=1000,
n_informative=50,
n_redundant=0,
random_state=1)
# разбиение набора данных на обучающую и тестовую выборки
print(X.shape, y.shape)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.50, random_state=1)
from xgboost_ray import RayDMatrix, RayParams, train
Теперь, когда классификатор готов к работе, можно приступить к настройке фреймворка для распределённого обучения, организовав с его помощью обучение модели на нескольких GPU. Другими словами — нужно указать то, сколько агентов нужно использовать системе, задать распределение CPU и GPU по агентам. Делается это с помощью объекта RayParams
. Он используется для разделения CPU и GPU по агентам. В данном примере XGBoost-модель обучают на машине с шестью ядрами CPU и с двумя GPU. Для обучения в подобной среде количество агентов нужно устанавливать так, чтобы оно, как минимум, равнялось двум — каждому при этом назначается по 3 CPU и по 1 GPU. Выполнение агентов в кластере будет автоматически организовано средствами Ray.
Так как в нашем примере используется лишь один компьютер — оба агента будут выполняться на нём. Но тот же код можно использовать и в кластере, содержащем десятки или даже сотни машин. Обратите внимание на то, что данные передаются XGBoost-Ray с использованием объекта RayDMatrix
. Этот объект хранит данные с использованием шардинга, в результате каждый из агентов может обращаться к своему фрагменту данных для проведения обучения.
train_set = RayDMatrix(X_train, y_train)
eval_set = RayDMatrix(X_test, y_test)
evals_result = {}
bst = train(
{
"objective": "binary:logistic",
"eval_metric": ["logloss", "error"],
},
train_set,
num_boost_round=10,
evals_result=evals_result,
evals=[(train_set, "train"), (eval_set, "eval")],
verbose_eval=True,
ray_params=RayParams(
num_actors=2,
gpus_per_actor=1,
cpus_per_actor=3, # Разделить вычислительные ресурсы компьютера между агентами поровну
))
bst.save_model("model.xgb")
print("Final training error: {:.4f}".format(
evals_result["train"]["error"][-1]))
print("Final validation error: {:.4f}".format(
evals_result["eval"]["error"][-1]))
Как уже было сказано, компьютер, на котором мы обучаем модель, обладает шестью процессорными ядрами.
Пришло время сравнить эффективность рассмотренных подходов к ускорению обучения XGBoost-моделей, узнать о том, какой из них позволяет обучать модели быстрее всего. Из следующей таблицы можно узнать, что самым эффективным методом ускорения обучения моделей является тот, который предусматривает применение фреймворка Ray. Это так благодаря тому, что он позволяет организовать распределённое обучение, задействовать несколько CPU и GPU, обеспечивает отказоустойчивость, поддерживает множество настраиваемых параметров. Этот метод, кроме того, позволяет ускорить обучение ещё сильнее. Мы воспользовались им, имея в распоряжении лишь один компьютер, а он способен организовать обучение на вычислительном кластере, состоящем из множества машин.
XGBoost-классификатор | Время обучения, с |
Использование | 41 |
Использование | 23 |
Использование инстанса EC2 | 19 |
Использование Ray (распределённое обучение, один компьютер с многоядерным процессором) | 15 |
Вот, для наглядности, графическое представление этих результатов.
В этом материале мы исследовали несколько методов, позволяющих ускорить обучение XGBoost-классификатора. В итоге мы выяснили, что распределённое обучение XGBoost-моделей с применением фреймворка Ray обходит все другие методы в плане скорости обучения. Это так из-за того, что XGBoost-Ray поддерживает обучение моделей с использованием вычислительных кластеров, позволяет полностью задействовать потенциал современных CPU и GPU, поддаётся тонкой настройке с помощью параметров наподобие RayParam
.
В следующем материале мы поговорим о развёртывании XGBoost-моделей с помощью Ray Serve. А если вы хотите углубиться в изучение Ray и XGBoost — можете заглянуть сюда и сюда.
Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.
Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.
Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.