fix: mlflow run — guard set_experiment под MLFLOW_RUN_ID + рецепт (tracking URI, venv, --env-manager local)
This commit is contained in:
@@ -106,9 +106,11 @@ python src/hyperparam_sweep.py --max-combos 20
|
|||||||
python src/serve_model.py --port 5001
|
python src/serve_model.py --port 5001
|
||||||
python src/grid_search_cv.py
|
python src/grid_search_cv.py
|
||||||
|
|
||||||
# Через MLflow Projects (изолированное окружение по MLproject)
|
# Через MLflow Projects (нужны MLFLOW_TRACKING_URI + активный venv)
|
||||||
mlflow run . -P n_estimators=100 -P max_depth=8
|
source .venv/bin/activate
|
||||||
mlflow run . -P epochs=10 -P batch_size=256 -P lr=0.001 --entry-point gpu
|
export MLFLOW_TRACKING_URI=http://localhost:5555
|
||||||
|
mlflow run . --env-manager local --experiment-name digits_classification -P n_estimators=100 -P max_depth=8
|
||||||
|
mlflow run . --env-manager local -e gpu --experiment-name mnist_cnn_gpu -P epochs=10 -P batch_size=256 -P lr=0.001
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -142,6 +144,7 @@ mlflow run . -P epochs=10 -P batch_size=256 -P lr=0.001 --entry-point gpu
|
|||||||
- `train_gpu.py` передаёт `input_example` → сигнатура авто-infer'ится.
|
- `train_gpu.py` передаёт `input_example` → сигнатура авто-infer'ится.
|
||||||
- `autolog_demo.py` намеренно отключает сигнатуры (`log_model_signatures=False`) как демо опций autolog — там warning ожидаем.
|
- `autolog_demo.py` намеренно отключает сигнатуры (`log_model_signatures=False`) как демо опций autolog — там warning ожидаем.
|
||||||
- **INFO про переменные окружения** (`OPENAI_API_KEY` и т.п.) при логировании подавлено через `MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING=false` в скриптах, логирующих модели.
|
- **INFO про переменные окружения** (`OPENAI_API_KEY` и т.п.) при логировании подавлено через `MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING=false` в скриптах, логирующих модели.
|
||||||
|
- **`mlflow run` (MLflow Projects) — три условия**, иначе падает: (1) нужно `export MLFLOW_TRACKING_URI=http://localhost:5555` (сервер работает) — иначе `mlflow run` создаёт run в дефолтном file-store → maintenance mode; (2) venv активирован (`source .venv/bin/activate`) — иначе `python: command not found` в подпроцессе entry-point; (3) `--env-manager local` — иначе MLflow создаёт новый venv из `python_env.yaml` (python 3.10, медленно, может не быть нужного интерпретатора). Скрипты `train_simple/train_gpu/hyperparam_sweep` не вызывают `set_experiment` под `mlflow run` (детект `MLFLOW_RUN_ID`), поэтому `--experiment-name` опционален.
|
||||||
- **`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`.
|
- **`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 как 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).
|
- **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).
|
||||||
- **MNIST: `yann.lecun.com/exdb/mnist/` умер (HTTP 404)** — `torchvision.MNIST (download=True)` падает при скачивании. В `train_gpu.py` есть `ensure_mnist()`: качает 4 gz-файла с рабочего зеркала `https://ossci-datasets.s3.amazonaws.com/mnist/` и **распаковывает их** (gunzip) в `data/MNIST/raw/` в файлы без `.gz`. Важно: torchvision.MNIST._check_exists() ищет именно РАСПАКОВАННЫЕ файлы (`train-images-idx3-ubyte` и т.п.), а не архивы — поэтому просто положить gz недостаточно, нужен gunzip. Если и S3 недоступен — положите 4 MNIST gz-файла вручную в `data/MNIST/raw/` (скрипт распакует их сам).
|
- **MNIST: `yann.lecun.com/exdb/mnist/` умер (HTTP 404)** — `torchvision.MNIST (download=True)` падает при скачивании. В `train_gpu.py` есть `ensure_mnist()`: качает 4 gz-файла с рабочего зеркала `https://ossci-datasets.s3.amazonaws.com/mnist/` и **распаковывает их** (gunzip) в `data/MNIST/raw/` в файлы без `.gz`. Важно: torchvision.MNIST._check_exists() ищет именно РАСПАКОВАННЫЕ файлы (`train-images-idx3-ubyte` и т.п.), а не архивы — поэтому просто положить gz недостаточно, нужен gunzip. Если и S3 недоступен — положите 4 MNIST gz-файла вручную в `data/MNIST/raw/` (скрипт распакует их сам).
|
||||||
|
|||||||
@@ -97,13 +97,25 @@ python src/grid_search_cv.py
|
|||||||
|
|
||||||
### 4. MLflow Projects (воспроизводимый запуск)
|
### 4. MLflow Projects (воспроизводимый запуск)
|
||||||
|
|
||||||
|
`mlflow run` нужен установленный `MLFLOW_TRACKING_URI` и активированный venv
|
||||||
|
(иначе: file-store maintenance mode и `python: command not found`).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Запуск через MLproject — MLflow сам создаст окружение
|
source .venv/bin/activate
|
||||||
mlflow run . -P n_estimators=200 -P max_depth=12
|
export MLFLOW_TRACKING_URI=http://localhost:5555 # сервер MLflow должен работать
|
||||||
mlflow run . -e gpu -P epochs=10 -P batch_size=256 -P lr=0.001
|
|
||||||
mlflow run . -e sweep -P max_combos=30
|
# --env-manager local — использовать текущий venv (не создавать новый из python_env.yaml)
|
||||||
|
mlflow run . --env-manager local --experiment-name digits_classification \
|
||||||
|
-P n_estimators=200 -P max_depth=12
|
||||||
|
mlflow run . --env-manager local -e gpu --experiment-name mnist_cnn_gpu \
|
||||||
|
-P epochs=10 -P batch_size=256 -P lr=0.001
|
||||||
|
mlflow run . --env-manager local -e sweep --experiment-name sweep_digits \
|
||||||
|
-P max_combos=30
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> `--experiment-name` теперь опционален (скрипты не конфликтуют с run'ом от
|
||||||
|
> `mlflow run`), но полезен, чтобы запуск попал в нужный эксперимент, а не в Default.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 Что изучает каждый урок
|
## 📚 Что изучает каждый урок
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ def main():
|
|||||||
X, y, test_size=0.2, random_state=42
|
X, y, test_size=0.2, random_state=42
|
||||||
)
|
)
|
||||||
|
|
||||||
mlflow.set_experiment(args.experiment_name)
|
# под `mlflow run` эксперимент уже задан Projects (MLFLOW_RUN_ID) —
|
||||||
|
# не переопределяем, иначе конфликт "active experiment ID does not match".
|
||||||
|
if not os.environ.get("MLFLOW_RUN_ID"):
|
||||||
|
mlflow.set_experiment(args.experiment_name)
|
||||||
|
|
||||||
best_acc = 0.0
|
best_acc = 0.0
|
||||||
best_run_id = None
|
best_run_id = None
|
||||||
|
|||||||
+4
-1
@@ -145,7 +145,10 @@ def main():
|
|||||||
print(" Apple Silicon GPU (MPS)")
|
print(" Apple Silicon GPU (MPS)")
|
||||||
|
|
||||||
# ─── MLflow эксперимент ───
|
# ─── MLflow эксперимент ───
|
||||||
mlflow.set_experiment(args.experiment_name)
|
# под `mlflow run` эксперимент уже задан Projects (MLFLOW_RUN_ID) —
|
||||||
|
# не переопределяем, иначе конфликт "active experiment ID does not match".
|
||||||
|
if not os.environ.get("MLFLOW_RUN_ID"):
|
||||||
|
mlflow.set_experiment(args.experiment_name)
|
||||||
|
|
||||||
# ─── Данные ───
|
# ─── Данные ───
|
||||||
transform = transforms.Compose([
|
transform = transforms.Compose([
|
||||||
|
|||||||
+4
-1
@@ -36,7 +36,10 @@ def main():
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# --- MLflow: задаём эксперимент ---
|
# --- MLflow: задаём эксперимент ---
|
||||||
mlflow.set_experiment(args.experiment_name)
|
# под `mlflow run` эксперимент уже задан Projects (MLFLOW_RUN_ID) —
|
||||||
|
# не переопределяем, иначе конфликт "active experiment ID does not match".
|
||||||
|
if not os.environ.get("MLFLOW_RUN_ID"):
|
||||||
|
mlflow.set_experiment(args.experiment_name)
|
||||||
|
|
||||||
# --- Данные ---
|
# --- Данные ---
|
||||||
digits = load_digits()
|
digits = load_digits()
|
||||||
|
|||||||
Reference in New Issue
Block a user