Files
depth_edges_annotate_worlduav/docs/analysis_optimization.md
pikaliov 686db62c25 Initial commit: World-UAV annotation pipeline
4-modality annotation pipeline (depth, edges, segmentation, chmv2) for 973K
drone/satellite images. SegEarth-OV3 open-vocabulary segmentation with 11
classes optimized for cross-view geo-localization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 11:22:01 +03:00

164 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Анализ и оптимизация пайплайна depth_edges_annotate_worlduav
## Обзор
Пайплайн для аннотации датасета World-UAV: четыре стадии (depth, edges, segmentation, chmv2), конфигурация через Gin, fallback-модели, атомарное сохранение, resume-логика. Нейросетевые модели (SegEarth-OV-3, Depth-Anything-3) вендорированы в `src/nn/`.
---
## 1. Инференс GPU -- самые крупные выигрыши
### 1.1 `torch.compile()` для моделей
В `models.py` после загрузки модели можно обернуть в `torch.compile(model, mode="reduce-overhead")`. Для DepthAnything и SegFormer это может дать **20-40% ускорения** на repeated batches за счет fusion ядер и устранения Python overhead. Особенно эффективно при большом количестве батчей.
### 1.2 AMP через `torch.autocast` вместо ручного `.half()`
Сейчас в `inference.py:79` и `inference.py:203` делается ручной каст `x = x.half()` при условии `model.parameters().dtype == torch.float16`. Это неоптимально:
- `torch.autocast("cuda", dtype=torch.float16)` автоматически выберет FP16 для matmul/conv, но оставит FP32 для нормализации и softmax -- меньше потерь точности и обычно быстрее
- Убирает необходимость в ручных проверках dtype
### 1.3 DA3: batch-инференс вместо поштучного цикла
`inference.py:59-74` -- DA3 обрабатывается через `model.inference()` API, который внутри делает preprocess + forward + postprocess. Для максимальной производительности можно вызывать низкоуровневый `model.forward()` напрямую (весь батч тензором на GPU), минуя конвертации tensor -> numpy -> PIL -> обратно.
### 1.4 SegEarth-OV3: batched backbone (реализовано в v3.2)
`predict_pil_batch()` батчит backbone SAM 3.1 (~80% времени) на до 8 изображений. Grounding decoder остается per-image. Дальнейшие оптимизации:
- `torch.cuda.Stream` для overlap compute/data-transfer
- Увеличение max_batch если VRAM позволяет (текущий лимит 8 hardcoded)
---
## 2. Data Pipeline -- ускорение загрузки
### 2.1 `persistent_workers=True` (реализовано)
DataLoader создается с `persistent_workers=True` при `num_workers > 0`. Воркеры не пересоздаются между батчами.
### 2.2 `prefetch_factor` (реализовано)
`prefetch_factor=4` для лучшего overlap загрузки с инференсом.
### 2.3 Decode на GPU через `torchvision.io` или `nvidia-dali`
`dataset.py` -- `Image.open().convert("RGB")` + `transforms.Resize()` работает на CPU через PIL. Для больших датасетов это bottleneck. Варианты:
- `torchvision.io.decode_image` + `torchvision.transforms.v2` -- resize на GPU
- NVIDIA DALI pipeline -- полный decode+resize+normalize на GPU, особенно выгоден при images > 10k
### 2.4 Предвычисление списка файлов
`dataset.py` -- `rglob("*")` обходит файловую систему при каждом запуске. Для больших датасетов (тысячи папок) это минуты. Можно кешировать список в `.file_cache.json` и обновлять только при изменении mtime корня.
---
## 3. I/O -- запись результатов
### 3.1 Асинхронная запись (реализовано)
`io_utils.py` -- `ThreadPoolExecutor` с 4 workers для неблокирующей записи файлов. GPU inference продолжается пока предыдущий батч пишется на диск.
### 3.2 Атомарная запись (реализовано)
Temp file + `os.replace()` для crash-safety. Resume-логика корректно обрабатывает прерванные записи.
### 3.3 Визуализации -- отложить или отключить
`save_vis=False` отключает PNG-визуализации. Для ускорения можно генерировать визуализации отдельным скриптом после всего инференса.
### 3.4 Pre-create output dirs (реализовано)
Все output_dir создаются одним проходом до начала обработки (`run_pipeline()` в `main.py:333-339`), а не per-image.
---
## 4. Edges стадия
### 4.1 Batched Sobel (реализовано)
Edges обрабатываются батчами по 32 изображения. `compute_edges_from_depth` поддерживает `[B, 1, H, W]`.
### 4.2 Sobel-ядра как module-level константы (реализовано)
`_SOBEL_X` и `_SOBEL_Y` -- module-level константы в `inference.py`.
### 4.3 Edges как побочный продукт depth
Если не нужен resume между стадиями -- считать edges прямо в `run_depth_stage` из только что вычисленного depth, не сохраняя и не загружая `.npy`. Текущая архитектура предпочитает гранулярный resume.
---
## 5. Resume и discovery
### 5.1 Completion manifest вместо per-file проверок
`filter_completed()` -- для каждого изображения вызывается `Path.exists()` (syscall). При 100k изображений x 4 стадии = 400k stat-вызовов. Альтернатива:
- `completed.json` / SQLite per stage
- Проверка по set-lookup вместо filesystem
### 5.2 `filter_completed` -- per-stage
Каждая стадия фильтрует отдельно. Можно за один проход собрать статусы всех стадий.
---
## 6. Память и типы данных
### 6.1 FP32 для CHMv2 (вынужденная мера)
CHMv2 (DINOv3 DPT head) выдает NaN в FP16. Всегда FP32 -- это увеличивает VRAM на ~0.65 GB vs FP16, но гарантирует корректность.
### 6.2 uint8 для сегментации (реализовано)
`infer_segmentation_batch` возвращает `uint8` для class IDs. При 5 классах это оптимально.
### 6.3 float16 для .npy (реализовано)
Depth, edges, CHM сохраняются в `.npy` как `float16` (если `save_npy=True`).
---
## 7. Вендорированные пакеты (src/nn/)
### 7.1 Текущая архитектура
SegEarth-OV-3 и Depth-Anything-3 **встроены в проект** как вендорированные пакеты в `src/nn/`. При `import src.nn` автоматически регистрируются пути в `sys.path`:
- `src/nn/` -- для `depth_anything_3.*`
- `src/nn/segearth_ov3/` -- для `sam3.*` и `segearthov3_segmentor`
**Преимущества:**
- Нет зависимости от внешних репозиториев
- Воспроизводимость -- фиксированная версия кода
- Нет конфликтов с системными пакетами
**Ограничения:**
- Обновление до новой версии модели требует ручного копирования
- Дублирование кода (~6.5 MB) -- допустимо для проекта с ~200 GB данных
### 7.2 BPE vocab
Файл `bpe_simple_vocab_16e6.txt.gz` встроен в `src/nn/segearth_ov3/sam3/assets/`. Дефолтный путь в `segearthov3_segmentor.py` вычисляется через `os.path.dirname(__file__)`. Копия в `in/weights/` используется приоритетно (если существует) для совместимости с существующими инсталляциями.
---
## Приоритет по соотношению усилие/выигрыш
| # | Оптимизация | Усилие | Выигрыш | Статус |
|---|-------------|--------|---------|--------|
| 1 | Async I/O через ThreadPool | Низкое | **Высокий** (overlap GPU/disk) | **Реализовано** |
| 2 | Batched backbone SegEarth-OV3 | Среднее | **Высокий** (~2.5-3x segm) | **Реализовано** |
| 3 | Pre-create output dirs | Минимальное | Средний | **Реализовано** |
| 4 | Batched Sobel edges | Низкое | Средний | **Реализовано** |
| 5 | dtype: uint8 для seg, float16 для npy | Низкое | Средний | **Реализовано** |
| 6 | `persistent_workers` + `prefetch_factor` | Минимальное | Низкий-Средний | **Реализовано** |
| 7 | Вендоринг моделей (src/nn/) | Среднее | Средний (reliability) | **Реализовано** |
| 8 | `torch.compile()` | Низкое | Средний (20-40%) | Не реализовано |
| 9 | `torch.autocast` вместо `.half()` | Низкое | Низкий-Средний | Не реализовано |
| 10 | DA3 прямой forward вместо `inference()` | Среднее | Средний | Не реализовано |
| 11 | Completion manifest вместо per-file exists | Среднее | Средний (при >100k img) | Не реализовано |
| 12 | GPU decode (DALI / torchvision.io) | Высокое | Средний | Не реализовано |