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.