Code-style guide and reference patterns for DL/CV research at the ЛИСАД laboratory (NADEZHDA / SOFIA CVGL projects). Files: - Стандарт написания кода для DL CV исследований (CVGL).md - Правила написания Python-кода (Gin-Config Strict Pattern).md - REQUIREMENTS_GIN_STYLE.md - Gin-Config Strict Pattern Reference Examples.md - Переход от argparse и dataclass к gin-config.md - gin-parse.md - Рекомендуемые gin-config категории.md - config_loader_reference.py - README.md (this commit) - .gitignore (Python artifacts)
439 lines
8.5 KiB
Markdown
439 lines
8.5 KiB
Markdown
---
|
||
|
||
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 <path>` — написать новый модуль по стандарту
|
||
|
||
- `/code-style review <path>` — проверить существующий код на соответствие
|
||
|
||
- `/code-style refactor <path>` — привести существующий код к стандарту
|
||
|
||
|
||
|
||
## 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_<name>_cfg(path2cfg: str) -> <ConfigClass>`
|
||
|
||
- Принимает путь к директории с конфигами (со слешем)
|
||
|
||
- Вызывает `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) |