Add dataloaders (v1/v2), analysis scripts, and documentation for working with UAV-GeoLoc (World-UAV). Co-authored-by: Cursor <cursoragent@cursor.com>
7.9 KiB
World-UAV-prepro
Эта папка — мой слой препроцесса/аналитики поверх датасета UAV-GeoLoc (World-UAV).
Здесь нет обучения моделей. Основные артефакты:
dataloader.py: компактный PyTorchDataset/DataLoaderдля train/eval по индекс-файламIndex/*.txt.dataloader_v2.py: расширенная версия лоадера с парсингом метаданных (height/rotation), утилитами GPS/локализационной ошибки и scene-based лоадером для кастомных сплитов.analyze/: оффлайн-скрипты, которые проверяют структуру датасета, схему нарезки спутника, и генерируют графики/примерные картинки.
Формат данных (ожидаемая структура датасета)
Оба лоадера предполагают, что корень датасета (root) выглядит примерно так:
<root>/
Country/...
Terrain/...
Rot/...
Index/
train_query.txt
train_db.txt
val_query.txt
val_db.txt
test_query.txt
test_db.txt
... и варианты *_country.txt, *_all.txt
На уровне сцены (примерно):
<root>/Terrain/<TerrainType>/<SceneName>/
positive.json
semi_positive.json
DB/
merge.tif
db_postion.txt
img/crop_X_Y.png
query/
height100_rot0/footage/*.jpeg
...
Index-файлы (ключевой интерфейс)
DB index (*_db*.txt)
По 1 пути на строку, путь относительно root:
Terrain/Mountain/Andes/DB/img/crop_0_0.png
Terrain/Mountain/Andes/DB/img/crop_0_1.png
...
Query index (*_query*.txt)
Формат строки:
<query_path> <scene_label_int> <positive_db_1> [positive_db_2 ...]
Пример:
Terrain/Mountain/Andes/query/height100_rot0/footage/height100_rot0_00.jpeg 12 Terrain/Mountain/Andes/DB/img/crop_10_7.png Terrain/Mountain/Andes/DB/img/crop_10_8.png
Важно: в путях могут встречаться пробелы (в вариантах/папках). Парсер в обоих лоадерах извлекает DB-пути по паттерну */DB/img/crop_*.png, а label берёт как последний числовой токен перед DB-путями.
dataloader.py (базовый)
Что даёт
- Train:
UAVGeoLocTrain:(query, positive, negative)triplets (негатив берётся случайно изtrain_db.txt, исключая positives этого scene label).UAVGeoLocPair:(query, positive)пары (под contrastive без explicit negative).
- Eval:
UAVGeoLocEval(mode="query"): одиночные query-изображения +label+ списокpositives.UAVGeoLocEval(mode="db"): одиночные DB-изображения.eval_collate_fn: collate, который оставляетpositivesсписком (variable-length).
build_dataloaders(...): собирает набор лоадеров на train/val/test.
Мини-пример использования
from dataloader import build_dataloaders
root = "/path/to/UAV-GeoLoc"
loaders = build_dataloaders(root, split="terrain", batch_size=32, img_size=512, num_workers=4, mode="triplet")
batch = next(iter(loaders["train"]))
print(batch["query"].shape, batch["positive"].shape, batch["negative"].shape, batch["label"])
dataloader_v2.py (расширенный)
Отличия от базовой версии
- Метаданные query:
- парсит
heightиrotationиз пути видаheight125_rot270/.... - возвращает их в батчах train/eval.
- парсит
- GPS / локализационная ошибка:
load_db_positions(...),haversine_m(...)compute_localization_error(...): метрики ошибки в метрах по retrieval predictions (top-1 индексы DB).
- Утилита нарезки спутника:
tile_satellite_image(...): генерирует кропы в стиле UAV-GeoLoc (stride по умолчаниюcrop_size // 2).
- Scene-based loader:
UAVGeoLocScene(scene_dir=...): читает сцену напрямую из папки (безIndex/*.txt), удобно для кастомных выборок/проверок (в т.ч. Rot subset).build_rot_loader(...): convenience лоадер дляRot/SouthernSuburbs.
Мини-пример: посчитать error (м) по top-1 предсказаниям
import numpy as np
from dataloader_v2 import build_dataloaders, compute_localization_error
root = "/path/to/UAV-GeoLoc"
loaders = build_dataloaders(root, split="terrain", batch_size=64, img_size=224, num_workers=4, mode="triplet")
q_ds = loaders["test_query"].dataset
d_ds = loaders["test_db"].dataset
# допустим, у вас есть top1 predictions как индексы DB:
pred = np.zeros(len(q_ds), dtype=np.int64)
stats = compute_localization_error(q_ds, d_ds, pred)
print(stats["mean_error_m"], stats["median_error_m"], stats["num_evaluated"])
Какой лоадер использовать
- Бери
dataloader.py, если тебе нужен минимальный, предсказуемый интерфейс:- train triplets/pairs
- eval query/db
- без метаданных и без геометрии/географии
- Бери
dataloader_v2.py, если:- в модели/логах важно
heightиrotation(например, для condition/аблаций) - хочешь считать ошибку локализации в метрах (по
db_postion.txt) - нужно грузить сцены напрямую из папки (без
Index/*.txt) или работать сRotsubset - нужен helper для tiling спутника
tile_satellite_image(...)
- в модели/логах важно
На практике: для базовых retrieval-экспериментов достаточно dataloader.py, а v2 — когда переходишь к “исследовательским” метрикам/контролю условий.
Какие Index/*.txt ожидаются для terrain/country/all
Оба лоадера используют один и тот же принцип: в Index/ лежат файлы вида:
train_query*.txt,train_db*.txtval_query*.txt,val_db*.txttest_query*.txt,test_db*.txt
Суффиксы:
terrain: суффикс пустой (train_query.txt,train_db.txt, …)country: суффикс_country(train_query_country.txt, …)all: суффикс_all(train_query_all.txt, …)
Fallback-логика в build_dataloaders
В dataloader.py и dataloader_v2.py build_dataloaders(...) делает сборку так:
- train: берёт строго
Index/train_query{suffix}.txtиIndex/train_db{suffix}.txtдля выбранногоsplit - val/test:
- сначала пытается открыть
Index/{phase}_query{suffix}.txt/Index/{phase}_db{suffix}.txt - если этих файлов нет, откатывается на несуффиксные
Index/{phase}_query.txt/Index/{phase}_db.txt
- сначала пытается открыть
Это удобно, если у тебя, например, train_*_country.txt есть, а val_*_country.txt ещё не сгенерен.
analyze/ (оффлайн анализ датасета)
Скрипты ориентированы на запуск “как есть”, но почти везде нужно поменять BASE/ROOT (путь к датасету).
Подробности см. analyze/README.md.