TL; DR Краткое руководство по использованию пакета Hyperopt HPO с RAPIDS в облаке Databricks для оптимизации точности классификатора случайного леса. (Полные примеры кода доступны здесь.)

В нашем предыдущем блоге мы показали, как использовать MLFlow вместе с RAPIDS cuML для более быстрого обучения моделей и более эффективного управления ими. Эти инструменты позволяют отдельным специалистам по данным и группам быстро выполнять итерации моделей и постоянно улучшать их, поддерживая плавный переход к производству. Но по мере того, как становится все проще обучать большое количество моделей, мы должны спросить - почему бы не позволить алгоритму сделать эту работу за нас? Здесь может вмешаться оптимизация гиперпараметров (HPO), которая поможет нам построить более точные модели с минимальными усилиями.

В этом блоге вы узнаете, как использовать пакет HPO hyperopt вместе с RAPIDS в облаке Databricks для оптимизации точности простого классификатора случайных лесов. RAPIDS ускорит обучение модели, а облако Databricks распараллелит ее для любого количества рабочих процессов. В обучающем примере (представленном здесь в репозитории cloud-ml-examples) это приводит к оптимизированной модели примерно в 40 раз быстрее, чем аналогичная модель, построенная на ЦП без RAPIDS.

Что такое оптимизация гиперпараметров?

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

Системы HPO автоматически создают десятки или сотни вариантов моделей с разными параметрами, сравнивают их точность и позволяют пользователям выбрать лучшую модель. Алгоритмы для HPO были областью академического интереса на протяжении десятилетий. В последнее время они стали популярными как высокопроизводительные вычисления, а ускорение графического процессора позволяет обучать большее количество моделей.

Наивные системы HPO могут исследовать доступные параметры, выполняя «поиск по сетке» - равномерно исследуя комбинации параметров в их допустимом диапазоне. Например, чтобы исследовать max_depth в диапазоне (5, 14) и n_estimators в диапазоне (50, 500) с шагом 50, поиск по сетке будет оценивать все 100 возможных комбинаций параметров:

max_depth=5, n_estimators=50
max_depth=5, n_estimators=100
max_depth=5, n_estimators=150
...
max_depth=14, n_estimators=500

Этот подход может быть исчерпывающим, но очень медленным и часто неэффективным. Если мы обучаем несколько моделей и видим, что низкий max_depth всегда приводит к плохой производительности для многих значений num_trees, хотим ли мы тратить время вычислений, чтобы снова и снова пробовать это значение параметра?

Интеллектуальные алгоритмы HPO непрерывно оценивают точность прошлых моделей и используют их, чтобы направлять следующие шаги исследования параметров. Hyperopt, одна из самых популярных систем HPO, для ускорения этого процесса использует алгоритм под названием Tree-structured Parzen Estimators (TPE). TPE моделирует взаимосвязь между гиперпараметрами и целевой функцией с кусочными функциями, имеющими древовидную структуру. Подробнее о внутреннем устройстве TPE см. Bergstra et al. 2011 .

Но вам не нужно разбираться в деталях TPE, потому что пакет hyperopt с открытым исходным кодом инкапсулирует алгоритм в дружественный Python API. Hyperopt можно использовать автономно в любой системе для оптимизации модели, но это становится наиболее интересным в сочетании с распределенной платформой, такой как Databricks.

Начало работы с RAPIDS и Hyperopt на Databricks

В каталоге Databricks в репозитории RAPIDSAI / cloud-ml-examples на GitHub у нас есть пример записной книжки, в которой просматривается весь код, необходимый для оптимизации простой модели с помощью гипероптики на Databricks, и отслеживается ее через MLFlow. Репо также содержит сценарии инициализации, которые упрощают установку RAPIDS в кластере Databricks.

Чтобы построить кластер RAPIDS-on-Databricks, начните с выбора среды выполнения Databricks, которая поддерживает графические процессоры. Мы протестировали эти сценарии на «Runtime 6.6 ML» (более поздние версии runtime могут быть еще несовместимы). Выберите тип рабочего, который поддерживает современные графические процессоры NVIDIA (Pascal или новее), и выберите тот же тип инстанса для драйвера. Для кластеров с поддержкой AWS любой из экземпляров «p3.» или «g4dn.» будет поддерживать RAPIDS - просто держитесь подальше от гораздо более старых экземпляров «p2.», которые имеют более раннее поколение графических процессоров.

Чтобы установить RAPIDS, вам нужно скопировать сценарии инициализации RAPIDS в хранилище данных DBFS. Скопируйте сценарий rapids_install_cuml0.13_cuda10.0_ubuntu16.04.sh из репозитория cloud-ml-examples в папку DBFS по вашему выбору, например, выполнив следующие команды в записной книжке Databricks:

dbfs configure
dbfs cp src/rapids_install_cuml0.13_cuda10.0_ubuntu16.04.sh dbfs:/databricks/init_scripts/

В разделе конфигурации Advanced Options добавьте путь DBFS к этому сценарию в качестве сценария инициализации для вашего кластера:

Теперь при запуске кластера он автоматически установит RAPIDS. Этот процесс может занять 10–15 минут во время запуска, но он не добавит дополнительного времени выполнения при запуске заданий после запуска.

Вот и все! Вы можете запустить записную книжку, подключить ее к этому кластеру и сразу начать использовать RAPIDS в интерактивном режиме. Для некоторых небольших заданий вы можете выполнять вычисления непосредственно в ноутбуке, работая на узле драйвера. Но для крупномасштабного HPO мы настроим Hyperopt для запуска заданий на нескольких рабочих, чтобы обеспечить истинное горизонтальное масштабирование.

Интеграция с Hyperopt

Databricks уже установила пользовательскую версию hyperopt в среде машинного обучения в своем облаке, так что мы можем импортировать ее прямо сейчас. Мы начнем с простой обучающей функции, основанной на том же наборе данных и оценке, которые мы использовали в блоге MLFlow. Опять же, мы обучаем классификатор, чтобы предсказывать, прибудет ли рейс вовремя, используя набор данных о прошлых рейсах Федерального управления гражданской авиации США. Мы хотим настроить гиперпараметры n_estimators (количество деревьев, которые нужно построить), max_depth (насколько глубоко может быть каждое дерево) и max_features (доля функций, которые следует учитывать при каждом разбиении), чтобы максимизировать точность.

Для интеграции модели с Hyperopt требуется четыре шага:

  1. Определите вашу целевую функцию,
  2. Определите пространство параметров,
  3. Создайте объект SparkTrials и
  4. Запустите hyperopt с функцией «hyperopt.fmin».

1. Определите вашу целевую функцию.

Hyperopt исследует параметры, чтобы минимизировать эту функцию, и мы можем свободно определять ее, как нам нравится. В задаче машинного обучения эта функция обычно влечет за собой обучение модели с заданными параметрами, а затем ее оценку на длительном наборе проверки для измерения ее точности.
Чтобы соответствовать API-интерфейсу hyperopt, эта целевая функция должна возвращать словарь со значением «потери», которое система должна минимизировать. В примере записной книжки это функция train_rapids.

def train_rapids(hyperopt_params):
   “””
   Pseudo training function
   1. Unpack hyperopt_params
   2. Train a new model with those hyperopt_params
   3. Compute accuracy as ‘acc’ on validation set
   “””
   # …. function body here ….
   return {‘loss’: acc, ‘status’: STATUS_OK}

2. Определите пространство параметров.

Для каждого параметра, который мы хотим исследовать, нам нужно дать гипероптему диапазон значений для рассмотрения в форме распределения вероятностей. API-интерфейс hyperopt предоставляет функции диапазона вероятностей, такие как hyperopt.hp.uniform(parameter_name, lower_bound, upper_bound), для однородной выборки между границами. Hyperopt также поддерживает распределения с целыми диапазонами или категориальными значениями.

search_space = [
   hyperopt.hp.uniform(‘max_depth’, 5, 20),
   hyperopt.hp.uniform(‘max_features’, 0., 1.0),
   hyperopt.hp.uniform(‘n_estimators’, 150, 1000)
]

3. Создайте объект «SparkTrials».

Это позволит отслеживать наш прогресс и обеспечить интеграцию с Apache Spark.

import hyperopt
spark_trials = hyperopt.SparkTrials(parallelism=MAX_PARALLEL)

4. Запустите hyperopt с функцией hyperopt.fmin.

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

results = hyperopt.fmin(fn=train_rapids,
   space=search_space,
   algo=algorithm,
   max_evals=2,
   trials=trials)

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

Здесь мы можем выбрать показатели из наших недавних прогонов на график. Здесь мы покажем, как изменяется точность при увеличении параметра max_depth.

Чтобы построить крупномасштабную модель с помощью примера записной книжки, используйте входной файл «airlines_20000000.parquet» в качестве параметра имени файла. При работе на двух узлах p3.2xlarge (с одним графическим процессором V100 в каждом) это займет около 17 минут для работы на графическом процессоре. Точность модели варьируется от 83% для худших моделей до 86% для высокоточных. Таким образом, вы можете значительно повысить точность всего за несколько минут работы. В зависимости от вашего бюджета и квот вы можете еще больше усилить параллелизм, чтобы выполнять задания быстрее. Поскольку HyperOpt невероятно параллельна, она очень хорошо масштабируется для больших систем.

Если вы хотите развернуть модель, вы можете воспользоваться встроенной интеграцией Hyperopt с репозиторием модели MLFlow на Databricks. См. Блог MLFlow для получения более подробной информации об управлении моделью MLFlow.

В записной книжке также есть пример кода для запуска HyperOpt на процессорах с помощью scikit-learn. Однако имейте в виду, что работа с двумя параллельными узлами займет около 12 часов.

Заключение

В этом блоге представлены лишь поверхностные сведения о возможностях HPO и RAPIDS. Репо cloud-ml-examples содержит несколько других демонстраций HPO. Если у вас есть комментарии, вопросы или проблемы, сообщите о проблеме по этому репо или задайте вопрос в RAPIDSAI Slack.

Кроме того, Джон Зедлевски выступил с докладом на тему Оптимизация моделей с помощью hyperopt и RAPIDS в облаке Databricks на Spark + AI Summit. Отметьте здесь для записи по запросу.