Фреймворк 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).

Кривая обучения модели и сравнение обучения с применением CPU и GPU
Кривая обучения модели и сравнение обучения с применением CPU и GPU

Видно, что при обучении 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-модели.

Поиск нужной службы AWS
Поиск нужной службы AWS
Выбор AMI
Выбор AMI

Для того чтобы узнать подробности об инстансах EC2 — обратитесь к этому материалу, посвящённому обучению XGBoost-моделей в облачной среде AWS.

После того, как инстанс будет готов к работе, там можно запустить тот же код, который мы уже рассматривали. В частности, речь идёт об обучении модели, созданной с параметром tree_method="gpu_hist". Если вы сравните время облачного и локального обучения модели, то окажется, что в облачной среде модели обучаются быстрее.

Распределённое обучение XGBoost-моделей с использованием библиотеки xgboost_ray

Мы уже разобрались с тем, что скорость обучения 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.

Распределённое обучение с применением нескольких узлов и GPU
Распределённое обучение с применением нескольких узлов и 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-классификатор

Время обучения, с

Использование tree_method="hist"

41

Использование tree_method="gpu_hist"

23

Использование инстанса EC2

19

Использование Ray (распределённое обучение, один компьютер с многоядерным процессором)

15

Вот, для наглядности, графическое представление этих результатов.

Сравнение различных методов ускорения обучения XGBoost-моделей
Сравнение различных методов ускорения обучения XGBoost-моделей

Итоги

В этом материале мы исследовали несколько методов, позволяющих ускорить обучение XGBoost-классификатора. В итоге мы выяснили, что распределённое обучение XGBoost-моделей с применением фреймворка Ray обходит все другие методы в плане скорости обучения. Это так из-за того, что XGBoost-Ray поддерживает обучение моделей с использованием вычислительных кластеров, позволяет полностью задействовать потенциал современных CPU и GPU, поддаётся тонкой настройке с помощью параметров наподобие RayParam.

В следующем материале мы поговорим о развёртывании XGBoost-моделей с помощью Ray Serve. А если вы хотите углубиться в изучение Ray и XGBoost — можете заглянуть сюда и сюда.

О, а приходите к нам работать? ????

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Присоединяйтесь к нашей команде.

Комментарии (1)


  1. imageman
    12.05.2022 21:16

    А как насчет необходимой памяти? Если данных терабайты, а памяти всего 16 ГБ.

    А что насчет точности моделей GPU и CPU? Вроде раньше были ограничения какие-то на GPU.