Files
depth_edges_annotate_worlduav/README.md
pikaliov 3b5778e303 Unify segmentation classes (17) across GTA-UAV and UAV_VisLoc
Extract shared UNIFIED_PROMPTS (17 classes, ID 0-16) into
scripts/seg_classes.py for transfer learning compatibility.
Both run_gta_uav.py and run_uav_visloc.py now import from it.

Key change: swimming pool moved from ID 13 → ID 16, so sports field
(ID 13), muddy ground (14), embankment (15) have stable IDs across
both datasets. Missing classes in a dataset = 0 pixels = 0 loss.

Updated: README, CLAUDE.md, segmentation_class_analysis.md, palette.
Deleted old UAV_VisLoc segmentations (need regeneration with 17 classes).

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

392 lines
19 KiB
Markdown
Raw 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.
# Multi-Modal Annotation Pipeline
Автоматическая генерация 4 модальностей (depth, edges, segmentation, canopy height) из RGB-изображений аэрофотосъёмки. Поддерживает два датасета:
| Модальность | Модель | Выход | Скорость |
|:---|:---|:---|:---|
| **Depth** | DA3-LARGE-1.1 (411M) | grayscale [256x256] | 18.4 img/s |
| **Edges** | Sobel из depth (CPU) | grayscale [256x256] | 419.6 img/s |
| **Segmentation** | SegEarth-OV3 (SAM 3.1) | class IDs [256x256] | ~3.5 img/s |
| **CHMv2** | DINOv3-ViTL16 (337M, FP32) | grayscale [256x256] | 31.7 img/s |
| **Consolidate** | SafeTensors (CPU) | `.safetensors` per image | ~5000 img/s |
| Датасет | Изображения | Сегм. классы | Скрипт |
|:---|:---|:---|:---|
| **World-UAV** | 973K (486K DB + 486K query) | 11 (базовые) | `python -m src.main` |
| **UAV_VisLoc** | 81K (75K DB + 6.7K drone) | 17 (unified) | `python scripts/run_uav_visloc.py` |
| **GTA-UAV-LR** | 48K (15K sat + 34K drone) | 17 (unified) | `python scripts/run_gta_uav.py` |
> UAV_VisLoc и GTA-UAV используют **единый набор 17 классов** (`scripts/seg_classes.py`) для совместимости при transfer learning.
## Quick Start
```bash
# World-UAV (основной датасет)
python -m src.main
# UAV_VisLoc
python scripts/run_uav_visloc.py
# GTA-UAV-LR
python scripts/run_gta_uav.py
# Тесты (143 шт, без GPU)
python -m pytest src/tests/ -v
```
## Структура проекта
```
.
├── in/
│ ├── config_files/ # Gin-конфигурация
│ │ ├── pipeline.gin # Пути, стадии, save_npy/save_vis, resume, source
│ │ ├── models.gin # Model IDs, weights_dir
│ │ ├── hardware.gin # GPU profile, batch_size (None=auto), FP16
│ │ ├── segmentation.gin # 11 промптов, threshold=0.15
│ │ └── input.gin # image_size (256)
│ └── weights/ # Веса моделей (не в git, >50MB)
│ ├── models--depth-anything--DA3-LARGE-1.1/
│ ├── sam3.1/sam3.1_multiplex.pt
│ └── dinov3-chmv2/
├── src/
│ ├── main.py # Entry point + pipeline orchestration
│ ├── nn/ # Вендорированные нейросетевые пакеты
│ │ ├── __init__.py # Регистрация sys.path при импорте
│ │ ├── segearth_ov3/ # SegEarth-OV-3 + SAM3 (копия репозитория)
│ │ │ ├── segearthov3_segmentor.py
│ │ │ ├── sam3/ # SAM 3.1 backbone (134 .py файла)
│ │ │ │ └── assets/bpe_simple_vocab_16e6.txt.gz
│ │ │ └── pamr.py
│ │ └── depth_anything_3/ # Depth-Anything-3 (копия пакета)
│ │ ├── api.py # DepthAnything3 class
│ │ ├── model/ # DA3 архитектура (DinoV2 + DPT)
│ │ ├── configs/ # YAML-конфиги моделей
│ │ └── utils/ # I/O, export, geometry
│ ├── augmentor/
│ │ ├── models.py # Загрузка/выгрузка моделей
│ │ ├── inference.py # Inference функции (depth, chmv2, edges, segm)
│ │ ├── io_utils.py # Сохранение файлов (sync + async) + палитра
│ │ └── dataset.py # Discovery, filtering, PyTorch Dataset
│ ├── conf/ # Gin-configurable dataclasses
│ ├── utils/ # Profiler, benchmark, GPU utils
│ └── tests/ # 143 теста (pytest)
├── scripts/
│ ├── run_uav_visloc.py # Запуск для UAV_VisLoc (16 классов)
│ ├── run_gta_uav.py # Запуск для GTA-UAV-LR (14 классов)
│ └── migrate_layout.py # Миграция со старого prefix-формата
└── docs/
├── segmentation_class_analysis.md # Анализ классов сегментации (11 классов)
├── segearth_ov3_architecture.md # Архитектура SegEarth-OV3 + SAM 3.1
├── analysis_optimization.md # Анализ производительности и оптимизации
└── skills_optimization_io_dl_ml.md # Справочник приемов оптимизации
```
### src/nn/ -- вендорированные пакеты
Нейросетевые модели **встроены внутрь проекта** в директории `src/nn/`. Не нужно клонировать внешние репозитории или устанавливать пакеты через pip:
- **`src/nn/segearth_ov3/`** -- полная копия [SegEarth-OV-3](https://github.com/earth-insights/SegEarth-OV-3): сегментатор + SAM3 backbone + BPE vocab
- **`src/nn/depth_anything_3/`** -- полная копия пакета из [Depth-Anything-3](https://github.com/ByteDance-Seed/Depth-Anything-3)
При `import src.nn` автоматически регистрируются пути в `sys.path`, и все внутренние импорты обоих пакетов работают без изменений.
## Конфигурация
### pipeline.gin
```python
PipelineConfig.input_root = '/path/to/UAV-GeoLoc' # Исходный датасет
PipelineConfig.output_root = '/path/to/World-UAV-aug' # Куда сохранять
PipelineConfig.stages = ['depth', 'edges', 'segmentation', 'chmv2']
PipelineConfig.save_npy = False # True = float16/uint8 .npy (промежуточные)
PipelineConfig.save_vis = True # True = .png визуализации
PipelineConfig.save_safetensors = True # True = .safetensors (для обучения, zero-copy mmap)
PipelineConfig.cleanup_npy = False # True = удалить .npy после консолидации
PipelineConfig.resume = True # Пропускать уже обработанные
PipelineConfig.subset = None # None=все, 'Rot', 'Country', 'Terrain'
PipelineConfig.source = 'db' # 'db' = спутник, 'query' = БПЛА, None = оба
```
### segmentation.gin (11 классов open-vocabulary)
```python
SegConfig.prompts = [
'background', # 0 -- unclassified
'building', # 1 -- buildings, rooftops
'road', # 2 -- roads, asphalt
'vegetation', # 3 -- trees, bushes, forest canopy
'water', # 4 -- rivers, canals, sea, lakes
'sand and gravel ground', # 5 -- soil, gravel, sand, dust, bare earth
'rocky terrain', # 6 -- rock, stone, lava, canyon walls
'farmland', # 7 -- agricultural terraces, fields
'railway', # 8 -- railway tracks, rails
'parking lot', # 9 -- parking areas
'sidewalk', # 10 -- sidewalks, pedestrian zones
]
SegConfig.threshold = 0.15
SegConfig.default_resolution = 1008
```
### Unified 17 классов (UAV_VisLoc + GTA-UAV)
Для transfer learning (pretrain GTA-UAV → fine-tune UAV_VisLoc) оба датасета используют **единый набор 17 классов** из `scripts/seg_classes.py`. Не каждый датасет содержит пиксели каждого класса — это нормально (0 пикселей = 0 loss).
| ID | Промпт | World-UAV | UAV_VisLoc | GTA-UAV |
|:--:|:---|:---:|:---:|:---:|
| 0 | background | + | + | + |
| 1 | building | + | + | + |
| 2 | road | + | + | + |
| 3 | vegetation | + | + | + |
| 4 | water | + | + | + |
| 5 | sand and gravel ground | + | + | + |
| 6 | rocky terrain | + | + | + |
| 7 | farmland | + | + | + |
| 8 | railway | + | + | + |
| 9 | parking lot | + | + | + |
| 10 | sidewalk | + | + | + |
| 11 | bare soil and plowed field | — | + | + |
| 12 | roof and rooftop | — | + | + |
| 13 | sports field and playground | — | + | редко |
| 14 | muddy ground and wetland | — | + | — |
| 15 | embankment and levee | — | + | — |
| 16 | swimming pool | — | редко | + |
> UAV_VisLoc threshold=0.1, GTA-UAV threshold=0.15. Подробный анализ: [`docs/segmentation_class_analysis.md`](docs/segmentation_class_analysis.md)
### hardware.gin
```python
HardwareConfig.profile_name = 'rtx4090'
HardwareConfig.total_ram_gb = 24.0
HardwareConfig.use_fp16 = True
HardwareConfig.batch_size = None # None = auto (из свободного VRAM)
HardwareConfig.num_workers = 4
```
## Как работает пайплайн
Стадии выполняются **последовательно** -- одна модель за раз:
```
DEPTH: загрузка DA3 -> auto_batch_size из VRAM -> все изображения -> выгрузка
EDGES: загрузка depth PNG/NPY -> Sobel (CPU, batch=32) -> выгрузка
SEGM: загрузка SegEarth-OV3 -> batched backbone (<=16 img) + per-image grounding -> выгрузка
CHMv2: загрузка DINOv3 (FP32) -> auto_batch_size из VRAM -> все изображения -> выгрузка
CONSOLIDATE: сборка depth+edge+segm+chm -> один .safetensors на изображение (CPU)
```
**SegEarth-OV3:** backbone SAM 3.1 выполняется одним forward pass на батч до 16 изображений через `predict_pil_batch()`. Grounding decoder (11 промптов x per-image) -- основной bottleneck (~84% времени). Text embeddings кэшируются при первом вызове. Подробная архитектура: [`docs/segearth_ov3_architecture.md`](docs/segearth_ov3_architecture.md)
**auto_batch_size** после загрузки модели считывает реальный свободный VRAM:
```
free_vram = total - reserved
batch = round_down_pow2(free_vram / act_per_sample * 0.7)
```
**Resume** проверяет существование файлов в соответствующих директориях модальностей. Пайплайн можно прервать Ctrl+C и перезапустить -- готовые пропускаются.
## Формат выхода
Модальность определяется **папкой**, а не суффиксом файла:
```
World-UAV-aug/
├── depth/Rot/SouthernSuburbs/DB/img/crop_12_4.png # vis
├── edge/Rot/SouthernSuburbs/DB/img/crop_12_4.png # vis
├── segm/Rot/SouthernSuburbs/DB/img/crop_12_4.png # vis (palette mode P)
├── chm/Rot/SouthernSuburbs/DB/img/crop_12_4.png # vis
├── npy/depth/Rot/SouthernSuburbs/DB/img/crop_12_4.npy # float16 intermediate
├── npy/edge/...
├── npy/segm/...
├── npy/chm/...
├── safetensors/Rot/SouthernSuburbs/DB/img/crop_12_4.safetensors # для обучения
└── manifest.json
```
### SafeTensors (рекомендуемый формат для обучения)
Один `.safetensors` файл на изображение, содержит все модальности:
| Ключ | Dtype | Shape | Описание |
|:---|:---|:---|:---|
| `depth` | float16 | [1, H, W] | Карта глубины [0, 1] |
| `edge` | float16 | [1, H, W] | Границы (Sobel) [0, 1] |
| `chm` | float16 | [1, H, W] | Canopy height [0, 1] |
| `segm` | uint8 | [1, H, W] | Class IDs [0, 10] (World-UAV) / [0, 16] (unified) |
Преимущества SafeTensors:
- **Zero-copy mmap** -- тензор читается прямо с диска без копирования в RAM (~0.1ms)
- **1 syscall** вместо 4 (один файл = все модальности)
- **Безопасность** -- нет pickle, нет arbitrary code execution
- **Стандарт HuggingFace** -- нативная поддержка в PyTorch
### PNG визуализации (только для просмотра)
| Стадия | Суффикс | PNG формат |
|:---|:---|:---|
| depth | `_depth` | grayscale (L), uint8, `value / 255.0` -> [0,1] |
| edges | `_edge` | grayscale (L), uint8 |
| segmentation | `_segm` | RGB palette, class ID = argmax по палитре |
| chmv2 | `_chm` | grayscale (L), uint8, `value / 255.0` -> [0,1] |
### Палитра сегментации
| ID | Класс | RGB | Датасеты |
|:--:|:---|:---|:---|
| 0 | background | (0, 0, 0) | оба |
| 1 | building | (220, 40, 40) | оба |
| 2 | road | (160, 160, 160) | оба |
| 3 | vegetation | (30, 180, 30) | оба |
| 4 | water | (30, 120, 220) | оба |
| 5 | sand and gravel ground | (180, 140, 80) | оба |
| 6 | rocky terrain | (120, 100, 80) | оба |
| 7 | farmland | (200, 200, 50) | оба |
| 8 | railway | (100, 60, 120) | оба |
| 9 | parking lot | (255, 165, 0) | оба |
| 10 | sidewalk | (200, 200, 200) | оба |
| 11 | bare soil | (140, 100, 50) | UAV_VisLoc |
| 12 | rooftop | (180, 60, 60) | UAV_VisLoc |
| 13 | sports field | (50, 200, 150) | UAV_VisLoc |
| 14 | muddy/wetland | (80, 100, 70) | UAV_VisLoc |
| 15 | embankment | (170, 130, 100) | UAV_VisLoc |
| 16 | swimming pool | (0, 200, 255) | GTA-UAV |
## Использование для обучения
### SafeTensors (рекомендуемый способ)
```python
from safetensors.torch import load_file
stem = "crop_12_4"
aug_root = Path("World-UAV-aug")
rel_parent = "Rot/SouthernSuburbs/DB/img"
# Zero-copy чтение всех модальностей за ~0.1ms
data = load_file(aug_root / "safetensors" / rel_parent / f"{stem}.safetensors", device="cpu")
depth = data["depth"] # [1, 256, 256] float16, [0, 1]
edge = data["edge"] # [1, 256, 256] float16, [0, 1]
chm = data["chm"] # [1, 256, 256] float16, [0, 1]
segm = data["segm"] # [1, 256, 256] uint8, class IDs [0, 10]
# Для Teacher NADEZHDA: segm -> one-hot
import torch.nn.functional as F
segm_onehot = F.one_hot(segm.long().squeeze(0), num_classes=17) # [H, W, 17]
segm_onehot = segm_onehot.permute(2, 0, 1).float() # [17, H, W]
```
### PNG fallback (для визуализации или legacy)
```python
from PIL import Image
import numpy as np
# Depth / Edge / CHM -- grayscale float [0, 1]
depth = np.array(Image.open(aug_root / "depth" / rel_parent / f"{stem}.png")) / 255.0
edge = np.array(Image.open(aug_root / "edge" / rel_parent / f"{stem}.png")) / 255.0
chm = np.array(Image.open(aug_root / "chm" / rel_parent / f"{stem}.png")) / 255.0
```
> PNG визуализации квантуют float16 в uint8 (256 уровней). Для обучения используйте SafeTensors.
### Миграция со старого формата
Если данные сгенерированы в старом prefix-формате (`crop_12_4_depth.png`), мигрируйте:
```bash
# Сначала проверить (dry-run)
python scripts/migrate_layout.py /mnt/data1tb/cvgl_datasets/World-UAV-aug --dry-run
# Выполнить миграцию
python scripts/migrate_layout.py /mnt/data1tb/cvgl_datasets/World-UAV-aug
```
## Скачивание весов
Веса скачиваются один раз в `in/weights/` (~10 GB суммарно):
```bash
# DA3-LARGE-1.1 (HuggingFace, открытый доступ)
python -c "
from huggingface_hub import snapshot_download
snapshot_download('depth-anything/DA3-LARGE-1.1', cache_dir='in/weights')
"
# SAM 3.1 (для SegEarth-OV3)
mkdir -p in/weights/sam3.1
cp /path/to/sam3.1_multiplex.pt in/weights/sam3.1/
# CHMv2 DINOv3 (gated, нужен доступ к facebook/dinov3-vitl16-chmv2-dpt-head)
python -c "
from transformers import CHMv2ForDepthEstimation, CHMv2ImageProcessor
model = CHMv2ForDepthEstimation.from_pretrained('facebook/dinov3-vitl16-chmv2-dpt-head')
proc = CHMv2ImageProcessor.from_pretrained('facebook/dinov3-vitl16-chmv2-dpt-head')
model.save_pretrained('in/weights/dinov3-chmv2')
proc.save_pretrained('in/weights/dinov3-chmv2')
"
```
> BPE vocab (`bpe_simple_vocab_16e6.txt.gz`) уже встроен в проект: `src/nn/segearth_ov3/sam3/assets/`. Отдельно скачивать не нужно.
## Известные особенности
- **CHMv2 работает только в FP32** -- в FP16 выдает NaN. Модель автоматически загружается в FP32 независимо от `use_fp16`
- **SegEarth-OV3 bottleneck** -- grounding decoder (11 промптов x per-image) = ~84% времени инференса. Text embeddings кэшируются. Batch size backbone = 16
- **16 сцен Country исключены** -- неполные (нет DB-кропов). Фильтруются автоматически через `INCOMPLETE_SCENES`
- **Ледники/снег** -- SegEarth-OV3 классифицирует как `water` (ограничение модели). Класс `snow and ice` убран как неэффективный
- **Verbose логи подавлены** -- DA3, transformers, SAM 3.1, HF Hub. Управляется через `_silence_model_loggers()`
## Оценка времени (RTX 4090, 24 GB, 973K images)
| Стадия | Время | % |
|:---|:---|:---|
| Depth | ~14.7 ч | 16% |
| Edges | ~0.6 ч | <1% |
| Segmentation (bs=16, 11 prompts) | ~77 ч | **~70%** |
| CHMv2 | ~8.5 ч | ~8% |
| Consolidate (.safetensors) | ~0.1 ч | <1% |
| **Итого** | **~101 ч (~4 дня)** | |
> При обработке только DB (спутник, `source='db'`): ~486K изображений, ~50 ч.
> При обработке только query (БПЛА, `source='query'`): ~486K изображений, ~50 ч.
## Тесты
```bash
# Все тесты (143 штуки, ~2.5 сек, без GPU)
python -m pytest src/tests/ -v
# Только pipeline integration
python -m pytest src/tests/test_pipeline_integration.py -v
# Только inference
python -m pytest src/tests/test_inference.py -v
```
Все тесты используют mock-модели -- GPU не требуется.
## Документация
| Документ | Описание |
|---|---|
| [`docs/segmentation_class_analysis.md`](docs/segmentation_class_analysis.md) | Анализ 392 локаций, выбор 11 классов, результаты тестирования |
| [`docs/segearth_ov3_architecture.md`](docs/segearth_ov3_architecture.md) | Архитектура SegEarth-OV3 + SAM 3.1, pipeline инференса, профиль производительности |
| [`docs/analysis_optimization.md`](docs/analysis_optimization.md) | Общий анализ и оптимизация пайплайна |
| [`docs/skills_optimization_io_dl_ml.md`](docs/skills_optimization_io_dl_ml.md) | Справочник приемов оптимизации I/O, DataLoader, ML |
## Зависимости
- Python 3.10+
- PyTorch 2.x + CUDA
- transformers >= 5.5
- huggingface_hub
- safetensors >= 0.4
- gin-config, tqdm, Pillow, coloredlogs, psutil, matplotlib
- omegaconf, einops (зависимости Depth-Anything-3)
- iopath (зависимость SAM3)
> SegEarth-OV-3 и Depth-Anything-3 **вендорированы** в `src/nn/` -- отдельная установка не требуется.