Обзор Optuna: подбор гиперпараметров модели начинается с разделения двух сущностей. Параметры модели настраиваются обучением на данных. Гиперпараметры задаёт человек до запуска обучения: глубина дерева, скорость обучения, число слоёв. Optuna перебирает комбинации гиперпараметров и сравнивает результаты trials.
Параметры модели и гиперпараметры
Параметры модели — это веса и смещения, которые алгоритм подбирает сам в процессе обучения на train-выборке. Гиперпараметры задаются до старта обучения и управляют тем, как именно будет идти этот процесс. В дереве решений это глубина и минимальное число объектов в листе, в градиентном бустинге — скорость обучения и число деревьев, в нейросети — размер батча и learning rate.
Разделение важно для постановки задачи оптимизации. Optuna выбирает значения гиперпараметров. Пользовательская objective-функция определяет, как обучить модель на train-выборке и вернуть метрику качества. Сохранение обученной модели нужно организовать отдельно.
Смешение уровней даёт две типичные ошибки. Первая: гиперпараметры смешивают с обучаемыми весами; число эпох относится к задаваемому бюджету обучения и тоже может быть гиперпараметром. Вторая: гиперпараметр фиксируется константой в коде, хотя именно его стоило перебирать. Различайте обучаемые величины, например веса, и настройки процесса обучения: последние могут задавать также расписание изменения learning rate.
Практический ориентир: в пространство поиска включают те гиперпараметры, влияние которых на метрику неочевидно. Константы, проверенные прошлыми экспериментами, оставляют фиксированными, чтобы не раздувать пространство. Каждое измерение увеличивает число комбинаций, и время поиска растёт вместе с ним.
Study, trial и objective на заполненном журнале
Документация Optuna описывает базовый порядок так: создаётся объект study, а функция objective передаётся методу optimize(). Функции, которые оптимизируются, по соглашению называют objective. Цель — найти значение x, минимизирующее выход objective. В ходе оптимизации Optuna многократно вызывает objective с разными значениями x.
Разберём заполненный учебный журнал для минимизации validation loss. Значения заданы искусственно для чтения структуры study; обучение по ним не проводилось:
| Trial | depth | lr | value (validation loss) |
|---|---|---|---|
| trial0 | 2 | 0.1 | 0.42 |
| trial1 | 4 | 0.05 | 0.35 |
| trial2 | 6 | 0.01 | 0.38 |
Лучший trial в этом журнале — trial1 со значением 0.35. Study — контейнер, который хранит все trials и их результаты. Trial — один запуск objective с конкретным набором гиперпараметров. Objective — функция, которую Optuna вызывает на каждом trial.
Контракт objective в этом примере: получить гиперпараметры, обучить модель на train, вернуть validation loss. Test-набор в objective не передаётся. Значение best нельзя интерпретировать без названия метрики и направления: 0.35 — это validation loss при минимизации, и меньшее число здесь лучше.
Чтение журнала даёт ответ на вопрос, какой trial выбирать. Optuna хранит историю и по ней строит следующие предложения. Samplers, по документации проекта, последовательно сужают пространство поиска, опираясь на записи предложенных значений и оценок objective.
Пространство suggest_int и suggest_float
Пространство поиска задаётся внутри objective через методы suggest_*. Для целочисленного гиперпараметра, например глубины дерева, применяется suggest_int. Для вещественного, например learning rate, — suggest_float. Категориальный параметр вроде типа активации задаётся через suggest_categorical.
Документация Optuna приводит пример с логарифмической шкалой: svc_c = trial.suggest_float(«svc_c», 1e-10, 1e10, log=True). Логарифмическая шкала уместна для величин, которые меняются на порядки: скорость обучения, коэффициент регуляризации. Линейная шкала подходит для величин с узким разумным диапазоном.
Направление оптимизации задаётся при создании study. По умолчанию Optuna минимизирует возвращаемое значение. Для метрики accuracy, которую нужно максимизировать, направление указывают явно. Значение best читается вместе с названием метрики и направлением: при maximize правило выбора меняется на противоположное.
Типичная ошибка — слишком широкий диапазон без логарифмической шкалы. Диапазон от 1e-10 до 1e10 при линейном семплировании почти все значения соберёт в верхней части, и малые learning rate останутся непроверенными. Логарифмическая шкала распределяет попытки равномерно по порядкам величины.
Вторая ошибка — пересекающиеся диапазоны у зависимых параметров. Если число слоёв и ширина слоя связаны, разумно строить условное пространство: сначала выбрать тип активации, затем под него задать диапазоны остальных величин. Документация Ray Tune показывает такой define-by-run подход, где ветка relu и ветка tanh получают разные границы width и height.
Train, validation, test
Данные делят на три части, и у каждой своя роль. Train-выборка идёт на обучение модели внутри trial. Validation-выборка возвращается objective как метрика, по которой Optuna сравнивает trials. Test-выборка остаётся нетронутой до финальной проверки выбранной конфигурации.
Документация MLflow в разделе про подбор гиперпараметров описывает деление на training и validation sets. Тот же принцип применим к objective в Optuna: обучение на train, оценка на validation, возврат validation-метрики.
Выбор лучшей модели по test-набору искажает оценку качества. Test участвует в отборе, и его метрика перестаёт быть независимой. Правильный порядок: Optuna отбирает конфигурацию по validation, после чего выбранная модель один раз оценивается на test. Test не передаётся в objective.
Практический приём — фиксировать разбиение данных до запуска study. Если каждый trial делит данные заново случайным образом, trials сравниваются на разных validation-выборках, и разница между ними частично объясняется разбиением. Один и тот же seed разбиения для всех trials делает сравнение честным.
Pruning и промежуточные метрики
Pruning — досрочное прекращение слабого trial. Документация Optuna формулирует условие так: чтобы включить pruning, нужно вызывать report() и should_prune() после каждого шага итеративного обучения. Без промежуточных метрик механизм не работает.
Лимит числа trials задаёт, сколько запусков сделать. Pruning решает, какие запуски доводить до конца. Это разные рычаги: n_trials ограничивает общий объём работы, pruning экономит время внутри уже запущенных trials. Trial, который на первых эпохах показывает метрику хуже остальных, останавливается и не тратит ресурсы.
Документация проекта отмечает, что модуль pruners рассчитан на одноцелевую оптимизацию. Для многоцелевых задач механизм применяют с оговорками. В примере Ray Tune сказано, что сложные планировщики вроде AsyncHyperBandScheduler могут работать с многоцелевой оптимизацией некорректно, поскольку ожидают скалярную оценку для сравнения trials.
Порядок включения pruning: внутри цикла обучения после каждой эпохи вызывается report() с промежуточным значением метрики, затем should_prune() возвращает решение о прекращении. Если should_prune() вернула истину, в objective вызывают raise optuna.TrialPruned(), чтобы остановить trial. Выберите промежуточную метрику, подходящую для сравнения хода trials, и согласуйте её направление с настройкой study.
Известный квадратный objective
Для проверки API удобна учебная функция f(x) = (x − 2)² на диапазоне [−5, 5]. У неё известный минимум 0 при x = 2. Задача прозрачна: видно, приближается ли поиск к точке 2.
Ограничение числа trials не гарантирует попадание в точку 2. Результат случайного семплирования заранее не выдумывается. Учебный пример показывает устройство API. Качество алгоритма поиска требует отдельной проверки на вашей задаче.
import optuna
def objective(trial):
x = trial.suggest_float("x", -5.0, 5.0)
return (x - 2.0) ** 2
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=20)
print(study.best_params)
print(study.best_value)
Что здесь происходит по шагам. create_study создаёт контейнер с направлением минимизации. optimize вызывает objective заданное число раз. Внутри objective suggest_float предлагает значение x из диапазона, а возвращаемое число — оценка этого значения. После запуска best_params хранит лучший набор, best_value — лучшее значение.
Что менять под себя: диапазон в suggest_float, тело objective и направление в create_study. Для реальной модели тело objective обучает модель на train и возвращает validation-метрику.
Optuna, Ray Tune и MLflow
Три инструмента закрывают разные обязанности. Optuna отвечает за поиск гиперпараметров: предлагает комбинации и ведёт историю trials. Ray Tune отвечает за оркестрацию: распределяет запуски по ресурсам, ограничивает параллелизм, управляет планировщиками. MLflow отвечает за tracking: записывает параметры, метрики и артефакты экспериментов.
| Инструмент | Обязанность | Что даёт читателю |
|---|---|---|
| Optuna | Поиск гиперпараметров | Sampler предлагает комбинации, study хранит trials |
| Ray Tune | Оркестрация запусков | Распределение по ресурсам, лимит параллельных trials |
| MLflow | Tracking экспериментов | Родительский run и дочерние runs с параметрами и метриками |
Документация Ray Tune описывает интеграцию через OptunaSearch: поисковый алгоритм Optuna подключается к Tune, а ConcurrencyLimiter ограничивает число одновременных trials. В примере документации лимит выставлен в 4. Там же показан define-by-run для условных пространств и многоцелевой режим с метриками loss и gain.
Документация MLflow описывает структуру из родительского run и дочерних runs: дочерний run создаётся с флагом nested=True. Родительский run соответствует study, дочерние — отдельным trials. Параметры, метрики и модели логируются по каждому trial.
Практическая связка: Optuna ведёт поиск, Ray Tune раздаёт trials по ресурсам, MLflow сохраняет историю. Каждый инструмент можно применять отдельно. Optuna работает без Ray Tune и без MLflow, а tracking подключается тогда, когда нужно сравнивать эксперименты между запусками.
Частые вопросы
Чем гиперпараметры отличаются от параметров модели?
Параметры модель подбирает сама в ходе обучения на train-выборке: веса, смещения, коэффициенты. Гиперпараметры задаются до запуска обучения и управляют его ходом: глубина дерева, скорость обучения, размер батча. Optuna ищет значения гиперпараметров, а веса пересчитываются внутри каждого trial.
Что такое study, trial и objective?
Study — контейнер, который хранит все trials и их результаты. Trial — один запуск objective с конкретным набором гиперпараметров. Objective — функция, которую Optuna вызывает многократно с разными значениями. В учебном журнале из трёх trials лучшим оказался trial1 со значением 0.35.
Как задать пространство поиска и направление оптимизации?
Пространство задаётся внутри objective методами suggest_int, suggest_float и suggest_categorical. Для величин, меняющихся на порядки, применяют логарифмическую шкалу. Направление указывают при создании study: по умолчанию идёт минимизация, для accuracy его меняют на максимизацию.
Почему нельзя выбирать лучшую модель по test-набору?
Test-набор нужен для независимой финальной оценки выбранной конфигурации. Если по нему отбирать лучший trial, он участвует в выборе, и его метрика перестаёт быть независимой. Отбор идёт по validation, а test применяется один раз в конце.
Как pruning экономит время и чем он отличается от лимита trials?
Лимит trials задаёт общее число запусков. Pruning позволяет остановить отдельный trial по промежуточным метрикам. В цикле обучения вызывают report() и should_prune(); при решении об остановке objective вызывает raise optuna.TrialPruned(). Модуль pruners рассчитан на одноцелевую оптимизацию.
