Параметры обучения, вынесенные из кода в структурированные файлы. Простой шаг, после которого перестают плодиться ветки «эксперимент с lr=3e-4».
Ключевые тезисы
- Иерархические собираются из кусков: модель, данные, задаются независимо.
- Переопределение из командной строки позволяет менять параметр, не трогая файл.
- перебирает сетку параметров одной командой, складывая результаты по отдельным папкам.
Какую задачу решает
Эксперимент начинается с одного скрипта и трёх констант наверху файла. Через месяц констант тридцать, часть закомментирована, а чтобы вспомнить, с каким получилась лучшая метрика, приходится лезть в историю git. Знакомая цена того, что параметры живут в коде.
Конфигурация выносит их наружу — в структурированные файлы, которые собираются из частей. Модель, датасет, и логгер описываются независимо и комбинируются: «эта модель на тех данных с таким оптимизатором» становится строкой запуска, а не новой веткой.
Побочная польза оказывается главной. Раз запуск полностью задан конфигом, его можно сохранить рядом с результатом — и через полгода воспроизвести. Раз параметры структурированы, по ним можно перебирать сетку одной командой вместо цикла в bash.
Ветка в git означает изменение кода. Если код не менялся, а поменялось число, ветка врёт: она говорит «здесь другая логика», хотя логика та же. Дальше начинается неизбежное — ветки расходятся, в одной поправили баг, в другой нет, и слить их нельзя, потому что различия перемешаны с параметрами. Конфигурация разрывает это: код один, ветка одна, а различие эксперимента живёт в файле, который лежит рядом с результатом. Проверка простая — если для запуска эксперимента нужно что-то закомментировать, параметр стоит не там.
Подробный разбор
Конфигурация раскладывается по группам, и каждая группа — это папка с вариантами. Запуск выбирает по одному варианту из каждой группы, и они собираются в один объект.
conf/
config.yaml # что берётся по умолчанию
model/
resnet18.yaml
resnet50.yaml
vit_base.yaml
data/
cifar10.yaml
imagenet.yaml
optimizer/
adamw.yaml
sgd.yamldefaults:
- model: resnet18
- data: cifar10
- optimizer: adamw
epochs: 30
seed: 42
# интерполяция: батч выводится из числа устройств
batch_size: ${eval:'64 * ${trainer.devices}'}Комбинация «resnet50 на imagenet с » перестаёт быть новым файлом: это три слова в команде запуска. Число возможных конфигураций растёт как произведение, а число файлов — как сумма.
python train.py model=vit_base optimizer.lr=3e-4 epochs=50model=vit_base— заменить весь вариант группы.optimizer.lr=3e-4— поменять одно поле внутри выбранного варианта.+trainer.precision=16— добавить ключ, которого в конфиге не было.~logging.wandb— убрать ключ целиком.
Итоговый сохраняется в папку запуска целиком, со всеми переопределениями. Это и есть воспроизводимость: чтобы повторить эксперимент, не нужно вспоминать команду — достаточно взять сохранённый файл.
python train.py --multirun \
model=resnet18,resnet50 \
optimizer.lr=1e-3,3e-4,1e-4 \
data.augment=true,falseДвенадцать комбинаций уходят последовательно или параллельно, каждая — в свою папку с собственным конфигом, логами и чекпоинтами. Никакого внешнего bash-цикла, и результаты не перетирают друг друга.
Подключаемые модули запуска отправляют те же двенадцать задач в кластера (Slurm, Ray) без изменения кода. Локальная отладка и кластерный перебор отличаются одним флагом.
YAML не знает, какие ключи допустимы: learning_rate вместо lr пройдёт молча, а модель обучится со значением по умолчанию. Через три часа вы увидите не тот результат и не поймёте почему.
from dataclasses import dataclass
@dataclass
class OptimizerConfig:
lr: float = 1e-3
weight_decay: float = 0.01
@dataclass
class TrainConfig:
optimizer: OptimizerConfig
epochs: int = 30
seed: int = 42Со схемой неизвестный ключ падает сразу с внятным сообщением, а строка в поле int не доедет до обучения. Плюс редактор начинает подсказывать имена полей.
Где применяется
- Серия экспериментовДвадцать конфигураций, отличающихся двумя параметрами, — одна команда.
- Воспроизводимость сохраняется рядом с чекпоинтом: запуск восстанавливается точно.
- Общий код на несколько задачОдин , разные под разные датасеты.
- Передача работыКоллеге отдаётся , а не инструкция «поменяй строку 47».
Плюсы, минусы и альтернативы
Плюсы
- Параметры отделены от кода: изменение эксперимента не меняет историю git.
- Сетка параметров перебирается штатно, без внешних скриптов.
- запуска сохраняется автоматически — воспроизводимость бесплатно.
- Типизация ловит опечатки в именах параметров до старта обучения.
Минусы
- Ещё один слой абстракции: понять, откуда взялось значение, бывает непросто.
- Динамическая композиция усложняет отладку — вызовов становится длиннее.
- Соблазн вынести в всё подряд, включая то, что параметром не является.
Брать, если
- Экспериментов больше десятка и они отличаются параметрами, а не логикой.
- переиспользуется на нескольких задачах.
Не брать, если
- Разовый скрипт с тремя параметрами — argparse проще и понятнее.
- Параметры меняются вместе с логикой: не спасёт от новой ветки кода.
Чем заменяют
Видеолекции
Записи университетских курсов, где эта тема звучит. Где у записи есть тайм-коды, ссылка открывает её с нужной секунды; где их не проставили — с начала.
Всё, что названо в описании, разобрано здесь же или в соседней теме — переходы под каждым определением.
Иерархический конфиг
Конфигурация собирается из независимых групп: модель, данные, .
Разбор ниже: Композиция конфиговПереопределение
Параметр меняется из командной строки без правки файла.
Разбор ниже: Переопределение из командной строкиМультизапуск
Перебор сетки параметров одной командой, каждый запуск в своей папке.
Разбор ниже: МультизапускТипизированный конфиг
Схема на дата-классах: опечатка в имени параметра ловится до запуска.
Разбор ниже: Типизированные конфигиИнтерполяция
Один параметр ссылается на другой — выводится из числа .
Разбор ниже: Композиция конфиговПрофильная компетенция для роли: Продуктовый инженер.
Усиливает профиль: ML Engineer, MLOps-инженер.
Спрашивают на собеседовании: Группа Астра — Платформа и эксплуатация ML.
Глава «MLOps» последний раз правилась . Нашли ошибку — напишите.