From 09d3232d9a8579df43262c7066576c6d3baa8d91 Mon Sep 17 00:00:00 2001 From: second_constantine Date: Tue, 21 Jul 2026 00:21:47 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20MNIST=20=D0=BA=D0=B0=D1=87=D0=B0=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D1=81=20ossci-datasets.s3=20(yann.lecun.c?= =?UTF-8?q?om=20=D1=83=D0=BC=D0=B5=D1=80=20=E2=80=94=20404)=20=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=20ensure=5Fmnist()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + src/train_gpu.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index ecb753c..15b4743 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -144,6 +144,7 @@ mlflow run . -P epochs=10 -P batch_size=256 -P lr=0.001 --entry-point gpu - **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 как 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/` в `data/MNIST/raw/`, после чего torchvision берёт локальные и в сеть не лезет. Если и S3 недоступен — положите 4 MNIST gz-файла вручную в `data/MNIST/raw/`. - **`input_example` для `mlflow.pytorch.log_model` — только numpy**, не `torch.Tensor`: MLflow 3.x валидирует пример входа и падает с `MlflowException ... but got ''`. В `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 с других машин (браузером по IP сервера)** — НЕ удалять флаги в `start_ui.sh`: `--host 0.0.0.0`, `--allowed-hosts "*"`, `--cors-allowed-origins "*"`, `export MLFLOW_ALLOW_ORIGIN="*"`, `--serve-artifacts` + `--artifacts-destination`, `--dev`. Без `--allowed-hosts "*"` MLflow режет запросы с `Host=:5555` (UI не открывается удалённо); без `--serve-artifacts` UI на удалённой машине не скачает артефакты (model/графики) по file://-путям. Эти флаги были в исходном проекте и случайно потерялись при миграции — восстановлены. diff --git a/src/train_gpu.py b/src/train_gpu.py index eab3c14..118f577 100644 --- a/src/train_gpu.py +++ b/src/train_gpu.py @@ -72,6 +72,40 @@ def get_device() -> torch.device: return torch.device("cpu") +def ensure_mnist(data_dir: str) -> None: + """Гарантирует наличие MNIST. + + torchvision.MNIST(download=True) тянет файлы с yann.lecun.com/exdb/mnist/, + который умер (HTTP 404). Кладём 4 gz-файла с рабочего зеркала + ossci-datasets.s3.amazonaws.com (официальный fallback PyTorch) в + data/MNIST/raw/ — после этого torchvision находит их и в сеть не лезет. + """ + import urllib.request + raw = os.path.join(data_dir, "MNIST", "raw") + os.makedirs(raw, exist_ok=True) + base = "https://ossci-datasets.s3.amazonaws.com/mnist/" + files = [ + "train-images-idx3-ubyte.gz", + "train-labels-idx1-ubyte.gz", + "t10k-images-idx3-ubyte.gz", + "t10k-labels-idx1-ubyte.gz", + ] + needed = [f for f in files if not os.path.exists(os.path.join(raw, f))] + if not needed: + return + print(f"📥 MNIST: докачиваю {len(needed)} файл(ов) с ossci-datasets.s3.amazonaws.com ...") + for fname in needed: + dst = os.path.join(raw, fname) + print(f" {fname}") + try: + urllib.request.urlretrieve(base + fname, dst) + except Exception as e: + raise RuntimeError( + f"Не удалось скачать {fname} с {base} ({e}). " + f"Положите 4 MNIST gz-файла вручную в {raw}/" + ) from e + + def main(): parser = argparse.ArgumentParser(description="MLflow + PyTorch GPU demo") parser.add_argument("--epochs", type=int, default=5) @@ -101,6 +135,7 @@ def main(): ]) data_dir = "data" os.makedirs(data_dir, exist_ok=True) + ensure_mnist(data_dir) # обходим 404 с yann.lecun.com — качаем с рабочего зеркала train_ds = datasets.MNIST(data_dir, train=True, download=True, transform=transform) test_ds = datasets.MNIST(data_dir, train=False, download=True, transform=transform)