Docs: clarify dense tensor maps format and training usage
All modalities are stored as dense spatial tensor maps (not RGB renders): - depth/edge/chm: [1,H,W] float16 continuous values - segm: [1,H,W] uint8 dense class ID map (0-16) Add training code examples: one-hot encoding, per-class embedding, aux-encoder injection. Document why tensors over RGB renders (70% info loss + OOD for DINOv3). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ python -m pytest src/tests/ -v
|
||||
|
||||
## Ключевые решения
|
||||
|
||||
- **Формат выхода:** SafeTensors (zero-copy mmap, ~0.1ms чтение). Не NPY, не PNG, не `.pt`.
|
||||
- **Формат выхода:** SafeTensors с **dense tensor maps** (zero-copy mmap, ~0.1ms). Все модальности — прямые тензоры (float16/uint8), не RGB-рендеры.
|
||||
- **Структура директорий:** модальность = папка (`depth/`, `edge/`, `segm/`, `chm/`, `safetensors/`), не суффикс файла.
|
||||
- **Стадии последовательно** — одна модель в GPU за раз (экономия VRAM).
|
||||
- **Сегментация:** SegEarth-OV3 (SAM 3.1 + open-vocabulary prompts). **17 unified классов** для всех датасетов (единые ID для transfer learning).
|
||||
@@ -66,6 +66,6 @@ docs/ — документация
|
||||
|
||||
- Не менять порядок/ID классов в `scripts/seg_classes.py` — все датасеты зависят от фиксированных ID.
|
||||
- Не использовать `.pt` (torch.save) для хранения тензоров — pickle, медленно.
|
||||
- Не рендерить depth/seg в RGB colormap для обучения — OOD для DINOv3, потеря информации.
|
||||
- Не рендерить depth/seg в RGB colormap для обучения — OOD для DINOv3, потеря ~70% информации. Использовать dense tensor maps из SafeTensors.
|
||||
- Не снижать threshold ниже 0.1 — увеличивает false positives без значимого улучшения recall.
|
||||
- Не менять `dark_water_std_thr` (0.18) — калибровано на GTA-UAV ocean (std 0.10-0.15). Ниже — не ловит, выше — false positives на normal images.
|
||||
|
||||
64
README.md
64
README.md
@@ -198,10 +198,10 @@ World-UAV-aug/
|
||||
|
||||
| Ключ | 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) |
|
||||
| `depth` | float16 | [1, H, W] | Dense depth map, непрерывная [0, 1], per-frame normalized |
|
||||
| `edge` | float16 | [1, H, W] | Dense edge map (Sobel magnitude), [0, 1] |
|
||||
| `chm` | float16 | [1, H, W] | Dense canopy height map, [0, 1], per-frame normalized |
|
||||
| `segm` | uint8 | [1, H, W] | Dense class ID map, значения [0, 16] (17 unified классов) |
|
||||
|
||||
Преимущества SafeTensors:
|
||||
- **Zero-copy mmap** -- тензор читается прямо с диска без копирования в RAM (~0.1ms)
|
||||
@@ -242,42 +242,54 @@ World-UAV-aug/
|
||||
|
||||
## Использование для обучения
|
||||
|
||||
Все модальности хранятся как **dense tensor maps** — прямые тензоры, не RGB-рендеры. Это ключевое решение (см. [dialog_fusion_modalities](docs/segmentation_class_analysis.md)): тензоры сохраняют полную информацию без потерь при квантовании/colormapping и не являются OOD-входом для DINOv3.
|
||||
|
||||
### SafeTensors (рекомендуемый способ)
|
||||
|
||||
```python
|
||||
from safetensors.torch import load_file
|
||||
|
||||
stem = "crop_12_4"
|
||||
aug_root = Path("World-UAV-aug")
|
||||
rel_parent = "Rot/SouthernSuburbs/DB/img"
|
||||
import torch.nn.functional as F
|
||||
|
||||
# Zero-copy чтение всех модальностей за ~0.1ms
|
||||
data = load_file(aug_root / "safetensors" / rel_parent / f"{stem}.safetensors", device="cpu")
|
||||
data = load_file("World-UAV-aug/safetensors/Rot/.../crop_12_4.safetensors")
|
||||
|
||||
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]
|
||||
# Все модальности — dense spatial maps, готовые для injection в backbone
|
||||
depth = data["depth"] # [1, H, W] float16, непрерывная глубина [0, 1]
|
||||
edge = data["edge"] # [1, H, W] float16, Sobel magnitude [0, 1]
|
||||
chm = data["chm"] # [1, H, W] float16, canopy height [0, 1]
|
||||
segm = data["segm"] # [1, H, W] uint8, dense class ID map [0, 16]
|
||||
```
|
||||
|
||||
### PNG fallback (для визуализации или legacy)
|
||||
### Подача в Teacher NADEZHDA
|
||||
|
||||
Каждая модальность подаётся в свой lightweight aux-encoder, затем через FiLM/Conv1x1 injection в DINOv3 patch tokens:
|
||||
|
||||
```python
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
# Depth / Edge / CHM → [B, 1, H, W] float → Conv aux-encoder → FiLM injection
|
||||
# Прямые тензоры, НЕ RGB-рендеры (turbo colormap = потеря 70% информации + OOD)
|
||||
aux_depth = depth_encoder(depth.float()) # [1, H, W] → [C, H, W]
|
||||
aux_edge = edge_encoder(edge.float())
|
||||
aux_chm = chm_encoder(chm.float())
|
||||
|
||||
# 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
|
||||
# Segmentation → dense class ID map → per-class embedding → spatial feature map
|
||||
# Вариант 1: one-hot → Conv
|
||||
segm_onehot = F.one_hot(segm.long().squeeze(0), num_classes=17) # [H, W, 17]
|
||||
segm_features = seg_conv(segm_onehot.permute(2, 0, 1).float()) # [17, H, W] → [C, H, W]
|
||||
|
||||
# Вариант 2: learned per-class embedding (SegAuxEncoder)
|
||||
# seg_emb = nn.Embedding(17, 32)
|
||||
# segm_features = seg_emb(segm.long().squeeze(0)).permute(2, 0, 1) # [H, W] → [32, H, W]
|
||||
```
|
||||
|
||||
> PNG визуализации квантуют float16 в uint8 (256 уровней). Для обучения используйте SafeTensors.
|
||||
### Почему тензоры, а не RGB-рендеры
|
||||
|
||||
| Формат | Пример depth | Потеря информации | Для DINOv3 |
|
||||
|---|---|---|---|
|
||||
| `float16` тензор (хранится) | `[0.4231, 0.4235, ...]` | ~0% | Прямой вход в aux-encoder |
|
||||
| `uint8` grayscale PNG | `[108, 108, ...]` | ~0.4% | Приемлемо |
|
||||
| `turbo colormap` RGB PNG | `[R=50, G=180, B=220]` | **~70%** | **OOD** — DINOv3 обучен на натуральных RGB |
|
||||
|
||||
> Для обучения **всегда** используйте SafeTensors. PNG визуализации — только для просмотра в Obsidian/файловом менеджере.
|
||||
|
||||
### Миграция со старого формата
|
||||
|
||||
|
||||
Reference in New Issue
Block a user