develop - hack_2026
This commit is contained in:
parent
5bc6df6e85
commit
157b7b89a6
|
|
@ -1,8 +1,9 @@
|
|||
# .dockerignore
|
||||
# Цель: контекст сборки должен быть маленьким. Образ собирается из src,
|
||||
# requirements.txt и run.sh (см. Dockerfile); чекпоинт в образ не копируется, а
|
||||
# монтируется в /app/models при запуске. Данные, тесты и служебные файлы
|
||||
# исключаются — DICOM-датасет не должен попадать в образ с медицинскими данными.
|
||||
# requirements.txt, run.sh и чекпоинта models/dxa_model.pth — он закоммичен в
|
||||
# репозиторий и копируется внутрь образа (см. Dockerfile), поэтому модели не
|
||||
# нужно монтировать при запуске. Данные, тесты и служебные файлы исключаются —
|
||||
# DICOM-датасет не должен попадать в образ с медицинскими данными.
|
||||
__pycache__
|
||||
**/__pycache__
|
||||
*.pyc
|
||||
|
|
|
|||
31
Dockerfile
31
Dockerfile
|
|
@ -1,12 +1,13 @@
|
|||
# DXA Quality Assessment — контейнер для инференса (CPU)
|
||||
#
|
||||
# Сборка: docker build -t rell.ru:5000/rell-bone-2026:latest .
|
||||
# Запуск: docker run -v /data/bone_2026/models:/app/models:ro -p 8000:8000 dxa-quality
|
||||
# Сборка: docker build -t dxa-quality .
|
||||
# Запуск: docker run -p 8000:8000 dxa-quality
|
||||
# или: docker compose up -d (сервис dxa-cpu)
|
||||
#
|
||||
# Веса в образ НЕ копируются: swarm монтирует каталог с чекпоинтом в
|
||||
# /app/models только для чтения, а models/ не попадает в git (см. .gitignore),
|
||||
# поэтому COPY models ломал бы сборку в CI. Путь к чекпоинту берётся из
|
||||
# DXA_MODEL_PATH и по умолчанию указывает на смонтированный каталог.
|
||||
# Чекпоинт лежит ВНУТРИ образа: models/dxa_model.pth отслеживается git (каталог
|
||||
# models/ не исключён в .gitignore) и копируется на этапе сборки. Монтировать
|
||||
# пути не нужно — условие приёмки в том, что модели уже в образе. Если всё-таки
|
||||
# смонтировать каталог в /app/models, он перекроет встроенный чекпоинт.
|
||||
#
|
||||
# Требования методики: зафиксированные версии зависимостей и работа без
|
||||
# внешних сервисов. Inference не скачивает веса из сети — они внутри
|
||||
|
|
@ -40,8 +41,7 @@ COPY run.sh ./run.sh
|
|||
RUN chmod +x ./run.sh
|
||||
|
||||
# Smoke-проверка импорта: падает на сборке, если расходятся зависимости или
|
||||
# модуль не найден, вместо тихой 500-й на каждом запросе в рантайме. Модель
|
||||
# здесь не загружается — чекпоинта в контексте сборки нет.
|
||||
# модуль не найден, вместо тихой 500-й на каждом запросе в рантайме.
|
||||
RUN python -c "import src.main; print('app import ok')"
|
||||
|
||||
# --- Проверка статики для офлайн-работы ---
|
||||
|
|
@ -54,6 +54,21 @@ RUN python -c "import os; \
|
|||
assert not missing, f'missing frontend assets: {missing}'; \
|
||||
print('frontend assets ok')"
|
||||
|
||||
# --- Чекпоинт внутри образа ---
|
||||
# Условие приёмки: модель уже в образе, чтобы проверяющему не приходилось
|
||||
# указывать путь к каталогу с весами. models/dxa_model.pth отслеживается git,
|
||||
# поэтому копирование работает и в CI.
|
||||
COPY models/dxa_model.pth /app/models/dxa_model.pth
|
||||
|
||||
# Проверка, что чекпоинт читается и содержит всё нужное для инференса: без этого
|
||||
# битый или забытый файл проявился бы только в рантайме как model_loaded: false
|
||||
# и HTTP 500 на каждый запрос анализа.
|
||||
RUN python -c "import torch; \
|
||||
ckpt=torch.load('/app/models/dxa_model.pth', map_location='cpu', weights_only=False); \
|
||||
missing=[k for k in ('model_state_dict','backbone','head','threshold') if k not in ckpt]; \
|
||||
assert not missing, f'checkpoint missing keys: {missing}'; \
|
||||
print('checkpoint ok:', ckpt['backbone'], ckpt['head'], 'threshold', ckpt['threshold'])"
|
||||
|
||||
# Каталоги монтирований swarm: создаём заранее, чтобы образ вёл себя одинаково
|
||||
# и при обычном `docker run` без volume.
|
||||
RUN mkdir -p /app/data /app/logs
|
||||
|
|
|
|||
123
Dockerfile_cuda
123
Dockerfile_cuda
|
|
@ -1,71 +1,106 @@
|
|||
# DXA Quality Assessment - Docker Container (GPU / CUDA)
|
||||
# Build: docker build -f Dockerfile_cuda -t dxa-quality-cuda .
|
||||
# Run: docker run --gpus all -v /path/to/data:/data -v /path/to/models:/app/models \
|
||||
# -p 8000:8000 dxa-quality-cuda
|
||||
# DXA Quality Assessment — контейнер для инференса (GPU / CUDA)
|
||||
#
|
||||
# Сборка: docker build -f Dockerfile_cuda -t dxa-quality:cuda .
|
||||
# Запуск: docker run --gpus all -p 8000:8000 dxa-quality:cuda
|
||||
# или: docker compose --profile cuda up -d dxa-cuda
|
||||
#
|
||||
# База — тот же python:3.11-slim, что и у CPU-варианта, а CUDA и cuDNN приходят
|
||||
# внутри колёс torch с индексом cu126. Отдельный nvidia/cuda-образ не нужен:
|
||||
# контейнеру достаточно драйвера хоста, который подставляет
|
||||
# nvidia-container-toolkit по флагу --gpus all (или секции deploy в compose).
|
||||
# Требуется драйвер NVIDIA >= 525; для H200 (sm_90) в кластере он заведомо новее.
|
||||
#
|
||||
# Индекс cu118 в прежней версии файла не работал: torch 2.8.0 под CUDA 11.8 не
|
||||
# публикуется (последняя версия там — 2.7.1), поэтому сборка падала на pip.
|
||||
# Для 2.8.0 доступны только cu126 и cu128; выбран cu126 как наиболее
|
||||
# распространённый. Под H200 нужен torch>=2.5, sm_90 поддерживается.
|
||||
#
|
||||
# Чекпоинт лежит ВНУТРИ образа (см. Dockerfile): монтировать пути не нужно.
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Base image with GPU support
|
||||
FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04
|
||||
|
||||
# Неинтерактивный режим для apt
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
python3.10 \
|
||||
python3-pip \
|
||||
python3.10-dev \
|
||||
python3.10-venv \
|
||||
build-essential \
|
||||
ninja-build \
|
||||
libgl1-mesa-glx \
|
||||
# libgl1/libglib2.0-0 нужны opencv (импортируется через зависимости проекта),
|
||||
# libgomp1 — для параллельных циклов torch. Список совпадает с CPU-образом.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgl1 \
|
||||
libglib2.0-0 \
|
||||
libsm6 \
|
||||
libxext6 \
|
||||
libxrender1 \
|
||||
libgomp1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Обновляем pip и ставим свежий meson (0.64.0+) — ДО всех Python-пакетов
|
||||
RUN pip3 install --no-cache-dir --upgrade pip "meson>=0.64.0"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# --- PyTorch под CUDA 11.8 (ставим отдельно, чтобы не тянулся CUDA 12.6) ---
|
||||
RUN pip3 install --no-cache-dir \
|
||||
torch==2.8.0 torchvision==0.23.0 \
|
||||
--index-url https://download.pytorch.org/whl/cu118
|
||||
# --- PyTorch под CUDA 12.6 ---
|
||||
# CUDA-колёса ставим первыми и с явным индексом: иначе pip взял бы с PyPI сборку
|
||||
# под CUDA 12.6/12.8 произвольной ревизии. torchvision 0.23.0 — парная к torch
|
||||
# 2.8.0 версия (другие комбинации несовместимы).
|
||||
RUN pip install --no-cache-dir --upgrade pip \
|
||||
&& pip install --no-cache-dir \
|
||||
--index-url https://download.pytorch.org/whl/cu126 \
|
||||
torch==2.8.0 torchvision==0.23.0
|
||||
|
||||
# --- Остальные зависимости ---
|
||||
# Список версий один на оба образа: requirements.txt. Уже установленный torch
|
||||
# pip не переустановит — версия из cu118 удовлетворяет требованию.
|
||||
# Отдельным слоем и после torch: список версий один на оба образа
|
||||
# (requirements.txt), а уже установленный torch==2.8.0+cu126 pip повторно не
|
||||
# поставит — требование torch==2.8.0 считается выполненным, потому что локальная
|
||||
# метка сборки при сравнении версий не учитывается.
|
||||
COPY requirements.txt ./
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# --- Код приложения ---
|
||||
# --- Код ---
|
||||
COPY src ./src
|
||||
|
||||
# Скрипт пакетной обработки (оценка берёт его из корня образа).
|
||||
COPY run.sh ./run.sh
|
||||
RUN chmod +x ./run.sh
|
||||
RUN mkdir -p models
|
||||
|
||||
# Smoke-проверка импорта: падает на сборке, если зависимость недоступна или
|
||||
# модуль не найден, вместо тихой 500-й в рантайме. Чекпоинт здесь не читается.
|
||||
RUN python3 -c "import src.main; print('app import ok')"
|
||||
# Smoke-проверка импорта: падает на сборке, если расходятся зависимости или
|
||||
# модуль не найден, вместо тихой 500-й на каждом запросе в рантайме.
|
||||
RUN python -c "import src.main; print('app import ok')"
|
||||
|
||||
# --- Проверка статики для офлайн-работы ---
|
||||
# Tailwind и FontAwesome лежат в src/api/static, обращений к CDN быть не должно.
|
||||
RUN python3 -c "import os; \
|
||||
# Веб-интерфейс не должен зависеть от CDN: Tailwind и FontAwesome лежат в
|
||||
# src/api/static/vendor и src/api/static/webfonts (см. index.html).
|
||||
RUN python -c "import os; \
|
||||
files=['src/api/static/vendor/tailwind.js','src/api/static/vendor/fontawesome.css', \
|
||||
'src/api/static/webfonts/fa-solid-900.woff2']; \
|
||||
missing=[f for f in files if not os.path.exists(f)]; \
|
||||
assert not missing, f'missing frontend assets: {missing}'; \
|
||||
print('frontend assets ok')"
|
||||
|
||||
# Expose API port
|
||||
EXPOSE 8000
|
||||
# --- Чекпоинт внутри образа ---
|
||||
# Условие приёмки: модель уже в образе, чтобы проверяющему не приходилось
|
||||
# указывать путь к каталогу с весами. models/dxa_model.pth отслеживается git,
|
||||
# поэтому копирование работает и в CI.
|
||||
COPY models/dxa_model.pth /app/models/dxa_model.pth
|
||||
|
||||
# Environment variables
|
||||
# Проверка, что чекпоинт читается и содержит всё нужное для инференса, а также
|
||||
# что сборка torch видит CUDA: без этого проблемы всплыли бы только в рантайме.
|
||||
RUN python -c "import torch; \
|
||||
ckpt=torch.load('/app/models/dxa_model.pth', map_location='cpu', weights_only=False); \
|
||||
missing=[k for k in ('model_state_dict','backbone','head','threshold') if k not in ckpt]; \
|
||||
assert not missing, f'checkpoint missing keys: {missing}'; \
|
||||
print('checkpoint ok:', ckpt['backbone'], ckpt['head'], 'threshold', ckpt['threshold']); \
|
||||
print('torch', torch.__version__, 'cuda built:', torch.version.cuda)"
|
||||
|
||||
# --- Переменные окружения ---
|
||||
# Читается кодом только DXA_MODEL_PATH (src/main.py). MODEL_PATH, DATA_PATH,
|
||||
# ANNOTATION_DIR swarm передаёт по инерции от прежней версии — код их не
|
||||
# использует, и они ни на что не влияют.
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONPATH=/app \
|
||||
DXA_MODEL_PATH=/app/models/dxa_model.pth
|
||||
DXA_MODEL_PATH=/app/models/dxa_model.pth \
|
||||
MODEL_PATH=/app/models \
|
||||
DATA_PATH=/app/data \
|
||||
ANNOTATION_DIR=/app/data/annotations
|
||||
|
||||
# Default command
|
||||
CMD ["python3", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
RUN mkdir -p /app/data /app/logs
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# HEALTHCHECK опирается на /api/v1/health, который отдаёт model_loaded.
|
||||
# На GPU-устройстве старт дольше: даём запас по start-period.
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python -c "import urllib.request,sys; \
|
||||
r=urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health', timeout=5); \
|
||||
sys.exit(0 if r.status==200 else 1)"
|
||||
|
||||
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
|
|
|
|||
19
QWEN.md
19
QWEN.md
|
|
@ -297,14 +297,19 @@ position_validator,universal_scorer,medical_quality}.py`) удалены 2026-09
|
|||
## Docker
|
||||
|
||||
```bash
|
||||
docker build -t dxa-quality .
|
||||
docker run -v /path/to/data:/data -p 8000:8000 dxa-quality
|
||||
docker compose up -d # CPU, http://localhost:8000
|
||||
docker compose --profile cuda up -d dxa-cuda # GPU (нужен nvidia-container-toolkit)
|
||||
```
|
||||
|
||||
Dockerfile ставит зафиксированные версии, копирует только `src/` и `run.sh`,
|
||||
проверяет импорт приложения и наличие офлайн-ассетов фронтенда на этапе сборки и
|
||||
имеет HEALTHCHECK. Чекпоинт в образ не копируется — он монтируется в `/app/models`
|
||||
при запуске (`DXA_MODEL_PATH`). Данные, тесты и `labels/` в образ не попадают
|
||||
Образы: `Dockerfile` (python:3.11-slim, torch из CPU-индекса) и `Dockerfile_cuda`
|
||||
(та же база, torch и torchvision из индекса `cu126` — под CUDA 11.8 колёс torch
|
||||
2.8.0 нет, индекс заканчивается на 2.7.1). Оба собираются из `src/`,
|
||||
`requirements.txt`, `run.sh` и **чекпоинта**: `models/dxa_model.pth` отслеживается
|
||||
git и копируется в `/app/models` на этапе сборки, поэтому монтировать пути при
|
||||
запуске не нужно (условие приёмки — модели уже внутри образа). Сборка проверяет
|
||||
импорт приложения, наличие офлайн-ассетов фронтенда и читаемость чекпоинта,
|
||||
образ имеет HEALTHCHECK. Данные, тесты и `labels/` в образ не попадают
|
||||
(`.dockerignore`), поэтому `./run.sh train` внутри контейнера возьмёт метки из
|
||||
имён файлов (с предупреждением); для обучения в контейнере смонтируйте `labels/`
|
||||
или передайте свой `--labels-csv`.
|
||||
или передайте свой `--labels-csv`. Если внешний `docker-swarm.yml` монтирует
|
||||
каталог с моделями в `/app/models`, монтирование перекроет встроенный чекпоинт.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
# DXA Quality Assessment — запуск сервиса в контейнере.
|
||||
#
|
||||
# Чекпоинт лежит внутри образа (models/dxa_model.pth копируется на этапе сборки),
|
||||
# поэтому монтировать пути не нужно: ни каталог с моделями, ни данные.
|
||||
# Данные для анализа загружаются через веб-интерфейс (http://localhost:8000).
|
||||
#
|
||||
# CPU — работает на любой машине, ничего кроме docker не требуется:
|
||||
# docker compose up -d # сервис dxa-cpu, порт 8000
|
||||
#
|
||||
# GPU — H200 и другие ускорители; нужен драйвер NVIDIA и nvidia-container-toolkit:
|
||||
# docker compose --profile cuda up -d dxa-cuda
|
||||
# имя сервиса указано явно: без него поднялись бы оба и разошлись по одному порту
|
||||
#
|
||||
# Пересобрать после правок кода: docker compose build [dxa-cpu|dxa-cuda]
|
||||
# Логи: docker compose logs -f dxa-cpu
|
||||
# Состояние: curl -s localhost:8000/api/v1/health
|
||||
# Остановить: docker compose down
|
||||
|
||||
name: dxa-quality
|
||||
|
||||
services:
|
||||
# Обычный инференс на CPU: torch ставится из CPU-индекса, GPU не используется.
|
||||
dxa-cpu:
|
||||
image: dxa-quality:cpu
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8000:8000"
|
||||
restart: unless-stopped
|
||||
|
||||
# Инференс на GPU: базовый образ тот же, но torch собран под CUDA 12.6.
|
||||
# Профиль cuda — чтобы на машинах без NVIDIA сервис не мешал запуску по умолчанию.
|
||||
dxa-cuda:
|
||||
profiles: ["cuda"]
|
||||
image: dxa-quality:cuda
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile_cuda
|
||||
ports:
|
||||
- "8000:8000"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: all
|
||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
|
|
@ -158,10 +158,10 @@
|
|||
<td>FastAPI: восемь маршрутов, включая <code>/api/v1/batch</code> и <code>/api/v1/export</code></td>
|
||||
<td>Разд. 10</td></tr>
|
||||
<tr><td>Обязательная контейнеризация, скрипт сборки и запуска в Linux</td>
|
||||
<td><code>Dockerfile</code> (python:3.11-slim), <code>Dockerfile_cuda</code> для GPU, <code>run.sh</code></td>
|
||||
<td>Разд. 14; сборка проверена, см. 14</td></tr>
|
||||
<td><code>Dockerfile</code> (python:3.11-slim, чекпоинт внутри образа), <code>Dockerfile_cuda</code> для GPU, <code>docker-compose.yml</code> на оба случая, <code>run.sh</code></td>
|
||||
<td>Разд. 14; сборка и запуск проверены, см. 14</td></tr>
|
||||
<tr><td>Фиксация зависимостей, включая базовый контейнер</td>
|
||||
<td><code>requirements.txt</code> с точными версиями, базовый образ по тегу, torch с CPU-индексом</td>
|
||||
<td><code>requirements.txt</code> с точными версиями, базовый образ по тегу, torch с CPU-индексом (CPU-вариант) и cu126 (GPU-вариант)</td>
|
||||
<td>Разд. 14</td></tr>
|
||||
<tr><td>Работа без обращения к внешним сервисам</td>
|
||||
<td>Офлайн-ассеты фронтенда, отсутствие сетевых вызовов в коде предсказания</td>
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
<td>Загрузка файлов, таблица результатов, панель деталей, панель «О модели»; все подписи и метрики получает с сервера</td></tr>
|
||||
<tr><td>Эвристики качества</td><td><code>src/quality/</code></td>
|
||||
<td>Числовые измерения снимка (резкость, плотные включения, полнота и поворот области) для панели деталей</td></tr>
|
||||
<tr><td>Инфраструктура</td><td><code>run.sh</code>, <code>Dockerfile</code>, <code>Dockerfile_cuda</code>, <code>Jenkinsfile</code></td>
|
||||
<tr><td>Инфраструктура</td><td><code>run.sh</code>, <code>docker-compose.yml</code>, <code>Dockerfile</code>, <code>Dockerfile_cuda</code>, <code>Jenkinsfile</code></td>
|
||||
<td>Единая точка входа для сборки, обучения, инференса и тестов; сборка образа и выкладка</td></tr>
|
||||
</table>
|
||||
|
||||
|
|
@ -729,16 +729,20 @@ seed'ах. Принято правило «только экспертная т
|
|||
<tr><th style="width:26%">Ресурс</th><th style="width:37%">Минимальная конфигурация</th><th>Рекомендуемая</th></tr>
|
||||
<tr><td>Процессор</td><td>2 ядра x86-64 или ARM64</td><td>4 ядра и более; инференс векторизован и масштабируется по кадрам</td></tr>
|
||||
<tr><td>Оперативная память</td><td>1.5 ГБ (измеренный пик ≈ 640 МБ + запас на ОС и веб-слой)</td><td>4 ГБ</td></tr>
|
||||
<tr><td>Графический ускоритель</td><td><b>Не требуется</b>: torch устанавливается из CPU-индекса, инференс на CPU укладывается в требование по времени</td><td>Любой GPU с поддержкой CUDA 11.8 — вариант сборки <code>Dockerfile_cuda</code></td></tr>
|
||||
<tr><td>Дисковое пространство</td><td>базовый образ python:3.11-slim (150 МБ) + зависимости и код; чекпоинт 43 МБ монтируется отдельно</td><td>плюс место под входные архивы DICOM и результаты</td></tr>
|
||||
<tr><td>Графический ускоритель</td><td><b>Не требуется</b>: torch устанавливается из CPU-индекса, инференс на CPU укладывается в требование по времени</td><td>Любой GPU с поддержкой CUDA 12.6, включая H200 (compute capability 9.0) — вариант сборки <code>Dockerfile_cuda</code></td></tr>
|
||||
<tr><td>Дисковое пространство</td><td>базовый образ python:3.11-slim (150 МБ) + зависимости, код и чекпоинт (43 МБ) — всё внутри образа</td><td>плюс место под входные архивы DICOM и результаты</td></tr>
|
||||
<tr><td>Сеть</td><td>Не требуется при работе: образ и веса фиксированы, обращений во внешние сервисы нет</td><td>Нужна только для сборки образа и загрузки базовых зависимостей</td></tr>
|
||||
</table>
|
||||
|
||||
<p><b>Размер образа (измерено):</b> 1.41 ГБ (1 412 385 143 байт) для сборки под
|
||||
<code>linux/arm64</code>. Базовый образ <code>python:3.11-slim</code> занимает 150 МБ, остальное —
|
||||
зависимости из <code>requirements.txt</code>, включая torch и torchvision из CPU-индекса; CUDA-колёса
|
||||
в образ не попадают. Данные, тесты, <code>labels/</code> и <code>assets/</code> в образ не входят,
|
||||
чекпоинт (43 МБ) монтируется отдельно.</p>
|
||||
<p><b>Размер образа (измерено).</b> CPU-вариант: 1.46 ГБ под <code>linux/arm64</code> и 1.8 ГБ под
|
||||
<code>linux/amd64</code>. GPU-вариант: 7.0 ГБ под <code>linux/amd64</code> — почти всё сверх базы
|
||||
занимают CUDA-библиотеки внутри колёс torch (<code>nvidia-cublas-cu12</code>,
|
||||
<code>nvidia-cudnn-cu12</code>, <code>nvidia-nccl-cu12</code> и другие). Базовый образ
|
||||
<code>python:3.11-slim</code> — 150 МБ; torch и torchvision берутся из CPU-индекса в CPU-варианте и из
|
||||
индекса <code>cu126</code> в GPU-варианте, поэтому CUDA-колёса в CPU-образ не попадают (там
|
||||
<code>torch 2.8.0+cpu</code> и ноль nvidia-пакетов). Данные, тесты, <code>labels/</code>,
|
||||
<code>assets/</code> и <code>docs/</code> в образ не входят; чекпоинт (43 МБ), наоборот, лежит внутри —
|
||||
монтировать каталог с моделями при запуске не нужно.</p>
|
||||
|
||||
<h2 id="s14">14. Сборка, запуск и развёртывание</h2>
|
||||
|
||||
|
|
@ -746,30 +750,40 @@ seed'ах. Принято правило «только экспертная т
|
|||
|
||||
<table>
|
||||
<tr><th style="width:30%">Элемент</th><th>Значение</th></tr>
|
||||
<tr><td>Базовый образ</td><td><code>python:3.11-slim</code> (фиксированный тег)</td></tr>
|
||||
<tr><td>Зависимости</td><td><code>requirements.txt</code> с точными версиями; torch и torchvision — из CPU-индекса PyTorch, чтобы в образ не попали CUDA-колёса</td></tr>
|
||||
<tr><td>Что копируется в образ</td><td>только <code>src/</code>, <code>requirements.txt</code> и <code>run.sh</code></td></tr>
|
||||
<tr><td>Что не копируется</td><td>данные, тесты, <code>labels/</code>, <code>assets/</code>, <code>docs/</code> (см. <code>.dockerignore</code>), а также чекпоинт</td></tr>
|
||||
<tr><td>Чекпоинт</td><td>монтируется при запуске в <code>/app/models</code>; путь задаётся переменной <code>DXA_MODEL_PATH</code> (по умолчанию <code>/app/models/dxa_model.pth</code>)</td></tr>
|
||||
<tr><td>Проверки на этапе сборки</td><td>импорт приложения (<code>import src.main</code>) и наличие офлайн-ассетов фронтенда; сборка падает при их отсутствии</td></tr>
|
||||
<tr><td>Базовый образ</td><td><code>python:3.11-slim</code> (фиксированный тег); у GPU-варианта он тот же — CUDA и cuDNN приходят внутри колёс torch, отдельный <code>nvidia/cuda</code>-образ не нужен</td></tr>
|
||||
<tr><td>Зависимости</td><td><code>requirements.txt</code> с точными версиями; CPU-вариант берёт torch и torchvision из CPU-индекса PyTorch, GPU-вариант — из индекса <code>cu126</code></td></tr>
|
||||
<tr><td>Что копируется в образ</td><td><code>src/</code>, <code>requirements.txt</code>, <code>run.sh</code> и чекпоинт <code>models/dxa_model.pth</code></td></tr>
|
||||
<tr><td>Что не копируется</td><td>данные, тесты, <code>labels/</code>, <code>assets/</code>, <code>docs/</code> (см. <code>.dockerignore</code>)</td></tr>
|
||||
<tr><td>Чекпоинт</td><td>копируется на этапе сборки и лежит в образе как <code>/app/models/dxa_model.pth</code>; путь задаётся переменной <code>DXA_MODEL_PATH</code>. Монтировать каталог с моделями не нужно</td></tr>
|
||||
<tr><td>Проверки на этапе сборки</td><td>импорт приложения (<code>import src.main</code>), наличие офлайн-ассетов фронтенда и читаемость чекпоинта (ключи <code>backbone</code>, <code>head</code>, <code>threshold</code>); сборка падает при их отсутствии</td></tr>
|
||||
<tr><td>Контроль состояния</td><td><code>HEALTHCHECK</code> обращается к <code>/api/v1/health</code> каждые 30 с</td></tr>
|
||||
<tr><td>Запуск</td><td><code>docker-compose.yml</code>: сервис <code>dxa-cpu</code> поднимается по умолчанию, GPU-сервис <code>dxa-cuda</code> — под профилем <code>cuda</code></td></tr>
|
||||
<tr><td>Точка входа</td><td><code>uvicorn src.main:app</code> на порту 8000</td></tr>
|
||||
</table>
|
||||
|
||||
<p>Если чекпоинт не смонтирован, сервис всё равно поднимается: <code>/api/v1/health</code> сообщает
|
||||
<p>Модель встроена в образ, поэтому штатно чекпоинт всегда на месте. Если файл всё же недоступен
|
||||
(например, образ повреждён), сервис всё равно поднимается: <code>/api/v1/health</code> сообщает
|
||||
<code>model_loaded: false</code>, а запросы анализа возвращают ошибку вместо тихой неверной оценки.
|
||||
Это сознательный выбор: отсутствие модели должно быть заметно сразу, а не проявляться как «странные»
|
||||
результаты.</p>
|
||||
|
||||
<p><b>Что проверено на самом образе.</b> Сборка прошла обе внутренние проверки
|
||||
(<code>app import ok</code>, <code>frontend assets ok</code>). Образ запущен и проверен в двух режимах:
|
||||
без смонтированного чекпоинта <code>/api/v1/health</code> отдаёт <code>model_loaded: false</code> и
|
||||
<code>exists: false</code>, а запрос анализа — HTTP 500 с телом <code>{"error": "Model not loaded"}</code>;
|
||||
с примонтированным каталогом моделей <code>/api/v1/health</code> сообщает <code>model_loaded: true</code>,
|
||||
<code>device: cpu</code>, эпоху 39 и файл разметки <code>labels/labels_images.csv</code>, запрос анализа
|
||||
отвечает корректной строкой результата, а <code>/api/v1/export</code> возвращает XLSX с ожидаемым
|
||||
набором столбцов. Сквозная проверка выполнялась в контейнере на той же машине, где снимались
|
||||
измерения производительности.</p>
|
||||
<p><b>Что проверено на самом образе.</b> Сборка проходит три внутренние проверки:
|
||||
<code>app import ok</code>, <code>frontend assets ok</code> и
|
||||
<code>checkpoint ok: resnet18 linear threshold -0.4930129051208496</code>. Контейнер запущен без единого
|
||||
монтирования (<code>docker run -d -p 8000:8000 dxa-quality:cpu</code>): чекпоинт присутствует внутри
|
||||
образа (<code>/app/models/dxa_model.pth</code>), <code>/api/v1/health</code> сообщает
|
||||
<code>model_loaded: true</code>, <code>device: cpu</code>, эпоху 39 и файл разметки
|
||||
<code>labels/labels_images.csv</code>, запрос <code>/api/v1/analyze</code> отвечает корректной строкой
|
||||
результата, а <code>/api/v1/export</code> возвращает XLSX с ожидаемым набором столбцов. Сквозная
|
||||
проверка выполнена в контейнере на той же машине, где снимались измерения производительности. Оба
|
||||
варианта дополнительно собраны под целевой <code>linux/amd64</code> (эмуляция на той же машине):
|
||||
CPU-образ содержит <code>torch 2.8.0+cpu</code> и ни одного nvidia-пакета, GPU-образ —
|
||||
<code>torch 2.8.0+cu126</code> с cuDNN 9.10.2 и библиотекой <code>libtorch_cuda.so</code>; в обоих
|
||||
сервис стартует, и <code>/api/v1/health</code>, <code>/api/v1/analyze</code> и
|
||||
<code>/api/v1/export</code> отвечают корректно (<code>device: cpu</code>, поскольку ускорителя в машине
|
||||
нет). Работа на самом GPU не проверялась: для неё нужна машина с драйвером NVIDIA, где критерий
|
||||
приёмки — <code>torch.cuda.is_available() == True</code> и <code>device: cuda</code> в
|
||||
<code>/api/v1/health</code>.</p>
|
||||
|
||||
<h3>14.2. Воспроизводимость</h3>
|
||||
|
||||
|
|
@ -788,7 +802,10 @@ seed'ах. Принято правило «только экспертная т
|
|||
<p><code>Jenkinsfile</code> выполняет три шага: сборка образа, публикация в реестр и выкладка в
|
||||
кластер. Скрипт <code>run.sh</code> — единая точка входа для разработки и эксплуатации: обучение,
|
||||
разметка, приведение имён файлов, инференс, сервис, сравнение вариантов разметки и тесты
|
||||
(перечень команд — приложение Б).</p>
|
||||
(перечень команд — приложение Б). Для запуска образа есть <code>docker-compose.yml</code> с двумя
|
||||
сервисами (14.1). Файл выкладки swarm (<code>/data/deploy/rell-bone-2026/docker-swarm.yml</code>) лежит
|
||||
вне репозитория: если он монтирует каталог с моделями в <code>/app/models</code>, монтирование
|
||||
перекроет встроенный чекпоинт, поэтому его нужно убрать при обновлении выкладки.</p>
|
||||
|
||||
<h2 id="s15">15. Тесты и проверки</h2>
|
||||
|
||||
|
|
@ -968,7 +985,7 @@ seed'ах. Принято правило «только экспертная т
|
|||
├── models/dxa_model.pth рабочий чекпоинт и отчёт обучения
|
||||
├── tests/ pytest + браузерные проверки интерфейса
|
||||
├── docs/ настоящий документ (HTML и PDF)
|
||||
├── run.sh, Dockerfile, Dockerfile_cuda, Jenkinsfile, requirements.txt</pre>
|
||||
├── run.sh, docker-compose.yml, Dockerfile, Dockerfile_cuda, Jenkinsfile, requirements.txt</pre>
|
||||
|
||||
<h2 id="a2">Приложение Б. Команды</h2>
|
||||
|
||||
|
|
@ -987,9 +1004,11 @@ python -m src.dxa.discriminator проверка вклада содер
|
|||
./run.sh test pytest (209 тестов)
|
||||
node tests/browser/ui_check.js проверки интерфейса (нужен сервер на 127.0.0.1:8123)
|
||||
|
||||
# контейнер
|
||||
docker build -t dxa-quality .
|
||||
docker run -v /path/to/data:/data -v /path/to/models:/app/models -p 8000:8000 dxa-quality</pre>
|
||||
# контейнер (чекпоинт лежит внутри образа, монтировать пути не нужно)
|
||||
docker compose up -d CPU-сервис в фоне, http://localhost:8000
|
||||
docker compose --profile cuda up -d dxa-cuda GPU-сервис (нужен nvidia-container-toolkit)
|
||||
docker build -t dxa-quality . сборка CPU-образа напрямую
|
||||
docker run -p 8000:8000 dxa-quality запуск без compose</pre>
|
||||
|
||||
<p class="sign">Документ подготовлен по фактическому состоянию репозитория; машинные отчёты обучения —
|
||||
<code>models/train_report.json</code>, обоснование разметки — <code>assets/labeling.md</code>.</p>
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue