claude_refactor_v3: Updated main (entry point), trainer_new (last version of train_gtauav), check: is extracted evluate() from train to evaluator.py correct in new context

This commit is contained in:
pikaliov
2026-05-05 11:28:09 +03:00
parent 4e148a29bb
commit 248bd331d2
4 changed files with 1321 additions and 26 deletions

View File

@@ -6,12 +6,10 @@ Computes R@K and MRR for both q→g (drone→satellite) and g→q (satellite→d
on the full satellite gallery. Multi-match: a query counts as a hit@K if ANY on the full satellite gallery. Multi-match: a query counts as a hit@K if ANY
of its valid satellite matches (sat_candidates) appears in the top-K. of its valid satellite matches (sat_candidates) appears in the top-K.
Body transplanted from src/training/train_gtauav.py::_evaluate (pre-step-4b) Body transplanted byte-for-byte from src/training/train_gtauav.py::_evaluate
with two changes: in the main branch. The single difference is the type annotation
1. Decorator @torch.no_grad() → @torch.inference_mode(). `model: AsymmetricEncoder` → `model: nn.Module` (relaxed for duck-typing
2. Type annotation `model: AsymmetricEncoder` → `model: nn.Module` across encoder families); semantically identical to the main-branch version.
(any encoder with encode_query/encode_gallery + fusion_query.gate_value
and fusion_gallery.gate_value duck-typed attributes).
Note: not to be confused with src/eval/evaluate.py (legacy v2 helper for Note: not to be confused with src/eval/evaluate.py (legacy v2 helper for
UAV-VisLoc with a different signature). This module lives at UAV-VisLoc with a different signature). This module lives at
@@ -19,13 +17,13 @@ src/eval/evaluator.py and is the active evaluator for v3 GTA-UAV-LR.
""" """
import logging import logging
from typing import Any
import torch import torch
import torch.nn as nn import torch.nn as nn
from torch.utils.data import DataLoader from torch.utils.data import DataLoader
from tqdm import tqdm from tqdm import tqdm
from src.models.asymmetric_encoder import AsymmetricEncoder
from src.datasets.gtauav_dataset import ( from src.datasets.gtauav_dataset import (
GTAUAVDataset, GTAUAVDataset,
GTAUAVDroneQuery, GTAUAVDroneQuery,
@@ -37,9 +35,9 @@ from src.datasets.gtauav_dataset import (
LOGGER = logging.getLogger("caption_test.evaluator") LOGGER = logging.getLogger("caption_test.evaluator")
@torch.inference_mode() @torch.no_grad()
def evaluate( def evaluate(
model: nn.Module, model: AsymmetricEncoder,
loader: DataLoader, loader: DataLoader,
device: str, device: str,
loss_fn: nn.Module | None = None, loss_fn: nn.Module | None = None,
@@ -57,8 +55,11 @@ def evaluate(
satellite matches (pair_pos_sate_img_list pair_pos_semipos_sate_img_list) satellite matches (pair_pos_sate_img_list pair_pos_semipos_sate_img_list)
appears in the top-K. appears in the top-K.
`max_batches` subsamples the drone queries (not the gallery) — useful
for a quick train-side sanity check.
Args: Args:
model: Encoder with `encode_query(drone_img, l1, l2, l3, altitude=...)` model: Encoder with `encode_query(drone_img, l1, l2, l3)`
and `encode_gallery(sat_img, l1, l2, l3)`. Must expose and `encode_gallery(sat_img, l1, l2, l3)`. Must expose
`fusion_query.gate_value` and `fusion_gallery.gate_value`. `fusion_query.gate_value` and `fusion_gallery.gate_value`.
loader: DataLoader over a GTAUAVDataset (used only to pull dataset loader: DataLoader over a GTAUAVDataset (used only to pull dataset
@@ -133,13 +134,9 @@ def evaluate(
if max_batches is not None and i >= max_batches: if max_batches is not None and i >= max_batches:
break break
drone_img = batch["drone_img"].to(device, non_blocking=True) drone_img = batch["drone_img"].to(device, non_blocking=True)
altitude = batch.get("altitude")
if altitude is not None:
altitude = altitude.to(device, non_blocking=True)
q = model.encode_query( q = model.encode_query(
drone_img, drone_img,
batch["caption_l1"], batch["caption_l2"], batch["caption_l3"], batch["caption_l1"], batch["caption_l2"], batch["caption_l3"],
altitude=altitude,
) )
query_embs.append(q.cpu()) query_embs.append(q.cpu())
query_valid_names.extend(batch["valid_sat_names"]) query_valid_names.extend(batch["valid_sat_names"])

View File

@@ -2,7 +2,7 @@
Usage: Usage:
python -m src.main gtauav_balanced python -m src.main gtauav_balanced
python -m src.main gtauav_balanced_sofia_v1 python -m src.main gtauav_balanced_stripnet
""" """
from __future__ import annotations from __future__ import annotations
@@ -13,7 +13,7 @@ import sys
import coloredlogs import coloredlogs
from src.conf.config_loader import load_all_configs from src.conf.config_loader import load_all_configs
from src.training.train_gtauav_old import train from src.training.trainer_new import Trainer
from src.utils.path_utils import get_proj_dir from src.utils.path_utils import get_proj_dir
logger = logging.getLogger("caption_test") logger = logging.getLogger("caption_test")
@@ -39,7 +39,7 @@ def main() -> None:
configs = load_all_configs(path2cfg, preset_name) configs = load_all_configs(path2cfg, preset_name)
train( trainer = Trainer(
pipeline_cfg=configs["pipeline"], pipeline_cfg=configs["pipeline"],
hardware_cfg=configs["hardware"], hardware_cfg=configs["hardware"],
training_cfg=configs["training"], training_cfg=configs["training"],
@@ -48,7 +48,10 @@ def main() -> None:
models_cfg=configs["models"], models_cfg=configs["models"],
) )
trainer.train()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,13 @@ from __future__ import annotations
"""Trainer for CVGL caption test on GTA-UAV-LR. """Trainer for CVGL caption test on GTA-UAV-LR.
Decomposed from src/training/train_gtauav.py::train into a class with one Decomposed from src/training/train_gtauav.py::train into a class with one
orchestrating method `run()` plus dedicated `_setup_*` / `_build_*` / orchestrating method `train()` plus dedicated `_setup_*` / `_build_*` /
`_train_*` / `_evaluate_*` methods. `_train_*` / `_evaluate_*` methods.
Lifecycle: Lifecycle:
Trainer(...) → run() → done. Trainer(...) → train() → done.
`run()` calls _build_* in dependency order, then _train_loop, then `train()` calls _build_* in dependency order, then _train_loop, then
_final_evaluation; cleanup is in a `finally` block. _final_evaluation; cleanup is in a `finally` block.
Currently supports DINOv3 and StripNet backbones only. SOFIA v1/v7.1 model Currently supports DINOv3 and StripNet backbones only. SOFIA v1/v7.1 model
@@ -80,7 +80,7 @@ _SUPPORTED_BACKBONES: frozenset[str] = frozenset({"dinov3", "stripnet"})
def _build_param_groups( def _build_param_groups(
model: nn.Module, model: AsymmetricEncoder,
lr: float, lr: float,
text_lr_factor: float, text_lr_factor: float,
stripnet_backbone_lr_factor: float = 0.1, stripnet_backbone_lr_factor: float = 0.1,
@@ -130,7 +130,7 @@ def _cosine_warmup_schedule(warmup_steps: int, total_steps: int):
def _embed_drone_queries( def _embed_drone_queries(
model: nn.Module, model: AsymmetricEncoder,
train_ds: GTAUAVDataset, train_ds: GTAUAVDataset,
device: str, device: str,
batch_size: int, batch_size: int,
@@ -155,7 +155,7 @@ def _embed_drone_queries(
) )
all_embs: list[torch.Tensor] = [] all_embs: list[torch.Tensor] = []
with torch.inference_mode(): with torch.inference_mode():
for batch in tqdm(loader, desc="dss-embed", unit="batch", leave=False): for batch in tqdm(loader, desc=" dss-embed-queries", unit="batch", leave=False):
drone_img = batch["drone_img"].to(device, non_blocking=True) drone_img = batch["drone_img"].to(device, non_blocking=True)
altitude = batch.get("altitude") altitude = batch.get("altitude")
if altitude is not None: if altitude is not None:
@@ -178,7 +178,7 @@ class Trainer:
All gin parameters arrive as 6 config objects; runtime state (model, All gin parameters arrive as 6 config objects; runtime state (model,
optimizer, loaders, ...) is built lazily by _build_* methods and lives optimizer, loaders, ...) is built lazily by _build_* methods and lives
on `self`. `run()` calls them in dependency order. on `self`. `train()` calls them in dependency order.
Backbones supported: 'dinov3', 'stripnet'. Backbones supported: 'dinov3', 'stripnet'.
""" """
@@ -232,7 +232,7 @@ class Trainer:
# Public entry point # Public entry point
# =================================================================== # ===================================================================
def run(self) -> None: def train(self) -> None:
"""Full pipeline: setup → build → train → evaluate → cleanup.""" """Full pipeline: setup → build → train → evaluate → cleanup."""
self._validate_backbone() self._validate_backbone()
clear_vram() clear_vram()
@@ -1052,4 +1052,3 @@ class Trainer:
if self.tracker is not None: if self.tracker is not None:
self.tracker.close() self.tracker.close()