Initial commit — gin-config strict-pattern coding standard

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)
This commit is contained in:
2026-04-27 17:12:38 +03:00
commit 3278322a17
10 changed files with 1970 additions and 0 deletions

278
REQUIREMENTS_GIN_STYLE.md Normal file
View File

@@ -0,0 +1,278 @@
# Требования к адаптации кода под gin-config стиль
Референсный проект: `test_bb_uav`
---
## 1. Структура директорий
Создать директорию для конфигурационных файлов:
```
depth_edges_annotate_worlduav/
├── in/
│ └── config_files/
│ ├── pipeline.gin # Стадии пайплайна, пути, форматы вывода
│ ├── hardware.gin # Профили GPU, batch size, FP16, workers
│ ├── models.gin # Идентификаторы моделей, fallback-стратегии
│ ├── input.gin # Размер изображений, нормализация, аугментации
│ └── segmentation.gin # Текстовые промпты, параметры сегментации
├── src/
│ ├── conf/
│ │ ├── __init__.py
│ │ ├── pipeline_conf.py # PipelineConfig (пути, стадии, resume, вывод)
│ │ ├── hardware_conf.py # HardwareConfig (GPU, batch, FP16, workers)
│ │ ├── models_conf.py # ModelsConfig (model IDs, fallback)
│ │ ├── input_conf.py # InputConfig (размер, нормализация)
│ │ └── seg_conf.py # SegConfig (промпты, параметры)
│ ├── augmentor/
│ │ ├── ... # Существующие модули (без изменения структуры)
│ └── augment_dataset.py # Точка входа (адаптировать)
```
---
## 2. Паттерн конфигурационных классов
Каждый конфиг-класс следует единому шаблону из `test_bb_uav`:
```python
import gin
@gin.configurable
class HardwareConfig:
def __init__(self, profile_name='rtx4090', use_fp16=True,
batch_size=None, num_workers=4, reserve_gb=2.0):
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
```
### Правила:
- Декоратор `@gin.configurable` только на классах (не на функциях)
- Все параметры имеют значения по умолчанию в `__init__`
- Класс хранит параметры как атрибуты экземпляра (`self.param = param`)
- Не использовать dataclass совместно с gin — заменить dataclass на обычные классы
- Допустима пост-обработка в `__init__` (вычисление производных значений)
---
## 3. Загрузка конфигов
### 3.1 Центральный загрузчик (ПРОДАКШЕН)
Один файл `src/conf/config_loader.py` содержит единственную функцию, которая парсит **все** .gin файлы за один вызов:
```python
def load_all_configs(path2cfg: str) -> dict[str, Any]:
"""Parse ALL .gin files at once and return all config objects."""
gin.clear_config() # ОБЯЗАТЕЛЬНО: сброс глобального состояния gin
gin_files = sorted(Path(path2cfg).glob("*.gin"))
gin.parse_config_files_and_bindings(
config_files=[str(f) for f in gin_files],
bindings=[],
)
return {
"pipeline": PipelineConfig(),
"hardware": HardwareConfig(),
"models": ModelsConfig(),
"input": InputConfig(),
"seg": SegConfig(),
}
```
### Правила:
- `gin.clear_config()` **обязателен** перед каждой загрузкой — без него параметры от предыдущих вызовов накапливаются (gin имеет глобальное состояние)
- Все .gin файлы парсятся **одним вызовом** `gin.parse_config_files_and_bindings()`
- Конфиг-объекты создаются **после** полной загрузки всех .gin
- В main() — **один вызов** `load_all_configs()`, не 5 отдельных `get_*_cfg()`
### 3.2 Индивидуальные загрузчики (ТОЛЬКО ДЛЯ ТЕСТИРОВАНИЯ)
Для unit-тестов и отладки — отдельные `get_<name>_cfg()` функции в том же файле:
```python
def get_hardware_cfg(path2cfg: str) -> HardwareConfig:
"""Load ONLY hardware config (for isolated testing)."""
gin.clear_config() # Обязательно!
gin.parse_config_file(f"{path2cfg}hardware.gin")
return HardwareConfig()
```
### Правила:
- Имя функции: `get_<name>_cfg(path2cfg: str) -> ConfigClass`
- **Обязательно** `gin.clear_config()` перед `gin.parse_config_file()`
- Используются **только** в тестах и notebooks, не в main()
### Референс: `develop_style_prompt/config_loader_reference.py`
---
## 4. Формат .gin файлов
Плоский формат `ClassName.param = value`:
```gin
# hardware.gin
HardwareConfig.profile_name = 'rtx4090'
HardwareConfig.use_fp16 = True
HardwareConfig.batch_size = 8
HardwareConfig.num_workers = 4
HardwareConfig.reserve_gb = 2.0
```
### Правила:
- Одна строка — один параметр
- Комментарии через `#`
- Строки в одинарных или двойных кавычках
- Списки в квадратных скобках: `[1, 2, 3]`
- Не использовать макросы, ссылки, `gin.constant()` или другие продвинутые фичи gin
- Каждый `.gin` файл соответствует одному конфиг-классу
---
## 5. Точка входа (main)
Адаптировать `augment_dataset.py` — использовать центральный загрузчик:
```python
from src.conf.config_loader import load_all_configs
from src.utils.utils_file_dir import get_proj_dir
def main() -> None:
proj_dir = get_proj_dir()
path2cfg = f"{proj_dir}in/config_files/"
# ОДИН вызов загружает ВСЕ конфиги:
configs = load_all_configs(path2cfg)
# Явная передача в пайплайн:
run_pipeline(
configs["pipeline"],
configs["hardware"],
configs["models"],
configs["input"],
configs["seg"],
)
```
```python
# Ищем pyproject.toml или .git как корень проекта:
MARKERS = ("pyproject.toml", ".git", "in")
def get_proj_dir() -> str:
current = Path(__file__).resolve().parent
for _ in range(10):
if any((current / m).exists() for m in MARKERS):
return str(current) + "/"
current = current.parent
raise RuntimeError("Project root not found")
```
### Правила:
- Убрать `argparse` — все параметры из gin-файлов
- **Один вызов** `load_all_configs()` вместо 5 отдельных `get_*_cfg()`
- `gin.clear_config()` вызывается **внутри** `load_all_configs()` автоматически
- Конфиг-объекты передаются **явно** через аргументы (не через глобальный gin)
- Функция `get_proj_dir()` определяет корень проекта автоматически
---
## 6. Распределение параметров по конфиг-классам
### PipelineConfig (`pipeline.gin`)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `input_root` | str | — | Путь к входным данным |
| `output_root` | str | — | Путь для выходных данных |
| `stages` | list | `['depth', 'edges', 'segmentation']` | Стадии пайплайна |
| `save_npy` | bool | `True` | Сохранять .npy файлы |
| `save_vis` | bool | `True` | Сохранять визуализации |
| `save_concat` | bool | `True` | Сохранять 6-канальный результат |
| `resume` | bool | `True` | Пропускать уже обработанные |
| `subset` | str | `None` | Фильтр по подмножеству |
| `source` | str | `None` | Фильтр по источнику (query/db) |
| `log_level` | str | `'INFO'` | Уровень логирования |
### HardwareConfig (`hardware.gin`)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `profile_name` | str | `'rtx4090'` | Имя профиля GPU |
| `use_fp16` | bool | `True` | Использовать half precision |
| `batch_size` | int | `None` | Размер батча (None = авто) |
| `num_workers` | int | `4` | Число DataLoader workers |
| `reserve_gb` | float | `2.0` | Резерв VRAM в ГБ |
### ModelsConfig (`models.gin`)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `depth_model_id` | str | `'depth-anything/...'` | HuggingFace ID модели глубины |
| `depth_fallback_id` | str | `'...'` | Fallback модель глубины |
| `seg_model_id` | str | `'...'` | ID модели сегментации |
| `seg_fallback_id` | str | `'...'` | Fallback модель сегментации |
| `depth_model_size` | str | `'Large'` | Размер модели глубины |
| `seg_model_size` | str | `'b5'` | Размер модели сегментации |
### InputConfig (`input.gin`)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `image_size` | int | `256` | Размер изображения |
| `sobel_blur_ksize` | int | `3` | Ядро Sobel для edges |
| `edge_normalize` | bool | `True` | Нормализация карты краев |
### SegConfig (`segmentation.gin`)
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
| `prompts` | list | `[...]` | Текстовые промпты для OV-сегментации |
| `threshold` | float | `0.3` | Порог сегментации |
---
## 7. Миграция существующих модулей
### Что удалить:
- `argparse` из `augment_dataset.py`
- `@dataclass` из `AugmentConfig` и `HardwareProfile` в `config.py`
- Словарь `PROFILES` с хардкодом профилей (перенести в gin)
- `DEFAULT_GEO_PROMPTS` из `models.py` (перенести в gin)
### Что сохранить:
- Структуру `src/augmentor/` (dataset, inference, models, io_utils)
- Логику fallback при загрузке моделей (но model ID из конфига)
- Логику discover_images, AugmentDataset
- Функции сохранения (save_depth, save_edges, save_segmentation)
### Что адаптировать:
- Все функции, принимающие `AugmentConfig`, должны принимать отдельные конфиг-объекты
- Захардкоженные значения (model IDs, промпты, размер 256) — в gin-файлы
- `pipeline_256.py` — удалить или адаптировать под новый стиль
---
## 8. Ограничения по использованию gin
Использовать **минимальный** набор возможностей gin:
- **Да**: `@gin.configurable`, `gin.parse_config_file()`
- **Нет**: `gin.register()`, `gin.constant()`, `gin.query_parameter()`, макросы, ссылки между конфигами
- Значения конфигов можно менять в runtime после загрузки (`config.param = new_value`)
---
## 9. Порядок выполнения миграции
1. Создать `src/conf/` с конфиг-классами и функциями загрузки
2. Создать `in/config_files/` с `.gin` файлами
3. Адаптировать `augment_dataset.py` — заменить argparse на gin-загрузку
4. Адаптировать `augmentor/models.py` — model IDs из конфига
5. Адаптировать `augmentor/inference.py` — параметры из конфига
6. Адаптировать `augmentor/dataset.py` — принимать конфиг-объекты
7. Удалить старый `config.py` (dataclass-версию)
8. Проверить, что `depth_edges_gen.py` и `depth_anything_v2_generate.py` используют новые конфиги
9. Удалить или адаптировать `pipeline_256.py`