--- 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)