Files
mlflow-practice/AGENTS.md
T

15 KiB
Raw Blame History

AGENTS.md — гид для агента по проекту mlflow-practice

Этот файл — ориентир для любого AI-агента (и человека), который будет работать с проектом. Читай его первым при входе в репозиторий.


🎯 Назначение проекта

Учебный проект для изучения MLflow на практике: от логирования экспериментов до Model Registry и serving моделей. Девять последовательных уроков, каждый — отдельный скрипт в src/. Поддерживает GPU (RTX 3090, CUDA) и macOS (Intel CPU / Apple Silicon MPS).

Не production-система. Цель — показать полный цикл MLOps на маленьких встроенных датасетах (digits, wine, MNIST).


📁 Карта проекта

mlflow-practice/
├── AGENTS.md               # ← этот файл (поддерживай актуальным!)
├── README.md               # пользовательская документация (как запускать)
├── CODE_WALKTHROUGH.md     # подробный разбор каждого файла с пояснениями
├── MLproject               # MLflow Projects: entry points main/gpu/sweep
├── python_env.yaml         # окружение для MLproject (python 3.10)
├── requirements.txt        # pip-зависимости
├── setup_server.sh         # установка окружения (РАЗВИЛКА macOS/Linux)
├── start_ui.sh             # запуск MLflow Tracking Server (UI на :5555, file-store)
├── .gitignore
├── scripts/
│   └── setup_git.sh        # настройка Git (HTTPS + токен)
├── src/                    # ← весь код уроков здесь
│   ├── train_simple.py       # Урок 1: sklearn + Tracking (ручное логирование)
│   ├── train_gpu.py          # Урок 2: PyTorch CNN, CUDA→MPS→CPU
│   ├── register_model.py     # Урок 3: Model Registry (версии, стадии)
│   ├── load_and_predict.py   # Урок 4: загрузка модели + предсказание
│   ├── compare_runs.py        # Урок 5: сравнение запусков через API
│   ├── autolog_demo.py       # Урок 6: mlflow.autolog()
│   ├── hyperparam_sweep.py   # Урок 7: перебор гиперпараметров вручную
│   ├── serve_model.py         # Урок 8: REST API сервер модели (Flask)
│   └── grid_search_cv.py     # Урок 9: GridSearchCV + autolog
├── data/                   # датасеты (MNIST скачается автоматически)
├── artifacts/              # графики, отчёты (логируются в MLflow)
└── mlruns/                 # локальный file store MLflow (в .gitignore)

🧩 Роль каждого файла (кратко)

Файл Что делает Датасет Фреймворк
train_simple.py RandomForest, ручное логирование params/metrics/model/artifacts digits sklearn
train_gpu.py CNN, логирование по эпохам, выбор устройства get_device() MNIST PyTorch
register_model.py ищет лучший run по метрике, регистрирует модель, стадия Production MLflow API
load_and_predict.py грузит models:/digits_rf_model/Production, предсказывает digits MLflow
compare_runs.py MlflowClient.search_runs, топ-N по метрике MLflow API
autolog_demo.py mlflow.autolog() для GradientBoosting wine sklearn
hyperparam_sweep.py ручной перебор комбинаций, --max-combos digits sklearn
serve_model.py Flask-сервер /predict, грузит модель из реестра digits Flask + MLflow
grid_search_cv.py GridSearchCV, autolog залогит каждую попытку digits sklearn

🖥️ Платформенная специфика

Выбор устройства в train_gpu.py

Функция get_device() определяет устройство в порядке: CUDA → MPS (Apple Silicon) → CPU. Тег MLflow device_type хранит выбор (cuda / mps / cpu) — по нему удобно фильтровать запуски в UI.

num_workers в DataLoader

На macOS с MPS многопроцессная загрузка нестабильна (fork + MPS), поэтому num_workers=0 на Darwin и 4 на Linux. pin_memory=True только для CUDA. Логика — в train_gpu.py рядом с DataLoader.

setup_server.sh — развивка по ОС

  • Darwin → macOS: проверка Homebrew, python@3.12 через brew, PyTorch из PyPI (без CUDA), проверка torch.backends.mps.is_available().
  • Linux → GPU-сервер: nvidia-smi, PyTorch из --index-url https://download.pytorch.org/whl/cu121, проверка VRAM.

При добавлении новой платформы — расширяй case "$OS" в начале скрипта.


🚀 Стандартные команды

# Окружение
bash setup_server.sh                 # установка (macOS или Linux)
source .venv/bin/activate
./start_ui.sh                        # MLflow UI → http://localhost:5555

# Уроки (в отдельном терминале, с активированным venv)
python src/train_simple.py --n-estimators 100 --max-depth 8
python src/train_gpu.py --epochs 5 --batch-size 128 --lr 0.001   # macOS/MPS
python src/register_model.py --experiment digits_classification
python src/load_and_predict.py
python src/compare_runs.py --experiment digits_classification --top 10
python src/autolog_demo.py
python src/hyperparam_sweep.py --max-combos 20
python src/serve_model.py --port 5001
python src/grid_search_cv.py

# Через MLflow Projects (изолированное окружение по MLproject)
mlflow run . -P n_estimators=100 -P max_depth=8
mlflow run . -P epochs=10 -P batch_size=256 -P lr=0.001 --entry-point gpu

🔧 Конвенции кода

  • Датасеты — только встроенные (load_digits, load_wine, MNIST через torchvision). Никаких внешних файлов в data/, кроме скачанного MNIST.
  • Логирование — параметры/метрики/модель/артефакты. Графики сохраняются в artifacts/ и логируются через mlflow.log_artifact.
  • Имена экспериментов: digits_classification, mnist_cnn_gpu, wine_autolog и т.п. Модель в реестре — digits_rf_model.
  • matplotlib.use("Agg") обязателен перед импортом pyplot — скрипты работают без GUI (на сервере).
  • Python ≥ 3.10 (см. python_env.yaml). type hints опциональны.
  • CLI через argparse — все скрипты с параметрами запускаются из CLI.

⚠️ Известные шероховатости / TODO

  • Нумерация уроков 8/9 расходилась между докстрингами и README/CODE_WALKTHROUGHисправлено: канон serve_model.py=Урок 8 / grid_search_cv.py=Урок 9, README.md и CODE_WALKTHROUGH.md выровнены под докстринги (порядок секций тоже).
  • requirements.txt включает torch/torchvision из PyPI (CPU/MPS). Для CUDA их нужно ставить отдельно через --index-url .../whl/cu121 (см. setup_server.sh, ветка Linux).
  • Порт MLflow UI = 5555 (не 5000): на macOS порт 5000 занят системным сервисом AirPlay Receiver (процесс ControlCenter), поэтому start_ui.sh использует 5555. На Linux можно вернуть 5000, но 5555 работает везде.
  • MLflow 3.x: artifact_path устарел — во всех log_model используется name=... (был artifact_path=...). При обновлении/добавлении log_model не используй artifact_path.
  • Сигнатура модели: train_simple.py логирует модель с явной signature= и input_example= (через mlflow.models.signature.infer_signature). Без этого MLflow пишет warning «Model logged without a signature and input example».
  • train_gpu.py передаёт input_example → сигнатура авто-infer'ится.
  • autolog_demo.py намеренно отключает сигнатуры (log_model_signatures=False) как демо опций autolog — там warning ожидаем.
  • INFO про переменные окружения (OPENAI_API_KEY и т.п.) при логировании подавлено через MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING=false в скриптах, логирующих модели.
  • File-store как СЕРВЕРНЫЙ бэкенд в maintenance mode (MLflow 3.x): mlflow server --backend-store-uri file://... по умолчанию падает с MlflowException ... filesystem tracking backend is in maintenance mode. Официальный opt-out — export MLFLOW_ALLOW_FILE_STORE=true (уже выставлено в start_ui.sh перед file-блоком). Это касается ТОЛЬКО сервера; клиентский file store (как пишут скрипты в ./mlruns) работает без opt-out. Альтернатива без opt-out — SQLite-бэкенд (закомментированный блок в start_ui.sh), но тогда скрипты должны логировать на сервер через mlflow.set_tracking_uri('http://localhost:5555').
  • input_example для mlflow.pytorch.log_model — только numpy, не torch.Tensor: MLflow 3.x валидирует пример входа и падает с MlflowException ... but got '<class 'torch.Tensor'>'. В train_gpu.py передаётся np.random.rand(1,1,28,28).astype(np.float32). Аналогично для других flavor'ов — пример должен быть DataFrame/ndarray/dict/list/скаляр.
  • urllib3 NotOpenSSLWarning на macOS (системный ssl собран с LibreSSL 2.8.3, urllib3 v2 просит OpenSSL 1.1.1+) — стороннее шумовое предупреждение, к проекту отношения не имеет; не подавляем (чтобы не прятать реальные предупреждения).
  • «Эксперимент не виден в UI» (главная причина): скрипты по умолчанию пишут в локальный file store ./mlruns, а start_ui.sh раньше поднимал сервер на SQLite (mlflow.db) — два разных хранилища, UI ничего не показывал. Теперь start_ui.sh использует --backend-store-uri file://${PWD}/mlrunsто же хранилище, что и скрипты, поэтому всё видно без настройки tracking URI. Альтернатива (SQLite-бэкенд) оставлена закомментированной в start_ui.sh; при её включении в скриптах нужно задать mlflow.set_tracking_uri('http://localhost:5555') (или MLFLOW_TRACKING_URI).
  • mlruns/, artifacts/*, data/MNIST/, mlflow.db — в .gitignore, в репозиторий не попадают.

🔄 Когда обновлять этот файл

AGENTS.md — живой документ. Обновляй его при:

  1. Добавлении/удалении файла в src/ — обнови карту проекта и таблицу ролей.
  2. Изменении платформенной логики (новое устройство, новая ОС в setup_server.sh, изменение get_device() или num_workers) — обнови раздел «Платформенная специфика».
  3. Изменении имён экспериментов/моделей в реестре — обнови «Конвенции».
  4. Изменении зависимостей или версии Python (requirements.txt, python_env.yaml) — проверь раздел команд и конвенции.
  5. Появлении новых entry points в MLproject — добавь в карту и команды.
  6. Обнаружении gotcha/шероховатости — занеси в «Известные шероховатости», чтобы следующий агент не наступал повторно.

Правило простое: если ты что-то изменил в структуре/поведении проекта, отрази это в AGENTS.md в том же коммите. Если файл устарел относительно кода — это баг, который нужно исправить.


📌 Шпаргалка по MLflow API (часто используемое в проекте)

mlflow.set_experiment("name")
with mlflow.start_run(run_name="...") as run:
    mlflow.log_param("k", v)
    mlflow.log_metric("acc", 0.95, step=epoch)
    mlflow.log_artifact("artifacts/curve.png")
    mlflow.sklearn.log_model(model, "model")          # sklearn flavor
    mlflow.pytorch.log_model(model, "model")          # pytorch flavor
    mlflow.set_tag("device_type", "mps")
    mlflow.autolog()                                  # авто-логирование

# Model Registry
client = MlflowClient()
client.search_runs([experiment_id], order_by=["metrics.accuracy DESC"])
mlflow.register_model("runs:/<run_id>/model", "digits_rf_model")
client.transition_model_version_stage("digits_rf_model", version=1, stage="Production")
mlflow.pyfunc.load_model("models:/digits_rf_model/Production")

🧭 С чего начать новому агенту

  1. Прочитай этот файл целиком.
  2. Прочитай README.md (пользовательский взгляд) и CODE_WALKTHROUGH.md (детальный разбор кода).
  3. Прогони bash setup_server.sh на целевой платформе, чтобы понять состояние окружения.
  4. Перед правками проверь git status — в этом окружении .git может быть read-only для агента (тогда коммит делает пользователь вручную).
  5. Любое структурное изменение → коммит + правка AGENTS.md.