Files
caption-test/CLAUDE.md
pikaliov cb477f4b40 Simplify model: shared DINOv3 WEB + MONA in last 12/24 blocks
Three related architecture changes, driven by a cost/simplicity trade-off:

1. **Shared encoder**: one DINOv3 LVD-1689M (WEB) processes both drone
   and satellite images. Previously asymmetric — separate WEB (drone) and
   SAT-493M (satellite) encoders. Saves ~303M frozen params and halves
   VRAM for the image tower. Expected to lose some satellite-domain
   inductive bias; MONA adapters pick up the slack.

2. **MONA in last 12/24 blocks**: adapters injected only in the top half
   of the ViT. The lowest 12 blocks keep their pretrained features
   untouched. Trainable MONA count drops from 14.0M (48 adapters × 2
   encoders) to 3.5M (24 adapters × 1 encoder).

3. **No DINO_SAT**: `nn_models/DINO_SAT` is no longer loaded by the
   default config. It stays on disk and the path param is kept for
   backward compat with asymmetric checkpoints.

Parameter counts (with text fusion + LoRA + gates):
  Before: 17.6M trainable / 733M total (2.35%)
  After:   7.06M trainable / 434M total (1.63%)

Also fixes a pre-existing resume bug: checkpoints now record
`shared_encoder`, `baseline_mode`, `mona_bottleneck`, `mona_last_n_blocks`
so `AsymmetricEncoder.load_checkpoint` can rebuild the right architecture.
Old checkpoints still load (missing keys fall back to asymmetric defaults
via `ckpt.get(..., <default>)`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 16:26:17 +03:00

25 KiB
Raw Blame History

Caption Quality Test for Cross-View Geo-Localization

Архитектура системы (v3, 2026-04-24) — GTA-UAV эксперимент

Shared DINOv3 ViT-L/16 (LVD-1689M, frozen + MONA in last 12/24 blocks)
для обеих веток — drone и satellite кодируются одним encoder.

QUERY BRANCH (drone + L1/L2/L3 captions):
  drone_img [B,3,256,256] --> DINOv3 ViT-L/16 (shared) --> d_img [B,1024]
                                                                        |
  L1 --> DGTRS-CLIP (248 tok) --> z₁ [768] --\                         |
  L2 --> DGTRS-CLIP (248 tok) --> z₂ [768] ---+-- cat --> MLP(2304→1024→1024) --> d_txt [B,1024]
  L3 --> DGTRS-CLIP (248 tok) --> z₃ [768] --/                         |
                                                                        |
                    q = σ(α_q)·d_img + (1σ(α_q))·d_txt   GatedFusion_q
                                        |
                                  q̂ = q/‖q‖₂ --> query [B,1024]

GALLERY BRANCH (satellite + satellite captions):
  sat_img [B,3,256,256] --> DINOv3 ViT-L/16 (shared, same weights) --> s_img [B,1024]
                                                                      |
  sat_L1 --> DGTRS-CLIP --> z₁ --\                                    |
  sat_L2 --> DGTRS-CLIP --> z₂ ---+-- cat --> MLP (shared) --> s_txt [B,1024]
  sat_L3 --> DGTRS-CLIP --> z₃ --/                                    |
                                                                      |
                    g = σ(α_g)·s_img + (1σ(α_g))·s_txt   GatedFusion_g
                                        |
                                  ĝ = g/‖g‖₂ --> gallery [B,1024]

Retrieval space: 1024-dim (DINOv3 native, без projection layers)
TextFusionMLP shared между query и gallery (одинаковый формат captions)
Для sat images без captions: s_txt=None → g = s_img (gate passthrough)

LOSS: L = 0.6·CE(q̂·ĝᵀ/τ, targets) + 0.4·CE(ĝ·q̂ᵀ/τ, targets)
      τ = 1/exp(logit_scale), learnable, clamped [0.01, 0.1], init=0.07
      label_smoothing=0.1

BATCH SAMPLING: MutuallyExclusiveSampler — в одном батче нет двух drone'ов
      с пересекающимися sat_candidates (исключает false negatives, которые
      иначе появляются из-за multi-positive структуры GTA-UAV).

BASELINE: σ(α_q)=σ(α_g)=1.0, text disabled, DGTRS not loaded

Text hierarchy (L1/L2/L3)

  • L1 overview: первое предложение P1 — краткое описание land-cover (15-30 tok)
  • L2 full: полные P1 + P2 — inventory + spatial layout (100-200 tok)
  • L3 fingerprint: P3 — уникальные landmarks для matching (20-50 tok)
  • Fusion: z_text = MLP([z₁; z₂; z₃]) — concat 3×768 → Linear(2304,1024) → GELU → Linear(1024,1024)
  • Shared MLP между query и gallery ветками (одинаковый формат captions)
  • Satellite captions: 6,546 из 14,640 sat images имеют captions. Для остальных gate passthrough (g = s_img) — per-sample mask в _fuse_with_mask возвращает чистые image features для samples без caption (без шума от пустых строк)

Text encoder: DGTRS-CLIP (official architecture)

  • Код: src/models/dgtrs/ — из github.com/MitsuiChen14/DGTRS (Apache-2.0)
  • KPS positional embedding: mask1 (pos 0-19, frozen) + mask2 (pos 20-247, trainable)
  • Transformer: sequence-first (LND), nn.MultiheadAttention, 12 layers
  • Tokenizer: BPE SimpleTokenizer (248 tokens, vocab 49408)

Trainable parameters: 7.06M из 434M (1.63%)

  • MONA adapters (shared DINOv3): 3.5M (2 per block × 12 last blocks, bottleneck=64)
  • LoRA (DGTRS-CLIP): 147K (Q+V, rank=4, 12 blocks)
  • TextFusionMLP (shared): Linear(2304,1024)+GELU+Linear(1024,1024) = ~3.4M
  • gate α_q + α_g: 2 scalars
  • logit_scale: 1 scalar (learnable temperature)
  • DINOv3 (1 encoder) + DGTRS: frozen backbone weights
  • Без projection layers — retrieval space = DINOv3 native 1024-dim
  • AMP: frozen layers fp16, adapters + loss fp32
  • Примечание: ранее была asymmetric setup (2×DINOv3 WEB+SAT, MONA во всех 24 блоках) с 17.6M trainable / 733M total. Упростили до shared + last-12 MONA.

Optimizer & Scheduler

  • AdamW с per-group LR: projections lr=1e-4, text encoder lr=1e-5
  • Linear warmup (2 epochs) + cosine annealing (per-step)
  • Gradient clipping: max_norm=1.0
  • AMP: fp16 для model forward, fp32 для loss (learnable temperature overflow fix)

Image input: 256x256

DINOv3 ViT-L/16 с patch_size=16 → 16x16=256 patches на 256x256. Train: augmentations (drone: crop+flip+rot+jitter+blur, sat: crop+flip+jitter). Eval: Resize(256) + CenterCrop(256) + ImageNet normalization.

Предыдущая архитектура (v2) — UAV-GeoLoc эксперимент

Использовала GeoRSCLIP ViT-B/32 (512-dim) для обеих веток + template captions. Код в src/models/dual_encoder.py, src/datasets/visloc_with_captions.py.

Ключевые файлы

V2 (UAV-GeoLoc, GeoRSCLIP)

Файл Назначение
src/models/dual_encoder.py GeoRSCLIP + GatedFusion + projection heads
src/losses/multi_infonce.py InfoNCE с cosine temperature schedule
src/datasets/visloc_with_captions.py UAV-GeoLoc loader + template captions из path metadata
src/training/train.py Training loop, логирование loss/gate/tau
src/eval/evaluate.py R@K metrics, delta_r_at_1
scripts/compare_runs.py Markdown/JSON сравнение baseline vs caption runs
scripts/generate_captions.py Offline caption generation (template/VLM/hybrid)

V3 (GTA-UAV, DINOv3 + DGTRS-CLIP) — DONE

Файл Назначение
src/models/dgtrs/model.py Официальная архитектура DGTRS-CLIP text encoder (Apache-2.0)
src/models/dgtrs/simple_tokenizer.py BPE tokenizer (248 tokens, vocab 49408)
src/models/asymmetric_encoder.py DINOv3ViT + TextFusionMLP + AsymmetricEncoder + GatedFusion + encode_query/encode_gallery (per-sample caption mask)
src/datasets/gtauav_dataset.py GTA-UAV-LR loader + L1/L2/L3 captions + GTAUAVSatGallery/GTAUAVDroneQuery (full retrieval eval)
src/datasets/mutually_exclusive_sampler.py BatchSampler: drone'ы в батче не делят sat_candidates (no false negatives)
src/datasets/dynamic_similarity_sampler.py DSS: embedding-kNN + mutex — батчи из визуально похожих drone'ов (GPU/CPU, опциональный LSH)
src/datasets/lsh_index.py Random-projection cosine-LSH для approximate kNN (opt-in; dss_use_lsh=True)
src/datasets/embedding_cache.py Дисковый кеш для drone embeddings — skip re-embed на resume
src/losses/multi_infonce.py Primary: SymmetricInfoNCE + MoCo queue, learnable τ clamp [0.01, 0.1], weights q2g=0.6 g2q=0.4, hard_mining_k для top-K hardest negatives
src/losses/weighted_infonce.py Alternative: per-sample adaptive label smoothing (активируется loss_type="weighted")
src/losses/hard_negatives.py NegativeMemoryBank (MoCo-style FIFO queue 4096 × 1024)
src/training/train_gtauav.py Training loop: full-gallery _evaluate, mutex sampler wiring, loss_type switch
scripts/smoke_eval.py / scripts/smoke_train.py Регрессионные smoke-тесты для eval и train pipeline
src/training/trackers.py Unified experiment tracker: W&B + TensorBoard + CSV
src/training/grad_monitor.py Gradient norm monitoring per param group
src/training/gradcam.py Grad-CAM visualization для DINOv3 encoders
src/training/profiling.py PyTorch Profiler wrapper + torchinfo model summary
src/training/plot_metrics.py Seaborn/matplotlib plots (каждую эпоху)
conf/gtauav_balanced.gin With text, gate=0.7, 10 epochs
conf/gtauav_baseline.gin No text, gate=1.0
conf/gtauav_text_heavy.gin Text-heavy, gate=0.3
conf/gtauav_image_heavy.gin Image-heavy, gate=0.9
scripts/make_split.py 80/20 random split из всех пар
scripts/filter_segmentation.py Scan segm masks, output meta JSON (exclude >=90% bg+water)

Backbones (v3)

DINOv3 ViT-L/16 — Shared (web pretrained)

  • Checkpoint: nn_models/DINO_WEB/dinov3-vitl16-pretrain-lvd1689m.pth
  • Arch: ViT-L/16, 24 layers, 16 heads, hidden=1024, MLP=4096, 303M params
  • Input: 256x256, ImageNet normalization, patch=16 → 256 patches
  • Register tokens: 4, RoPE theta=100.0
  • MONA: 24 адаптера в последних 12 блоках (blocks 12-23), bottleneck=64, 3.5M trainable
  • Status: frozen кроме MONA
  • Примечание: ранее asymmetric — использовался отдельно nn_models/DINO_SAT/model.safetensors (sat493m pretrain) для satellite ветки. Упростили до shared WEB-энкодера.

DGTRS-CLIP ViT-L-14 (LRSCLIP) — Text encoder

  • Checkpoint: nn_models/LRSCLIP/DGTRS-CLIP-ViT-L-14.pt
  • Код: src/models/dgtrs/ — официальная архитектура из github.com/MitsuiChen14/DGTRS
  • Text dim: 768, max tokens: 248 (KPS: mask1 pos 0-19 frozen + mask2 pos 20-247 trainable)
  • Transformer: 12 layers, 12 heads, sequence-first (LND), QuickGELU
  • Tokenizer: BPE SimpleTokenizer (vocab 49408), 248 token context
  • Содержит: полную CLIP модель (visual + text), используем только text encoder (124M params)
  • Status: partial unfreeze (last resblock + ln_final + text_projection, ~7.6M trainable)

GeoRSCLIP ViT-B/32 (v2, legacy)

  • Checkpoint: checkpoints/RS5M_ViT-B-32.pt
  • Image encoder: ViT-B/32, 224x224, 512-dim, ~86M params — frozen
  • Text encoder: 77 tokens, 512-dim — partial unfreeze

GatedFusion

  • query = sigma(alpha) * drone_feat + (1 - sigma(alpha)) * text_feat
  • alpha — один learnable scalar в logit-space
  • init_gate = 0.7 → начальный вес image = 70%, text = 30%
  • baseline_mode = True → gate = 1.0, text полностью игнорируется
  • Gate value логируется каждую эпоху для интерпретации вклада текста

Text Hierarchy (L1/L2/L3)

Три уровня описаний из VLM-generated captions:

Уровень Контент Длина Источник
L1 overview Краткое описание сцены <=30 tok Конденсация P1
L2 full description Детальное описание через Qwen3-VL <=200 tok Полный P1+P2
L3 fingerprint Ключевые landmark'ы <=30 tok Конденсация P3

Все три уровня кодируются одним LRSCLIP (248 tok max). Альтернатива (Stage 2): RemoteCLIP для L1/L3 + LRSCLIP для L2.

Датасет: GTA-UAV-LR

  • RGB: /home/servml/Документы/datasets/GTA-UAV-LR/

    • Drone: 33,763 PNG (512x384), altitudes 100-600m
    • Satellite: 14,640 PNG (256x256 RGBA)
    • Pairs: cross-area-drone2sate-{train,test}.json (primary split)
    • Metadata: *_drone_meta.csv (height, yaw, roll, pitch)
    • Origin: GTA V simulation (Los Santos)
  • Captions: /home/servml/Документы/datasets/GTA-UAV-LR-captions/

    • Drone: 33,411 JSON (32,635 multi-paragraph P1/P2/P3 + 776 short water-only)
    • Satellite: 6,546 JSON (все multi-paragraph)
    • Формат: 3 абзаца (P1 Inventory + P2 Spatial + P3 Fingerprint)
    • Token counts: ~430 output tokens per caption
  • Segmentation: /home/servml/Документы/datasets/GTA-UAV-LR-aug/

    • 48,403 images, 17 классов (background, building, road, vegetation, water, ...)
    • Modalities: segm/, depth/, edge/, chm/, safetensors/
    • Query: 512x512, DB: 256x256

Фильтрация сегментации

Meta-файл meta/seg_filter.json: исключение изображений с >=90% background(class 0) + water(class 4).

  • Total: 48,403 → Passed: 37,498 (77.5%) / Excluded: 10,905 (22.5%)
  • Drone: 31,188 passed / 2,575 excluded
  • Satellite: 6,310 passed / 8,330 excluded (преимущественно open water tiles)

Датасет: UAV-GeoLoc (v2, legacy)

  • Путь: /mnt/data1tb/cvgl_datasets/UAV-GeoLoc/
  • Train: 206,108 queries, 94,709 DB crops (140 scenes, Terrain split)
  • Val: 62,368 queries, 26,597 DB crops (40 scenes)
  • Test: 33,472 queries, 11,684 DB crops (20 scenes)
  • Index: Index/train_query.txtquery_path 0 pos_crop1 pos_crop2 ...

Конфигурации

V3 (GTA-UAV)

Параметры:

  • 10 epochs, batch 64, AMP, image 256x256
  • Optimizer: AdamW, per-group LR: proj=1e-4, text=1e-5 (10x lower)
  • Scheduler: linear warmup (2 epochs) + cosine annealing (per-step)
  • Loss: SymmetricInfoNCE (q2g=0.6, g2q=0.4) с learnable τ (init=0.07, clamp [0.01, 0.1])
  • Hard mining: top-K=512 hardest negatives per query из MoCo queue (размер 4096); hard_mining_k=0 отключает
  • Batch sampler: sampler_type="dss" (default) — DynamicSimilaritySampler с re-embedding каждую эпоху: пакует визуально похожих drone'ов в один батч (+hardness) с mutex-constraint (no false negatives). Первая эпоха warmup mutex-only. Средний in-batch cosine sim ~0.71 vs 0.26 у mutex. kNN на GPU (dss_knn_device="cuda") — 1.6s vs 17s на CPU. Опциональный LSH (dss_use_lsh=True) для scale 100K+. Embedding cache (dss_cache_dir) — skip re-embed на resume.
  • Eval: full satellite gallery (~2684 unique tiles для test_20) с multi-match R@K (учитывает все positive/semi-positive)
  • Augmentations:
    • Drone: RandomResizedCrop(0.7-1.0), HFlip, Rotation(15°), ColorJitter, Grayscale(5%), GaussianBlur
    • Satellite: RandomResizedCrop(0.7-1.0), HFlip, ColorJitter, Grayscale(5%)
    • Eval: Resize+CenterCrop (clean, no augmentation)
  • Split: 80/20 random из всех 33,708 пар (meta/train_80.json / meta/test_20.json)
  • Train: 26,966 → 24,891 after seg filter
  • Test: 6,742 → 6,252 after seg filter
  • Скрипт: python -m scripts.make_split --ratio 0.8 --seed 42

V3 (GTA-UAV, gin)

Конфиг Gate init Описание
conf/gtauav_balanced.gin 0.7 (30% text) Primary test
conf/gtauav_baseline.gin 1.0 (no text) Reference baseline
conf/gtauav_text_heavy.gin 0.3 (70% text) Stress test
conf/gtauav_image_heavy.gin 0.9 (10% text) Image-dominant

V2 (UAV-GeoLoc, gin)

Конфиг Gate init Описание
conf/balanced.gin 0.7 (30% text) Primary test
conf/baseline_no_text.gin 1.0 (no text) Reference baseline
conf/text_heavy.gin 0.3 (70% text) Stress test

Запуск

V3 (GTA-UAV)

# 1. Filter segmentation (exclude 90%+ background/water)
python -m scripts.filter_segmentation --output meta/seg_filter.json

# 2. Train with gin config (recommended)
python -m src.training.train_gtauav --config conf/gtauav_balanced.gin \
    --filter-meta meta/seg_filter.json

# 3. Baseline (no text)
python -m src.training.train_gtauav --config conf/gtauav_baseline.gin \
    --filter-meta meta/seg_filter.json

# 4. With diagnostics (W&B + Grad-CAM + Profiler)
python -m src.training.train_gtauav --config conf/gtauav_balanced.gin \
    --filter-meta meta/seg_filter.json --wandb --gradcam --profile

# 5. CLI overrides (gin params take priority)
python -m src.training.train_gtauav --config conf/gtauav_balanced.gin \
    --filter-meta meta/seg_filter.json \
    --gin-param 'TrainConfigGTAUAV.batch_size=16'

# 6. Compare
python -m scripts.compare_runs \
    --baseline_report out/gtauav/baseline/eval_report.json \
    --full_report out/gtauav/with_text/eval_report.json \
    --output out/gtauav/comparison.md

# 7. TensorBoard
tensorboard --logdir out/gtauav/with_text/tb_logs

V2 (UAV-GeoLoc)

python -m src.training.train --config conf/baseline_no_text.gin
python -m src.training.train --config conf/balanced.gin
python -m scripts.compare_runs \
    --baseline_report out/caption_test/baseline_no_text/eval_report.json \
    --full_report out/caption_test/balanced/eval_report.json \
    --output out/caption_test/comparison.md

Метрики и Decision rule

Primary metric: Delta R@1 (drone -> satellite)

Delta R@1 Verdict
>= +3% PASS — captions informative, proceed to production
+1% to +3% MARGINAL — add VLM refinement, re-run
0 to +1% WEAK — redesign caption pipeline
< 0 HARMFUL — critical bug

Eval metrics: R@1, R@5, R@10 для drone->satellite и satellite->drone Splits (GTA-UAV): cross-area (primary, harder) и same-area (sanity check) Logged per epoch: loss, temperature (tau), gate value (sigma(alpha)), lr

Бюджет времени (RTX 4090, 24 GB)

V3 (GTA-UAV, DINOv3 ViT-L/16, 256x256)

Фаза Оценка
VRAM: DINOv3-L (shared) + LRSCLIP + batch 64 ~10-14 GB (было ~18-22 с 2× DINOv3)
GPU mem (smoke test, batch 4) 3.1 GB
Batch size 64 (default)
Total params 434M (7.06M trainable, 1.63%) — shared encoder + MONA в last 12/24 blocks

V2 (UAV-GeoLoc, GeoRSCLIP)

Фаза Время
Один training run (10 epochs, 206K queries, batch 128) ~15-30 мин
Full test (3 варианта) ~1-1.5 ч
Evaluation per run ~2-5 мин

Связанные проекты

Text Annotation Pipeline

  • Путь: /home/servml/Документы/pikaliov_obsidian/(Полякова ВЕ_Система для генерации текстовых описаний для БПЛА)/2_work/2_text_annotation/code/
  • VLM: Qwen3-VL-8B AWQ (1.68 s/img)
  • Scoring: SigLIP 2 (drone P3) + CLIP-RSICD (satellite P1+P2)
  • Формат описаний: 3 абзаца (P1 Inventory + P2 Spatial Map + P3 Fingerprint)
  • Метрики: FDR, FNR, NumAcc, LLaVA-Critic C1-C6

UAV-VisLoc Prepare

  • Путь: /home/servml/Документы/code/Yaroslav/UAV-VisLoc-prepare/scripts/prepare_dataset.py
  • Статус: выполнен (2026-04-17), данные в /home/servml/Документы/datasets/UAV_VisLoc_processed/ (25 GB)
  • Задача: нарезка satellite кропов 512x512, stride 256 + resize drone -> 512x512
  • Подробности: см. ниже

Downstream: NADEZHDA Teacher (DINOv3 + Multi-FiLM)

caption-test — первый этап валидации. При Δ R@1 >= +3% переход к полному teacher'у:

Этап 1 (caption-test): GeoRSCLIP + GatedFusion(text) → валидация текста
Этап 2 (teacher):      DINOv3-L + Multi-FiLM(depth, seg, CHM, normals, text)
Этап 3 (distillation): teacher ~300M → student ~5M → Jetson Orin NX

Auxiliary modalities (предвычисляются из 512x512 офлайн)

Модальность Модель Формат для teacher Каналы
Depth DepthAnything V2 continuous, log(1+d) 1
Normals Sobel от depth continuous 3
Segmentation SegFormer-B5 binary per-class masks (top-K) 16-17
Canopy Height Meta HRCH binary bins (1-5m, 5-15m, >15m) + occupancy 4-5
Text Qwen3-VL-8B / MobileCLIP2 embedding -

Асимметрия sat/drone

  • CHM: только satellite (модель обучена на nadir, на oblique drone не работает)
  • Satellite: ~27 aux каналов, Drone: ~21 aux каналов

Fusion: Multi-FiLM

aux_features → FiLM(γ, β) → γ * DINOv3_tokens + β

Binary masks — natural FiLM gates. Modality dropout: text 0.3, CHM 0.5, seg 0.15, depth 0.1.

Планируемый эксперимент H5

Сравнение T_bin (binary masks) vs T_pyr (native feature pyramids) vs T_hybrid. Прогноз: binary masks лучше на cross-domain из-за робастности к aux-model artifacts.


Датасеты (справочник)

UAV-VisLoc

  • Путь: /home/servml/Документы/datasets/UAV_VisLoc_dataset/
  • Структура: 11 маршрутов (папки 01-11), каждая содержит:
    • drone/ — drone-снимки (XX_NNNN.JPG)
    • satelliteXX.tif — спутниковая карта
    • XX.csv — GPS-метаданные drone (num, filename, date, lat, lon, height, Omega, Kappa, Phi1, Phi2)
  • Исключение: маршрут 09 — спутник разбит на 4 тайла (satellite09_01-01.tif и т.д.)
  • Satellite coordinates: satellite_ coordinates_range.csv — bbox каждой карты (LT_lat_map, LT_lon_map, RB_lat_map, RB_lon_map)
  • Splits: visloc_train.csv, visloc_test.csv — списки drone-снимков (TSV, full absolute paths)
  • Размеры: Drone 3976x2652 / 3000x2000 (6774 снимков), Satellite от 3000x170 до 43421x38408
  • GSD спутника: ~0.30 м/px (единый zoom level Google Earth для всех карт). GSD по долготе варьируется 0.23-0.27 м/px из-за косинусного эффекта широты (40°N vs 25°N), но это не разная высота съёмки. Кроп 512x512 покрывает ~154x154 м везде.

UAV-GeoLoc

  • Путь: /mnt/data1tb/cvgl_datasets/UAV-GeoLoc/
  • Подмножества: Country (171 scene), Terrain (200 scenes), Rot (1 scene)
  • Формат пар: positive.json, semi_positive.json, db_postion.txt
  • Index: train_query.txtquery_path label pos_crop1 pos_crop2 ...
  • Drone: синтетика Google Earth Studio 3D, 512x512, FOV 30deg, heights 100/125/150m
  • Satellite: кропы из merge.tif, доминирующий размер 200x200

Скрипт подготовки UAV-VisLoc

  • Путь: /home/servml/Документы/code/Yaroslav/UAV-VisLoc-prepare/scripts/prepare_dataset.py
  • Статус: выполнен (2026-04-17)

Запуск

python scripts/prepare_dataset.py \
    --src /home/servml/Документы/datasets/UAV_VisLoc_dataset \
    --dst /home/servml/Документы/datasets/UAV_VisLoc_processed \
    --crop-size 512 --stride 256 --target-size 512

Pipeline

  1. Resize drone -> 512x512 (JPEG, quality=95)
  2. Stitch satellite tiles для маршрута 09 (4 тайла -> 44800x33280)
  3. Нарезка satellite -> кропы 512x512, stride 256, сохранение без downscale (PNG)
  4. GPS для каждого кропа из bbox карты + позиция в grid
  5. Match drone->crop через vectorized haversine (positive = ближайший, semi-positive = +/-1 в grid)
  6. Metadata: positive.json, semi_positive.json, db_postion.txt (per route)
  7. Index: train_query.txt, test_query.txt, train_db.txt, test_db.txt, all_db.txt

Форматы выходных файлов (совместимость с UAV-GeoLoc)

Файл Формат
positive.json {frame_id: [crop_name]}, ключ = frame ID без route prefix ("0001")
semi_positive.json {frame_id: [crop1, crop2, ...]}, соседи +/-1 в grid
db_postion.txt tab-separated: name\tlon\tlat\tscale_lon\tscale_lat
train_query.txt route/drone/file.JPG 0 route/DB/img/crop1.png ...
train_db.txt / test_db.txt все кропы всех маршрутов (gallery одинаковая, split по query)

Результаты (target-size 512)

  • Drone: 6,744 images 512x512 (без маршрута 07: 30 excluded)
  • Satellite кропов: 74,807 (512x512, без downscale)
  • Размер на диске: 25 GB
  • Median distance drone->crop: 25.9m, P99: 45.7m
  • Память при генерации: до ~8.7 GB RAM (маршрут 09 stitched 44800x33280)
  • Разрешение 512 для downstream задач (сегментация, depth, normals); resize до 256x256 в dataloader

Ревью и исправления (2026-04-17)

  1. train_db.txt/test_db.txt содержали только matched кропы -> теперь все ~74K (полная gallery)
  2. db_position.txt -> db_postion.txt (совместимость с UAV-GeoLoc), добавлены scale_lon/scale_lat, tab-separator
  3. positive.json ключи были filename (01_0001.JPG) -> теперь frame_id (0001)
  4. Semi-positive поиск O(n) -> O(1) через dict lookup по (x,y) grid
  5. Удален мёртвый код (haversine_m, defaultdict import)

Известные ограничения

  • Нет val split (только train/test, как в оригинальном UAV-VisLoc)
  • 6 drone в маршруте 06 (06_0093-06_0098) за пределами спутниковой карты (distance >1000m)
  • Большие спутниковые карты загружаются целиком в RAM при генерации (до 8.7 GB для route 09)