XGBoost и LightGBM зарекомендовали себя на многих наборах табличных данных как наиболее эффективные алгоритмы машинного обучения. Но когда данных очень много, как их использовать?

XGBoost и LightGBM доминируют во всех недавних соревнованиях kaggle по табличным данным. Просто перейдите на любую страницу соревнований (табличные данные) и посмотрите ядра, и вы увидите. В этих соревнованиях данные не являются «огромными» - ну, не говорите мне, что данные, которые вы обрабатываете, огромны, если их можно обучить на вашем ноутбуке. В этих случаях для построения моделей XGBoost и LightGBM достаточно ноутбука Jupyter.

Когда данные становятся больше, но не сверхбольшими, а вы все еще хотите использовать записные книжки Jupyter, скажем, для построения моделей - один из способов - использовать некоторые уловки по сокращению памяти (например, код ArjanGroen: https: // www .kaggle.com / arjanso / сокращение-dataframe-memory-size-by-65 ); или воспользуйтесь облачными сервисами, скажем, арендуйте EC2 на AWS. Например, экземпляры r5.24xlarge имеют 768 ГиБ памяти по цене 6 долларов в час, и я думаю, что он уже может обрабатывать большой объем данных, которые, по мнению вашего начальника, действительно большие.

Но что, если данных еще больше?

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

1 XGBoost4j на Scala-Spark
2 LightGBM на Spark (PySpark / Scala / R)
3 XGBoost с H2O.ai
4 XGBoost на Amazon SageMaker

Я хотел бы указать на некоторые проблемы каждого инструмента, основываясь на моем личном опыте, и предоставить некоторые ресурсы, если вы хотите их использовать. Я также буду рад узнать от вас, были ли у вас похожие проблемы / как вы их решаете! Прокомментируйте, пожалуйста, ниже.

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

XGBoost против LightGBM

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

Поэтому разработчики XGBoost позже улучшили свои алгоритмы, чтобы догнать LightGBM, позволяя пользователям также запускать XGBoost в режиме разделения по листам (grow_policy = ‘lossguide’). Теперь XGBoost намного быстрее с этим улучшением, но LightGBM по-прежнему примерно в 1,3–1,5 раза быстрее XGB, основываясь на моих тестах на нескольких наборах данных. (Добро пожаловать, чтобы поделиться результатами своих тестов!)

Читатели могут выбрать любой вариант по своему усмотрению. И еще кое-что: у XGBoost есть функция, которой не хватает LightGBM - монотонное ограничение. Это принесет в жертву точность модели и увеличит время обучения, но может улучшить интерпретируемость модели. (Ссылка: https://xgboost.readthedocs.io/en/latest/tutorials/monotonic.html и https://github.com/dotnet/machinelearning/issues/1651)

Найдите "золотую середину" в деревьях с градиентным усилением.

Для алгоритма случайного леса чем больше построено деревьев, тем меньше дисперсия модели. Но до некоторой степени вы не можете улучшить модель, добавляя больше деревьев.

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

Чтобы найти «золотую середину», вы можете выполнить перекрестную проверку или просто выполнить разделение набора для проверки и обучения, а затем использовать время ранней остановки, чтобы найти, где следует остановить обучение; или вы можете построить несколько моделей с разным количеством деревьев (скажем, 50, 100, 200), а затем выбрать лучшую из них.

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

1. XGBoost4j на Scala-Spark

Если читатель планирует использовать этот вариант, https://xgboost.readthedocs.io/en/latest/jvm/xgboost4j_spark_tutorial.html - хорошая отправная точка. Я хотел бы указать здесь на несколько проблем (на момент публикации этой статьи):

  1. XGBoost4j не поддерживает Pyspark.
  2. XGBoost4j не поддерживает режим разделения по листам, что делает его медленнее. Https://github.com/dmlc/xgboost/issues/3724
  3. Поскольку он находится в Spark, все пропущенные значения должны быть вменены (векторный ассемблер не допускает пропущенных значений). А это может снизить точность модели. Http://docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/gbm-faq/missing_values.html
  4. Ранняя остановка может все еще содержать ошибки. Если вы следите за их последними выпусками в https://github.com/dmlc/xgboost/releases, то обнаружите, что в последнее время они все еще исправляют эти ошибки.

2. LightGBM на Spark (Scala / Python / R)

Основные проблемы, основанные на моем личном опыте:

  1. Отсутствие документации и хороших примеров. Https://github.com/Azure/mmlspark/blob/master/docs/lightgbm.md
  2. Все пропущенные значения должны быть вменены (аналогично XGBoost4j).
  3. У меня также были проблемы с параметром «Ранняя остановка» в валидаторе искрового кросса. (Чтобы проверить, работает ли она должным образом, выберите меньший набор данных, выберите очень большое количество раундов с ранней остановкой = 10 и посмотрите, сколько времени потребуется для обучения модели. После ее обучения сравните точность модели с точностью, построенной с использованием Python. Если он плохо подходит, скорее всего, ранняя остановка вообще не работает.)

Некоторые примеры кодов (не включая векторный ассемблер):

from mmlspark import LightGBMClassifier
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
lgb_estimator = LightGBMClassifier(learningRate=0.1, 
                                   numIterations=1000,
                                   earlyStoppingRound=10,
                                   labelCol="label")
paramGrid = ParamGridBuilder().addGrid(lgb_estimator.numLeaves, [30, 50]).build()
eval = BinaryClassificationEvaluator(labelCol="label",metricName="areaUnderROC")
crossval = CrossValidator(estimator=lgb_estimator,
                          estimatorParamMaps=paramGrid, 
                          evaluator=eval, 
                          numFolds=3)     
cvModel  = crossval.fit(train_df[["features", "label"]])

3. XGBoost на H2O.ai

Это мое личное любимое решение. Модель может быть построена с использованием H2O.ai, интегрированной в конвейер Pysparkling Water (H2O.ai + PySpark):
https://www.slideshare.net/0xdata/productionizing-h2o-models-using-sparkling -воды-якуб-хава

Легко построить модель с оптимизированным количеством раундов с перекрестной проверкой -

# binary classification
features = ['A', 'B', 'C']
train['label'] = train['label'].asfactor() # train is an H2O frame
cv_xgb = H2OXGBoostEstimator(
    ntrees = 1000,
    learn_rate = 0.1,
    max_leaves = 50,
    stopping_rounds = 10,
    stopping_metric = "AUC",
    score_tree_interval = 1,
    tree_method="hist",
    grow_policy="lossguide",
    nfolds=5, 
    seed=0)
cv_xgb.train(x = features, y = 'label', training_frame = train)

А модель XGBoost можно сохранить и использовать в Python с cv_xgb.save_mojo(). Используйте h2o.save_model(), если хотите сохранить модель в формате h2o.

Моя единственная жалоба по этому поводу заключается в том, что сохраненная модель (сохраненная с save.mojo) не может использоваться с пакетом SHAP для генерации важности функции SHAP (но важность функции XGBoost, .get_fscore(), работает нормально). Похоже, есть некоторые проблемы с исходным пакетом XGBoost.
https://github.com/slundberg/shap/issues/464
https://github.com/dmlc/xgboost / issues / 4276

(Обновления: похоже, они только что реализовали SHAP в своем последнем выпуске - https://github.com/h2oai/h2o-3/blob/373ca6b1bc7d194c6c70e1070f2f6f416f56b3d0/Changes.md)

4. XGBoost в SageMaker

Это довольно новое решение от AWS. Двумя основными функциями являются автоматическая настройка гиперпараметров с байесовской оптимизацией, и модель может быть развернута в качестве конечной точки. Несколько примеров можно найти на их Github: https://github.com/awslabs/amazon-sagemaker-examples/tree/master/introduction_to_applying_machine_learning. Вот некоторые из моих опасений по этому поводу:

  1. Инструменты настройки параметров менее удобны для пользователей (специалистов по обработке данных) по сравнению с другими решениями:
    https://github.com/awslabs/amazon-sagemaker-examples/blob/master/hyperparameter_tuning/xgboost_direct_marketing/hpo_xgboost_direct_marketing_APP. И
    https://github.com/awslabs/amazon-sagemaker-examples/blob/master/hyperparameter_tuning/analyze_results/HPO_Analyze_TuningJob_Results.ipynb
  2. Пока неизвестно, является ли байесовская оптимизация лучшим вариантом для настройки параметров XGB. Если вы посмотрите статьи, деревья повышения градиента не упоминаются / не тестируются. Https://docs.aws.amazon.com/sagemaker/latest/dg/automatic-model-tuning-how-it-works.html
  3. Параметр настраивается с помощью одного набора проверок, а не перекрестных проверок.
  4. Я не понял, как использовать артефакт модели, обученный с помощью встроенного алгоритма XGBoost в Python XGBoost.

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

* * * * *

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