24 июня

Распределенное обучение XGBoost и параллельное прогнозирование с Apache Spark

Блог компании OTUS. Онлайн-образованиеApacheBig DataМашинное обучение
Перевод
Автор оригинала: Iftach Schonbaum
Привет, Хабр! Уже в конце июля Otus запускает новый курс «Промышленный ML на больших данных». Традиционно, в преддверии старта нового курса, мы подготовили для вас перевод полезного материала.




Общие сведения


В бустинге (из ансамбля моделей машинного обучения), алгоритмы реализуют последовательный процесс (в отличие от бэггинга, где он распараллелен), который генерирует слабые обучающие алгоритмы и комбинирует их с сильным (как и во всех методах ансамбля). В бустинге на каждой итерации процесса модель пытается адаптивно исправить ошибки предыдущей итерации, в отличие от бэггинга, в котором слабые обучающие алгоритмы обучаются независимо.



Один из алгоритмов бустинга, градиентный бустинг, использует градиентный спуск для минимизации функции потерь прямо в этих последовательных моделях (в отличие от алгоритма AdaBoost, где обучение происходит посредством изменения весов обучающих экземпляров).

Слабые обучающие алгоритмы, созданные при градиентном бустинге во время обучения, обычно реализуются в виде деревьев решений. Самое неэффективное в градиентном бустинге – это последовательный процесс создания деревьев, поскольку в таком случае создается всего одно дерево за раз.

Чтобы обойти это ограничение Тяньцзи Ченом и Карлосом Гестрином было предложено улучшение алгоритма градиентного бустинга, которое называется XGBoost, что расшифровывается как Extreme Gradient Boosting или экстремальный градиентный бустинг. Это своего рода градиентный бустинг на стероидах, который используется в основном для классификации, но также порой для регрессии и ранжирования.

По сравнению со стандартным градиентным бустингом, новый метод существенно увеличивает производительность за счет гиперпараметров, поддержки GPU, кроссвалидации и регуляризации алгоритмов. В целом модель получается более эффективной, быстрее обучается и менее подвержена переобучению.

В последнее время XGBoost обрел большую популярность и выиграл множество соревнований по машинному обучению в Kaggle. Считается, что он обладает большой вычислительной мощностью и точностью.



XGBoost и Apache Spark


Во время стандартного workflow в ML используются такие системы как Spark для создания пайплайна машинного обучения, где вы предварительно обрабатываете и чистите данные, а затем результат передается на этап машинного обучения, зачастую с помощью Spark MLlib, если вы уже используете Spark.

В контексте этой статьи важно то, что в XGBoost есть распараллеливание процесса построения дерева, что позволяет производить между узлами распределенное обучение и прогнозирование. То есть если я, как пользователь Apache Spark MLlib, могу использовать его для расширения возможностей обучения XGBoost и работы на продакшене, то, по сути, я могу радоваться высокой производительности XGBoost и мощным механизмам работы Spark для инженерии признаков и построения ML-пайплайнов.

Встречайте XGBoost4J-Spark — проект, который объединяет XGBoost и Apache Spark, добавляя XGBoost к фреймворку Apache Spark MLlib.

XGBoost4J-Spark дает возможность построить пайплайн MLlib, который предварительно обрабатывает данные перед обучением модели XGBoost, обучает ее и может использоваться для параллельного прогнозирования на продкшене. С помощью этой библиотеки каждый воркер XGBoost оборачивается в таск Spark, при этом обучающий датасет из памяти Spark отправляется воркерам XGBoost, которые невидимо существуют в исполнителях Spark.



Чтобы начать писать приложение с машинным обучением на XGBoost4J-Spark, вам нужно сначала добавить соответствующую зависимость:

<dependency>
    <groupId>ml.dmlc</groupId>
    <artifactId>xgboost4j-spark</artifactId>
    <version>0.90</version>
</dependency>

Подготовка данных (пример с ирисами)


Как говорилось ранее, XGBoost4J-Spark позволяет «подогнать» данные под интерфейс XGBoost.

Как только мы считаем датасет «Цветы Ириса» в DataFrame, нам нужно будет:

  • Преобразовать столбцы из String к Double;
  • Объединить столбцы признаков в вектора, чтобы данные соответствовали интерфейсу фреймворка машинного обучения Spark.

import org.apache.spark.ml.feature.StringIndexer
import org.apache.spark.ml.feature.VectorAssembler
val stringIndexer = new StringIndexer().
  setInputCol("class").
  setOutputCol("classIndex").
  fit(irisDF)
val labelTransformed = stringIndexer.transform(irisDF).drop("class")
val vectorAssembler = new VectorAssembler().
  setInputCols(Array("sepal length", "sepal width", "petal length", "petal width")).
  setOutputCol("features")
val xgbInput = vectorAssembler.transform(labelTransformed).select("features", "classIndex")

В DataFrame выше в результате будут два столбца, “features”: вектор – представляющий признаки ириса и “classIndex”: лейбл типа Double. Такой DataFrame можно спокойно скормить обучающему движку XGBoost4J-Spark.

Распределенное обучение


import ml.dmlc.xgboost4j.scala.spark.XGBoostClassifier

val xgbClassifier = new XGBoostClassifier().
      setFeaturesCol("features").
      setLabelCol("classIndex").
      setObjective("multi:softmax")
      setMaxDepth(2).
      setNumClass(3).
      setNumRound(100).
      setNumWorkers(10).

Полный список параметров XGBoost вы можете найти здесь. Обратите внимание, что в XGBoost4J-Spark вы также можете использовать camelСase, как в примере выше.

Заметки


  1. multi:softmax означает, что мы делаем многоклассовую классификацию с помощью функции softmax. Для этого нужно задать количество классов с помощью параметра num_class.
  2. max_depth – это максимальная глубина дерева, созданного на каждой итерации бустинга. Увеличение этого значения сделает модель сложной и склонной к переобучению. При обучении глубоких деревьев XGBoost потребляет много памяти.
  3. num_rounds – количество раундов бустинга.
  4. Параметр num_workers определяет сколько параллельных воркеров нам нужно при обучении XGBoostClassificationModel. Позже этот параметр станет отложенными тасками в Spark, которые в перспективе будут обрабатываться менеджером кластера (в большинстве случаев YARN).

Ранняя остановка поддерживается с помощью параметров num_early_stopping_rounds и maximize_evaluation_metrics.

Теперь мы можем создать трансформер, обучив классификатор XGBoost на входном DataFrame. В результате процесса обучения мы получаем модель, которую можно использовать для получения прогнозов.

val xgbClassificationModel = xgbClassifier.fit(xgbInput)

Параллельное прогнозирование


XGBoost4j-Spark поддерживает пакетное прогнозирование и точечное прогнозирование.

Для пакетного прогнозирования модель берет DataFrame со столбцом, содержащим векторы признаков, делает прогноз для каждого вектора признаков и выводит новый DataFrame с результатами. В этом процессе XGBoost4J-Spark запускает таск Spark с воркером XGBoost для каждой части входного DataFrame для параллельного пакетного прогнозирования.

val predictionsDf = xgbClassificationModel.transform(inputDF)
predictionsDf.show()
+----------------+----------+-------------+-------------+----------+
|       features |classIndex|rawPrediction| probability |prediction|
+----------------+----------+-------------+-------------+----------+
|[5.1,3.5,1.2,.. |       0.0|[3.4556984...|[0.9957963...|       0.0|
|[4.7,3.2,1.3,.. |       0.0|[3.4556984...|[0.9961891...|       0.0|
|[5.7,4.4,1.5,.. |       0.0|[3.4556984...|[0.9964334...|       0.0|
+----------------+----------+-------------+-------------+----------+

Для точечного прогнозирования модель принимает один вектор.

val features = xgbInput.head().getAs[Vector]("features")
val result = xgbClassificationModel.predict(features)

Точечное прогнозирование с помощью XGBoost не рекомендуется из-за больших накладных расходов, поскольку они будут сравнимы с единичным прогнозом.

На данный момент последняя версия (0.9) XGBoost4J-Spark требует Spark 2.4.x., в основном потому, что теперь в нем используются средства org.apache.spark.ml.param.shared, которые доступны не полностью в более ранних версиях Spark.

Также эта версия включает в себя более последовательную обработку пропущенных значений, лучшую производительность для многоядерных процессоров, улучшение управления кэшированием разделенных обучающих данных для сокращения времени обучения и т.д.

Узнать больше вы можете в документации XGBoost.

Источники


XGBoost с CUDA
XGBoost в Spark c GPU и RAPIDS XGboost4J-Spark



Узнать о курсе подробнее.


Теги:Machine LearningSparkBig DataApache SparkXgboost
Хабы: Блог компании OTUS. Онлайн-образование Apache Big Data Машинное обучение
+9
1,2k 15
Комментировать
Лучшие публикации за сутки