MLflow: учёт экспериментов, когда моделей стало много
Если вы дообучаете модель хотя бы неделю подряд, у вас уже минимум десяток прогонов с разными гиперпараметрами, версиями данных и чекпоинтами — и часть из них вы не сможете сейчас отличить друг от друга. Через месяц вопрос «а как мы получили вот этот результат» превращается в археологию по именам файлов вида model_final_v2_real_fixed.pt. MLflow решает именно это: систематически фиксирует, что использовалось в каждом запуске и что из этого получилось, а не заставляет вас помнить это самому.
Содержание
- Проблема: почему заметок и имён файлов быстро перестаёт хватать
- Что именно фиксирует MLflow при каждом запуске
- Разворачиваем MLflow Tracking Server на своём сервере
- Интеграция в код обучения
- Model Registry: какая версия модели сейчас в проде
- Практическая ценность: воспроизводимость и решения, а не просто журнал
Проблема: почему заметок и имён файлов быстро перестаёт хватать
Пока экспериментов пять, держать их в голове или в блокноте несложно. Проблема начинается на масштабе — когда за неделю активной работы накапливается 30-50 запусков с разными комбинациями learning rate, batch size, версий датасета и архитектуры.
Типичные вопросы, на которые перестаёт хватать памяти и файловых имён:
- Какой именно набор параметров дал вот этот конкретный чекпоинт с val_accuracy 0.891?
- Какая версия модели сейчас реально стоит в проде — та, что с augmentation, или без?
- Чем текущий эксперимент отличается от предыдущего успешного варианта — поменяли одну переменную или пять сразу?
- Куда делся график с confusion matrix для запуска трёхнедельной давности?
Ручной учёт (таблица в Excel, папки experiment_1, experiment_2_fixed, заметки в Notion) какое-то время работает, но ломается ровно тогда, когда становится нужнее всего — в момент, когда экспериментов много и цена ошибки в выборе модели растёт. Таблицу забывают обновить после неудачного прогона, файлы переименовывают вручную и путают версии, а связь «эти метрики получены именно этим кодом с именно этими данными» держится только в памяти автора.
MLflow — open-source инструмент, который берёт эту рутину на себя: при каждом запуске обучения он автоматически фиксирует параметры, метрики, артефакты и связывает их в один просматриваемый и сравнимый объект — без ручного ведения таблиц.
Что именно фиксирует MLflow при каждом запуске
Центральное понятие в MLflow — run (запуск): один прогон обучения или эксперимента. Для каждого run автоматически сохраняются четыре вещи:
- Параметры (params) — гиперпараметры, с которыми запущено обучение: learning rate, batch size, число эпох, версия датасета, архитектура, seed. Пишутся один раз при старте и не меняются.
- Метрики (metrics) — числовые показатели качества: loss, accuracy, F1, perplexity и что угодно ещё. В отличие от параметров метрики можно логировать по шагам (по эпохам или по батчам), и MLflow сам построит график изменения метрики во времени.
- Артефакты (artifacts) — файлы: сама обученная модель (веса), графики (confusion matrix, ROC-кривая), логи обучения, конфиги, примеры предсказаний. Хранятся отдельно от базы метаданных — на диске или в S3-совместимом хранилище.
- Метаданные запуска — время старта и завершения, статус (FINISHED/FAILED/RUNNING), тег с версией кода (git commit), кто и с какой машины запустил.
Вся эта информация попадает в единый веб-интерфейс — MLflow UI, — где можно открыть таблицу всех запусков эксперимента, отсортировать по нужной метрике и сравнить несколько запусков бок о бок: какие параметры отличались и как это отразилось на метриках. Это заменяет ручную таблицу сравнения, которую иначе пришлось бы поддерживать вручную и которая почти неизбежно расходится с реальностью через пару недель.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть ИИ на сервереРазворачиваем MLflow Tracking Server на своём сервере
Для одного человека и небольших экспериментов достаточно mlflow ui локально с файловым хранилищем. Но если над моделями работает больше одного человека или экспериментов действительно много, нужен отдельный tracking-сервер с полноценной базой данных под метаданные и объектным хранилищем под артефакты — иначе локальная файловая база (mlruns/) станет тяжёлой и её неудобно расшаривать между машинами.
Практическая схема: PostgreSQL под backend store (параметры, метрики, метаданные экспериментов) и MinIO под артефакты (S3-совместимое хранилище, поднятое на своём сервере — про его установку у нас есть отдельный разбор: MinIO в docker-compose).
Официальный образ mlflow не включает драйверы для Postgres и S3, поэтому нужен свой Dockerfile:
FROM python:3.11-slim
RUN pip install --no-cache-dir mlflow psycopg2-binary boto3
И docker-compose.yml:
services:
postgres:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_DB: mlflow
POSTGRES_USER: mlflow
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
minio:
image: minio/minio:latest
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
volumes:
- miniodata:/data
mlflow:
build: .
restart: unless-stopped
depends_on:
- postgres
- minio
environment:
MLFLOW_S3_ENDPOINT_URL: http://minio:9000
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER}
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD}
command: >
mlflow server
--backend-store-uri postgresql://mlflow:${POSTGRES_PASSWORD}@postgres:5432/mlflow
--default-artifact-root s3://mlflow-artifacts/
--host 0.0.0.0 --port 5000
ports:
- "5000:5000"
volumes:
pgdata:
miniodata:
Бакет mlflow-artifacts в MinIO нужно создать заранее (через консоль MinIO на порту 9001 или mc mb). После docker compose up -d интерфейс MLflow доступен на порту 5000.
Важный нюанс: у open-source MLflow нет встроенной авторизации в UI — любой, кто достучится до порта 5000, увидит все эксперименты и сможет их менять. На боевом сервере порт наружу лучше не выставлять вообще, а доступ давать через reverse proxy с basic-auth (о том, как вообще устроен путь запроса через reverse proxy — в отдельной статье):
server {
listen 443 ssl;
server_name mlflow.example.internal;
location / {
auth_basic "MLflow";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
}
}
Если поднимаете сервер под обучение и эксперименты с нуля, включая базовое окружение, у нас есть более общий разбор — пошаговая настройка VPS под обучение и эксперименты.
Интеграция в код обучения
На стороне клиента нужен только пакет mlflow и несколько строк вокруг существующего тренировочного цикла — переписывать сам пайплайн обучения не требуется.
import mlflow
mlflow.set_tracking_uri("https://mlflow.example.internal")
mlflow.set_experiment("resnet-finetune")
with mlflow.start_run(run_name="lr_1e-4_batch_32_aug"):
mlflow.log_param("learning_rate", 1e-4)
mlflow.log_param("batch_size", 32)
mlflow.log_param("dataset_version", "v3_cleaned")
mlflow.log_param("augmentation", True)
for epoch in range(epochs):
train_loss = train_one_epoch(model, train_loader, optimizer)
val_acc = evaluate(model, val_loader)
mlflow.log_metric("train_loss", train_loss, step=epoch)
mlflow.log_metric("val_accuracy", val_acc, step=epoch)
mlflow.log_artifact("confusion_matrix.png")
mlflow.pytorch.log_model(model, artifact_path="model")
Для популярных фреймворков (scikit-learn, PyTorch Lightning, Keras, XGBoost) в MLflow есть режим автологирования — не нужно вручную вызывать log_param/log_metric для стандартных вещей:
import mlflow.sklearn
mlflow.sklearn.autolog()
# дальше обучаете модель как обычно —
# параметры и метрики попадут в MLflow автоматически
model.fit(X_train, y_train)
Автологирование удобно как отправная точка, но для нестандартных метрик (кастомная бизнес-метрика, промежуточные графики) всё равно придётся логировать вручную — autolog покрывает типовые случаи, а не всё подряд.
Model Registry: какая версия модели сейчас в проде
Отдельный модуль MLflow — Model Registry — решает вторую часть проблемы: не «какие параметры дали этот результат», а «какая из обученных моделей сейчас реально используется и чем она отличается от других версий-кандидатов».
Модель регистрируется из конкретного run:
result = mlflow.register_model(
model_uri="runs:/<run_id>/model",
name="resnet-finetune"
)
Каждая регистрация создаёт новую версию модели с сохранённой ссылкой на run, из которого она получена — то есть на все параметры и метрики этого run можно вернуться в любой момент. Дальше версии можно помечать алиасами, чтобы явно указать, какая используется в продакшене:
from mlflow import MlflowClient
client = MlflowClient()
client.set_registered_model_alias("resnet-finetune", "production", result.version)
Приложение в проде обращается не к конкретному номеру версии, а к алиасу:
model = mlflow.pyfunc.load_model("models:/resnet-finetune@production")
Это снимает конкретный вопрос «а какая версия сейчас в проде» — ответ один клик в UI Model Registry, а не переписка в чате «кто последний деплоил модель». Когда появляется новый кандидат лучше текущего — алиас переставляется на новую версию, старая остаётся зарегистрированной и доступной для отката.
Практическая ценность: воспроизводимость и решения, а не просто журнал
Три конкретных сценария, где наличие такого учёта окупает время на его настройку:
Воспроизводимость задним числом. Через несколько недель или месяцев к вам возвращаются с вопросом «а как была получена вот эта модель с такими метриками». Без систематического учёта ответ — это попытка вспомнить или перебрать старые файлы. С MLflow — это открыть run и увидеть точный набор параметров, версию датасета и артефакты, которые к этому результату привели.
Прозрачность продакшен-версии. В команде из нескольких человек рано или поздно возникает рассинхрон: кто-то думает, что в проде модель А, а на самом деле там уже стоит модель Б после чужого деплоя. Model Registry с алиасами делает эту информацию видимой для всех, а не устной договорённостью.
Сравнение вариантов при принятии решения. Когда нужно выбрать, какой из пяти опробованных подходов брать дальше в работу, сравнение в таблице MLflow UI (метрики нескольких run рядом, с сортировкой и фильтрами) занимает пару минут — вместо восстановления результатов из разрозненных заметок и повторного прогона того, что уже считалось.
Практический совет по внедрению один: начинайте использовать систематический учёт экспериментов рано — с первых же прогонов активной экспериментальной работы, — а не тогда, когда уже накопилось полсотни неучтённых запусков и наводить в них порядок задним числом дороже, чем вести учёт с самого начала. Разница в стоимости огромная: добавить три строки логирования в уже написанный тренировочный цикл — вопрос пяти минут, а восстановить утерянный контекст по полусотне безымянных чекпоинтов — это часы, а иногда и вовсе невозможно, если исходные данные уже перезаписаны следующей версией датасета.
Если вы дообучаете модель через LoRA, стоит сразу логировать в MLflow и это — какой базовый чекпоинт брался, какой ранг адаптера и какой датасет; подробнее про сам процесс — в статье про LoRA-файнтюнинг своей модели на VPS.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть ИИ на сервереНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
MLflow бесплатный?
Да, это open-source проект под Apache 2.0. Вы разворачиваете и обслуживаете его сами на своём сервере — платите только за инфраструктуру (сервер, диск под артефакты), а не за лицензию.
Нужен ли отдельный сервер под MLflow или можно на той же машине, что и обучение?
Можно и на той же машине для соло-работы с небольшим объёмом артефактов. Но если моделей много (веса по несколько гигабайт) или работает больше одного человека, разумнее вынести tracking-сервер и хранилище артефактов отдельно, чтобы не конкурировать за диск и GPU с самим обучением.
Что если я уже накопил кучу неучтённых экспериментов — стоит ли заводить MLflow сейчас?
Стоит, но не пытайтесь восстановить историю всех старых запусков — это обычно не окупается. Заведите MLflow под будущие эксперименты, а старые лучшие модели зарегистрируйте в Model Registry вручную с той информацией, которую удалось восстановить.
Чем MLflow отличается от простого сохранения чекпоинтов на диск?
Чекпоинт — это только файл с весами. MLflow добавляет к нему структурированную связь с параметрами, метриками и кодом, из которых он получен, плюс интерфейс для сравнения десятков таких запусков между собой — просто файлы на диске этого не дают.
Можно ли логировать эксперименты из нескольких машин в один MLflow-сервер?
Да, для этого он и разворачивается отдельно — любой клиент с доступом к MLFLOW_TRACKING_URI пишет в общую базу, и все эксперименты команды видны в одном месте.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →