2025, Oct 19 05:16
Относительная интерполяция в Hydra/OmegaConf: как ссылаться на соседние ключи в групповых конфигах
Почему ${feat_size} в группах Hydra/OmegaConf не подставляется и как исправить: относительная интерполяция (${...feat_size}) или полный путь (${net.feat_size})
Hydra упрощает сборку конфигураций, но со строковой интерполяцией возникают тонкости, особенно когда параметры разбиты на группы. Частая ситуация — внутри группового файла сослаться на «соседний» ключ и в итоге увидеть в выводе буквальную строку интерполяции, а не ожидаемое подставленное значение.
Пример, который выглядит корректно, но не вычисляется
Возьмем основной конфиг, который выбирает конфигурацию модели через группу:
defaults:
  - net: net_a
  - _self_
И файл из группы:
# net/net_a.yaml
feat_size: 106
stages:
  unit_1:
    in_size: ${feat_size}
    emb_size: 64
    out_size: 64
Ожидается, что in_size станет 106. Но при печати собранной конфигурации модели in_size может отображаться как буквальная строка «${feat_size}», а не число.
Что на самом деле происходит
Интерполяция в OmegaConf (которую использует Hydra) по умолчанию абсолютная и вычисляется лениво. «Ленивая» означает, что в распечатанной структуре может остаться исходная строка, но при обращении к конкретному ключу подставится верное значение. Абсолютная адресация — путь считается от корня собранной конфигурации. Поскольку групповой файл монтируется под узлом, имя которого совпадает с названием группы, нужное значение находится не в корне как feat_size, а под этим узлом. Поэтому для абсолютной интерполяции в такой схеме корректная ссылка — ${net.feat_size}.
Если проверить конкретное значение напрямую, например прочитать stages.unit_1.in_size, вы инициируете вычисление. Печать всей конфигурации при этом может по‑прежнему показывать исходную строку, поэтому точечная проверка нужного ключа в такой ситуации надежнее.
Аккуратное решение
Есть два равноправных способа явно выразить намерение.
Первый — сослаться на абсолютный путь от корня, включая узел группы, например ${net.feat_size}. Это соответствует реальной структуре после сборки.
Второй, обычно более уместный в групповом файле, — использовать относительную интерполяцию. OmegaConf поддерживает относительные ссылки, не зависящие от абсолютного положения узла. В данном случае нужно сослаться на ключ из того же словаря, это можно записать так:
# net/net_a.yaml
feat_size: 106
stages:
  unit_1:
    in_size: ${...feat_size}
    emb_size: 64
    out_size: 64
Относительная интерполяция делает ссылку устойчивой даже при изменении пути, по которому файл подключается, избавляя от жесткой привязки к имени группы и месту её крепления в итоговом дереве.
Почему это важно
Понимание того, что по умолчанию интерполяция абсолютная и вычисляется лениво, помогает избежать ложных тревог при проверке. Это также объясняет, почему ссылка вида ${key}, подразумевающая корень, в групповом файле может не сработать и почему запись ${...key} надежнее. Относительная интерполяция убирает зависимость от абсолютного пути узла и делает перестройку дерева конфигураций гораздо менее рискованной.
Выводы
Ссылаясь на соседние значения внутри группового конфига Hydra, предпочитайте относительную интерполяцию вроде ${...feat_size}. Если используете абсолютную, указывайте полный путь, например ${net.feat_size}. А проверяя, что именно подставляет Hydra, сверяйте конкретный ключ, а не только строковое представление всей конфигурации.
Статья основана на вопросе на StackOverflow от Dan Jackson и ответе Omry Yadan.