Перевод tracking на SQLite + HTTP-клиенты (file-store запрещён в MLflow 3.x)
- start_ui.sh: SQLite backend (sqlite:///mlflow.db) вместо file-store - все скрипты src/: mlflow.set_tracking_uri(http://localhost:5555) с env-override - README: сервер должен быть запущен до запуска скриптов - AGENTS.md: обновлена архитектура хранения и gotcha
This commit is contained in:
@@ -28,7 +28,7 @@ mlflow-practice/
|
||||
├── 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)
|
||||
├── start_ui.sh # запуск MLflow Tracking Server (UI на :5555, SQLite backend)
|
||||
├── .gitignore
|
||||
├── scripts/
|
||||
│ └── setup_git.sh # настройка Git (HTTPS + токен)
|
||||
@@ -44,7 +44,7 @@ mlflow-practice/
|
||||
│ └── grid_search_cv.py # Урок 9: GridSearchCV + autolog
|
||||
├── data/ # датасеты (MNIST скачается автоматически)
|
||||
├── artifacts/ # графики, отчёты (логируются в MLflow)
|
||||
└── mlruns/ # локальный file store MLflow (в .gitignore)
|
||||
└── mlruns/ # старые запуски file-store (в .gitignore, не используется)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -143,10 +143,10 @@ mlflow run . -P epochs=10 -P batch_size=256 -P lr=0.001 --entry-point gpu
|
||||
- `autolog_demo.py` намеренно отключает сигнатуры (`log_model_signatures=False`) как демо опций autolog — там warning ожидаем.
|
||||
- **INFO про переменные окружения** (`OPENAI_API_KEY` и т.п.) при логировании подавлено через `MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING=false` в скриптах, логирующих модели.
|
||||
- **`python -m venv` падает на Linux (ensurepip)**: на Debian/Ubuntu без пакета `python3.13-venv` (или `python3-venv`) создание venv падает на шаге `ensurepip` (`non-zero exit status 1`). `setup_server.sh` ловит это и пробует fallback: `venv --without-pip` + bootstrap pip через `get-pip.py`. Альтернатива руками — `sudo apt-get install -y python3.13-venv python3.13-dev`.
|
||||
- **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')`.
|
||||
- **File-store как tracking backend запрещён в MLflow 3.x** (maintenance mode): падает и `mlflow server --backend-store-uri file://...`, и клиент-скрипт с дефолтным `./mlruns` — оба с `MlflowException ... in maintenance mode`. Поэтому проект использует **SQLite** (`sqlite:///mlflow.db`) как tracking backend, а скрипты логируют на сервер по HTTP. Опциональный opt-out `MLFLOW_ALLOW_FILE_STORE=true` НЕ используем (он может быть убран в будущем). Артефакты при этом лежат на локальном диске (`./artifacts`, file artifact repository — он НЕ в maintenance mode).
|
||||
- **`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`).
|
||||
- **Архитектура хранения (SQLite + HTTP-клиенты)**: `start_ui.sh` поднимает сервер с `--backend-store-uri sqlite:///${PWD}/mlflow.db`. Все скрипты в `src/` содержат `mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))` — пишут на сервер. UI и скрипты работают с **одной** sqlite-базой → эксперименты сразу видны. **Сервер должен быть запущен до запуска скриптов** (иначе `ConnectionError` к localhost:5555). Переопределить адрес: `export MLFLOW_TRACKING_URI=http://<host>:5555` (например, при логировании на удалённый сервер).
|
||||
- `mlruns/`, `artifacts/*`, `data/MNIST/`, `mlflow.db` — в `.gitignore`,
|
||||
в репозиторий не попадают.
|
||||
|
||||
|
||||
@@ -48,13 +48,19 @@ pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
|
||||
pip install flask # для serve_model.py
|
||||
```
|
||||
|
||||
### 2. Запуск MLflow UI
|
||||
### 2. Запуск MLflow UI (Tracking Server)
|
||||
|
||||
```bash
|
||||
./start_ui.sh
|
||||
# → http://10.0.0.7:5555
|
||||
```
|
||||
|
||||
> Сервер использует SQLite-бэкенд (`mlflow.db`). Скрипты логируют на него
|
||||
> по HTTP (`http://localhost:5555`), поэтому **сервер должен быть запущен
|
||||
> и работать в отдельном терминале всё время, пока вы запускаете уроки**.
|
||||
> Иначе скрипты упадут с `ConnectionError` к `localhost:5555`.
|
||||
> Адрес можно переопределить: `export MLFLOW_TRACKING_URI=http://<host>:5555`.
|
||||
|
||||
### 3. Уроки по порядку
|
||||
|
||||
```bash
|
||||
|
||||
@@ -21,6 +21,7 @@ import mlflow.sklearn
|
||||
# Подавляем INFO MLflow о переменных окружения (напр. OPENAI_API_KEY) при логировании модели
|
||||
import os
|
||||
os.environ.setdefault("MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING", "false")
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -11,6 +11,9 @@ import argparse
|
||||
import mlflow
|
||||
from mlflow.tracking import MlflowClient
|
||||
|
||||
import os
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
@@ -18,6 +18,7 @@ import mlflow.sklearn
|
||||
# Подавляем INFO MLflow о переменных окружения (напр. OPENAI_API_KEY) при логировании модели
|
||||
import os
|
||||
os.environ.setdefault("MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING", "false")
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -21,6 +21,9 @@ from sklearn.model_selection import train_test_split
|
||||
|
||||
import mlflow
|
||||
|
||||
import os
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="MLflow hyperparameter sweep")
|
||||
|
||||
@@ -12,6 +12,9 @@ from sklearn.datasets import load_digits
|
||||
|
||||
import mlflow
|
||||
|
||||
import os
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
# Загружаем модель из реестра по имени и стадии
|
||||
|
||||
@@ -15,6 +15,9 @@ import argparse
|
||||
import mlflow
|
||||
from mlflow.tracking import MlflowClient
|
||||
|
||||
import os
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Register best model in MLflow")
|
||||
|
||||
@@ -24,6 +24,9 @@ import numpy as np
|
||||
from sklearn.datasets import load_digits
|
||||
|
||||
import mlflow
|
||||
|
||||
import os
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
from flask import Flask, request, jsonify
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import mlflow.pytorch
|
||||
# Подавляем INFO MLflow о переменных окружения (напр. OPENAI_API_KEY) при логировании модели
|
||||
import os
|
||||
os.environ.setdefault("MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING", "false")
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
|
||||
|
||||
# ─── Модель: простая CNN ───
|
||||
|
||||
@@ -24,6 +24,7 @@ import mlflow.sklearn
|
||||
# Подавляем INFO MLflow о переменных окружения (напр. OPENAI_API_KEY) при логировании модели
|
||||
import os
|
||||
os.environ.setdefault("MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING", "false")
|
||||
mlflow.set_tracking_uri(os.environ.get("MLFLOW_TRACKING_URI", "http://localhost:5555"))
|
||||
from mlflow.models.signature import infer_signature
|
||||
|
||||
|
||||
|
||||
+18
-25
@@ -3,45 +3,38 @@
|
||||
# Запуск MLflow Tracking Server
|
||||
# Откройте в браузере: http://localhost:5555
|
||||
#
|
||||
# Backend store = file://$(pwd)/mlruns (тот же каталог, куда скрипты
|
||||
# пишут по умолчанию). Поэтому UI видит все эксперименты/запуски
|
||||
# без доп. настройки tracking URI в скриптах.
|
||||
# Backend store = SQLite (mlflow.db) — recommended MLflow backend.
|
||||
# Скрипты в src/ логируют на этот сервер (http://localhost:5555) через
|
||||
# mlflow.set_tracking_uri(...) — поэтому UI и скрипты работают с одной
|
||||
# базой, и эксперименты сразу видны в UI.
|
||||
#
|
||||
# ВАЖНО: file-store как СЕРВЕРНЫЙ бэкенд в новых MLflow (3.x) переведён в
|
||||
# maintenance mode и по умолчанию запрещён. Официальный opt-out —
|
||||
# MLFLOW_ALLOW_FILE_STORE=true (его и выставляем ниже). Это касается только
|
||||
# `mlflow server`; клиентский file store (как пишут скрипты) работает и без него.
|
||||
# ⚠️ file-store как tracking backend в новых MLflow (3.x) переведён в
|
||||
# maintenance mode и запрещён (ошибка и на сервере, и у клиента-скрипта).
|
||||
# Поэтому используем sqlite. Артефакты при этом лежат на локальном диске
|
||||
# в ./artifacts (file-based artifact repository — он НЕ в maintenance mode).
|
||||
#
|
||||
# Альтернатива — SQLite-бэкенд (recommended MLflow, без opt-out). Тогда
|
||||
# раскомментируйте блок SQLITE ниже и закомментируйте FILE, а в скриптах
|
||||
# задайте mlflow.set_tracking_uri("http://localhost:5555")
|
||||
# (или export MLFLOW_TRACKING_URI=http://localhost:5555).
|
||||
# Запустите сервер ДО запуска скриптов обучения:
|
||||
# ./start_ui.sh # в одном терминале
|
||||
# python src/train_simple.py ... # в другом (нужен работающий сервер)
|
||||
# ============================================================
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
PORT=5555
|
||||
PORT="${MLFLOW_PORT:-5555}"
|
||||
|
||||
echo "🚀 Запускаем MLflow Tracking Server..."
|
||||
echo " UI: http://localhost:${PORT}"
|
||||
echo " Store: file://${PWD}/mlruns"
|
||||
echo " UI: http://localhost:${PORT}"
|
||||
echo " Backend: sqlite:///${PWD}/mlflow.db"
|
||||
echo " Artifacts: file://${PWD}/artifacts"
|
||||
echo ""
|
||||
echo " Скрипты логируют сюда через MLFLOW_TRACKING_URI=http://localhost:${PORT}"
|
||||
echo " (можно переопределить: export MLFLOW_TRACKING_URI=http://<host>:${PORT})"
|
||||
echo ""
|
||||
echo " Нажмите Ctrl+C для остановки"
|
||||
echo ""
|
||||
|
||||
# ─── FILE backend (по умолчанию — единое хранилище со скриптами) ───
|
||||
# MLFLOW_ALLOW_FILE_STORE=true — opt-out из maintenance mode file-store бэкенда.
|
||||
export MLFLOW_ALLOW_FILE_STORE=true
|
||||
mlflow server \
|
||||
--backend-store-uri "file://${PWD}/mlruns" \
|
||||
--backend-store-uri "sqlite:///${PWD}/mlflow.db" \
|
||||
--default-artifact-root "file://${PWD}/artifacts" \
|
||||
--host 0.0.0.0 \
|
||||
--port "${PORT}"
|
||||
|
||||
# ─── SQLITE backend (альтернатива — см. комментарий в шапке) ──────
|
||||
# mlflow server \
|
||||
# --backend-store-uri sqlite:///mlflow.db \
|
||||
# --default-artifact-root ./artifacts \
|
||||
# --host 0.0.0.0 \
|
||||
# --port "${PORT}"
|
||||
|
||||
Reference in New Issue
Block a user