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:
101
gin-parse.md
Normal file
101
gin-parse.md
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
|
||||
Хороший вопрос. Вижу проблему в текущем паттерне — каждый `get_*_cfg()` вызывает `gin.parse_config_file()` отдельно, а gin имеет **глобальное состояние**. Если вызвать два загрузчика подряд — второй `gin.parse_config_file()` **добавляет** параметры к первому, не очищая.
|
||||
|
||||
## Проблемы текущего подхода
|
||||
|
||||
```python
|
||||
# Текущий паттерн — каждый загрузчик парсит свой .gin:
|
||||
fdir_conf = get_fdir_cfg(path2cfg) # gin.parse_config_file("file_dir.gin")
|
||||
input_conf = get_inputval_cfg(path2cfg) # gin.parse_config_file("input.gin")
|
||||
train_conf = get_train_cfg(path2cfg) # gin.parse_config_file("train.gin")
|
||||
```
|
||||
|
||||
|Проблема|Почему|
|
||||
|:--|:--|
|
||||
|**Gin state accumulates**|Второй `parse_config_file` не очищает первый — параметры накапливаются|
|
||||
|**Порядок зависимость**|Если `input.gin` случайно переопределит параметр из `file_dir.gin` — тихая ошибка|
|
||||
|**Нет единой точки загрузки**|Разбросанные `gin.parse_config_file()` в каждом файле conf/|
|
||||
|**Дублирование кода**|Каждый `get_*_cfg()` — одинаковые 3 строки|
|
||||
|
||||
## Рекомендуемое решение
|
||||
|
||||
**Один раз загрузить все .gin файлы, один раз создать все конфиги:**
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
import gin
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_all_configs(path2cfg: str) -> dict[str, object]:
|
||||
"""Load all gin configs at once and return all config objects.
|
||||
|
||||
Args:
|
||||
path2cfg: Path to config directory (with trailing slash).
|
||||
|
||||
Returns:
|
||||
Dict with config objects keyed by name.
|
||||
"""
|
||||
gin.clear_config() # Reset global state — critical!
|
||||
|
||||
# Parse ALL .gin files in one call:
|
||||
gin_files = sorted(Path(path2cfg).glob("*.gin"))
|
||||
gin.parse_config_files_and_bindings(
|
||||
[str(f) for f in gin_files],
|
||||
bindings=[], # No CLI overrides
|
||||
)
|
||||
|
||||
# Instantiate all configs (gin state is now fully populated):
|
||||
return {
|
||||
"pipeline": PipelineConfig(),
|
||||
"hardware": HardwareConfig(),
|
||||
"models": ModelsConfig(),
|
||||
"input": InputConfig(),
|
||||
"seg": SegConfig(),
|
||||
}
|
||||
```
|
||||
|
||||
**Использование в main:**
|
||||
|
||||
```python
|
||||
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"],
|
||||
)
|
||||
```
|
||||
|
||||
## Сохранить ли отдельные `get_*_cfg()` ?
|
||||
|
||||
**Да, но как обёртки для тестирования** (когда нужен один конфиг в изоляции):
|
||||
|
||||
```python
|
||||
def get_hardware_cfg(path2cfg: str) -> HardwareConfig:
|
||||
"""Load ONLY hardware config (for testing/debugging)."""
|
||||
gin.clear_config()
|
||||
gin.parse_config_file(f"{path2cfg}hardware.gin")
|
||||
return HardwareConfig()
|
||||
```
|
||||
|
||||
Ключевое: добавить `gin.clear_config()` перед каждым `parse_config_file()`.
|
||||
|
||||
## Итого: что изменить
|
||||
|
||||
|Было|Стало|
|
||||
|:--|:--|
|
||||
|Каждый `get_*_cfg()` парсит свой .gin|**`load_all_configs()`** парсит все .gin за один вызов|
|
||||
|Нет `gin.clear_config()`|**Обязательный** `gin.clear_config()` перед загрузкой|
|
||||
|5 отдельных вызовов в main|**1 вызов** `load_all_configs()`|
|
||||
|Отдельные `get_*_cfg()` для продакшена|Оставить **только для тестирования**|
|
||||
|
||||
Хотите, чтобы я создал файл `src/conf/config_loader.py` с этим паттерном и обновил `REQUIREMENTS_GIN_STYLE.md`?
|
||||
Reference in New Issue
Block a user