claude_refactor_v2: temp changes before src changes
This commit is contained in:
62
src/conf/config_loader.py
Normal file
62
src/conf/config_loader.py
Normal file
@@ -0,0 +1,62 @@
|
||||
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(),
|
||||
}
|
||||
|
||||
43
src/conf/hardware_conf.py
Normal file
43
src/conf/hardware_conf.py
Normal file
@@ -0,0 +1,43 @@
|
||||
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()
|
||||
|
||||
54
src/conf/models_conf.py
Normal file
54
src/conf/models_conf.py
Normal file
@@ -0,0 +1,54 @@
|
||||
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()
|
||||
|
||||
57
src/conf/pipeline_conf.py
Normal file
57
src/conf/pipeline_conf.py
Normal file
@@ -0,0 +1,57 @@
|
||||
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()
|
||||
|
||||
48
src/conf/tracking_conf.py
Normal file
48
src/conf/tracking_conf.py
Normal file
@@ -0,0 +1,48 @@
|
||||
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()
|
||||
|
||||
79
src/conf/training_conf.py
Normal file
79
src/conf/training_conf.py
Normal file
@@ -0,0 +1,79 @@
|
||||
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