clean up to baseline
This commit is contained in:
@@ -1,62 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
from src.conf.hardware_conf import HardwareConfig
|
|
||||||
from src.conf.models_conf import ModelsConfig
|
|
||||||
from src.conf.pipeline_conf import PipelineConfig
|
|
||||||
from src.conf.tracking_conf import TrackingConfig
|
|
||||||
from src.conf.training_conf import TrainingConfig
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def load_all_configs(path2cfg: str) -> dict[str, Any]:
|
|
||||||
"""Parse ALL .gin files in path2cfg and return all config objects.
|
|
||||||
|
|
||||||
This is the PRODUCTION entry point — main() calls this once. Individual
|
|
||||||
get_*_cfg() loaders exist only for unit tests / notebooks.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path2cfg: Path to config directory (WITH trailing slash).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dict with config objects keyed by name:
|
|
||||||
{
|
|
||||||
"pipeline": PipelineConfig,
|
|
||||||
"hardware": HardwareConfig,
|
|
||||||
"models": ModelsConfig,
|
|
||||||
"training": TrainingConfig,
|
|
||||||
"tracking": TrackingConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
FileNotFoundError: If path2cfg contains no .gin files.
|
|
||||||
"""
|
|
||||||
cfg_dir = Path(path2cfg)
|
|
||||||
gin_files = sorted(cfg_dir.glob("*.gin"))
|
|
||||||
if not gin_files:
|
|
||||||
raise FileNotFoundError(f"No .gin files found in {cfg_dir}")
|
|
||||||
|
|
||||||
# MANDATORY: reset gin global state before parsing — without clear_config(),
|
|
||||||
# parameters from previous parses accumulate (gin holds global bindings).
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_files_and_bindings(
|
|
||||||
config_files=[str(f) for f in gin_files],
|
|
||||||
bindings=[],
|
|
||||||
)
|
|
||||||
logger.info("Loaded %d gin files from %s", len(gin_files), cfg_dir)
|
|
||||||
|
|
||||||
# Instantiate AFTER all bindings are parsed.
|
|
||||||
return {
|
|
||||||
"pipeline": PipelineConfig(),
|
|
||||||
"hardware": HardwareConfig(),
|
|
||||||
"models": ModelsConfig(),
|
|
||||||
"training": TrainingConfig(),
|
|
||||||
"tracking": TrackingConfig(),
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
|
|
||||||
@gin.configurable
|
|
||||||
class HardwareConfig:
|
|
||||||
"""GPU profile + memory/compute optimisation flags.
|
|
||||||
|
|
||||||
Everything that changes when you switch hardware (4090 → A100 → Jetson)
|
|
||||||
lives here. batch_size and grad_accum_steps are hardware-bound: they
|
|
||||||
determine VRAM footprint, not the training recipe.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
device: str = "cuda",
|
|
||||||
batch_size: int = 8,
|
|
||||||
grad_accum_steps: int = 1,
|
|
||||||
num_workers: int = 4,
|
|
||||||
use_amp: bool = True,
|
|
||||||
gradient_checkpointing: bool = True,
|
|
||||||
reserve_gb: float = 2.0,
|
|
||||||
) -> None:
|
|
||||||
self.device = device
|
|
||||||
self.batch_size = batch_size
|
|
||||||
self.grad_accum_steps = grad_accum_steps
|
|
||||||
self.num_workers = num_workers
|
|
||||||
self.use_amp = use_amp
|
|
||||||
self.gradient_checkpointing = gradient_checkpointing
|
|
||||||
self.reserve_gb = reserve_gb
|
|
||||||
# Derived (RTX 4090 default; override per profile):
|
|
||||||
self.total_vram_gb = 24.0
|
|
||||||
self.available_vram_gb = self.total_vram_gb - self.reserve_gb
|
|
||||||
self.effective_batch_size = self.batch_size * self.grad_accum_steps
|
|
||||||
|
|
||||||
|
|
||||||
def get_hardware_cfg(path2cfg: str) -> HardwareConfig:
|
|
||||||
"""Load ONLY hardware config (TESTING ONLY — use load_all_configs in production)."""
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_file(f"{path2cfg}hardware.gin")
|
|
||||||
return HardwareConfig()
|
|
||||||
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
|
|
||||||
@gin.configurable
|
|
||||||
class ModelsConfig:
|
|
||||||
"""Model checkpoints + architecture switches.
|
|
||||||
|
|
||||||
Default checkpoint paths are relative to the project root (matching the
|
|
||||||
repository layout: nn_models/DINO_WEB/, nn_models/DINO_SAT/, etc.).
|
|
||||||
These are gitignored and must be downloaded separately — see README.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
# Checkpoints — relative to project root, defaults match repo layout.
|
|
||||||
dino_web_path: str = "nn_models/DINO_WEB/dinov3-vitl16-pretrain-lvd1689m.pth",
|
|
||||||
dino_sat_path: str = "nn_models/DINO_SAT/model.safetensors",
|
|
||||||
lrsclip_path: str = "nn_models/LRSCLIP/DGTRS-CLIP-ViT-L-14.pt",
|
|
||||||
stripnet_path: str = "nn_models/STRIPNET/stripnet_s.pth",
|
|
||||||
# Backbone selection.
|
|
||||||
backbone: str = "dinov3",
|
|
||||||
shared_encoder: bool = True,
|
|
||||||
baseline_mode: bool = False,
|
|
||||||
# Fusion.
|
|
||||||
init_gate: float = 0.7,
|
|
||||||
# MONA (DINOv3).
|
|
||||||
mona_bottleneck: int = 64,
|
|
||||||
mona_last_n_blocks: int = 12,
|
|
||||||
# StripNet-specific.
|
|
||||||
stripnet_freeze: bool = True,
|
|
||||||
stripnet_mona_last_n_stages: int = 2,
|
|
||||||
) -> None:
|
|
||||||
self.dino_web_path = dino_web_path
|
|
||||||
self.dino_sat_path = dino_sat_path
|
|
||||||
self.lrsclip_path = lrsclip_path
|
|
||||||
self.stripnet_path = stripnet_path
|
|
||||||
self.backbone = backbone
|
|
||||||
self.shared_encoder = shared_encoder
|
|
||||||
self.baseline_mode = baseline_mode
|
|
||||||
self.init_gate = init_gate
|
|
||||||
self.mona_bottleneck = mona_bottleneck
|
|
||||||
self.mona_last_n_blocks = mona_last_n_blocks
|
|
||||||
self.stripnet_freeze = stripnet_freeze
|
|
||||||
self.stripnet_mona_last_n_stages = stripnet_mona_last_n_stages
|
|
||||||
|
|
||||||
|
|
||||||
def get_models_cfg(path2cfg: str) -> ModelsConfig:
|
|
||||||
"""Load ONLY models config (TESTING ONLY — use load_all_configs in production)."""
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_file(f"{path2cfg}models.gin")
|
|
||||||
return ModelsConfig()
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
|
|
||||||
@gin.configurable
|
|
||||||
class PipelineConfig:
|
|
||||||
"""Pipeline orchestration: data IO, training schedule, output, resume.
|
|
||||||
|
|
||||||
Defaults match the current `belka_refactor` HEAD: hardcoded servml paths
|
|
||||||
are preserved verbatim. To switch to a different machine, override in
|
|
||||||
pipeline.gin — never edit defaults here.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
# Data paths (defaults match servml workstation).
|
|
||||||
train_json: str = "meta/train_80.json",
|
|
||||||
test_json: str = "meta/test_20.json",
|
|
||||||
rgb_root: str = "/home/servml/Документы/datasets/GTA-UAV-LR",
|
|
||||||
caption_root: str = "/home/servml/Документы/datasets/GTA-UAV-LR-captions",
|
|
||||||
filter_meta: str | None = None,
|
|
||||||
# Training schedule.
|
|
||||||
epochs: int = 10,
|
|
||||||
warmup_epochs: int = 2,
|
|
||||||
eval_every: int = 1,
|
|
||||||
# Reproducibility & output.
|
|
||||||
seed: int = 42,
|
|
||||||
output_dir: str = "out/gtauav/with_text",
|
|
||||||
resume_from: str | None = None,
|
|
||||||
) -> None:
|
|
||||||
self.train_json = train_json
|
|
||||||
self.test_json = test_json
|
|
||||||
self.rgb_root = rgb_root
|
|
||||||
self.caption_root = caption_root
|
|
||||||
self.filter_meta = filter_meta
|
|
||||||
self.epochs = epochs
|
|
||||||
self.warmup_epochs = warmup_epochs
|
|
||||||
self.eval_every = eval_every
|
|
||||||
self.seed = seed
|
|
||||||
self.output_dir = output_dir
|
|
||||||
self.resume_from = resume_from
|
|
||||||
|
|
||||||
|
|
||||||
def get_pipeline_cfg(path2cfg: str) -> PipelineConfig:
|
|
||||||
"""Load ONLY pipeline config (TESTING ONLY — use load_all_configs in production).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path2cfg: Path to config directory (with trailing slash).
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Instantiated PipelineConfig.
|
|
||||||
"""
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_file(f"{path2cfg}pipeline.gin")
|
|
||||||
return PipelineConfig()
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
|
|
||||||
@gin.configurable
|
|
||||||
class TrackingConfig:
|
|
||||||
"""Experiment tracking + diagnostics.
|
|
||||||
|
|
||||||
Independent axis: changing these flags does not affect training results,
|
|
||||||
only what is observed/recorded.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
use_wandb: bool = False,
|
|
||||||
use_tb: bool = True,
|
|
||||||
wandb_project: str = "caption-test-gtauav",
|
|
||||||
wandb_run_name: str | None = None,
|
|
||||||
wandb_entity: str | None = None,
|
|
||||||
log_grad_norms: bool = True,
|
|
||||||
use_gradcam: bool = False,
|
|
||||||
gradcam_every: int = 5,
|
|
||||||
gradcam_samples: int = 8,
|
|
||||||
use_profiler: bool = False,
|
|
||||||
profiler_warmup: int = 3,
|
|
||||||
profiler_active: int = 5,
|
|
||||||
) -> None:
|
|
||||||
self.use_wandb = use_wandb
|
|
||||||
self.use_tb = use_tb
|
|
||||||
self.wandb_project = wandb_project
|
|
||||||
self.wandb_run_name = wandb_run_name
|
|
||||||
self.wandb_entity = wandb_entity
|
|
||||||
self.log_grad_norms = log_grad_norms
|
|
||||||
self.use_gradcam = use_gradcam
|
|
||||||
self.gradcam_every = gradcam_every
|
|
||||||
self.gradcam_samples = gradcam_samples
|
|
||||||
self.use_profiler = use_profiler
|
|
||||||
self.profiler_warmup = profiler_warmup
|
|
||||||
self.profiler_active = profiler_active
|
|
||||||
|
|
||||||
|
|
||||||
def get_tracking_cfg(path2cfg: str) -> TrackingConfig:
|
|
||||||
"""Load ONLY tracking config (TESTING ONLY — use load_all_configs in production)."""
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_file(f"{path2cfg}tracking.gin")
|
|
||||||
return TrackingConfig()
|
|
||||||
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import gin
|
|
||||||
|
|
||||||
|
|
||||||
@gin.configurable
|
|
||||||
class TrainingConfig:
|
|
||||||
"""Training recipe: loss + optimizer + sampler.
|
|
||||||
|
|
||||||
These three move together when you tune learning. Changing tau usually
|
|
||||||
pairs with changing lr; switching sampler_type usually pairs with
|
|
||||||
re-tuning loss weights. Keeping them in one config matches the actual
|
|
||||||
workflow of running ablations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
# --- Loss ---
|
|
||||||
loss_type: str = "symmetric",
|
|
||||||
tau_init: float = 0.07,
|
|
||||||
tau_min: float = 0.01,
|
|
||||||
tau_max: float = 0.1,
|
|
||||||
learnable_temperature: bool = True,
|
|
||||||
label_smoothing: float = 0.1,
|
|
||||||
weight_q2g: float = 0.6,
|
|
||||||
weight_g2q: float = 0.4,
|
|
||||||
hard_mining_k: int = 0,
|
|
||||||
neg_bank_size: int = 0,
|
|
||||||
# --- Optimizer ---
|
|
||||||
learning_rate: float = 1e-4,
|
|
||||||
text_lr_factor: float = 0.1,
|
|
||||||
stripnet_backbone_lr_factor: float = 0.1,
|
|
||||||
weight_decay: float = 1e-4,
|
|
||||||
grad_clip: float = 1.0,
|
|
||||||
# --- Sampler ---
|
|
||||||
sampler_type: str = "mutex",
|
|
||||||
dss_warmup_epochs: int = 1,
|
|
||||||
dss_reembed_every: int = 1,
|
|
||||||
dss_knn_device: str = "cuda",
|
|
||||||
dss_use_lsh: bool = False,
|
|
||||||
dss_lsh_num_tables: int = 8,
|
|
||||||
dss_lsh_num_bits: int = 14,
|
|
||||||
dss_cache_dir: str | None = None,
|
|
||||||
) -> None:
|
|
||||||
# Loss.
|
|
||||||
self.loss_type = loss_type
|
|
||||||
self.tau_init = tau_init
|
|
||||||
self.tau_min = tau_min
|
|
||||||
self.tau_max = tau_max
|
|
||||||
self.learnable_temperature = learnable_temperature
|
|
||||||
self.label_smoothing = label_smoothing
|
|
||||||
self.weight_q2g = weight_q2g
|
|
||||||
self.weight_g2q = weight_g2q
|
|
||||||
self.hard_mining_k = hard_mining_k
|
|
||||||
self.neg_bank_size = neg_bank_size
|
|
||||||
# Optimizer.
|
|
||||||
self.learning_rate = learning_rate
|
|
||||||
self.text_lr_factor = text_lr_factor
|
|
||||||
self.stripnet_backbone_lr_factor = stripnet_backbone_lr_factor
|
|
||||||
self.weight_decay = weight_decay
|
|
||||||
self.grad_clip = grad_clip
|
|
||||||
# Sampler.
|
|
||||||
self.sampler_type = sampler_type
|
|
||||||
self.dss_warmup_epochs = dss_warmup_epochs
|
|
||||||
self.dss_reembed_every = dss_reembed_every
|
|
||||||
self.dss_knn_device = dss_knn_device
|
|
||||||
self.dss_use_lsh = dss_use_lsh
|
|
||||||
self.dss_lsh_num_tables = dss_lsh_num_tables
|
|
||||||
self.dss_lsh_num_bits = dss_lsh_num_bits
|
|
||||||
self.dss_cache_dir = dss_cache_dir
|
|
||||||
|
|
||||||
|
|
||||||
def get_training_cfg(path2cfg: str) -> TrainingConfig:
|
|
||||||
"""Load ONLY training config (TESTING ONLY — use load_all_configs in production)."""
|
|
||||||
gin.clear_config()
|
|
||||||
gin.parse_config_file(f"{path2cfg}training.gin")
|
|
||||||
return TrainingConfig()
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user