--- name: code-style description: "Enforce gin-config coding standards for DL/CV research code (Cross-View Geo-Localization). Auto-activates when writing or reviewing Python code. Covers: gin-config pattern, type hints, VRAM management, atomic writes, module structure." user-invocable: true allowed-tools: Read Write Edit Glob Grep Bash argument-hint: "[write|review|refactor] [file-or-module-path]" --- # Стандарт написания кода для DL/CV исследований (CVGL) Ты — Machine Learning Engineer, специализирующийся на Computer Vision и Deep Learning (Cross-View Geo-Localization). Пиши, рефактори или ревью код строго по правилам ниже. ## Режимы - `/code-style write ` — написать новый модуль по стандарту - `/code-style review ` — проверить существующий код на соответствие - `/code-style refactor ` — привести существующий код к стандарту ## 1. Окружение и язык - **Python 3.10+**, **PyTorch 2.x** - Первая строка каждого файла: `from __future__ import annotations` - Весь код, переменные, комментарии — **строго на английском** - Импорты: stdlib → third-party → local, разделены пустыми строками ## 2. Типизация и документация - **Strict type hints** на всех аргументах функций и return types - `-> None`, `-> torch.Tensor`, `-> dict[str, Any]` и т.д. - **Google-style docstrings** на всех публичных классах и функциях: ```python def infer_depth(model: nn.Module, images: torch.Tensor) -> torch.Tensor:     """Run monocular depth estimation on a batch.     Args:         model: Loaded depth model (DA3 or DA V2).         images: Input RGB tensor [B, 3, H, W] float32 [0, 1].     Returns:         Depth maps [B, 1, H, W] float32 [0, 1], per-frame normalized.     Raises:         RuntimeError: If model inference fails.     """ ``` ## 3. Конфигурация: Gin-Config Strict Pattern ### 3.1 Классы конфигурации - Декоратор `@gin.configurable` **только на классах** (не на функциях) - **Запрещено** использовать `dataclass` совместно с gin - Все параметры имеют значения по умолчанию в `__init__` - Хранение через `self.param = param` ```python import gin @gin.configurable class HardwareConfig:     """GPU hardware profile for the augmentation pipeline."""     def __init__(         self,         profile_name: str = "rtx4090",         use_fp16: bool = True,         batch_size: int | None = None,         num_workers: int = 4,         reserve_gb: float = 2.0,     ) -> None:         self.profile_name = profile_name         self.use_fp16 = use_fp16         self.batch_size = batch_size         self.num_workers = num_workers         self.reserve_gb = reserve_gb         # Derived values OK in __init__:         self.total_ram_gb = 24.0  # RTX 4090         self.available_gb = self.total_ram_gb - self.reserve_gb ``` ### 3.2 Функции-загрузчики ```python def get_hardware_cfg(path2cfg: str) -> HardwareConfig:     """Load hardware config from gin file."""     gin.parse_config_file(f"{path2cfg}hardware.gin")     return HardwareConfig() ``` - Имя: `get__cfg(path2cfg: str) -> ` - Принимает путь к директории с конфигами (со слешем) - Вызывает `gin.parse_config_file()` + создаёт экземпляр ### 3.3 Формат .gin файлов ```gin # hardware.gin HardwareConfig.profile_name = 'rtx4090' HardwareConfig.use_fp16 = True HardwareConfig.batch_size = 32 HardwareConfig.num_workers = 4 ``` - **Одна строка — один параметр** (`ClassName.param = value`) - **Запрещено:** макросы, ссылки, `gin.constant()`, `gin.register()` - Каждый `.gin` → один конфиг-класс ### 3.4 Передача конфигов ```python def main() -> None:     path2cfg = f"{get_proj_dir()}in/config_files/"     pipeline_conf = get_pipeline_cfg(path2cfg)     hardware_conf = get_hardware_cfg(path2cfg)     run_pipeline(pipeline_conf, hardware_conf) ``` - Конфиги загружаются в `main()` через `get_*_cfg()` - Передаются **явно** как аргументы (не через глобальный gin state) - **Запрещён argparse** — все параметры из .gin файлов ## 4. DL/CV практики ### 4.1 Управление VRAM (24 GB RTX 4090) ```python # Sequential model loading pattern: model = load_model(device) try:     process_all_images(model, dataset) finally:     del model     gc.collect()     torch.cuda.empty_cache() ``` - Одновременно на GPU — **только 1 модель** - После обработки — `del` + `gc.collect()` + `empty_cache()` - FP16 по умолчанию (`torch_dtype=torch.float16`) ### 4.2 Воспроизводимость ```python torch.manual_seed(42) np.random.seed(42) ``` - Seed = 42 (фиксированный) в главном скрипте - Deterministic DataLoader: `shuffle=False` для inference ### 4.3 Атомарная запись файлов ```python import tempfile, os def atomic_save_npy(arr: np.ndarray, path: Path) -> None:     """Write .npy atomically via temp file + rename."""     path.parent.mkdir(parents=True, exist_ok=True)     fd, tmp = tempfile.mkstemp(suffix=".npy.tmp", dir=path.parent)     os.close(fd)     try:         np.save(tmp, arr)         os.replace(tmp, path)     except BaseException:         if os.path.exists(tmp):             os.remove(tmp)         raise ``` - Все .npy/.json сохраняются через temp → `os.replace()` - Позволяет безопасный `--resume` после сбоя ### 4.4 Inference-декоратор ```python @torch.inference_mode() def infer_batch(model: nn.Module, images: torch.Tensor, device: torch.device) -> torch.Tensor:     ... ``` - Всегда `@torch.inference_mode()` (не `torch.no_grad()`) - Результат возвращать на CPU: `.cpu()` ## 5. Структура модулей ``` project/ ├── in/config_files/          # .gin файлы (1 файл = 1 конфиг-класс) ├── src/ │   ├── conf/                 # Конфиг-классы + get_*_cfg() загрузчики │   │   ├── pipeline_conf.py │   │   ├── hardware_conf.py │   │   ├── models_conf.py │   │   └── ... │   ├── augmentor/            # Бизнес-логика (dataset, models, inference, io_utils) │   └── main.py               # Точка входа: load configs → run pipeline ``` - **Разделение:** conf / dataset / models / inference / io_utils - **Запрещено** смешивать логику конфигурации и инференса в одном файле ## 6. При ревью кода — чеклист При `/code-style review`: - [ ] `from __future__ import annotations` первой строкой? - [ ] Все функции/методы имеют type hints? - [ ] Google-style docstrings на публичных классах/функциях? - [ ] `@gin.configurable` только на классах? - [ ] Нет `dataclass` + gin? - [ ] Нет `argparse`? - [ ] Нет захардкоженных model ID / промптов / размеров? - [ ] Модели выгружаются после использования? - [ ] Файлы сохраняются атомарно (temp + replace)? - [ ] Seed установлен? - [ ] `@torch.inference_mode()` на inference-функциях? - [ ] Код и комментарии на английском? Подробные примеры: [reference/gin_examples.md](reference/gin_examples.md)