fuse_proj: Initial operational package for 3 researchers (Pavlenko/Blizno/Moroz)
Multimodal fusion research on StripNet+GTA-UAV proxy: - 3 independent fusion tracks: condition-aware (A), token/bottleneck (B), role-aware (C) - Shared interfaces, protocol, dataset audit, baseline benchmarks - Canonical version-chain references to vault (SPEC, ANALYSIS, TRIAGE) - Personalized task plans and decision tables for each researcher - 3 generated DOCX task assignment files with milestones and DoD checklist - Full modality dropout diagnostics and missing-modality robustness requirements - Data contract, benchmark registry, experiment tracking infrastructure Operational documents: - docs/00_project/: MERIDIAN context, protocol, repository reuse guide, experiment specification - docs/01_tasks/: Master assignment + 3 individual researcher tracks + joint integration - docs/02_references/: Core literature, version-chain bases, code maps - docs/03_codebase_guides/: Existing code snapshots from vault - scripts/: gen_task_plans.js (DOCX generation), placeholder infrastructure - vendor_reference/: Snapshots of caption_test, depth_edges_annotate, existing SOFIA/SegModel code - reports/, results/, experiments/: Shared output structure for all 3 researchers 3 DOCX files generated from gen_task_plans.js (Times New Roman 14pt, GOST format): - План_заданий_Павленко_БВ.docx (Condition-Aware track, fusion API owner) - План_заданий_Близно_МВ.docx (Token/Bottleneck track, benchmark owner) - План_заданий_Мороз_ЕС.docx (Role-Aware track, data contract owner) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
Очень интересная идея. Вот мой анализ:
|
||||
|
||||
## CHMv2 vs Depth Anything V3 для CVGL
|
||||
|
||||
|Аспект|DA3-BASE (depth)|CHMv2 (canopy height)|
|
||||
|:--|:--|:--|
|
||||
|**Что предсказывает**|Относительную глубину сцены (расстояние до камеры)|**Абсолютную высоту растительности** (в метрах)|
|
||||
|**Backbone**|ViT (собственный)|**DINOv3 ViT-L/16 Sat** (тот же что наш Teacher!)|
|
||||
|**Обучающие данные**|Наземные/уличные фото|**Спутниковые снимки + LiDAR**|
|
||||
|**Домен**|General (domain gap для satellite)|**Native satellite** (нет domain gap)|
|
||||
|**Выход**|Relative [0,1] per-frame|**Абсолютный** (метры)|
|
||||
|**Разрешение**|Произвольное|Метровое (satellite)|
|
||||
|**HuggingFace**|`depth-anything/DA3-BASE`|[`facebook/dinov3-vitl16-chmv2-dpt-head`](https://huggingface.co/facebook/dinov3-vitl16-chmv2-dpt-head)|
|
||||
|**Информативность для CVGL**|Рельеф + масштаб (general)|**Высота деревьев** (специфична)|
|
||||
|
||||
## Мой вердикт: использовать **оба** как отдельные модальности
|
||||
|
||||
**Почему не заменять, а дополнять:**
|
||||
|
||||
1. **DA3 и CHMv2 дают ортогональную информацию:**
|
||||
|
||||
- DA3 depth → **рельеф и структура зданий** (перепады высот крыш, дорожная сетка)
|
||||
- CHMv2 → **высота растительности** (парки vs пустыри, лес vs поле)
|
||||
- Для matching: два здания на одном рельефе различаются окружающей растительностью
|
||||
2. **CHMv2 построен на DINOv3 Sat** — том самом backbone, который наш Teacher использует. Это значит:
|
||||
|
||||
- Features CHMv2 **совместимы** с Teacher's feature space
|
||||
- L_feat дистилляция от CHMv2-features к Student будет эффективнее, чем от DA3
|
||||
3. **CHMv2 работает нативно на спутниковых снимках** — нет domain gap. DA3 обучен на наземных фото → на satellite качество ниже (это наша гипотеза AH3)
|
||||
|
||||
4. **Для дроновых снимков:** DA3 лучше (дрон ≈ наземный ракурс), CHMv2 хуже (обучен на satellite nadir)
|
||||
|
||||
|
||||
## Предлагаемая конфигурация: 7-канальный выход
|
||||
|
||||
```
|
||||
Channels: RGB(3) + Depth(1) + CanopyHeight(1) + Edges(1) + SegID(1) = 7ch
|
||||
```
|
||||
|
||||
|Канал|Модель|Для drone|Для satellite|
|
||||
|:--|:--|:--|:--|
|
||||
|0-2: RGB|—|Основа|Основа|
|
||||
|3: **Depth**|DA3-BASE|**Хорошо** (похож на training domain)|Средне (domain gap)|
|
||||
|4: **Canopy Height**|CHMv2|Средне (обучен на sat)|**Отлично** (native domain)|
|
||||
|5: Edges|Sobel из depth|Хорошо|Хорошо|
|
||||
|6: SegID|SegEarth-OV3|Хорошо|Хорошо|
|
||||
|
||||
**Ключевое преимущество:** DA3 и CHMv2 **комплементарны по доменам**: DA3 лучше для drone, CHMv2 лучше для satellite. Teacher, обучающийся на обоих, получает лучшее из двух миров.
|
||||
|
||||
## Что нужно для реализации
|
||||
|
||||
1. Добавить `canopy_height` как новую стадию в pipeline
|
||||
2. Модель: `facebook/dinov3-vitl16-chmv2-dpt-head` (HuggingFace transformers)
|
||||
3. Вход: RGB satellite/drone image
|
||||
4. Выход: `canopy.npy` [1, H, W] float32 (метры, абсолютные)
|
||||
5. Обновить `segmentation.gin` → добавить `canopy_model_id`
|
||||
6. Обновить `concat` → 7ch вместо 6ch
|
||||
|
||||
Хотите добавить CHMv2 в пайплайн?
|
||||
|
||||
Sources:
|
||||
|
||||
- [CHMv2 paper (arXiv:2603.06382)](https://arxiv.org/abs/2603.06382)
|
||||
- [CHMv2 model on HuggingFace](https://huggingface.co/facebook/dinov3-vitl16-chmv2-dpt-head)
|
||||
- [DINOv3 GitHub](https://github.com/facebookresearch/dinov3)
|
||||
- [Meta AI blog post](https://ai.meta.com/blog/world-resources-institute-dino-canopy-height-maps-v2/)
|
||||
@@ -0,0 +1,857 @@
|
||||
---
|
||||
type: protocol
|
||||
status: draft
|
||||
date: 2026-05-21
|
||||
component: teacher-text
|
||||
phase: E1-aux
|
||||
dataset: GTA-UAV-LR
|
||||
visual_encoder: StripNet-small (frozen + Conv-MONA last-2 stages)
|
||||
n_candidates: 8 primary + 3 optional (5-10 to choose)
|
||||
related:
|
||||
- "[[HYP_text_encoder_variants_v3]]"
|
||||
- "[[DELTA_E1_text_encoder_F_variants_v3]]"
|
||||
- "[[ANALYSIS_text_encoder_v2]]"
|
||||
- "[[ANALYSIS_text_encoders_for_scene_caption_fusion_v2]]"
|
||||
- "[[DELTA_E1_pair_D_text_fusion_v2]]"
|
||||
- "[[../../../3_work/4_cvgl_work/caption_test/_index]]"
|
||||
tags:
|
||||
- protocol
|
||||
- methodology
|
||||
- text-encoder
|
||||
- benchmark
|
||||
- GTA-UAV
|
||||
- StripNet
|
||||
- fusion
|
||||
- pair-d
|
||||
- sofia-legacy-bb
|
||||
author: claude
|
||||
---
|
||||
|
||||
# PROTOCOL: Бенчмарк текстовых энкодеров для CVGL со StripNet на GTA-UAV-LR
|
||||
|
||||
> Методичка для сотрудницы (Полякова В.Е.). Фиксирует **визуальный энкодер = StripNet-small**, варьирует **текстовый энкодер** (5–10 вариантов из 4 семейств), оценивает по 5 группам метрик с decision-rule. Опирается на готовую инфраструктуру [[../../../3_work/4_cvgl_work/caption_test/_index|caption_test workspace]] и канонические гипотезы [[HYP_text_encoder_variants_v3]] / [[DELTA_E1_pair_D_text_fusion_v2]].
|
||||
|
||||
---
|
||||
|
||||
## §0. TL;DR
|
||||
|
||||
| Что | Решение |
|
||||
|:--|:--|
|
||||
| **Цель** | Найти оптимальный text-encoder для CVGL-fusion в связке с лёгким viz-encoder (StripNet-small) на синтетическом UAV-датасете GTA-UAV-LR с captions 3-абзацного формата (~430 токенов output) |
|
||||
| **Visual encoder (фикс)** | StripNet-small, ImageNet-1K pretrain, frozen + **Conv-MONA** в последних 2 stages (~2-3M trainable) + Linear(512→1024) |
|
||||
| **Text encoders (var, 8 primary + 3 opt)** | 4 семейства: **(a)** Generic CLIP 77-tok, **(b)** RS-specialised 77-tok, **(c)** RS-specialised long-ctx 248-tok, **(d)** Generic long-ctx 248–512 tok. Опц. (e) Universal text-embed 8K |
|
||||
| **Датасет** | GTA-UAV-LR (33,763 drone / 14,640 sat / 6,546 sat-captions / 33,411 drone-captions, формат P1/P2/P3 ≈ 90–140 слов) |
|
||||
| **Split** | Primary: `cross-area` (harder) + Secondary: `same-area` (sanity) |
|
||||
| **Метрики** | A: R@1/R@5/R@10 + ΔR@1 vs baseline; B: caption-fit (token use, margin); C: efficiency (params/VRAM/latency); D: training dynamics (τ, gate, conv); E: robustness (L1/L2/L3, cross-area gap) |
|
||||
| **Регламент** | 3 seeds × 8 encoders × 10 epochs, MoCo queue 4096, SymmetricInfoNCE, AdamW + linear-warmup-cosine |
|
||||
| **Decision rule** | Best encoder = max R@1@cross-area при p<0.05 (bootstrap CI). 4 deep-dives: RS-spec vs generic / long-ctx vs short / domain vs context / RS+long combined |
|
||||
| **Сроки** | ~2 недели (1 неделя — реализация text encoder factory + smoke tests, 1 неделя — runs + analysis) |
|
||||
|
||||
---
|
||||
|
||||
## §1. Контекст и цель
|
||||
|
||||
### 1.1 Зачем
|
||||
|
||||
Внешняя задача: **выбрать text-encoder для full MERIDIAN Pair D** (см. [[../00_overall/SPEC_fusion_ACF_MERIDIAN_v5]]) на основе чистого CVGL-эксперимента, который изолирует вклад текстового модуля от тяжёлого виз-энкодера (DINOv3-L), используя **легковесный** viz-encoder (StripNet-small ~28M) как **«capability floor»**.
|
||||
|
||||
> [!info] Логика контроля
|
||||
> Если на слабом виз-энкодере (StripNet) текстовый модуль даёт **значимый** ΔR@1 — это **upper-bound** ценности этого текстового энкодера для production-сценария SOFIA (студент ~5–10M params на Jetson). На сильном энкодере (DINOv3-L) вклад текста может «съесться» избыточной capacity визуальной ветки и быть недооценён.
|
||||
|
||||
### 1.2 Что НЕ изучаем
|
||||
|
||||
- ❌ **Архитектуру fusion** — фиксируем `GatedFusion(σ(α)·image + (1−σ(α))·text)` + `TextFusionMLP(3×D_text → 1024 → 1024)`. Это уже валидировано [[DELTA_E1_pair_D_text_fusion_v2]].
|
||||
- ❌ **Hierarchical attention** над абзацами — отдельный research arm, в этот бенчмарк не входит.
|
||||
- ❌ **Caption generation quality** — captions уже сгенерированы Qwen3-VL-8B AWQ + audit pipeline (см. [[../../07_text_pipeline/PIPELINE_text_annotation_full_v2]]).
|
||||
- ❌ **TextFiLM PEFT** в SatHead/UAVHead (это для SOFIA v7.6/v7.7, не для caption_test legacy stack).
|
||||
|
||||
### 1.3 Связь с проектом
|
||||
|
||||
- **Downstream:** результат напрямую питает выбор `T_text canonical` в [[HYP_text_encoder_variants_v3]] (сейчас anchor — F13 RemoteCLIP).
|
||||
- **Upstream:** не модифицирует SOFIA v7.6/v7.7 backbone; затрагивает только Pair D fusion слой.
|
||||
- **Параллельные эксперименты:** результат ортогонален E1 для full Teacher (DINOv3-L) — может быть проведён независимо.
|
||||
|
||||
---
|
||||
|
||||
## §2. Визуальный энкодер (фиксированный): StripNet
|
||||
|
||||
### 2.1 Конфигурация
|
||||
|
||||
| Поле | Значение |
|
||||
|:--|:--|
|
||||
| Архитектура | StripNet-small (Strip-R-CNN backbone, hierarchical DWConv с полосовыми ядрами) |
|
||||
| Pretrain | ImageNet-1K (head dropped) |
|
||||
| Размер | ~28M params (~10× меньше DINOv3-L) |
|
||||
| Output | Stage-4 feature map [B, 512, H/32, W/32] |
|
||||
| Pooling | AdaptiveAvgPool2d(1) → [B, 512] |
|
||||
| Projection | `Linear(512 → 1024)` (trunc-normal init, std=0.02) → **retrieval space 1024-dim** |
|
||||
| Trainable | Conv-MONA в stages 3 & 4 (2 adapters per block × 6 blocks ≈ 2–3M params), bottleneck=64 + Linear projection (~525K) |
|
||||
| Frozen | Все остальные веса (BN в eval mode постоянно) |
|
||||
| Shared | **True** — один и тот же StripNet используется для drone- и sat-ветки (как в `gtauav_balanced_stripnet.gin`) |
|
||||
|
||||
### 2.2 Реализация (готова)
|
||||
|
||||
- Wrapper: [`src/models/stripnet_encoder.py::StripNetEncoder`](../../../3_work/4_cvgl_work/caption_test/src/models/stripnet_encoder.py)
|
||||
- Backbone: [`src/models/stripnet/model.py`](../../../3_work/4_cvgl_work/caption_test/src/models/stripnet/model.py)
|
||||
- Conv-MONA: [`src/models/stripnet/conv_mona.py`](../../../3_work/4_cvgl_work/caption_test/src/models/stripnet/conv_mona.py)
|
||||
- Checkpoint: `nn_models/STRIPNET/stripnet_s.pth`
|
||||
- Конфиг-шаблон: [`conf/gtauav_balanced_stripnet.gin`](../../../3_work/4_cvgl_work/caption_test/conf/gtauav_balanced_stripnet.gin)
|
||||
|
||||
### 2.3 Почему именно StripNet (а не SOFIA v7.6 / v7.7)
|
||||
|
||||
| Кандидат | Pro | Contra | Verdict |
|
||||
|:--|:--|:--|:--|
|
||||
| **StripNet-small** | Готов, проверен, ImageNet pretrain, lightweight (~28M), один для обеих веток | Не state-of-the-art | ✅ **выбран** — упрощает контроль text-effect |
|
||||
| SOFIA v7.6 (as-built) | Production-canonical, multi-modal | Pretrain weights пока нет, требует pretrain stage | ❌ отложен |
|
||||
| DINOv3-L (current default) | Strongest visual capability | Слишком много capacity — может маскировать вклад текста | ❌ для этого бенчмарка |
|
||||
|
||||
> [!warning] Frozen visual encoder
|
||||
> StripNet backbone frozen — это **намеренно**. Если разморозить, сигнал «вклад текста» смешается с finetuning виз-энкодера на GTA-UAV. Адаптация виз-энкодера к домену — отдельный эксперимент (см. `gtauav_balanced_stripnet_unfrozen.gin` для контроля).
|
||||
|
||||
---
|
||||
|
||||
## §3. Кандидаты текстовых энкодеров
|
||||
|
||||
### 3.1 Таксономия (4 семейства × ~2 представителя каждое = 8 primary)
|
||||
|
||||
| ID | Encoder | Семейство | Ctx (tok) | Dim | Params (text) | Pretrain | HuggingFace / Source |
|
||||
|:---|:--|:--|:-:|:-:|:-:|:--|:--|
|
||||
| **TE-1** | **OpenCLIP ViT-L/14** | (a) Generic-77 | 77 | 768 | ~124M | LAION-2B | `laion/CLIP-ViT-L-14-laion2B-s32B-b82K` |
|
||||
| **TE-2** | **MobileCLIP2-S2** | (a) Generic-77 edge | 77 | 512 | ~64M | DataCompDR-1B | `apple/MobileCLIP2-S2` (см. [[B28]]) |
|
||||
| **TE-3** | **RemoteCLIP ViT-L/14** | (b) RS-77 ⭐ | 77 | 768 | ~124M | RET-3 (165K img-text) | `chendelong/RemoteCLIP-ViT-L-14` ([[F13_2023_RemoteCLIP A Vision Language Foundation Model for Remote Sensing]]) |
|
||||
| **TE-4** | **GeoRSCLIP ViT-B/32** | (b) RS-77 legacy | 77 | 512 | ~63M | RS5M (5M img-text) | `Zilun/GeoRSCLIP` |
|
||||
| **TE-5** | **DGTRS-CLIP / LRSCLIP ViT-L/14** | (c) RS-long ⭐ | 248 | 768 | ~124M | RS5M + DGTRSD | `MitsuiChen14/DGTRS` (уже интегрирован в `src/models/dgtrs/`) |
|
||||
| **TE-6** | **Long-CLIP-B** | (d) Generic-long | 248 | 512 | ~63M | LAION recap | `BeichenZhang/LongCLIP-B` ([[F82_2024_Long-CLIP_ECCV]]) |
|
||||
| **TE-7** | **LongCLIP-L** | (d) Generic-long | 248 | 768 | ~124M | LAION recap | `BeichenZhang/LongCLIP-L` |
|
||||
| **TE-8** | **SigLIP-2 base/256** | (a) Generic strong | 64 / **256** (v2) | 768 | ~109M | WebLI-100B | `google/siglip2-base-patch16-256` |
|
||||
|
||||
⭐ — приоритетные кандидаты (RS-domain canonical + RS-long anchor).
|
||||
|
||||
### 3.2 Опциональные расширения (если позволяет бюджет)
|
||||
|
||||
| ID | Encoder | Когда добавлять |
|
||||
|:--|:--|:--|
|
||||
| **TE-9** | **FarSLIP ViT-B/16** ([[F5]]) | Если хотим протестировать fine-grained UAV-pretrain CLIP |
|
||||
| **TE-10** | **PriorCLIP ViT-B/32** ([[F7]]) | Retrieval-focused CLIP — наиболее близкая task-alignment |
|
||||
| **TE-11** | **BGE-M3** | Sanity: универсальный 8K-token text-only embedder (sentence-level) — проверка «нужен ли CLIP-стиль вообще» |
|
||||
|
||||
> [!tip] Минимальный/полный набор
|
||||
> - **Минимум (5):** TE-1, TE-3, TE-5, TE-6, TE-7 — покрывает все 4 семейства, даёт чистый ablation **domain vs context-length**.
|
||||
> - **Базовый (8):** TE-1..TE-8 — рекомендуется.
|
||||
> - **Полный (11):** + TE-9/TE-10/TE-11 — для глубокого исследования.
|
||||
|
||||
### 3.3 Что сравнение **изолирует**
|
||||
|
||||
| Парное сравнение | Что говорит ΔR@1 |
|
||||
|:--|:--|
|
||||
| TE-3 vs TE-1 (RemoteCLIP vs OpenCLIP, оба 77-tok 768d) | RS-domain pretrain effect |
|
||||
| TE-5 vs TE-3 (DGTRS vs RemoteCLIP, оба RS, 248 vs 77) | Long-context **в RS-domain** |
|
||||
| TE-6 vs TE-1 (LongCLIP-B vs OpenCLIP, оба generic, 248 vs 77) | Long-context **в generic-domain** |
|
||||
| TE-5 vs TE-6 (DGTRS vs LongCLIP-B, оба 248-tok) | RS-domain **при равном context** |
|
||||
| TE-7 vs TE-6 (LongCLIP-L vs LongCLIP-B) | Capacity при равном context+domain |
|
||||
| TE-8 vs TE-1 (SigLIP-2 vs OpenCLIP) | SigLIP loss + WebLI pretrain effect |
|
||||
| TE-2 vs TE-1 (MobileCLIP2 vs OpenCLIP) | Cost-efficient generic baseline |
|
||||
| TE-11 vs all (BGE-M3 vs CLIP-family) | Нужен ли visual-aligned pretrain |
|
||||
|
||||
---
|
||||
|
||||
## §4. Датасет: GTA-UAV-LR + captions
|
||||
|
||||
### 4.1 Источники
|
||||
|
||||
| Что | Путь / Формат |
|
||||
|:--|:--|
|
||||
| RGB drone | `/home/servml/Документы/datasets/GTA-UAV-LR/drone/` — 33,763 PNG 512×384, alt 100–600m |
|
||||
| RGB satellite | `/home/servml/Документы/datasets/GTA-UAV-LR/sat/` — 14,640 PNG 256×256 RGBA |
|
||||
| Pairs | `cross-area-drone2sate-{train,test}.json` (primary) + `same-area-*` (sanity) |
|
||||
| Drone captions | `/home/servml/Документы/datasets/GTA-UAV-LR-captions/drone/*.json` — 33,411 (32,635 multi-paragraph + 776 water-only) |
|
||||
| Sat captions | `/home/servml/Документы/datasets/GTA-UAV-LR-captions/sat/*.json` — 6,546 multi-paragraph |
|
||||
| Segmentation filter | `meta/seg_filter.json` — 17 classes, exclude ≥90% bg+water → 48,403 → 37,498 pass |
|
||||
|
||||
### 4.2 Формат captions (3 paragraphs)
|
||||
|
||||
```
|
||||
P1 Inventory: land-cover inventory (15-30 слов summary + ~80 слов details)
|
||||
P2 Spatial: layout + spatial relations (~80-100 слов)
|
||||
P3 Fingerprint: уникальные landmarks для matching (~30-50 слов)
|
||||
─────────────────────────────────────────
|
||||
Total: ~90-140 слов ≈ 120-430 BPE tokens (sat ~430 в среднем)
|
||||
```
|
||||
|
||||
Hierarchy levels (как в текущем pipeline):
|
||||
|
||||
| Уровень | Контент | Длина (слова / tokens) | Использование в Mode A |
|
||||
|:--|:--|:-:|:--|
|
||||
| **L1 overview** | первое предложение P1 | ≤30 слов / ≤45 tok | encoders с ctx≤77 |
|
||||
| **L2 full** | P1+P2 целиком | ~100-200 слов / ~150-300 tok | encoders с ctx≥248 |
|
||||
| **L3 fingerprint** | P3 целиком | ≤50 слов / ≤80 tok | encoders с ctx≤77 (альт.) или конкатенация с L1/L2 |
|
||||
|
||||
### 4.3 Split-стратегия
|
||||
|
||||
| Split | Train pairs | Test pairs | Покрытие captions |
|
||||
|:--|:-:|:-:|:--|
|
||||
| **cross-area** (primary) | 26,966 → **24,891** after seg-filter | 6,742 → **6,252** | drone ≥98%, sat ≈44.7% (gate passthrough для остальных) |
|
||||
| **same-area** (sanity) | аналогично | аналогично | то же |
|
||||
|
||||
**Источник split:** `meta/train_80.json` / `meta/test_20.json` (`python -m scripts.make_split --ratio 0.8 --seed 42`).
|
||||
|
||||
> [!warning] Per-sample caption mask
|
||||
> Для sat без caption: `s_txt = None` → gate passthrough (`g = s_img`). Это правильно реализовано в `_fuse_with_mask` (см. [`asymmetric_encoder.py`](../../../3_work/4_cvgl_work/caption_test/src/models/asymmetric_encoder.py)). **Не** подавать пустую строку — внесёт шум.
|
||||
|
||||
---
|
||||
|
||||
## §5. Архитектура fusion (фиксирована)
|
||||
|
||||
```
|
||||
QUERY (drone):
|
||||
drone_img [B,3,256,256] → StripNet (shared, frozen+MONA) → d_img [B,1024]
|
||||
|
|
||||
L1 → T_e (encoder TE-k) → z₁ [D_text] ──┐ |
|
||||
L2 → T_e (encoder TE-k) → z₂ [D_text] ──┼─ cat [3·D_text] → |
|
||||
L3 → T_e (encoder TE-k) → z₃ [D_text] ──┘ TextFusionMLP(3·D_text → 1024 → 1024)
|
||||
→ d_txt [B,1024] |
|
||||
|
|
||||
q = σ(α_q)·d_img + (1−σ(α_q))·d_txt GatedFusion_q
|
||||
|
|
||||
q̂ = q/‖q‖₂ → query [B,1024]
|
||||
|
||||
GALLERY (satellite, аналогично с shared StripNet + shared TextFusionMLP)
|
||||
|
||||
LOSS: SymmetricInfoNCE с MoCo queue 4096 × 1024
|
||||
L = 0.6·CE(q̂·ĝᵀ/τ, targets) + 0.4·CE(ĝ·q̂ᵀ/τ, targets)
|
||||
τ = 1/exp(logit_scale) — learnable, clamp [0.01, 0.1], init=0.07
|
||||
label_smoothing=0.1
|
||||
```
|
||||
|
||||
**Что меняется между TE-1..TE-8:**
|
||||
|
||||
- `T_e` — модуль text encoder (загрузка + tokenizer + forward).
|
||||
- `D_text` — размерность text embedding (512 или 768).
|
||||
- `TextFusionMLP` пересоздаётся с `Linear(3·D_text → 1024)` — это **единственное** место где dim-mismatch важен.
|
||||
- `max_tokens` для tokenizer — 77, 248, 512 или 256.
|
||||
|
||||
**Что НЕ меняется:**
|
||||
|
||||
- StripNet weights/MONA config.
|
||||
- GatedFusion (init_gate=0.7, learnable α).
|
||||
- Loss / sampler / scheduler / split.
|
||||
- Retrieval-space dim = 1024.
|
||||
|
||||
---
|
||||
|
||||
## §6. Метрики оценки (5 групп)
|
||||
|
||||
### 6.1 Группа A — Retrieval quality (primary)
|
||||
|
||||
| Метрика | Что показывает | Метод |
|
||||
|:--|:--|:--|
|
||||
| **R@1, R@5, R@10** (drone→sat, **cross-area**) | Основной CVGL signal | Full satellite gallery (~2684 unique tiles в test_20) с multi-match (учитывает все positive/semi-positive) |
|
||||
| R@1, R@5, R@10 (sat→drone, cross-area) | Симметрия retrieval | Инвертированный GT (для каждого sat-tile собрать drone-индексы из `valid_idx_per_query`); знаменатель — sat-tiles с ≥1 positive drone |
|
||||
| R@1, R@5, R@10 (drone→sat, **same-area**) | Sanity check (легче) | То же |
|
||||
| AP / MRR | Mean reciprocal rank | Стандарт |
|
||||
| **ΔR@1** vs visual-baseline | Главный текстовый эффект | `ΔR@1 = R@1(TE-k) − R@1(StripNet-only, gate=1.0)` |
|
||||
|
||||
### 6.2 Группа B — Caption-fit (alignment quality)
|
||||
|
||||
| Метрика | Что показывает | Метод |
|
||||
|:--|:--|:--|
|
||||
| **Token usage histogram** | Сколько % captions не помещаются в `max_tokens` энкодера | На train+test, отдельно для drone/sat и для L1/L2/L3/full |
|
||||
| **% truncated** | Сколько captions обрезано (≥`max_tokens`) | Для 77-tok encoders на L2 ожидаем ~95%+ truncation — это **ожидаемая слабость** generic-77 |
|
||||
| **Intra-class cos-sim** | Средняя cos-sim между текст-эмбеддингами одной локации (разные drone на тот же sat) | Каждый sat-tile с ≥2 drone-captions; усреднить по тестовой выборке |
|
||||
| **Inter-class cos-sim** | Средняя cos-sim между текст-эмбеддингами **разных** локаций | Random pairs |
|
||||
| **Margin** = intra − inter | Дискриминативность текстового пространства | Чем больше — тем лучше |
|
||||
| **Caption-only R@1** | Retrieval только по text-эмбеддингам (без image) | Замораживаем gate σ(α)=0.0, запускаем eval |
|
||||
|
||||
### 6.3 Группа C — Efficiency
|
||||
|
||||
| Метрика | Единица | Метод |
|
||||
|:--|:--|:--|
|
||||
| **Text params** | M | `sum(p.numel() for p in text_encoder.parameters())` |
|
||||
| **Trainable params** (LoRA + projection) | M | filter `p.requires_grad` |
|
||||
| **Text VRAM** (peak, batch 64, fp16) | GB | `torch.cuda.max_memory_allocated()` после text-encode |
|
||||
| **Text latency** (batch 64, fp16, warm) | ms | `torch.cuda.synchronize()` + 50 warmup iters + 100 measure |
|
||||
| **Text FLOPs** | G | `torchinfo.summary()` |
|
||||
| Full pipeline VRAM (image+text+loss, batch 64) | GB | То же на full forward |
|
||||
|
||||
### 6.4 Группа D — Training dynamics
|
||||
|
||||
| Метрика | Что показывает |
|
||||
|:--|:--|
|
||||
| Convergence epochs (до plateau R@1) | Скорость обучения |
|
||||
| Final loss | Стабильность |
|
||||
| **Learnable τ** (logit_scale) trajectory | Если τ → tau_min (0.01) — embedding-space слишком concentrated; если → tau_max (0.1) — недоразличимы |
|
||||
| **Gate value σ(α_q), σ(α_g)** trajectory | <0.5 — text-доминирующий; ≈0.7 — баланс; >0.9 — text почти не вкладывается |
|
||||
| Gradient norm для text-encoder LoRA params | Если ≈ 0 — text не учится, LoRA neutralized |
|
||||
|
||||
### 6.5 Группа E — Robustness и ablations
|
||||
|
||||
| Тест | Что варьируется | Что показывает |
|
||||
|:--|:--|:--|
|
||||
| **E.1 L1-only** | Подаём только L1 (overview) | Влияет ли overview (короткий) |
|
||||
| **E.2 L2-only** | Подаём только L2 (full P1+P2) | Влияет ли длинный inventory |
|
||||
| **E.3 L3-only** | Подаём только L3 (fingerprint) | Чистый retrieval-signature эффект |
|
||||
| **E.4 L1+L3** | Конкатенация L1+L3 (без L2) | Можно ли отказаться от middle-level |
|
||||
| **E.5 Truncation analysis** | Принудительно truncate L1+L2+L3 до 77 tok | Сколько теряют long-ctx encoders, если их «зажать» |
|
||||
| **E.6 Cross-area gap** | ΔR@1(cross) − ΔR@1(same) | Domain-transfer robustness |
|
||||
| **E.7 Caption-quality robustness** | Inject 10% random captions (label noise) | Устойчивость к noisy VLM output |
|
||||
|
||||
---
|
||||
|
||||
## §7. Протокол эксперимента (фазы 0–4)
|
||||
|
||||
### Фаза 0 — Подготовка (≈ 3 дня)
|
||||
|
||||
1. **Реализация `TextEncoderFactory`** в `src/models/text_encoders/`:
|
||||
```
|
||||
src/models/text_encoders/
|
||||
├── __init__.py # factory: get_text_encoder(name, ckpt, max_tokens, ...)
|
||||
├── base.py # ABC: forward(input_ids, attn_mask) → [B, D]
|
||||
├── openclip_wrapper.py # TE-1, TE-6, TE-7 (open_clip lib)
|
||||
├── mobileclip_wrapper.py # TE-2 (apple mobileclip2)
|
||||
├── remoteclip_wrapper.py # TE-3
|
||||
├── georsclip_wrapper.py # TE-4
|
||||
├── dgtrs_wrapper.py # TE-5 (re-use existing src/models/dgtrs/)
|
||||
├── siglip2_wrapper.py # TE-8 (transformers)
|
||||
├── bgem3_wrapper.py # TE-11 opt (FlagEmbedding)
|
||||
└── tokenizers.py # unified tokenizer interface
|
||||
```
|
||||
|
||||
2. **Адаптация `TextFusionMLP`** — принимать `text_dim` параметром:
|
||||
```python
|
||||
@gin.configurable
|
||||
class TextFusionMLP(nn.Module):
|
||||
def __init__(self, text_dim: int = 768, num_levels: int = 3, out_dim: int = 1024):
|
||||
super().__init__()
|
||||
self.fc1 = nn.Linear(text_dim * num_levels, out_dim)
|
||||
self.fc2 = nn.Linear(out_dim, out_dim)
|
||||
```
|
||||
|
||||
3. **gin-конфиги** — один файл на encoder:
|
||||
```
|
||||
conf/te_bench/
|
||||
├── te1_openclip_vitl.gin
|
||||
├── te2_mobileclip2.gin
|
||||
├── te3_remoteclip_vitl.gin
|
||||
├── te4_georsclip_vitb32.gin
|
||||
├── te5_dgtrs.gin # текущий gtauav_balanced_stripnet.gin (rename)
|
||||
├── te6_longclip_b.gin
|
||||
├── te7_longclip_l.gin
|
||||
├── te8_siglip2_base.gin
|
||||
├── baseline_stripnet_only.gin # gate=1.0, text disabled
|
||||
└── _shared_stripnet.gin # общие настройки (наследование)
|
||||
```
|
||||
|
||||
4. **Smoke-тесты** для каждого encoder:
|
||||
- Загрузка ckpt (отсутствующие — `huggingface-cli download`)
|
||||
- Forward-pass на 4 captions, проверка `[B, D_text]` shape
|
||||
- Tokenizer truncation behavior
|
||||
- `scripts/smoke_text_encoder.py --encoder te3_remoteclip_vitl`
|
||||
|
||||
5. **Token-usage profiling** (Группа B готовится здесь, до runs):
|
||||
- Скрипт `scripts/profile_caption_tokens.py` — генерирует JSON с распределениями для всех encoders.
|
||||
|
||||
### Фаза 1 — Baseline (≈ 1 день)
|
||||
|
||||
Запуск **StripNet-only** (без text):
|
||||
```bash
|
||||
python -m src.training.train_gtauav --config conf/te_bench/baseline_stripnet_only.gin \
|
||||
--filter-meta meta/seg_filter.json --seed 42
|
||||
# повторить для seed=123, 456
|
||||
```
|
||||
|
||||
Сохранить:
|
||||
- `R@1/R@5/R@10` × `{cross-area, same-area}` × `{q2g, g2q}`
|
||||
- `eval_report_baseline_seed{42,123,456}.json`
|
||||
- Усреднить → **reference baseline R@1**
|
||||
|
||||
### Фаза 2 — Main bench (≈ 5–7 дней)
|
||||
|
||||
Для каждого `TE-k ∈ {1..8}` × `seed ∈ {42, 123, 456}` = **24 runs** (10 epochs каждый):
|
||||
|
||||
```bash
|
||||
for ENC in te1 te2 te3 te4 te5 te6 te7 te8; do
|
||||
for SEED in 42 123 456; do
|
||||
python -m src.training.train_gtauav \
|
||||
--config conf/te_bench/${ENC}*.gin \
|
||||
--filter-meta meta/seg_filter.json \
|
||||
--gin-param "TrainConfigGTAUAV.seed=${SEED}" \
|
||||
--gin-param "TrainConfigGTAUAV.output_dir=out/te_bench/${ENC}/seed${SEED}"
|
||||
done
|
||||
done
|
||||
```
|
||||
|
||||
**Логирование (обязательно):**
|
||||
- W&B project: `cvgl-text-encoder-bench-stripnet` (или TB)
|
||||
- CSV: `out/te_bench/{ENC}/seed{S}/metrics.csv` (epoch, train_loss, val_R@1/5/10, tau, gate_q, gate_g, grad_norm_text)
|
||||
- Eval report: `eval_report.json` (final R@K + Δ vs baseline)
|
||||
|
||||
### Фаза 3 — Ablations (≈ 3 дня)
|
||||
|
||||
Для **двух best encoders** (top-2 по R@1 из Фазы 2):
|
||||
|
||||
| Ablation | Команда |
|
||||
|:--|:--|
|
||||
| E.1 L1-only | `--gin-param "Dataset.caption_levels=['L1']"` |
|
||||
| E.2 L2-only | `--gin-param "Dataset.caption_levels=['L2']"` |
|
||||
| E.3 L3-only | `--gin-param "Dataset.caption_levels=['L3']"` |
|
||||
| E.4 L1+L3 | `--gin-param "Dataset.caption_levels=['L1','L3']"` |
|
||||
| E.5 Truncation (только для long-ctx) | `--gin-param "TextEncoder.max_tokens=77"` |
|
||||
| E.6 Cross vs Same | Eval на обоих split автоматически |
|
||||
| E.7 Noisy captions | `--gin-param "Dataset.caption_noise_pct=0.1"` |
|
||||
|
||||
Все ablations — **1 seed** (42), 10 epochs.
|
||||
|
||||
### Фаза 4 — Mode B (fixed-text, fair comparison) (≈ 2 дня)
|
||||
|
||||
Альтернативный режим: **все encoders получают одинаковый текст L3** (~50 слов, ≤80 tok — помещается во ВСЕ encoders). Это устраняет преимущество long-ctx encoders.
|
||||
|
||||
```bash
|
||||
for ENC in te1 te2 te3 te4 te5 te6 te7 te8; do
|
||||
python -m src.training.train_gtauav --config conf/te_bench/${ENC}*.gin \
|
||||
--gin-param "Dataset.caption_levels=['L3']" \
|
||||
--gin-param "TextEncoder.max_tokens=80" \
|
||||
--gin-param "TrainConfigGTAUAV.output_dir=out/te_bench_modeB/${ENC}_seed42" \
|
||||
--seed 42
|
||||
done
|
||||
```
|
||||
|
||||
**Интерпретация:**
|
||||
- Если best-Mode-A ≠ best-Mode-B → разрыв = **context-length contribution**
|
||||
- Если best-Mode-A == best-Mode-B → encoder арх+pretrain выигрывает независимо от длины
|
||||
|
||||
### Фаза 5 — Анализ и отчёт (≈ 2 дня)
|
||||
|
||||
См. §10 (статистика) + §13 (deliverables).
|
||||
|
||||
---
|
||||
|
||||
## §8. Сводная таблица experiment matrix
|
||||
|
||||
| Phase | Runs | Seeds | Encoders | Caption levels | Epochs | ≈ время на RTX 4090 |
|
||||
|:-:|:-:|:-:|:-:|:--|:-:|:--|
|
||||
| 0 (smoke) | 8 | 1 | 8 | 1 | 0.1 | 1 день (включая код) |
|
||||
| 1 (baseline) | 3 | 3 | — | — | 10 | ~3 ч |
|
||||
| 2 (main) | 24 | 3 | 8 | L1+L2+L3 | 10 | ~24 ч |
|
||||
| 3 (ablation E.1–E.4) | 2×4 = 8 | 1 | 2 (best) | L1 / L2 / L3 / L1+L3 | 10 | ~8 ч |
|
||||
| 3 (ablation E.5–E.7) | 2×3 = 6 | 1 | 2 | varies | 10 | ~6 ч |
|
||||
| 4 (Mode B) | 8 | 1 | 8 | L3 fixed | 10 | ~8 ч |
|
||||
| **Итого** | **57** | — | — | — | — | **~50–60 ч GPU** |
|
||||
|
||||
> [!tip] Параллелизация
|
||||
> При наличии 2-х GPU — Mode A + Mode B можно гонять параллельно (разные encoders на разных GPU). Bottleneck — VRAM на больших encoders (LongCLIP-L + StripNet ≈ 12 GB на batch 64 при fp16).
|
||||
|
||||
---
|
||||
|
||||
## §9. Decision rules
|
||||
|
||||
### 9.1 Primary: выбор canonical text encoder
|
||||
|
||||
```
|
||||
Best_TE = argmax_{k ∈ {1..8}} R@1_cross-area(TE_k)
|
||||
при условии:
|
||||
(1) p < 0.05 vs TE_baseline (bootstrap CI 95% не пересекаются)
|
||||
(2) Δ R@1 ≥ +1.5% (минимально значимый размер эффекта)
|
||||
```
|
||||
|
||||
### 9.2 Secondary: 4 диагностических вопроса
|
||||
|
||||
| Вопрос | Контраст | Verdict if Δ ≥ +1.0% |
|
||||
|:--|:--|:--|
|
||||
| **Q1: RS-domain важнее generic?** | TE-3 vs TE-1 | RS-domain выигрывает |
|
||||
| **Q2: Long-context важнее short?** | TE-5 vs TE-3 (в RS), TE-6 vs TE-1 (в generic) | Long-context выигрывает |
|
||||
| **Q3: Что доминирует?** | TE-5 vs TE-6 (RS-long vs generic-long, оба 248) | RS-domain (если TE-5 > TE-6); context-length (если ≈) |
|
||||
| **Q4: Capacity scaling?** | TE-7 vs TE-6 (L vs B при равных условиях) | Larger params помогают |
|
||||
|
||||
### 9.3 Tertiary: Pareto-trade-off
|
||||
|
||||
Построить scatter-plot **R@1 vs (params · latency)**:
|
||||
- **Pareto front**: encoders которые не доминируются по обеим осям
|
||||
- **Knee point**: encoder с лучшим соотношением — кандидат для production SOFIA
|
||||
|
||||
### 9.4 Promotion criteria
|
||||
|
||||
Победитель **рекомендуется в [[HYP_text_encoder_variants_v3]] как T_text canonical update**, если:
|
||||
|
||||
1. ✅ Δ R@1 vs baseline ≥ **+3.0%** (substantial)
|
||||
2. ✅ p < 0.05 (bootstrap)
|
||||
3. ✅ Cross-area gap (E.6) не растёт критически (Δ_cross-vs-same ≤ +2%)
|
||||
4. ✅ Caption-only R@1 (B.6) > 0 (text-only действительно discriminates)
|
||||
5. ✅ Учитывает Pareto: на equivalent R@1 предпочесть encoder с меньшим cost
|
||||
|
||||
Иначе — обновление **deferred**, current canonical (F13 RemoteCLIP) сохраняется.
|
||||
|
||||
---
|
||||
|
||||
## §10. Статистический анализ
|
||||
|
||||
### 10.1 Bootstrap CI 95% для R@K
|
||||
|
||||
Стандартный bootstrap на per-query результатах (`hits@k ∈ {0,1}` для каждого query):
|
||||
|
||||
```python
|
||||
def bootstrap_ci(hits: np.ndarray, n_iter: int = 10000, alpha: float = 0.05) -> tuple[float, float]:
|
||||
"""Returns (low, high) CI bounds for mean(hits)."""
|
||||
boot_means = np.array([
|
||||
hits[np.random.randint(0, len(hits), len(hits))].mean()
|
||||
for _ in range(n_iter)
|
||||
])
|
||||
return np.percentile(boot_means, [100*alpha/2, 100*(1-alpha/2)])
|
||||
```
|
||||
|
||||
Применить к каждому `(TE_k, seed)` → 3 CI на encoder → объединённый CI через `meta-analysis fixed-effects model`.
|
||||
|
||||
### 10.2 Парные тесты
|
||||
|
||||
| Тест | Что | Когда применять |
|
||||
|:--|:--|:--|
|
||||
| **McNemar's test** | Парные hits/misses между двумя encoders на тех же queries | Сравнение TE-k vs TE-baseline (один seed) |
|
||||
| **Wilcoxon signed-rank** | Парные R@1 across seeds | Сравнение TE-k vs TE-j (multi-seed) |
|
||||
| **Friedman test** | Все 8 encoders × 3 seeds | Общий тест «есть ли разница вообще» — pre-screening |
|
||||
|
||||
### 10.3 Multiple comparisons correction
|
||||
|
||||
- При 8 парных сравнениях с baseline → **Bonferroni-Holm** (controlling FWER) или **Benjamini-Hochberg** (controlling FDR)
|
||||
- При 28 pairwise (все против всех) → **Nemenyi post-hoc** после Friedman
|
||||
|
||||
### 10.4 Reporting
|
||||
|
||||
Финальная таблица должна содержать для каждого encoder:
|
||||
|
||||
```
|
||||
| TE-k | R@1 mean ± std | CI95% (low, high) | ΔR@1 vs base | p-value | Effect size (Cohen's h) |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §11. Инфраструктура и code drops
|
||||
|
||||
### 11.1 Что нужно реализовать (новое)
|
||||
|
||||
| Файл | Назначение | LOC ориентир |
|
||||
|:--|:--|:-:|
|
||||
| `src/models/text_encoders/base.py` | ABC + интерфейс `TextEncoderBase.forward(captions: list[str]) → [B, D]` | ~80 |
|
||||
| `src/models/text_encoders/{openclip,mobileclip,remoteclip,georsclip,dgtrs,longclip,siglip2,bgem3}_wrapper.py` | По одному файлу на encoder, унифицированный API | ~100 каждый |
|
||||
| `src/models/text_encoders/__init__.py` | gin-configurable factory `get_text_encoder(name, ...)` | ~50 |
|
||||
| `src/models/text_fusion_mlp.py` | Параметризованный TextFusionMLP (text_dim, num_levels, out_dim) | ~40 |
|
||||
| `scripts/profile_caption_tokens.py` | Token-usage histogram (Группа B) | ~120 |
|
||||
| `scripts/smoke_text_encoder.py` | Smoke-test per encoder | ~80 |
|
||||
| `scripts/benchmark_text_latency.py` | Latency + VRAM measurement (Группа C) | ~100 |
|
||||
| `scripts/te_bench_aggregate.py` | Aggregate 24 runs → CSV/MD report | ~150 |
|
||||
| `scripts/te_bench_statistical_test.py` | Bootstrap + McNemar + correction | ~200 |
|
||||
| `conf/te_bench/_shared_stripnet.gin` + 8 per-encoder gin-конфигов | Эксперименты | ~30 каждый |
|
||||
|
||||
### 11.2 Что уже есть (повторно использовать)
|
||||
|
||||
- `src/models/stripnet_encoder.py` — StripNet wrapper
|
||||
- `src/models/asymmetric_encoder.py` — DualEncoder + GatedFusion (parametrize text_dim)
|
||||
- `src/datasets/gtauav_dataset.py` — loader + L1/L2/L3
|
||||
- `src/losses/multi_infonce.py` — SymmetricInfoNCE + MoCo queue
|
||||
- `src/training/train_gtauav.py` — training loop
|
||||
- `src/training/trackers.py` — W&B + TB + CSV
|
||||
- `scripts/make_split.py` / `scripts/filter_segmentation.py`
|
||||
|
||||
### 11.3 Зависимости (новые)
|
||||
|
||||
```text
|
||||
open_clip_torch>=2.24.0 # TE-1, TE-6, TE-7
|
||||
mobileclip # TE-2 (pip install git+https://github.com/apple/ml-mobileclip)
|
||||
transformers>=4.40 # TE-8 (SigLIP-2 через AutoModel)
|
||||
FlagEmbedding # TE-11 BGE-M3 (опц.)
|
||||
# RemoteCLIP, GeoRSCLIP, DGTRS — через open_clip + custom ckpts
|
||||
```
|
||||
|
||||
### 11.4 Конфиг-шаблон (пример te3_remoteclip_vitl.gin)
|
||||
|
||||
```gin
|
||||
include 'conf/te_bench/_shared_stripnet.gin'
|
||||
|
||||
# ---- Text encoder ----
|
||||
TrainConfigGTAUAV.text_encoder_name = "remoteclip"
|
||||
TrainConfigGTAUAV.text_encoder_arch = "ViT-L-14"
|
||||
TrainConfigGTAUAV.text_encoder_ckpt = "nn_models/REMOTECLIP/RemoteCLIP-ViT-L-14.pt"
|
||||
TrainConfigGTAUAV.text_dim = 768
|
||||
TrainConfigGTAUAV.text_max_tokens = 77
|
||||
TrainConfigGTAUAV.text_unfreeze = "lora_qv_rank4_last12" # или "frozen", "last_resblock"
|
||||
|
||||
# ---- Caption levels (Mode A: всё что влезает в 77 tok → L3 only) ----
|
||||
TrainConfigGTAUAV.caption_levels = ["L3"] # L3 наиболее discriminative для 77-tok
|
||||
|
||||
# ---- Output ----
|
||||
TrainConfigGTAUAV.output_dir = "out/te_bench/te3_remoteclip"
|
||||
```
|
||||
|
||||
Для long-ctx (TE-5, TE-6, TE-7):
|
||||
```gin
|
||||
TrainConfigGTAUAV.caption_levels = ["L1", "L2", "L3"] # Mode A: full hierarchy
|
||||
TrainConfigGTAUAV.text_max_tokens = 248
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## §12. Риски и митигации
|
||||
|
||||
| ID | Риск | Severity | Митигация |
|
||||
|:--|:--|:-:|:--|
|
||||
| R1 | Разные encoders требуют разных tokenizers → bugs при загрузке | High | Unified `TokenizerWrapper` с `.encode(text, max_len) → input_ids` + smoke-tests Фазы 0 |
|
||||
| R2 | LoRA-rank 4 может быть слишком слабо для некоторых encoders | Med | Альтернатива: full last-resblock unfreeze (`last_resblock` mode) — `~7.6M trainable` как в DGTRS текущий |
|
||||
| R3 | Long-ctx encoders занимают много VRAM → batch reduction → шумнее loss | Med | gradient_accum_steps до 8 при необходимости (как уже в balanced.gin) |
|
||||
| R4 | Truncation в 77-tok encoders отрезает L3 fingerprint | High | **Намеренно** подаём L3 only (≤80 tok) — не L1+L2+L3 (это нечестное сравнение) |
|
||||
| R5 | Caption distribution biased (76% drone vs 44% sat) | Med | Use per-sample mask для sat без captions (уже реализовано); анализировать metric с/без sat-text отдельно |
|
||||
| R6 | StripNet pretrain weights могут быть несовместимы с domain GTA-UAV (synthetic) | Med | Контрольный run с `gtauav_balanced_stripnet_unfrozen.gin` (баланс уже учтён) — если разморозка не помогает, проблема в text-fusion |
|
||||
| R7 | 3 seeds — маленькая выборка для bootstrap | Low-Med | Использовать **per-query** bootstrap (на 6,252 test queries — статистики достаточно) |
|
||||
| R8 | Confounding: разные encoders имеют разный init для LoRA | Low | Фиксированный seed для LoRA init + 3 seeds для всего остального |
|
||||
| R9 | gate σ(α) может «выключить» text на проигравших encoders | Med | Логировать gate per epoch; в анализе сравнивать **при равном gate** (Mode A с init_gate=0.5 fixed-no-learn — ablation) |
|
||||
|
||||
---
|
||||
|
||||
## §13. Deliverables
|
||||
|
||||
По завершении бенчмарка сотрудница сдаёт:
|
||||
|
||||
1. **Код** в `3_work/4_cvgl_work/caption_test/`:
|
||||
- `src/models/text_encoders/` (все 8 wrappers + factory + base)
|
||||
- `conf/te_bench/` (10 gin-конфигов: 8 encoder + baseline + shared)
|
||||
- `scripts/` (5 новых скриптов)
|
||||
2. **Runs** в `out/te_bench/`:
|
||||
- 24 main runs (Mode A) + 8 Mode B + 14 ablations = **46 артефактов** (eval_report.json, metrics.csv, TB logs)
|
||||
3. **Сводный отчёт** `2_hypotesis/03_fusion/03_text/REPORT_te_bench_StripNet_GTA_UAV.md`:
|
||||
- Все таблицы (R@K × encoder × seed)
|
||||
- 4 диагностических ответа на Q1–Q4
|
||||
- Pareto-plot + knee-point рекомендация
|
||||
- Bootstrap CI + p-values
|
||||
- Финальная рекомендация (update T_text canonical YES/NO)
|
||||
4. **Update в [[HYP_text_encoder_variants_v3]]** (если promotion criteria met):
|
||||
- Новая версия `_v4` с обновлённой canonical
|
||||
- Изменения в [[DELTA_E1_text_encoder_F_variants_v3]] → `_v4`
|
||||
5. **Memory entry** в `~/.claude/memory/`:
|
||||
- `text_encoder_bench_stripnet_gta_uav.md`
|
||||
|
||||
---
|
||||
|
||||
## §14. Бюджет времени и ресурсов
|
||||
|
||||
### 14.1 Время
|
||||
|
||||
| Фаза | Дни | Что |
|
||||
|:--|:-:|:--|
|
||||
| 0. Setup | 3 | Реализация wrappers + smoke + token profiling |
|
||||
| 1. Baseline | 1 | 3 baseline runs + verification |
|
||||
| 2. Main (24 runs × ~1 ч) | 5 | Запуски + промежуточный мониторинг |
|
||||
| 3. Ablations (14 runs) | 3 | Запуски + анализ |
|
||||
| 4. Mode B (8 runs) | 2 | Запуски + сравнение |
|
||||
| 5. Analysis + report | 2 | Stat. tests + REPORT.md + recommendations |
|
||||
| **Итого** | **~14–16 дней** | — |
|
||||
|
||||
### 14.2 Ресурсы
|
||||
|
||||
| Ресурс | Объём |
|
||||
|:--|:--|
|
||||
| GPU | RTX 4090 24 GB (1 шт. достаточно; 2 — ускоряет в 2×) |
|
||||
| Disk | ~30 GB (8 ckpt encoders + 46 run-folders с TB logs) |
|
||||
| Network | ~10 GB на HuggingFace download (encoders) — однократно |
|
||||
| RAM | 32 GB достаточно |
|
||||
|
||||
### 14.3 Чек-листы перед запуском
|
||||
|
||||
**Pre-Фаза 0:**
|
||||
- [ ] HuggingFace tokens настроены, доступ к gated моделям (если есть)
|
||||
- [ ] `nn_models/` директория готова, ~30 GB свободно
|
||||
- [ ] `STRIPNET/stripnet_s.pth` загружен
|
||||
- [ ] Captions датасета на месте (`drone/*.json` + `sat/*.json`)
|
||||
- [ ] `meta/seg_filter.json` сгенерирован
|
||||
- [ ] `meta/train_80.json` / `meta/test_20.json` сгенерированы
|
||||
|
||||
**Pre-Фаза 2:**
|
||||
- [ ] Все 8 smoke-тестов проходят
|
||||
- [ ] Baseline R@1 зафиксирован (запомнить число!)
|
||||
- [ ] W&B project создан или TB-папка создана
|
||||
- [ ] `scripts/te_bench_aggregate.py` оттестирован на dry-run
|
||||
|
||||
**Pre-Фаза 5:**
|
||||
- [ ] Все 46 run-folder содержат `eval_report.json`
|
||||
- [ ] `metrics.csv` собраны
|
||||
- [ ] Bootstrap скрипт оттестирован на baseline runs
|
||||
|
||||
---
|
||||
|
||||
## §15. Cross-references
|
||||
|
||||
### 15.1 Канонические гипотезы / анализы
|
||||
|
||||
- [[HYP_text_encoder_variants_v3]] — текущий canonical T_text mapping (RemoteCLIP F13 anchor, 5-variant CLIP-RS family)
|
||||
- [[DELTA_E1_text_encoder_F_variants_v3]] — F-variants taxonomy
|
||||
- [[ANALYSIS_text_encoder_v2]] — taxonomy by context-length
|
||||
- [[ANALYSIS_text_encoders_for_scene_caption_fusion_v2]] — caption-encoder fit matrix
|
||||
- [[DELTA_E1_pair_D_text_fusion_v2]] — Pair D fusion architecture spec
|
||||
|
||||
### 15.2 Литература (тесно связанные статьи)
|
||||
|
||||
- [[../../../1_lit_research/3_fusion/F13_2023_RemoteCLIP A Vision Language Foundation Model for Remote Sensing|F13 RemoteCLIP (TGRS 2024)]] — TE-3 anchor
|
||||
- [[../../../1_lit_research/3_fusion/F82_2024_Long-CLIP_ECCV|F82 Long-CLIP (ECCV 2024)]] — TE-6/TE-7 anchor
|
||||
- [[../../../1_lit_research/3_fusion/F5_2025_FarSLIP Discovering Effective CLIP Adaptation for Fine-Grained Remote Sensing Understanding|F5 FarSLIP]] — TE-9 (опц.)
|
||||
- [[../../../1_lit_research/3_fusion/F7_2025_PriorCLIP Visual Prior Guided Vision-Language Model for Remote Sensing Image-Text Retrieval|F7 PriorCLIP]] — TE-10 (опц.)
|
||||
- [[../../../1_lit_research/3_fusion/F3_2025_DOFA-CLIP Multimodal Vision–Language Foundation Models for Earth Observation|F3 DOFA-CLIP]] — альтернатива
|
||||
- [[../../../1_lit_research/3_fusion/F14_2025_WeatherPrompt Multi-modality Representation Learning for All-Weather Drone Visual Geo-Localization|F14 WeatherPrompt]] — направление captions для UAV-CVGL
|
||||
|
||||
### 15.3 Код / workspace
|
||||
|
||||
- [[../../../3_work/4_cvgl_work/caption_test/_index|caption_test workspace]]
|
||||
- [`asymmetric_encoder.py`](../../../3_work/4_cvgl_work/caption_test/src/models/asymmetric_encoder.py) — целевой файл для расширения
|
||||
- [`stripnet_encoder.py`](../../../3_work/4_cvgl_work/caption_test/src/models/stripnet_encoder.py) — фиксированный визуальный encoder
|
||||
- [`gtauav_balanced_stripnet.gin`](../../../3_work/4_cvgl_work/caption_test/conf/gtauav_balanced_stripnet.gin) — текущий шаблон (TE-5 base case)
|
||||
|
||||
### 15.4 Caption pipeline
|
||||
|
||||
- [[../../07_text_pipeline/PIPELINE_text_annotation_full_v2]] — как captions генерировались (Qwen3-VL-8B AWQ + audit)
|
||||
- [[../../07_text_pipeline/HYP_caption_quality_visloc_v2]] — критерии качества captions
|
||||
|
||||
---
|
||||
|
||||
## Приложение A — Полный список encoders с конкретными ckpts/URL
|
||||
|
||||
| ID | Model | HF/Source URL | Ckpt path (предложение) | Лицензия |
|
||||
|:--|:--|:--|:--|:-:|
|
||||
| TE-1 | OpenCLIP ViT-L/14 LAION-2B | https://huggingface.co/laion/CLIP-ViT-L-14-laion2B-s32B-b82K | `nn_models/OPENCLIP/clip-vitl14-laion2b.pt` | MIT |
|
||||
| TE-2 | MobileCLIP2-S2 | https://huggingface.co/apple/MobileCLIP2-S2 | `nn_models/MOBILECLIP2/mobileclip2-s2.pt` | Apple ML Research |
|
||||
| TE-3 | RemoteCLIP ViT-L/14 | https://huggingface.co/chendelong/RemoteCLIP | `nn_models/REMOTECLIP/RemoteCLIP-ViT-L-14.pt` | Apache-2.0 |
|
||||
| TE-4 | GeoRSCLIP ViT-B/32 | https://huggingface.co/Zilun/GeoRSCLIP | `nn_models/GEORSCLIP/RS5M_ViT-B-32.pt` | Apache-2.0 |
|
||||
| TE-5 | DGTRS-CLIP ViT-L/14 (LRSCLIP) | https://github.com/MitsuiChen14/DGTRS | `nn_models/LRSCLIP/DGTRS-CLIP-ViT-L-14.pt` ✅ | Apache-2.0 |
|
||||
| TE-6 | Long-CLIP-B | https://huggingface.co/BeichenZhang/LongCLIP-B | `nn_models/LONGCLIP/longclip-b.pt` | MIT |
|
||||
| TE-7 | LongCLIP-L | https://huggingface.co/BeichenZhang/LongCLIP-L | `nn_models/LONGCLIP/longclip-l.pt` | MIT |
|
||||
| TE-8 | SigLIP-2 base/256 | https://huggingface.co/google/siglip2-base-patch16-256 | `nn_models/SIGLIP2/siglip2-base-patch16-256/` | Apache-2.0 |
|
||||
| TE-9 (опц.) | FarSLIP ViT-B/16 | https://github.com/UniModal4Reasoning/FarSLIP | `nn_models/FARSLIP/farslip-vitb16.pt` | TBD |
|
||||
| TE-10 (опц.) | PriorCLIP ViT-B/32 | TBD (см. F7 paper) | `nn_models/PRIORCLIP/...` | TBD |
|
||||
| TE-11 (опц.) | BGE-M3 | https://huggingface.co/BAAI/bge-m3 | `nn_models/BGE-M3/` | MIT |
|
||||
|
||||
---
|
||||
|
||||
## Приложение B — Шаблон gin-конфига для нового encoder
|
||||
|
||||
```gin
|
||||
# conf/te_bench/_shared_stripnet.gin (БАЗА для всех TE-*)
|
||||
include 'conf/gtauav_balanced_stripnet.gin'
|
||||
|
||||
# ---- Backbone (фиксирован для всего бенчмарка) ----
|
||||
TrainConfigGTAUAV.backbone = "stripnet"
|
||||
TrainConfigGTAUAV.stripnet_path = "nn_models/STRIPNET/stripnet_s.pth"
|
||||
TrainConfigGTAUAV.stripnet_mona_last_n_stages = 2
|
||||
TrainConfigGTAUAV.shared_encoder = True
|
||||
|
||||
# ---- Training (фиксировано) ----
|
||||
TrainConfigGTAUAV.epochs = 10
|
||||
TrainConfigGTAUAV.batch_size = 64
|
||||
TrainConfigGTAUAV.learning_rate = 1e-4
|
||||
TrainConfigGTAUAV.text_lr_factor = 0.1 # text_lr = 1e-5
|
||||
TrainConfigGTAUAV.warmup_epochs = 2
|
||||
TrainConfigGTAUAV.use_amp = True
|
||||
|
||||
# ---- Loss (фиксировано) ----
|
||||
TrainConfigGTAUAV.loss_type = "symmetric"
|
||||
TrainConfigGTAUAV.tau_init = 0.07
|
||||
TrainConfigGTAUAV.weight_q2g = 0.6
|
||||
TrainConfigGTAUAV.weight_g2q = 0.4
|
||||
TrainConfigGTAUAV.neg_bank_size = 4096
|
||||
InfoNCELoss.hard_mining_k = 0
|
||||
|
||||
# ---- Fusion (фиксировано) ----
|
||||
TrainConfigGTAUAV.init_gate = 0.7
|
||||
TrainConfigGTAUAV.baseline_mode = False
|
||||
|
||||
# ---- Sampler (фиксировано) ----
|
||||
TrainConfigGTAUAV.sampler_type = "mutex" # для fair-comparison; DSS опционально
|
||||
|
||||
# ---- Eval (фиксировано) ----
|
||||
TrainConfigGTAUAV.eval_every = 1
|
||||
TrainConfigGTAUAV.eval_splits = ["cross-area", "same-area"]
|
||||
|
||||
# ---- Tracking ----
|
||||
TrainConfigGTAUAV.use_tb = True
|
||||
TrainConfigGTAUAV.use_wandb = False # включить при необходимости
|
||||
TrainConfigGTAUAV.log_grad_norms = True
|
||||
|
||||
# Encoder-specific параметры — в дочернем конфиге te{1..8}_*.gin
|
||||
```
|
||||
|
||||
```gin
|
||||
# conf/te_bench/te5_dgtrs.gin (пример для TE-5 — DGTRS-CLIP, baseline)
|
||||
include 'conf/te_bench/_shared_stripnet.gin'
|
||||
|
||||
TrainConfigGTAUAV.text_encoder_name = "dgtrs"
|
||||
TrainConfigGTAUAV.text_encoder_ckpt = "nn_models/LRSCLIP/DGTRS-CLIP-ViT-L-14.pt"
|
||||
TrainConfigGTAUAV.text_dim = 768
|
||||
TrainConfigGTAUAV.text_max_tokens = 248
|
||||
TrainConfigGTAUAV.text_unfreeze = "lora_qv_rank4_last12"
|
||||
|
||||
TrainConfigGTAUAV.caption_levels = ["L1", "L2", "L3"] # Mode A: full hierarchy
|
||||
TrainConfigGTAUAV.output_dir = "out/te_bench/te5_dgtrs"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Приложение C — Чек-лист для каждого encoder wrapper
|
||||
|
||||
```python
|
||||
# src/models/text_encoders/base.py
|
||||
from __future__ import annotations
|
||||
from abc import ABC, abstractmethod
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
|
||||
|
||||
class TextEncoderBase(nn.Module, ABC):
|
||||
"""Unified interface for all text encoders in the benchmark.
|
||||
|
||||
Subclasses must implement `encode_text(captions)` returning [B, embed_dim].
|
||||
"""
|
||||
|
||||
embed_dim: int
|
||||
max_tokens: int
|
||||
|
||||
@abstractmethod
|
||||
def encode_text(self, captions: list[str]) -> torch.Tensor:
|
||||
"""Tokenize + encode + project. Returns [B, embed_dim]."""
|
||||
|
||||
@torch.no_grad()
|
||||
def encode_text_eval(self, captions: list[str]) -> torch.Tensor:
|
||||
return self.encode_text(captions)
|
||||
```
|
||||
|
||||
**Каждый wrapper обязан:**
|
||||
- [ ] Принимать `checkpoint_path`, `max_tokens`, `unfreeze_mode` в `__init__`
|
||||
- [ ] Реализовать `encode_text(list[str]) → [B, D]`
|
||||
- [ ] Корректно обрабатывать truncation (длинные captions)
|
||||
- [ ] Передавать ckpt в `strict=False` если архитектура содержит лишние ключи
|
||||
- [ ] Реализовать `train()` override для frozen base + trainable adapters (как в `StripNetEncoder`)
|
||||
- [ ] Логировать `embed_dim` и `n_trainable_params` при загрузке
|
||||
|
||||
---
|
||||
|
||||
## Приложение D — Минимальный sanity-check после Фазы 0
|
||||
|
||||
Перед запуском Фазы 2 (main bench) проверить на 1 batch (drone+sat+captions):
|
||||
|
||||
```bash
|
||||
python -m scripts.smoke_text_encoder --encoder te3_remoteclip_vitl \
|
||||
--batch_size 4 --device cuda
|
||||
|
||||
# Ожидаемый вывод:
|
||||
# [smoke] loaded RemoteCLIP-ViT-L-14, n_params=124M, n_trainable=147K (LoRA)
|
||||
# [smoke] tokenized 4 captions: max_tokens=77, avg_tokens=72, n_truncated=1
|
||||
# [smoke] encode_text: [4, 768], norm=1.0 ± 0.0 (L2-normalized)
|
||||
# [smoke] intra-caption cos-sim: 0.62 (sanity > 0)
|
||||
# [smoke] inter-caption cos-sim: 0.38 (sanity < intra)
|
||||
# [smoke] OK
|
||||
```
|
||||
|
||||
Если smoke не проходит — **не запускать Фазу 2**.
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
Статус: draft v1
|
||||
Date: 2026-05-21
|
||||
Author: claude (для Поляковой В.Е.)
|
||||
Conclusion: 8 primary encoders × 3 seeds × 10 epochs + 14 ablations + 8 Mode B = 46 runs (~50–60 GPU-часов), 5 групп метрик с decision rule по 4 diagnostic questions + Pareto + promotion criteria.
|
||||
```
|
||||
|
||||
#protocol #methodology #text-encoder #benchmark #GTA-UAV #StripNet #fusion #pair-d
|
||||
@@ -0,0 +1,652 @@
|
||||
---
|
||||
title: "Методология автоматического аннотирования набора данных World-UAV: карты глубины, контурные карты, семантические маски и кросс-вью карты высот"
|
||||
type: methodology
|
||||
version: "3.3"
|
||||
created: 2026-04-07
|
||||
updated: 2026-04-08
|
||||
dataset: "World-UAV (UAV-GeoLoc, IEEE RA-L 2025)"
|
||||
hardware: "RTX 4090 (24GB VRAM)"
|
||||
downstream_task: "Cross-view geo-localization (drone<->satellite)"
|
||||
models:
|
||||
depth: "Depth Anything V3 LARGE-1.1 (411M)"
|
||||
edges: "Sobel filters from depth"
|
||||
segmentation: "SegEarth-OV3 (SAM 3.1 + PE-L+)"
|
||||
chmv2: "DINOv3-ViTL16-CHMv2-DPT (337M, FP32)"
|
||||
tags:
|
||||
- type/methodology
|
||||
- component/dataset
|
||||
- method/segmentation
|
||||
- dataset/worlduav
|
||||
- task/experiment
|
||||
- priority/high
|
||||
---
|
||||
|
||||
# Методология автоматического аннотирования набора данных World-UAV
|
||||
|
||||
**Содержание (12 разделов):**
|
||||
|
||||
- **Раздел 1.** Постановка задачи: формальная формулировка, связь с LUPI-дистилляцией
|
||||
- **Раздел 2.** World-UAV: структура, объем, неполные сцены
|
||||
- **Раздел 3.** Модели-генераторы: DA3-LARGE, Sobel, SegEarth-OV3, CHMv2
|
||||
- **Раздел 4.** Пайплайн обработки: sequential pipeline, формат выхода, manifest
|
||||
- **Раздел 5.** Протокол обработки: оценка времени, запуск
|
||||
- **Раздел 6.** Контроль качества: валидация, визуальная инспекция, метрики
|
||||
- **Раздел 7.** Формат хранения и интеграция с даталоадером
|
||||
- **Раздел 8.** Гипотезы аннотирования (AH1-AH6)
|
||||
- **Раздел 9.** Архитектура кода
|
||||
- **Раздел 10.** Риски и митигации
|
||||
- **Раздел 11.** Timeline и ресурсы
|
||||
- **Раздел 12.** Библиография
|
||||
|
||||
> **Цель:** разработать воспроизводимую методологию автоматической генерации четырех вспомогательных модальностей (depth, edges, segmentation, cross-view height map) из RGB-изображений набора данных World-UAV для последующего использования в LUPI-дистилляции системы MERIDIAN.
|
||||
|
||||
---
|
||||
|
||||
## 1. Постановка задачи
|
||||
|
||||
### 1.1. Формальная формулировка
|
||||
|
||||
Пусть $I \in \mathbb{R}^{H \times W \times 3}$ -- RGB-изображение из World-UAV (drone query или satellite DB crop). Задача автоматического аннотирования формулируется как генерация четырех карт-аннотаций:
|
||||
|
||||
$$\mathcal{A}: I \mapsto (D, E, S, M)$$
|
||||
|
||||
где:
|
||||
- $D \in \mathbb{R}^{H' \times W'}$ -- карта глубины (monocular depth), $D_{ij} \in [0, 1]$ (per-frame normalized)
|
||||
- $E \in \mathbb{R}^{H' \times W'}$ -- контурная карта (structural edges), $E_{ij} \in [0, 1]$ (edge magnitude)
|
||||
- $S \in \mathbb{Z}^{H' \times W'}$ -- семантическая сегментационная маска, $S_{ij} \in \{0, \ldots, C-1\}$ (class index)
|
||||
- $M \in \mathbb{R}^{H' \times W'}$ -- кросс-вью карта высот (CHMv2), $M_{ij} \in [0, 1]$ (per-frame normalized)
|
||||
|
||||
### 1.2. Связь с downstream-задачей (LUPI-CVGL)
|
||||
|
||||
Сгенерированные аннотации используются как **привилегированная информация** при обучении Teacher модели системы MERIDIAN:
|
||||
|
||||
- **Teacher** (DINOv3-L, ~356M) обучается на расширенном наборе модальностей: $\{I_{sat}, I_{drone}, D+E, S, M\}$
|
||||
- **Student** (SOFIA, ~6-8M) при инференсе использует только 2: $\{I_{sat}, I_{drone}\}$
|
||||
|
||||
Привилегированные модальности ($D$, $E$, $S$, $M$) доступны **только при обучении** Teacher. Knowledge distillation переносит эту информацию в Student через Loss LUPI:
|
||||
|
||||
$$L_{LUPI} = \|z_{Student}^{drone} - \text{sg}(z_{Teacher}^{fused})\|^2$$
|
||||
|
||||
### 1.3. Почему edges, а не normals
|
||||
|
||||
| Критерий | Edges | Normals |
|
||||
|:---------|:------|:--------|
|
||||
| Структурные контуры (дороги, здания) | **Выделяет** | Не фокусируется |
|
||||
| Инвариантность к освещению | **Высокая** | Зависит от depth quality |
|
||||
| Cross-view matching utility | **Высокая** -- границы видны с обоих ракурсов | Низкая -- нормали шумные для наклонных снимков |
|
||||
| Computational cost | **~1 мс/img** (Sobel, CPU) | ~5 мс/img (DSINE, GPU) |
|
||||
| Число каналов | **1** (magnitude) | 3 (xyz-вектор) |
|
||||
|
||||
### 1.4. Зачем CHMv2 (cross-view height map)
|
||||
|
||||
CHMv2 (DINOv3-ViTL16-CHMv2-DPT) обучен на DINOv3 backbone специально для оценки высот из спутниковых и аэроснимков. В отличие от DA3, который обучен преимущественно на наземных изображениях:
|
||||
|
||||
- **CHMv2** лучше работает на nadir-view (спутниковые патчи) -- обучен на аэрофотосъемке
|
||||
- **DA3** лучше работает на oblique-view (drone кадры) -- обучен на ground-level
|
||||
- Комбинация двух моделей глубины ($D$ + $M$) дает Teacher **ортогональные depth representations**
|
||||
|
||||
> **Важно:** CHMv2 **нестабилен в FP16** (выдает NaN). Модель всегда загружается в FP32.
|
||||
|
||||
---
|
||||
|
||||
## 2. Набор данных: World-UAV (UAV-GeoLoc)
|
||||
|
||||
### 2.1. Обзор
|
||||
|
||||
| Параметр | Значение |
|
||||
|:---------|:---------|
|
||||
| Venue | IEEE Robotics and Automation Letters, Q1 |
|
||||
| Авторы | Wu et al. (NUDT + Zhejiang University) |
|
||||
| Число сцен | **372** (171 Country + 200 Terrain + 1 Rot) |
|
||||
| Всего изображений | **973,256** (фактически найдено при обработке) |
|
||||
| Query (drone) | 652,744 (512x512 JPEG, синтетические Google Earth Studio) |
|
||||
| DB (satellite) | 274,683 (PNG, 11 размеров: 100-1000 px) |
|
||||
| Subset Rot | 7,341 изображений |
|
||||
| Subset Country | 455,638 изображений |
|
||||
| Subset Terrain | 510,277 изображений |
|
||||
| Размер на диске | ~181 GB |
|
||||
|
||||
### 2.2. Неполные сцены (исключаются из обработки)
|
||||
|
||||
**16 сцен Country** не содержат DB-кропов, positive.json:
|
||||
|
||||
| Город | Сцены | Кол-во |
|
||||
|:------|:------|:-------|
|
||||
| Edinburgh | CastleHill, Dalry, Haymarket, NewTown, Stockbridge | 5 |
|
||||
| London | CamdenTown, CoventGarden, Fitzrovia, Mayfair, SoHo | 5 |
|
||||
| Manchester | Ancoats, Castlefield, Deansgate, NorthernQuarter, Piccadilly | 5 |
|
||||
| Birmingham | JewelleryQuarter | 1 |
|
||||
|
||||
Дополнительно исключаются: `Index`, `charts`, `__MACOSX`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Модели-генераторы
|
||||
|
||||
### 3.1. Depth: Depth Anything V3 LARGE-1.1
|
||||
|
||||
| Параметр | Значение |
|
||||
|:---------|:---------|
|
||||
| Модель | DA3-LARGE-1.1 (ViT-based unified architecture) |
|
||||
| HuggingFace ID | `depth-anything/DA3-LARGE-1.1` |
|
||||
| Параметры | **410.94M** |
|
||||
| Precision | FP16 (при `use_fp16=True`) |
|
||||
| VRAM | **1.5 GB** weights |
|
||||
| Inference speed | **18.4 img/s** (batch=4, 256x256, RTX 4090) -- замерено |
|
||||
| Выход | grayscale PNG [256, 256] uint8 [0, 255] (per-frame normalized) |
|
||||
| Fallback | DA V2 Large (transformers API) |
|
||||
| Код | `src/nn/depth_anything_3/` (вендорированный пакет) |
|
||||
| Веса | `in/weights/models--depth-anything--DA3-LARGE-1.1/` |
|
||||
|
||||
**Архитектура DA3:** DinoV2 backbone (ViT-Large, 24 блока, 1024 dim) + DualDPT head (depth + ray prediction). Поддерживает multi-view inference с camera conditioning, но в пайплайне используется monocular mode (single image).
|
||||
|
||||
### 3.2. Edges: Sobel из карты глубины
|
||||
|
||||
| Параметр | Значение |
|
||||
|:---------|:---------|
|
||||
| Метод | Sobel filters (3x3) на depth map |
|
||||
| Реализация | `torch.nn.functional.conv2d` с Sobel-ядрами |
|
||||
| Inference speed | **419.6 img/s** (CPU, batch=32) -- замерено |
|
||||
| Выход | grayscale PNG [256, 256] uint8 [0, 255] |
|
||||
| Зависимость | Edges вычисляются из depth в том же batch-цикле |
|
||||
|
||||
**Алгоритм:**
|
||||
|
||||
$$S_x = \frac{1}{8}\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}, \quad E = \sqrt{(S_x * D)^2 + (S_y * D)^2}, \quad E = E / \max(E)$$
|
||||
|
||||
### 3.3. Segmentation: SegEarth-OV3 (SAM 3.1)
|
||||
|
||||
| Параметр | Значение |
|
||||
|:---------|:---------|
|
||||
| Модель | SegEarth-OV3 (training-free OV semantic segmentation) |
|
||||
| Backbone | SAM 3.1 Multiplex (~3.3 GB checkpoint) |
|
||||
| VRAM | **3.2 GB** (batch=1), до **~10 GB** (batch=8) |
|
||||
| Inference speed (per-image) | **3.9 img/s** (batch=1, без батчинга backbone) -- замерено |
|
||||
| Inference speed (batched) | **~10-12 img/s** (batch=8, batched backbone) -- оценка |
|
||||
| Макс. batch size | **8** (ограничение в `_infer_segearth_ov3`, hardcoded) |
|
||||
| Промпты | 5 классов: background, building, road, vegetation, water |
|
||||
| Fallback | SegFormer-B5 (ADE20K, 150 classes) |
|
||||
| Код | `src/nn/segearth_ov3/` (вендорированный пакет) |
|
||||
| Веса | `in/weights/sam3.1/sam3.1_multiplex.pt` |
|
||||
| BPE vocab | `src/nn/segearth_ov3/sam3/assets/bpe_simple_vocab_16e6.txt.gz` (встроен) |
|
||||
|
||||
**Архитектура SegEarth-OV3:** SAM3 backbone (ViT-H, 1008x1008, RoPE) + VETextEncoder (CLIP-like, BPE tokenizer) + TransformerEncoderFusion (6 layers, cross-attention) + TransformerDecoder (200 object queries) + PixelDecoder (mask prediction). Для каждого текстового промпта выполняется grounding: fusion instance masks (decoder) + semantic masks (segmentation head), фильтрация по presence score.
|
||||
|
||||
**Batched backbone inference (v3.2):**
|
||||
|
||||
Основной bottleneck SegEarth-OV3 -- backbone forward pass (SAM 3.1 ViT), занимающий ~80% времени инференса. Реализован `predict_pil_batch`:
|
||||
|
||||
1. **`set_image_batch(images)`** -- один backbone pass на весь батч (вместо B отдельных `set_image()`)
|
||||
2. **`_slice_backbone_out(backbone_out, i)`** -- слайсинг backbone features `[B, 256, H, W] -> [1, 256, H, W]` для каждого изображения
|
||||
3. **Per-image grounding** -- для каждого изображения: цикл по 5 промптам -> легкий grounding decoder + text encoder
|
||||
|
||||
Grounding decoder (~20% времени) остается per-image, но backbone (~80%) амортизируется на весь батч. При OOM или ошибке -- автоматический fallback на per-image `predict_pil()`.
|
||||
|
||||
**Палитра сегментации:**
|
||||
|
||||
| Класс | ID | Цвет | RGB |
|
||||
|:------|:--:|:-----|:----|
|
||||
| background | 0 | Черный | (0, 0, 0) |
|
||||
| building | 1 | Красный | (220, 40, 40) |
|
||||
| road | 2 | Серый | (160, 160, 160) |
|
||||
| vegetation | 3 | Зеленый | (30, 180, 30) |
|
||||
| water | 4 | Синий | (30, 120, 220) |
|
||||
|
||||
### 3.4. CHMv2: DINOv3-ViTL16-CHMv2-DPT
|
||||
|
||||
| Параметр | Значение |
|
||||
|:---------|:---------|
|
||||
| Модель | CHMv2ForDepthEstimation (DPT head на DINOv3 backbone) |
|
||||
| HuggingFace ID | `facebook/dinov3-vitl16-chmv2-dpt-head` |
|
||||
| Параметры | **336.88M** |
|
||||
| FLOPs | **457.98 GFLOPs** (fvcore, 518x518 input) |
|
||||
| Precision | **FP32 only** (FP16 выдает NaN -- обнаружено при валидации) |
|
||||
| VRAM | **1.3 GB** weights (FP32) |
|
||||
| Inference speed | **31.7 img/s** (batch=4, 256x256, RTX 4090) -- замерено |
|
||||
| Выход | grayscale PNG [256, 256] uint8 [0, 255] (per-frame normalized) |
|
||||
| Веса | `in/weights/dinov3-chmv2/` (safetensors, 1.3 GB) |
|
||||
|
||||
### 3.5. Сравнение моделей (benchmark на 100 изображениях, RTX 4090)
|
||||
|
||||
| | DA3-LARGE | Sobel edges | SegEarth-OV3 (batch=1) | SegEarth-OV3 (batch=8) | CHMv2 (DINOv3) |
|
||||
|:---|:---------|:-----------|:----------------------|:----------------------|:---------------|
|
||||
| Params | 411M | 0 | ~1B+ (SAM 3.1) | ~1B+ (SAM 3.1) | 337M |
|
||||
| VRAM | 1.5 GB | 0 | 3.2 GB | ~10 GB | 1.3 GB |
|
||||
| Precision | FP16 | CPU | BF16 | BF16 | **FP32** |
|
||||
| Speed | **18.4 img/s** | **419.6 img/s** | **3.9 img/s** | **~10-12 img/s** (оценка) | **31.7 img/s** |
|
||||
| 100 img time | 5.44 s | 0.24 s | **25.49 s** | **~8-10 s** (оценка) | 3.15 s |
|
||||
| Peak VRAM (sequential) | | | | **~10 GB** (SegEarth batch=8 -- наибольшая из загружаемых) | |
|
||||
|
||||
---
|
||||
|
||||
## 4. Пайплайн обработки
|
||||
|
||||
### 4.1. Sequential pipeline (одна модель за раз)
|
||||
|
||||
Модели загружаются **последовательно** -- каждая стадия загружает свою модель, обрабатывает все изображения, затем выгружает модель перед следующей стадией. Это позволяет использовать максимальный batch size для каждой модели и упрощает resume по стадиям:
|
||||
|
||||
```
|
||||
Stage 1: DEPTH
|
||||
+-- load DA3-LARGE-1.1 [GPU, ~1.5 GB FP16]
|
||||
+-- process ALL images (batched, auto_batch_size)
|
||||
+-- save_async {stem}_depth.png [ThreadPool, 4 workers]
|
||||
+-- unload_model() [del + torch.cuda.empty_cache()]
|
||||
|
||||
Stage 2: EDGES
|
||||
+-- load saved depth from .npy/.png [CPU]
|
||||
+-- compute Sobel edges (CPU, batch=32)
|
||||
+-- save_async {stem}_edge.png
|
||||
+-- (no GPU model to unload)
|
||||
|
||||
Stage 3: SEGMENTATION
|
||||
+-- load SegEarth-OV3 (SAM 3.1) [GPU, ~3.2-10 GB]
|
||||
+-- process ALL images (batched backbone, max_batch=8, ~10-12 img/s)
|
||||
| +-- predict_pil_batch(): 1 backbone pass на <=8 изображений
|
||||
| +-- _slice_backbone_out(): слайс features per-image
|
||||
| +-- grounding decoder: per-image x 5 промптов (легкий)
|
||||
+-- save_async {stem}_segm.png
|
||||
+-- unload_model()
|
||||
|
||||
Stage 4: CHMv2
|
||||
+-- load DINOv3-ViTL16-CHMv2-DPT [GPU, ~1.3 GB FP32]
|
||||
+-- process ALL images (batched, auto_batch_size)
|
||||
+-- save_async {stem}_chm.png
|
||||
+-- unload_model()
|
||||
```
|
||||
|
||||
### 4.2. Формат выхода
|
||||
|
||||
Файлы сохраняются в `World-UAV-aug/` с **сохранением структуры** исходного датасета. Исходные изображения **не копируются**. Имя файла = имя исходного изображения + суффикс стадии:
|
||||
|
||||
```
|
||||
World-UAV-aug/
|
||||
+-- Rot/SouthernSuburbs/DB/img/
|
||||
| +-- crop_12_4_depth.png # grayscale [256, 256] -- DA3 depth
|
||||
| +-- crop_12_4_edge.png # grayscale [256, 256] -- Sobel edges
|
||||
| +-- crop_12_4_segm.png # RGB palette [256, 256, 3] -- semantic seg
|
||||
| +-- crop_12_4_chm.png # grayscale [256, 256] -- CHMv2 height
|
||||
+-- Country/...
|
||||
+-- Terrain/...
|
||||
```
|
||||
|
||||
### 4.3. Суффиксы и формат файлов
|
||||
|
||||
| Стадия | Суффикс | Формат PNG | Для обучения |
|
||||
|:-------|:--------|:-----------|:-------------|
|
||||
| depth | `_depth` | grayscale (L) uint8 | `value = pixel / 255.0` -> float [0,1], 1 канал |
|
||||
| edges | `_edge` | grayscale (L) uint8 | `value = pixel / 255.0` -> float [0,1], 1 канал |
|
||||
| segmentation | `_segm` | RGB palette (3ch) | Загружать class ID из int-маски, не из RGB |
|
||||
| chmv2 | `_chm` | grayscale (L) uint8 | `value = pixel / 255.0` -> float [0,1], 1 канал |
|
||||
|
||||
> **Для обучения:** depth, edge, chm используются как grayscale 1-канальные float [0,1]. Colormap-визуализации не нужны -- они теряют информацию при обратном преобразовании. Segm используется через class index (0-4), не через RGB.
|
||||
|
||||
### 4.4. Конфигурация (Gin framework)
|
||||
|
||||
Все параметры задаются в `in/config_files/*.gin`:
|
||||
|
||||
| Файл | Ключевые параметры |
|
||||
|:-----|:-------------------|
|
||||
| `pipeline.gin` | input_root, output_root, stages, save_npy, save_vis, save_concat, resume, subset, source, log_level |
|
||||
| `models.gin` | depth_model_id, depth_fallback_id, chmv2_model_id, seg_model_type, seg_fallback_id, weights_dir |
|
||||
| `hardware.gin` | profile_name, total_ram_gb, reserve_gb, use_fp16, batch_size (None=auto), num_workers |
|
||||
| `segmentation.gin` | prompts, threshold (0.3), default_resolution (1008) |
|
||||
| `input.gin` | image_size (256), sobel_kernel_size (3), edge_normalize, imagenet_mean/std |
|
||||
|
||||
### 4.5. Manifest (manifest.json)
|
||||
|
||||
По завершении пайплайна генерируется `{output_root}/manifest.json` с полной метаинформацией:
|
||||
|
||||
```json
|
||||
{
|
||||
"pipeline_version": "3.3.0-sequential",
|
||||
"image_size": 256,
|
||||
"profile": "rtx4090",
|
||||
"models": {
|
||||
"depth": "DA3-LARGE-1.1",
|
||||
"edges": "Sobel from depth (CPU)",
|
||||
"segmentation": "segearth-ov3",
|
||||
"chmv2": "facebook/dinov3-vitl16-chmv2-dpt-head"
|
||||
},
|
||||
"seg_prompts": ["background", "building", "road", "vegetation", "water"],
|
||||
"total_images": 973256,
|
||||
"stages": {
|
||||
"depth": {"processed": "...", "time_sec": "..."},
|
||||
"edges": {"processed": "...", "time_sec": "..."},
|
||||
"segmentation": {"processed": "...", "time_sec": "..."},
|
||||
"chmv2": {"processed": "...", "time_sec": "..."}
|
||||
},
|
||||
"timestamp": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### 4.6. Auto batch size
|
||||
|
||||
Batch size определяется автоматически по свободной VRAM:
|
||||
|
||||
```python
|
||||
free_mb = (cuda_total - cuda_reserved) / (1024*1024) - overhead_mb
|
||||
batch_size = round_down_power_of_2(free_mb / act_per_sample_mb * 0.7)
|
||||
```
|
||||
|
||||
Можно зафиксировать вручную через `hardware.gin` (`batch_size = 8`). При `batch_size = None` используется автоматический расчет.
|
||||
|
||||
### 4.7. Подавление логов
|
||||
|
||||
Все verbose логи моделей подавлены:
|
||||
- `DA3_LOG_LEVEL=ERROR` -- кастомный DA3 Logger (не стандартный Python logging)
|
||||
- `TRANSFORMERS_VERBOSITY=error` -- transformers
|
||||
- `HF_HUB_DISABLE_PROGRESS_BARS=1` -- tqdm загрузки весов
|
||||
- Все сторонние Python loggers на уровень `ERROR`
|
||||
|
||||
---
|
||||
|
||||
## 5. Протокол обработки
|
||||
|
||||
### 5.1. Оценка времени (экстраполяция из benchmark 100 img)
|
||||
|
||||
**v3.1 (per-image SegEarth-OV3):**
|
||||
|
||||
| Стадия | 100 img | 973K img | % общего времени |
|
||||
|:-------|:--------|:---------|:-----------------|
|
||||
| Depth (DA3-LARGE) | 5.44 s | **14.7 ч** | 6% |
|
||||
| Edges (Sobel) | 0.24 s | **0.6 ч** | <1% |
|
||||
| Segmentation (SegEarth-OV3, batch=1) | 25.49 s | **69 ч** (~2.9 дней) | **74%** |
|
||||
| CHMv2 (DINOv3) | 3.15 s | **8.5 ч** | 4% |
|
||||
| **Итого** | 34.33 s | **~93 ч** (~3.9 дней) | 100% |
|
||||
|
||||
**v3.2+ (batched backbone, batch<=8) -- оценка:**
|
||||
|
||||
| Стадия | 100 img | 973K img | % общего времени |
|
||||
|:-------|:--------|:---------|:-----------------|
|
||||
| Depth (DA3-LARGE) | 5.44 s | **14.7 ч** | 14% |
|
||||
| Edges (Sobel) | 0.24 s | **0.6 ч** | <1% |
|
||||
| Segmentation (SegEarth-OV3, batch<=8) | ~8-10 s | **~22-27 ч** (~1 день) | **~55%** |
|
||||
| CHMv2 (DINOv3) | 3.15 s | **8.5 ч** | 8% |
|
||||
| **Итого** | ~17-19 s | **~46-51 ч** (~2 дней) | 100% |
|
||||
|
||||
> **Примечание:** оценки для batched backbone теоретические (backbone ~80% времени амортизируется на батч, grounding ~20% остается per-image). Реальные цифры зависят от VRAM overhead и размера изображений. Требуется benchmark на реальных данных.
|
||||
|
||||
### 5.2. Запуск
|
||||
|
||||
```bash
|
||||
# Полный пайплайн (все subset'ы, все стадии, resume=True):
|
||||
python -m src.main
|
||||
```
|
||||
|
||||
Resume проверяет наличие `.png` **или** `.npy` файлов **для каждой стадии отдельно**. Пайплайн можно прервать и перезапустить в любой момент -- уже обработанные изображения пропускаются. В sequential-архитектуре resume гранулярный: можно перезапустить только конкретную стадию (например, segmentation), не затрагивая уже завершенные стадии (depth, edges).
|
||||
|
||||
### 5.3. Оценка дискового пространства
|
||||
|
||||
| Режим | Per-image | 973K images |
|
||||
|:------|:---------|:-----------|
|
||||
| Только PNG (save_npy=False) | ~60 KB x 4 | **~228 GB** |
|
||||
| PNG + NPY (save_npy=True) | ~508 KB | ~484 GB |
|
||||
|
||||
---
|
||||
|
||||
## 6. Контроль качества
|
||||
|
||||
### 6.1. Автоматическая валидация
|
||||
|
||||
| Проверка | Уровень | Механизм |
|
||||
|:---------|:--------|:---------|
|
||||
| Файл существует | Per-image | `_filter_all_done()` при resumption |
|
||||
| Shape корректен | Per-stage | Проверка при inference |
|
||||
| Range корректен | Per-stage | depth/edges/chm in [0,1], seg in [0, C-1] |
|
||||
| NaN detection | Per-stage | CHMv2 в FP32 (FP16 выдает NaN -- обнаружено и исправлено) |
|
||||
| Atomic write | Per-image | Temp file + `os.replace()` (POSIX atomic) |
|
||||
| Per-frame normalization | Per-image | Каждый depth/chm map нормализуется индивидуально |
|
||||
|
||||
### 6.2. Визуальная инспекция
|
||||
|
||||
Для каждого subset:
|
||||
- **20 случайных query** (drone) + **20 случайных db** (satellite)
|
||||
- PNG-визуализации генерируются автоматически рядом с исходными файлами
|
||||
- Проверка: контуры зданий/дорог видны на edges? Классы корректны на segm?
|
||||
|
||||
### 6.3. Обнаруженные проблемы и решения
|
||||
|
||||
| Проблема | Причина | Решение |
|
||||
|:---------|:--------|:--------|
|
||||
| CHMv2 output полностью черный | FP16 вызывает NaN в DINOv3 DPT head | CHMv2 всегда в FP32 |
|
||||
| DA3 verbose логи (Processed Images, Model Forward Pass) | Кастомный Logger, не Python logging | `DA3_LOG_LEVEL=ERROR` env var |
|
||||
| `bpe_simple_vocab_16e6.txt.gz` не найден | SegEarth ищет по относительному пути | BPE vocab встроен в `src/nn/segearth_ov3/sam3/assets/`, дефолтный путь вычисляется от `__file__` |
|
||||
|
||||
### 6.4. Количественные метрики
|
||||
|
||||
| Метрика | Описание | Threshold |
|
||||
|:--------|:---------|:----------|
|
||||
| Depth coverage | % пикселей с depth in (0.01, 0.99) | > 80% |
|
||||
| Edge density | % ненулевых пикселей edges | 5-40% |
|
||||
| Seg class balance | Entropy распределения классов | > 1.0 bits |
|
||||
| Seg coverage | % фоновых (class=0) пикселей | < 70% |
|
||||
|
||||
---
|
||||
|
||||
## 7. Формат хранения и интеграция с даталоадером
|
||||
|
||||
### 7.1. Интеграция с World-UAV DataLoader
|
||||
|
||||
```python
|
||||
class UAVGeoLocMultiModal(UAVGeoLocTrain):
|
||||
def __init__(self, root, aug_root, ...):
|
||||
super().__init__(root, ...)
|
||||
self.aug_root = Path(aug_root)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
query, positive, negative, label, height, rotation = super().__getitem__(idx)
|
||||
query_path = self._get_query_path(idx)
|
||||
|
||||
stem = Path(query_path).stem
|
||||
aug_dir = self.aug_root / Path(query_path).parent
|
||||
|
||||
# Загрузка grayscale PNG как float [0, 1], 1 канал
|
||||
depth = np.array(Image.open(aug_dir / f"{stem}_depth.png")) / 255.0 # [H, W]
|
||||
edges = np.array(Image.open(aug_dir / f"{stem}_edge.png")) / 255.0
|
||||
chm = np.array(Image.open(aug_dir / f"{stem}_chm.png")) / 255.0
|
||||
|
||||
# Сегментация -- class index (НЕ из RGB, а из отдельного источника)
|
||||
# Если save_npy=True: seg = np.load(aug_dir / f"{stem}_segm.npy")
|
||||
# Если только PNG: нужно обратное преобразование palette -> class ID
|
||||
|
||||
# Конкатенация для Teacher: RGB(3) + depth(1) + edge(1) + chm(1) = 6ch
|
||||
aux = np.stack([depth, edges, chm], axis=0) # [3, H, W]
|
||||
|
||||
return query, positive, negative, label, aux
|
||||
```
|
||||
|
||||
> **Рекомендация:** для сегментации включить `save_npy=True` или сохранять class index напрямую (uint8), т.к. обратное преобразование RGB palette -> class ID ненадежно.
|
||||
|
||||
---
|
||||
|
||||
## 8. Гипотезы аннотирования (AH1-AH6)
|
||||
|
||||
**AH1. Depth+edges дают больший прирост R@1 при LUPI-дистилляции, чем depth alone.**
|
||||
Основание: edges инвариантны к текстуре/освещению, выделяют структурные контуры -- наиболее устойчивые к кросс-вью трансформации.
|
||||
|
||||
**AH2. SegEarth-OV3 превосходит SegFormer-B5 по downstream CVGL utility.**
|
||||
Основание: OV-сегментация использует RS-специфичные промпты (building, road, water), не ограничена 150 классами ADE20K.
|
||||
|
||||
**AH3. Качество monocular depth деградирует для nadir-view спутниковых патчей сильнее, чем для oblique drone-кадров.**
|
||||
Основание: DA3 обучен преимущественно на наземных изображениях; CHMv2 обучен на аэрофотосъемке -- компенсирует этот разрыв.
|
||||
|
||||
**AH4. Edges из depth (Sobel) > Canny edges из RGB для CVGL.**
|
||||
Основание: Sobel на depth выделяет границы по геометрии (перепад высот), а не по текстуре (которая различается drone<->sat).
|
||||
|
||||
**AH5. CHMv2 + DA3 depth вместе > каждый по отдельности.**
|
||||
Основание: DA3 и CHMv2 обучены на разных доменах (ground-level vs aerial). Комбинация дает Teacher два ортогональных depth representation, каждый из которых лучше работает на "своем" типе изображений.
|
||||
|
||||
**AH6. Автоматическая аннотация 973K изображений за ~2 дня на одном GPU экономически оправдана.**
|
||||
Основание: ручная разметка -- десятки тысяч человеко-часов. Шумная автоматическая аннотация при LUPI допустима, т.к. Student не использует эти модальности при инференсе.
|
||||
|
||||
---
|
||||
|
||||
## 9. Архитектура кода
|
||||
|
||||
### 9.1. Структура модулей
|
||||
|
||||
```
|
||||
src/
|
||||
├── nn/ # Вендорированные нейросетевые пакеты
|
||||
│ ├── __init__.py # Регистрация sys.path при import src.nn
|
||||
│ ├── segearth_ov3/ # SegEarth-OV-3 (полная копия репозитория)
|
||||
│ │ ├── segearthov3_segmentor.py # SegEarthOV3Segmentation class
|
||||
│ │ ├── sam3/ # SAM 3.1 backbone (134 .py файла)
|
||||
│ │ │ ├── __init__.py # build_sam3_image_model()
|
||||
│ │ │ ├── model_builder.py # Сборка модели из компонентов
|
||||
│ │ │ ├── model/ # Sam3Image, Sam3Processor, ViT, encoder/decoder
|
||||
│ │ │ └── assets/bpe_simple_vocab_16e6.txt.gz # BPE tokenizer vocab
|
||||
│ │ └── pamr.py # Probabilistic Affinity Mask Refinement
|
||||
│ └── depth_anything_3/ # Depth-Anything-3 (полная копия пакета)
|
||||
│ ├── api.py # DepthAnything3 class (main API)
|
||||
│ ├── model/ # DA3 архитектура
|
||||
│ │ ├── da3.py # DepthAnything3Net, NestedDepthAnything3Net
|
||||
│ │ ├── dinov2/ # DinoV2 backbone (ViT)
|
||||
│ │ ├── dpt.py, dualdpt.py # DPT heads
|
||||
│ │ └── cam_enc.py, cam_dec.py # Camera encoder/decoder
|
||||
│ ├── configs/ # YAML-конфиги моделей (da3-large.yaml и др.)
|
||||
│ ├── utils/ # I/O processors, export, geometry, alignment
|
||||
│ └── registry.py # Реестр моделей
|
||||
├── augmentor/
|
||||
│ ├── dataset.py # ImageRecord, discover_images, INCOMPLETE_SCENES,
|
||||
│ │ # attach_output_dirs, filter_completed, STAGE_SUFFIX,
|
||||
│ │ # stage_filename, AugmentDataset
|
||||
│ ├── inference.py # infer_depth_batch, infer_chmv2_batch (FP32 only),
|
||||
│ │ # compute_edges_from_depth, infer_segmentation_batch,
|
||||
│ │ # _infer_segearth_ov3 (batched backbone, max_batch=8),
|
||||
│ │ # _infer_segformer
|
||||
│ ├── io_utils.py # save_depth_async, save_chmv2_async, save_edges_async,
|
||||
│ │ # save_segmentation_async, _save_float16_map,
|
||||
│ │ # _atomic_save_npy, make_palette, _FIXED_PALETTE
|
||||
│ └── models.py # load_depth_model (DA3 via src.nn),
|
||||
│ # load_chmv2_model (FP32, NaN в FP16),
|
||||
│ # load_segmentation_model (SegEarth via src.nn),
|
||||
│ # _resolve_cache_dir, unload_model
|
||||
├── conf/ # Gin-configurable dataclasses
|
||||
│ ├── config_loader.py # load_all_configs()
|
||||
│ ├── hardware_conf.py # HardwareConfig + auto_batch_size
|
||||
│ ├── input_conf.py # InputConfig (image_size=256, sobel, imagenet stats)
|
||||
│ ├── models_conf.py # ModelsConfig (depth, chmv2, seg IDs, fallbacks, weights_dir)
|
||||
│ ├── pipeline_conf.py # PipelineConfig (paths, stages, resume, subset, source)
|
||||
│ └── seg_conf.py # SegConfig (prompts, threshold, default_resolution)
|
||||
├── utils/
|
||||
│ ├── benchmark.py # BenchmarkResult, benchmark_depth, benchmark_chmv2,
|
||||
│ │ # benchmark_edges, benchmark_segmentation, benchmark_full_pipeline
|
||||
│ ├── configure_gpu.py # GPU configuration utilities
|
||||
│ ├── profiler.py # log_system_info, log_disk_info, log_vram_snapshot
|
||||
│ └── utils_file_dir.py # get_proj_dir
|
||||
├── tests/ # 125 тестов (pytest), 6 test-файлов
|
||||
│ ├── test_config.py # Config dataclass tests (12 tests)
|
||||
│ ├── test_models_and_benchmark.py # Model loading + benchmarking (62 tests)
|
||||
│ ├── test_inference.py # Inference functions (18 tests)
|
||||
│ ├── test_io_utils.py # I/O and save functions (16+ tests)
|
||||
│ ├── test_dataset.py # Discovery and filtering (12 tests)
|
||||
│ └── test_pipeline_integration.py # End-to-end stage tests (8 tests)
|
||||
└── main.py # Sequential pipeline:
|
||||
# run_pipeline -> run_depth_stage, run_edges_stage,
|
||||
# run_segmentation_stage, run_chmv2_stage
|
||||
# manifest generation, _silence_model_loggers(),
|
||||
# log_system_info(), log_disk_info()
|
||||
```
|
||||
|
||||
### 9.2. Механизм вендоринга (src/nn/)
|
||||
|
||||
Нейросетевые пакеты **встроены внутрь проекта** и не требуют внешних репозиториев:
|
||||
|
||||
| Пакет | Источник | Расположение | Размер |
|
||||
|:------|:---------|:-------------|:-------|
|
||||
| SegEarth-OV-3 | [earth-insights/SegEarth-OV-3](https://github.com/earth-insights/SegEarth-OV-3) | `src/nn/segearth_ov3/` | ~5 MB (134 .py + BPE vocab) |
|
||||
| Depth-Anything-3 | [ByteDance-Seed/Depth-Anything-3](https://github.com/ByteDance-Seed/Depth-Anything-3) | `src/nn/depth_anything_3/` | ~1.6 MB (85 .py + YAML configs) |
|
||||
|
||||
**Как работает:** `src/nn/__init__.py` при импорте добавляет в `sys.path`:
|
||||
- `src/nn/` -- делает доступным `from depth_anything_3.api import DepthAnything3`
|
||||
- `src/nn/segearth_ov3/` -- делает доступным `from segearthov3_segmentor import SegEarthOV3Segmentation` и `from sam3 import build_sam3_image_model`
|
||||
|
||||
Все внутренние импорты обоих пакетов работают **без изменений** -- код идентичен оригинальным репозиториям.
|
||||
|
||||
**Загрузка моделей:** `src/augmentor/models.py` содержит `import src.nn` (регистрация путей) и далее использует стандартные импорты:
|
||||
```python
|
||||
from depth_anything_3.api import DepthAnything3 # depth
|
||||
from segearthov3_segmentor import SegEarthOV3Segmentation # segmentation
|
||||
```
|
||||
|
||||
### 9.3. Ключевые design decisions
|
||||
|
||||
| Решение | Обоснование |
|
||||
|:--------|:-----------|
|
||||
| **Вендорированные пакеты в src/nn/** | Нет зависимости от внешних репозиториев; воспроизводимость; нет конфликтов sys.path |
|
||||
| **Sequential pipeline** (одна модель за раз) | Максимальный batch size для каждой модели; гранулярный resume по стадиям; упрощенная обработка ошибок |
|
||||
| **Batched backbone для SegEarth-OV3** | `predict_pil_batch()`: 1 backbone pass на <=8 img, затем per-image grounding. Backbone ~80% времени -> ~2.5-3x ускорение стадии. Fallback на per-image при OOM |
|
||||
| Stem-based file naming | `{stem}_{suffix}.png` -- файлы в той же директории, структура 1:1 с исходным датасетом |
|
||||
| Grayscale PNG для depth/edge/chm | 1 канал, пригодный для обучения (`pixel / 255.0`); colormapped PNG теряет информацию |
|
||||
| CHMv2 в FP32 | FP16 вызывает NaN (обнаружено при валидации на реальных данных) |
|
||||
| Per-image atomic save | Crash-safe: temp file + `os.replace()` |
|
||||
| Async I/O (ThreadPoolExecutor) | GPU inference не блокируется записью на диск |
|
||||
| BPE vocab встроен в src/nn/ | Файл `bpe_simple_vocab_16e6.txt.gz` в `sam3/assets/`, дефолтный путь вычисляется от `__file__` |
|
||||
| 125 unit tests (6 test-файлов) | Полное покрытие: inference, I/O, pipeline, benchmark, config, dataset (все mocked) |
|
||||
|
||||
### 9.4. Веса моделей
|
||||
|
||||
Все веса хранятся в `in/weights/`:
|
||||
|
||||
```
|
||||
in/weights/
|
||||
├── models--depth-anything--DA3-LARGE-1.1/ # HF cache (safetensors)
|
||||
├── models--nvidia--segformer-b5-finetuned-ade-640-640/ # SegFormer fallback
|
||||
├── sam3.1/sam3.1_multiplex.pt # 3.3 GB (SAM 3.1 checkpoint)
|
||||
├── dinov3-chmv2/ # 1.3 GB (safetensors + config)
|
||||
└── bpe_simple_vocab_16e6.txt.gz # CLIP BPE (опциональная копия)
|
||||
```
|
||||
|
||||
> BPE vocab уже встроен в `src/nn/segearth_ov3/sam3/assets/`. Копия в `in/weights/` используется приоритетно, если существует.
|
||||
|
||||
---
|
||||
|
||||
## 10. Риски и митигации
|
||||
|
||||
| Риск | Вероятность | Митигация |
|
||||
|:-----|:-----------|:----------|
|
||||
| **R1:** SegEarth-OV3 не загрузится | Низкая (вендорирован) | Автоматический fallback на SegFormer-B5 |
|
||||
| **R2:** ~2 дней на GPU (batched) | Средняя | Resume позволяет прерывать/продолжать; можно запускать по subset'ам |
|
||||
| **R2a:** SegEarth-OV3 OOM при batch=8 | Низкая (RTX 4090, ~10 GB) | Автоматический fallback на per-image `predict_pil()` при ошибке `predict_pil_batch()` |
|
||||
| **R3:** DA3 не загрузится | Низкая (вендорирован) | Fallback на DA V2 Large (transformers) |
|
||||
| **R4:** Диск закончится (~228 GB только PNG) | Низкая | `save_vis = False` для экономии |
|
||||
| **R5:** CHMv2 NaN в FP16 | **Решено** | Модель загружается в FP32 |
|
||||
| **R6:** Segmentation palette неинтуитивная | **Решено** | Фиксированная палитра: red=building, gray=road, green=vegetation, blue=water |
|
||||
|
||||
---
|
||||
|
||||
## 11. Timeline и ресурсы
|
||||
|
||||
### 11.1. Фазы
|
||||
|
||||
| Фаза | Длительность | Статус |
|
||||
|:-----|:-------------|:-------|
|
||||
| **0. Setup** | -- | Выполнено: DA3, SegEarth-OV3, CHMv2 установлены, веса скачаны |
|
||||
| **1. Smoke test (100 img)** | -- | Выполнено: 34.33 s, все стадии работают |
|
||||
| **2. Валидация качества** | -- | Выполнено: CHMv2 FP16->FP32 fix, palette fix |
|
||||
| **2a. Вендоринг моделей** | -- | Выполнено: SegEarth-OV3 и DA3 перенесены в src/nn/ |
|
||||
| **3. Полный запуск (973K)** | ~2 дней (batched backbone) | В процессе |
|
||||
| **4. Final validation** | 0.5 дня | -- |
|
||||
|
||||
### 11.2. Ресурсы
|
||||
|
||||
| Ресурс | Требование |
|
||||
|:-------|:-----------|
|
||||
| GPU | RTX 4090 (24 GB VRAM), peak ~10 GB (SegEarth batch=8, sequential) |
|
||||
| RAM | >= 32 GB |
|
||||
| SSD | >= 250 GB свободно (только PNG) |
|
||||
| GPU-часы | ~46-51 ч (batched) / ~93 ч (per-image) |
|
||||
|
||||
---
|
||||
|
||||
## 12. Библиография
|
||||
|
||||
1. Wu et al., "UAV-GeoLoc: A Large-Vocabulary Dataset and Geometry-Transformed Method for UAV Geo-Localization," IEEE RA-L, 2025.
|
||||
2. Yang et al., "Depth Anything V3: Recovering the Visual Space from Any Views," arXiv:2511.10647, 2025.
|
||||
3. Li et al., "SegEarth-OV3: Exploring SAM 3.1 for Open-Vocabulary Semantic Segmentation in Remote Sensing Images," arXiv:2512.08730, 2025.
|
||||
4. Ravi et al., "SAM 3.1: Segment Anything in Images and Videos," Meta AI, 2025.
|
||||
5. Oquab et al., "DINOv3: Learning Robust Visual Features without Supervision," Meta AI, 2025.
|
||||
6. Vapnik & Vashist, "A New Learning Paradigm: Learning Using Privileged Information," Neural Networks, 2009.
|
||||
7. Xie et al., "SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers," NeurIPS, 2021.
|
||||
8. Lin et al., "Sample4Geo: Hard Negative Sampling For Cross-View Geo-Localisation," ICCV, 2023.
|
||||
@@ -0,0 +1,251 @@
|
||||
---
|
||||
tags: [task/code]
|
||||
---
|
||||
|
||||
|
||||
#work #depth_and_normals #discussion
|
||||
|
||||
# Нейросети для спутниковых и БПЛА-снимков: глубина, нормали, сегментация
|
||||
|
||||
Современные предобученные модели позволяют извлекать из одного RGB-изображения карту глубины, карту нормалей поверхности и семантическую сегментацию — но **ни одна модель не решает все три задачи одновременно именно для аэрокосмических снимков**. Лучшей стратегией на 2025–2026 год остаётся комбинирование специализированных моделей: Depth Anything V2 или Metric3D v2 для глубины, DSINE или StableNormal для нормалей, и Prithvi-EO-2.0 или дообученный SegFormer для сегментации. Все перечисленные модели помещаются в **24 ГБ VRAM** видеокарты RTX 4090 и имеют открытые веса. Ключевое ограничение — модели глубины и нормалей обучены преимущественно на наземных изображениях, и надирные (вертикальные) аэрокосмические виды остаются для них out-of-distribution.
|
||||
|
||||
---
|
||||
|
||||
## Оценка глубины: от Depth Anything V2 до Metric3D v2
|
||||
|
||||
### Модели относительной глубины (affine-invariant)
|
||||
|
||||
**Depth Anything V2** (ByteDance/TikTok, NeurIPS 2024) — наиболее практичный выбор для аэрофотосъёмки. Архитектура DINOv2 ViT + DPT-декодер, четыре размера: Small (24.8M параметров, ~2 ГБ VRAM), Base (97.5M, ~3 ГБ), Large (335M, ~5 ГБ) и Giant (1.3B, ~12–14 ГБ). Вариант Large обрабатывает кадр за **~0.2 секунды** на RTX 4090. Прямое тестирование на БПЛА-снимках (arXiv:2503.04513, 2025) показало среднюю абсолютную ошибку высот **4.29 м** (медиана 2.40 м) при съёмке с 200 м, что составляет ~5% относительной ошибки. Модель значительно превосходит MiDaS v3.1 на воздушных изображениях, но испытывает трудности с деревьями при надирной съёмке и резкими перепадами высот (>50 м). В 2025 году вышла версия V3 с улучшенной производительностью.
|
||||
|
||||
- **GitHub**: https://github.com/DepthAnything/Depth-Anything-V2
|
||||
- **HuggingFace**: `depth-anything/Depth-Anything-V2-Large-hf`
|
||||
- **Инференс**: `pipeline("depth-estimation", model="depth-anything/Depth-Anything-V2-Large-hf")` или нативный PyTorch API `model.infer_image(img)`
|
||||
|
||||
**Marigold v1.1** (ETH Zurich, CVPR 2024 Oral) — диффузионная модель на базе Stable Diffusion U-Net (~948M параметров, ~10 ГБ VRAM). Обеспечивает исключительную детализацию границ и отличную обобщающую способность за счёт генеративных prior'ов SD. Скорость: ~5 с/кадр при 10 шагах денойзинга, LCM-вариант позволяет работать за 1 шаг. Встроена в HuggingFace Diffusers (`MarigoldDepthPipeline`). Бенчмарки: NYUv2 AbsRel **0.055**, δ1 **0.964**. Для аэроснимков может обобщаться лучше дискриминативных моделей благодаря диффузионным prior'ам, обученным на миллиардах изображений.
|
||||
|
||||
**DepthFM** (CompVis/LMU, AAAI 2025 Oral) — flow matching модель на базе SD2.1, требует всего 1–2 шага инференса (~1–2 с/кадр, ~10 ГБ VRAM). Качество сопоставимо с Marigold при многократно меньшей латентности. GitHub: https://github.com/CompVis/depth-fm
|
||||
|
||||
**Lotus V1** (HKUST, ICLR 2025) — адаптированная SD U-Net с прямым предсказанием (не шумовое). Заявляет SOTA на zero-shot бенчмарках при обучении всего на **59K сэмплах**. ~10 ГБ VRAM. Внимание: **Lotus-2 на базе FLUX требует ≥40 ГБ и НЕ поместится на RTX 4090**. GitHub: https://github.com/EnVision-Research/Lotus
|
||||
|
||||
**MiDaS v3.1** (Intel ISL) — классическая модель с множеством backbone-вариантов (от LeViT до BEiT-L-512). Все помещаются на RTX 4090. Уступает Depth Anything V2 на аэрокосмических снимках, но полезна как проверенный baseline. GitHub: https://github.com/isl-org/MiDaS
|
||||
|
||||
### Модели метрической (абсолютной) глубины
|
||||
|
||||
**Metric3D v2** (HKUST/Intel/Tencent, TPAMI 2024) — **лучший выбор для метрической глубины**. Уникальная трансформация в каноническое камерное пространство снимает неоднозначность масштаба при известных параметрах камеры. Предсказывает одновременно метрическую глубину **и** нормали поверхности. Варианты: ViT-Small (~6 ГБ), ViT-Large (~12 ГБ), ViT-Giant2 (~20 ГБ) — все помещаются на RTX 4090. Чемпион CVPR 2023 Monocular Depth Challenge. Требует focal length — для дронов и спутников это обычно известно.
|
||||
|
||||
- **GitHub**: https://github.com/YvanYin/Metric3D
|
||||
- **Инференс**: `model = torch.hub.load('yvanyin/metric3d', 'metric3d_vit_large', pretrain=True)`
|
||||
|
||||
**UniDepth V2** (ETH Zurich, CVPR 2024 / 2025) — **не требует параметров камеры**: self-promptable камерный модуль самостоятельно предсказывает интринсики. NYUv2 δ1=**0.988**, KITTI δ1=**0.964**. ~10 ГБ VRAM. Особенно интересен для БПЛА, когда intrinsics неизвестны. GitHub: https://github.com/lpiccinelli-eth/UniDepth
|
||||
|
||||
**Depth Pro** (Apple, ICLR 2025) — метрическая глубина с встроенной оценкой фокусного расстояния, рекордная чёткость границ (SI-boundary-F1 SOTA). Генерирует карту глубины **2.25 МП за 0.3 с**. ~10 ГБ VRAM. GitHub: https://github.com/apple/ml-depth-pro
|
||||
|
||||
**ZoeDepth** (Intel ISL) — пионерская модель с метрическими «bins» поверх MiDaS. Метрические головы обучены на NYUv2 (до 10 м) и KITTI (до 80 м) — **диапазон глубин аэроснимков (100–500 м) полностью вне распределения обучения**. Используется как baseline, но для спутниковых данных не рекомендуется.
|
||||
|
||||
### Специализированные модели для аэрокосмических данных
|
||||
|
||||
Выделенных моделей моноглубины для спутниковых снимков с открытыми весами практически нет. Наиболее релевантны:
|
||||
|
||||
- **Sat-DN** (2025) — использует Depth Anything V2 как prior для спутникового NeRF-реконструирования
|
||||
- **SelfSupervisedAerialDepthEstimator** (ISPRS 2020) — самоконтролируемое обучение на аэровидео: https://github.com/Max-Hermann/SelfSupervisedAerialDepthEstimator
|
||||
- **WHU-OMVS Dataset** — 32K косых аэроснимков с глубиной (768×384, высота ~220 м) для обучения
|
||||
|
||||
**Ключевой вывод**: для практического применения на аэрокосмических данных оптимально использовать Depth Anything V2 Large для относительной глубины (быстро, проверено) или Metric3D v2 для метрической глубины (при известных intrinsics), с дальнейшим fine-tuning на целевых данных.
|
||||
|
||||
---
|
||||
|
||||
## Предсказание нормалей поверхности: от StableNormal до DSINE
|
||||
|
||||
Специализированных моделей нормалей для аэроснимков **не существует** — все модели обучены на наземных/indoor сценах. Однако ряд архитектур потенциально хорошо переносим.
|
||||
|
||||
**StableNormal** (SIGGRAPH Asia 2024) — двухэтапная диффузионная модель: YOSO (одношаговый эстиматор) + SG-DRN (семантически направленное уточнение на DINO-prior'ах). Turbo-вариант в **10× быстрее** полной версии. Mean Angular Error: ScanNet **17.43°** (turbo), NYUv2 **18.79°**. ~10–15 ГБ VRAM.
|
||||
|
||||
- **GitHub**: https://github.com/Stable-X/StableNormal
|
||||
- **Инференс**: `predictor = torch.hub.load("Stable-X/StableNormal", "StableNormal", trust_repo=True)`
|
||||
|
||||
**DSINE** (CVPR 2024 Oral) — **лёгкая регрессионная модель** на EfficientNet с уникальными геометрическими inductive biases: per-pixel ray direction (Ray ReLU) и оценка относительного вращения между соседними пикселями. Всего **~3–4 ГБ VRAM**, обучалась за 12 часов на одной RTX 4090. Принимает camera intrinsics как вход — для дронов/спутников это преимущество. Наиболее перспективна для аэроснимков среди чисто normal-моделей благодаря явному кодированию геометрии камеры.
|
||||
|
||||
- **GitHub**: https://github.com/baegwangbin/DSINE
|
||||
- **Инференс**: `normal_predictor = torch.hub.load("hugoycj/DSINE-hub", "DSINE", trust_repo=True)`
|
||||
|
||||
**Marigold-Normals v1.1** (ETH Zurich, CVPR 2024) — диффузионная модель нормалей на базе SD, интегрирована в HuggingFace Diffusers. E2E-FT вариант (`GonzaloMG/marigold-e2e-ft-normals`) работает за **один шаг** (~6–8 ГБ VRAM). Камерное пространство, выход [-1, 1].
|
||||
|
||||
```python
|
||||
from diffusers import MarigoldNormalsPipeline
|
||||
pipe = MarigoldNormalsPipeline.from_pretrained("prs-eth/marigold-normals-v1-1").to("cuda")
|
||||
output = pipe(image)
|
||||
```
|
||||
|
||||
**GeoWizard** (HKUST, ECCV 2024) — **совместное предсказание глубины и нормалей** одной диффузионной моделью с «geometry switcher» и выбором домена (indoor/outdoor/object). ~10–14 ГБ VRAM. GitHub: https://github.com/fuxiao0719/GeoWizard
|
||||
|
||||
**Metric3D v2** — помимо метрической глубины, предсказывает нормали + карту уверенности. Дискриминативный, быстрый. Единственная модель, дающая одновременно **метрическую глубину и нормали** в одном проходе.
|
||||
|
||||
**GenPercept** (ICLR 2025) — SD2.1 U-Net как одношаговый детерминированный экстрактор фичей. Поддерживает глубину, нормали, сегментацию, матирование — разные чекпоинты. ~8–10 ГБ VRAM. GitHub: https://github.com/aim-uofa/GenPercept
|
||||
|
||||
**Omnidata v2** (EPFL/Stanford, ICCV 2021) — DPT-Hybrid архитектура, ~4–6 ГБ VRAM. Широко используется как baseline и генератор pseudo-labels. Уступает более новым моделям по точности, но остаётся де-факто стандартом.
|
||||
|
||||
### Сводная таблица нормалей
|
||||
|
||||
|Модель|MAE ScanNet ↓|MAE NYUv2 ↓|VRAM|Скорость|Тип|
|
||||
|---|---|---|---|---|---|
|
||||
|**Lotus-G/D**|SOTA (лучший)|SOTA|~10 ГБ|~1 с|Diffusion|
|
||||
|**StableNormal-turbo**|17.43°|18.79°|~12 ГБ|~1 с|Diffusion 2-stage|
|
||||
|**DSINE**|18.61°|—|**~3 ГБ**|**<0.1 с**|CNN regression|
|
||||
|**GenPercept**|20.65°|20.90°|~9 ГБ|~0.4 с|SD one-step|
|
||||
|**Marigold-Normals**|21.28°|20.86°|~10 ГБ|~5 с|Diffusion|
|
||||
|**GeoWizard**|21.44°|20.36°|~12 ГБ|~5 с|Diffusion joint|
|
||||
|**Metric3D v2**|конкурентно|—|~12 ГБ|~0.3 с|ViT discriminative|
|
||||
|**Omnidata v2**|~22°+|~22°+|~5 ГБ|~0.2 с|DPT|
|
||||
|
||||
### Проблемы нормалей при надирной съёмке
|
||||
|
||||
При виде строго сверху большинство поверхностей (крыши, земля) имеют нормаль, направленную прямо вверх [0, 0, 1], что создаёт **сильно сконцентрированное распределение**, нехарактерное для обучающих данных. Косые виды (30–60° от надира) гораздо ближе к обучающим данным. Практический подход — вычисление нормалей из карты глубины через градиент (DSINE включает такой notebook), что при хорошей карте глубины может дать более стабильные результаты, чем прямое предсказание.
|
||||
|
||||
---
|
||||
|
||||
## Семантическая сегментация аэрокосмических снимков
|
||||
|
||||
### Фундаментальные модели дистанционного зондирования
|
||||
|
||||
**Prithvi-EO-2.0** (IBM/NASA, 2024–2025) — **лидирующая открытая геопространственная foundation model**. ViT + MAE, предобучена на 4.2M глобальных временных рядов HLS (Harmonized Landsat Sentinel-2). Версии: 300M и 600M параметров. Результат **75.6%** на GEO-Bench (на 8% выше v1.0), превосходит 6 других геопространственных FM. Вход: 6 каналов (R, G, B, NIR, SWIR1, SWIR2), поддерживает временные последовательности. Дообучка через **TerraTorch** или MMSegmentation. Дообученные варианты для flood mapping, burn scars, crop classification.
|
||||
|
||||
- **HuggingFace**: `ibm-nasa-geospatial/Prithvi-EO-2.0-600M`
|
||||
- **GitHub**: https://github.com/NASA-IMPACT/Prithvi-EO-2.0
|
||||
- **VRAM**: помещается на RTX 4090; для fine-tuning может потребоваться gradient accumulation
|
||||
|
||||
**SkySense / SkySense++** (CVPR 2024 / Nature Machine Intelligence 2025) — мультимодальная FM миллиардного масштаба, предобучена на 21.5M временных последовательностей. Превосходит 18 RSFM на 16 датасетах по 7 задачам. SkySense++ с семантическим усилением. Может потребовать multi-GPU оптимизацию для RTX 4090. GitHub: https://github.com/Jack-bo1220/SkySense
|
||||
|
||||
**Clay Foundation Model** — гибкая open-source EO FM, принимает изображения **любого источника** (дроны, самолёты, спутники), любого размера, разрешения и набора спектральных каналов. Обучена на ~70M изображений. Выдаёт эмбеддинги — требует дообучки для сегментации. Apache 2.0 / OpenRAIL-M. GitHub: https://github.com/Clay-foundation/model
|
||||
|
||||
**SatlasPretrain** (Allen AI) — foundation model, предобученная на **100+ задачах** (land cover, crop classification, building detection) на Sentinel-2 и high-res (0.5–2 м) аэроснимках. Backbone Swin-v2-B + FPN. Отдельные веса для Sentinel-2 и high-res RGB. HuggingFace: `allenai/satlas-pretrain`
|
||||
|
||||
**SatMAE** (NeurIPS 2022) / **Cross-Scale-MAE** (NeurIPS 2023) / **SpectralGPT** (IEEE TPAMI 2024) — MAE/GPT-варианты для мультиспектральных данных. Требуют fine-tuning. SpectralGPT имеет модели Base (~100M), Large (~300M), Huge (~600M) — обучен на 8× RTX 4090.
|
||||
|
||||
### Дообученные модели сегментации
|
||||
|
||||
**SegFormer** (NVIDIA) — серия B0–B5, нативно RGB, HuggingFace `pipeline("image-segmentation")`. На UAVid достигает **~70% mIoU** (8 классов). B0: ~2 ГБ VRAM, B5: ~8 ГБ. Легко дообучается на аэроданных через HuggingFace Trainer или MMSegmentation.
|
||||
|
||||
**GeoSeg Toolbox** — специализированный toolbox для RS-сегментации на PyTorch Lightning + timm. Включает **UNetFormer**, DC-Swin и другие архитектуры с предобученными весами для ISPRS Vaihingen/Potsdam, LoveDA, UAVid. GitHub: https://github.com/WangLibo1995/GeoSeg
|
||||
|
||||
**MMSegmentation** (OpenMMLab) — унифицированный фреймворк с конфигурациями для ISPRS Potsdam/Vaihingen, LoveDA, iSAID. Поддерживает PSPNet, DeepLabV3+, UPerNet, SegFormer, Swin, HRNet, OCRNet. GitHub: https://github.com/open-mmlab/mmsegmentation
|
||||
|
||||
**TorchGeo** (Microsoft) — PyTorch domain library для геопространственных данных. **110+ предобученных моделей**, 120+ датасетов. Включает ResNet18/50 с MoCo-весами на Sentinel-2, DOFA, CROMA. Автоматическая CRS-репроекция и data fusion. Стандарт для воспроизводимых бенчмарков.
|
||||
|
||||
```python
|
||||
from torchgeo.datamodules import InriaAerialImageLabelingDataModule
|
||||
from torchgeo.trainers import SemanticSegmentationTask
|
||||
task = SemanticSegmentationTask(model="unet", backbone="resnet50", weights=True, in_channels=3)
|
||||
```
|
||||
|
||||
### Специализированные модели для зданий и дорог
|
||||
|
||||
**SpaceNet-победители** — U-Net-варианты с ResNet50/EfficientNet encoder'ами. SpaceNet 8 (1-е место): Swin Transformer + UPerNet (здания/наводнения), SegFormer (дороги), ImageNet-22K pretrained. Building F1: **~0.885–0.89**. Веса на AWS S3.
|
||||
|
||||
**Microsoft Global ML Building Footprints** — **1.4B+ полигонов зданий** по всему миру. Precision/Recall по Европе: **94.3%/85.9%**. Однако **веса модели НЕ опубликованы** — доступны только выходные полигоны (CDLA Permissive 2.0).
|
||||
|
||||
**Google Open Buildings** — 1.8B детекций зданий по Африке, Латинской Америке, Азии. Open Buildings 2.5D Temporal предсказывает высоту зданий с MAE **1.5 м** (на Sentinel-2). **Веса также НЕ опубликованы**.
|
||||
|
||||
**SamGeo / segment-geospatial** — обёртка SAM для геопространственных данных, QGIS-плагин. Работает с RGB, ViT-H ~4–8 ГБ VRAM. `pip install segment-geospatial`. GitHub: https://samgeo.gishub.org/
|
||||
|
||||
**D-LinkNet** — победитель DeepGlobe Road Extraction Challenge (CVPR 2018). LinkNet + dilated convolutions + pretrained ResNet.
|
||||
|
||||
### SOTA результаты на ключевых датасетах
|
||||
|
||||
На **ISPRS Potsdam**: DyHRNet, AD-HRNet, MST-DeepLabv3+ достигают **82–85% mIoU** (6 классов). На **LoveDA**: **52–60% mIoU** (сложнее из-за domain gap urban/rural). На **Inria Aerial**: DeepLabV3+ достигает **~80%+ MPA** для бинарной сегментации зданий.
|
||||
|
||||
---
|
||||
|
||||
## Мульти-задачные модели и пайплайны
|
||||
|
||||
### Модели «глубина + нормали» в одном проходе
|
||||
|
||||
|Модель|Глубина|Нормали|Сегментация|Тип|
|
||||
|---|---|---|---|---|
|
||||
|**Metric3D v2**|✅ Метрическая|✅|❌|Discriminative|
|
||||
|**GeoWizard**|✅ Относительная|✅|❌|Diffusion joint|
|
||||
|**Omnidata**|✅ Относительная|✅|❌*|Отдельные модели|
|
||||
|**Lotus**|✅ Относительная|✅|❌|Отдельные чекпоинты|
|
||||
|**GenPercept**|✅|✅|✅|Отдельные UNet-чекпоинты|
|
||||
|
||||
**TaskPrompter / InvPT++** (ICLR 2023 / TPAMI 2024) — **единственная модель с одновременным предсказанием глубины + нормалей + семантической сегментации + контуров** в одном проходе. Архитектура ViT/Swin encoder → TaskPrompter decoder. Обучена на NYUD-v2, PASCAL-Context. Не специализирована для аэроснимков, но архитектура переносима. GitHub: https://github.com/prismformore/Multi-Task-Transformer
|
||||
|
||||
**MultiMAE** (EPFL, ECCV 2022) — MAE для нескольких модальностей (RGB, depth, segmentation). Предобученная на ImageNet-1K с pseudo-labels. GitHub: https://github.com/EPFL-VILAB/MultiMAE
|
||||
|
||||
### Рекомендуемый практический пайплайн для RTX 4090
|
||||
|
||||
Для обработки аэрокосмических RGB-снимков оптимальная комбинация:
|
||||
|
||||
1. **Глубина**: Depth Anything V2 Large (~5 ГБ, 0.2 с/кадр) для относительной глубины ИЛИ Metric3D v2 ViT-Large (~12 ГБ) для метрической глубины с intrinsics
|
||||
2. **Нормали**: DSINE (~3 ГБ, <0.1 с) для быстрого инференса с intrinsics ИЛИ вычисление нормалей из карты глубины через градиент
|
||||
3. **Сегментация**: Fine-tuned SegFormer-B5 через TorchGeo (~8 ГБ) или Prithvi-EO-2.0 через TerraTorch
|
||||
4. **Данные**: TorchGeo + rasterio/GDAL для загрузки GeoTIFF и пакетного инференса
|
||||
|
||||
Все три модели последовательно помещаются в 24 ГБ; при использовании DSINE + DA V2 Large можно запускать их параллельно (~8 ГБ суммарно), освобождая VRAM для сегментации.
|
||||
|
||||
---
|
||||
|
||||
## Датасеты для обучения и оценки
|
||||
|
||||
### Сегментация и land cover
|
||||
|
||||
|Датасет|Разрешение|Классы|Размер|Источник|
|
||||
|---|---|---|---|---|
|
||||
|**ISPRS Potsdam**|5 см|6 (здания, деревья, авто, покрытия, вег., фон)|38 тайлов 6000×6000|Аэросъёмка|
|
||||
|**ISPRS Vaihingen**|9 см|6 (аналогично)|33 тайла|Аэросъёмка|
|
||||
|**LoveDA**|30 см|7 (здания, дороги, вода, лес, с/х, пустоши, фон)|5987 изображений|Google Earth|
|
||||
|**iSAID**|0.5–1 м|15 (корабли, мосты, самолёты, вертолёты и др.)|2806 изображений, 655K инстансов|Спутник/аэро|
|
||||
|**SpaceNet 1–8**|30–50 см|Здания, дороги, наводнения|67K км², 11M+ зданий|WorldView-2/3|
|
||||
|**DeepGlobe**|50 см|7 классов land cover + дороги|~1800 изображений|DigitalGlobe|
|
||||
|**Inria Aerial**|30 см|2 (здание/фон)|360 тайлов 5000×5000|Аэросъёмка|
|
||||
|**UAVid**|~см|8 (здания, дороги, деревья, авто, люди)|420 кадров 4K|БПЛА-видео|
|
||||
|**GID**|~1 м|5–15 классов land cover|150 изображений 7200×6800|Gaofen-2|
|
||||
|**EuroSAT**|10 м|10 классов|27000 патчей 64×64|Sentinel-2|
|
||||
|**BigEarthNet**|10–60 м|43 CLC-класса (multi-label)|590K патчей|Sentinel-2|
|
||||
|**fMoW**|0.3–1.5 м|63 функциональных категории|1M+ изображений|DigitalGlobe|
|
||||
|
||||
### Датасеты с ground truth высоты/глубины
|
||||
|
||||
Это критически важные ресурсы для fine-tuning моделей глубины на аэроданных:
|
||||
|
||||
- **ISPRS Potsdam/Vaihingen** — включают **DSM (Digital Surface Model)** с разрешением 5/9 см — одни из лучших данных для fine-tuning глубины
|
||||
- **DFC2019** (IEEE GRSS) — спутниковое стерео + **LiDAR** для семантической 3D-реконструкции городов (Jacksonville, Omaha)
|
||||
- **DFC2022 (MiniFrance)** — VHR EO-данные + land cover + **DEM**
|
||||
- **DFC2023** — мультимодальный бенчмарк с **3D-реконструкцией зданий** из спутникового стерео
|
||||
- **WHU-OMVS** — 32K косых аэроснимков с глубиной (768×384, ~220 м высота)
|
||||
- **US3D** (IARPA CORE3D) — спутниковое стерео + LiDAR + семантические метки
|
||||
|
||||
---
|
||||
|
||||
## Сводная таблица совместимости с RTX 4090
|
||||
|
||||
|Модель|Задача|VRAM|RTX 4090|Скорость|Framework|
|
||||
|---|---|---|---|---|---|
|
||||
|Depth Anything V2 Large|Глубина (относ.)|~5 ГБ|✅|0.2 с|PyTorch, HF|
|
||||
|Depth Anything V2 Giant|Глубина (относ.)|~14 ГБ|✅|0.5 с|PyTorch, HF|
|
||||
|Metric3D v2 ViT-L|Глубина (метр.) + нормали|~12 ГБ|✅|0.3 с|PyTorch|
|
||||
|Metric3D v2 ViT-G2|Глубина (метр.) + нормали|~20 ГБ|⚠️ впритык|0.5 с|PyTorch|
|
||||
|UniDepth V2|Глубина (метр.)|~10 ГБ|✅|0.2 с|PyTorch|
|
||||
|Depth Pro|Глубина (метр.)|~10 ГБ|✅|0.3 с|PyTorch|
|
||||
|Marigold v1.1|Глубина (относ.)|~10 ГБ|✅|5 с|Diffusers|
|
||||
|DSINE|Нормали|**~3 ГБ**|✅|**<0.1 с**|PyTorch|
|
||||
|StableNormal-turbo|Нормали|~12 ГБ|✅|~1 с|PyTorch|
|
||||
|Marigold-Normals E2E-FT|Нормали|~7 ГБ|✅|~0.5 с|Diffusers|
|
||||
|GeoWizard|Глубина + нормали|~12 ГБ|✅|~5 с|Diffusers|
|
||||
|Lotus V1|Глубина / нормали|~10 ГБ|✅|~1 с|PyTorch|
|
||||
|**Lotus-2**|Глубина / нормали|**~40 ГБ**|**❌**|~5 с|FLUX-based|
|
||||
|Prithvi-EO-2.0-600M|Сегментация|~8–12 ГБ|✅|~0.5 с|PyTorch, TerraTorch|
|
||||
|SegFormer-B5|Сегментация|~8 ГБ|✅|~0.1 с|HF Transformers|
|
||||
|SAM ViT-H (SamGeo)|Сегментация|~8 ГБ|✅|~0.5 с|PyTorch|
|
||||
|TaskPrompter|Все 3 задачи|~10 ГБ|✅|~0.3 с|PyTorch|
|
||||
|
||||
---
|
||||
|
||||
## Ключевые выводы и рекомендации
|
||||
|
||||
Главный результат этого обзора — **существует острый разрыв между качеством общих моделей глубины/нормалей и их применимостью к надирным аэрокосмическим видам**. Все SOTA-модели обучены на наземных изображениях, и прямое применение к спутниковым снимкам даёт деградацию качества, особенно для деревьев и вертикальных структур. Косые аэровиды (30–60° от надира) обрабатываются существенно лучше, чем строго вертикальные.
|
||||
|
||||
Для сегментации ситуация значительно лучше: экосистема Prithvi-EO, TorchGeo, SatlasPretrain и GeoSeg предоставляет зрелые инструменты, обученные непосредственно на спутниковых данных. Практический путь к мульти-задачному пайплайну — это **комбинация Depth Anything V2 + DSINE + дообученный SegFormer**, работающая последовательно на RTX 4090 с суммарным временем обработки кадра менее 1 секунды.
|
||||
|
||||
Для проектов, требующих метрической 3D-реконструкции, Metric3D v2 остаётся лучшим стартом — при условии fine-tuning на аэроданных с LiDAR ground truth (ISPRS DSM, DFC2019). Диффузионные модели (Marigold, GeoWizard) предлагают лучшую генерализацию за счёт prior'ов Stable Diffusion, но проигрывают в скорости и не дают метрических значений. Абсолютно новая ниша — **foundation models для remote sensing** (Prithvi-2, SkySense++, Clay) — пока не покрывает задачи глубины и нормалей, но объединение их с геометрическими моделями представляет перспективное направление для 2026 года.
|
||||
|
||||
#task/code
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
tags: [dataset/cvusa, dataset/sues200, dataset/univ1652, method/quantization, task/code]
|
||||
---
|
||||
|
||||
|
||||
#work #depth_and_normals #discussion
|
||||
|
||||
Вот ключевые результаты расчёта для ваших параметров — **384×384, fp16, RTX 4090 (24 ГБ)**:
|
||||
|
||||
**Рекомендуемые батчи** (с запасом 30% на фрагментацию CUDA):
|
||||
|
||||
|Модель|Батч|VRAM|~мс/сэмпл|
|
||||
|---|---|---|---|
|
||||
|Depth Anything V2 Large|**32**|12.4 ГБ|~12 мс|
|
||||
|DSINE (нормали)|**64**|8.0 ГБ|~5 мс|
|
||||
|SegFormer-B5 (сегментация)|**32**|8.6 ГБ|~8 мс|
|
||||
|
||||
Суммарное время обработки одного кадра через все три модели — **~25 мс** (~40 FPS), то есть 1000 изображений обработается примерно за 25 секунд.
|
||||
|
||||
Скрипт работает в двух режимах. В **последовательном** режиме (по умолчанию) модели загружаются по очереди и каждая получает максимум VRAM — отсюда большие батчи. В **параллельном** (`--parallel`) все три модели сидят в памяти одновременно, но батч ограничивается самой «тяжёлой» моделью (DA V2 → 0.35 ГБ/сэмпл), и единый батч составит ~56 — всё равно комфортно.
|
||||
|
||||
Запуск: `python pipeline.py --input ./images --output ./results --img-size 384`. Для просмотра расчёта без обработки: `python pipeline.py --vram-report`.
|
||||
|
||||
Стандартный размер в cross-view geo-localization — **не 384, а 256×256**. В экспериментах на University-1652 с ViT-backbone было показано, что разрешение 256×256 достигает SOTA-результатов при значительно меньших вычислительных затратах, а переход к 512×512 даёт прирост лишь ~6.67% по R@1 при четырёхкратном увеличении потребления ресурсов — что делает его непрактичным для БПЛА. [MDPI](https://www.mdpi.com/2072-4292/15/19/4667) При этом Sample4Geo и ConGeo ресайзят изображения до 384×384 для спутниковых видов [arXiv](https://arxiv.org/html/2403.13965v2), а TransGeo за счёт attention-guided non-uniform cropping удаляет неинформативные патчи из аэроснимков, перенаправляя сэкономленные вычисления на увеличение разрешения важных областей [arXiv](https://arxiv.org/html/2406.09722v1) — то есть даже при номинальном входе 256×256 модель фактически «зумит» в полезные регионы.
|
||||
|
||||
Для вашей задачи с развёртыванием на Jetson Orin это критически важная находка: **256×256 — оптимальный размер для модели геолокализации**, и вот почему.
|
||||
|
||||
Во-первых, вычислительный бюджет. TransGeo с чистым трансформерным backbone (SAIG — всего 18.2M параметров против 44.9M у TransGeo) демонстрирует меньшие требования к GPU-памяти и времени инференса, чем CNN-аналоги [ResearchGate](https://www.researchgate.net/publication/363906289_TransGeo_Transformer_Is_All_You_Need_for_Cross-view_Image_Geo-localization). На Jetson Orin Nano 8GB с разделяемой памятью у вас остаётся ~5–6 ГБ на всё, включая и вспомогательные модели (глубина, сегментация), и саму модель геолокализации. При 256×256 ViT-based модель с 18–25M параметров в TensorRT FP16 займёт ~200–400 МБ — это вполне укладывается в бюджет.
|
||||
|
||||
Во-вторых, природа данных. Датасеты University-1652 и SUES-200 содержат изображения дронов и спутников, где тренировочные изображения кропаются до разрешения 256×256×3 [PubMed Central](https://pmc.ncbi.nlm.nih.gov/articles/PMC11548418/). Это значит, что предобученные веса моделей оптимизированы именно под этот размер. Переход на 384 потребует либо переобучения, либо интерполяции позиционных эмбеддингов (для ViT), что на практике даёт нестабильные результаты без fine-tuning.
|
||||
|
||||
В-третьих, архитектура пайплайна. Ваши вспомогательные каналы (глубина, нормали, сегментация) можно подавать на вход геолокализационной модели двумя способами: как дополнительные каналы к RGB (тогда вход становится 256×256×N), либо как отдельные эмбеддинги через multi-modal fusion. В обоих случаях **все модули должны работать на одном и том же разрешении** — и 256×256 позволяет уместить весь пайплайн на Jetson.
|
||||
|
||||
Итоговая рекомендация для вашей системы: **обучайте и тестируйте всё на 256×256**. Вспомогательные модели (DA V2 Small для глубины, Sobel для нормалей, SegFormer-B0 для сегментации) генерируют карты 256×256, которые конкатенируются с RGB и подаются в geo-localization backbone (SAIG или ConvNeXt-Tiny через Sample4Geo). При этом размер 256 кратен и 14 (для ViT patch size), и 16 (для CNN stride), и 32 (для любого стандартного encoder'а), что исключает артефакты ресайза. На Jetson Orin 8GB такой пайплайн должен укладываться в ~2–3 ГБ GPU-памяти с TensorRT FP16, оставляя запас для системных процессов.
|
||||
|
||||
|
||||
**Размер входа**: 256×256 вместо 384×384. Это стандарт для University-1652, SUES-200, CVUSA — датасетов, на которых обучаются и тестируются Sample4Geo, TransGeo, SAIG и ConGeo. Число 256 кратно одновременно 14 (ViT patch), 16 (CNN stride) и 32 (encoder stride), что исключает артефакты интерполяции в любой архитектуре.
|
||||
|
||||
**Три профиля оборудования** (`--profile rtx4090 / jetson8 / jetson4`): каждый профиль автоматически выбирает подходящие модели и батчи. На RTX 4090 ставятся тяжёлые модели (DA V2 Large + DSINE + SegFormer-B5), на Jetson — лёгкие (DA V2 Small + Sobel + SegFormer-B0).
|
||||
|
||||
**Нормали через Sobel**: для Jetson вместо отдельной нейросети нормали вычисляются из карты глубины через Sobel-фильтры — это ~1 мс на CPU и 0 МБ дополнительной GPU-памяти. Формула простая: `n = normalize(-dz/dx, -dz/dy, 1)`.
|
||||
|
||||
**8-канальный выход** `{filename}_8ch.npy` — тензор `[8, 256, 256]` для прямой конкатенации с входом модели геолокализации: RGB(3) + Depth(1) + Normals(3) + SegID(1). При 256×256 весь пайплайн вспомогательных каналов занимает на Jetson 8GB всего ~280 МБ пиковой памяти, оставляя ~5.6 ГБ для самой модели геолокализации (SAIG ~18M params или Sample4Geo с ConvNeXt-Tiny).
|
||||
|
||||
#dataset/cvusa #dataset/sues200 #dataset/univ1652 #method/quantization #task/code
|
||||
Reference in New Issue
Block a user