从实例化配置中获取原始 Hydra 配置

Get original Hydra configuration from instantiated config

Hydra I can automatically instantiate my classes中,例如

_target_: ClassA
foo: bar
model:
  _target_: ClassB
  hello: world

这导致递归实例化 classes,例如“内部 class”实例传递给“外部 classes”的地方:

ClassA(
   foo="bar"
   model=ClassB(
      hello="world"
   )
)

有没有办法让 ClassA 获得 ClassB 的原始配置结构,以便我同时拥有实例 ClassB 和原始结构,例如模型及其超参数

model:
  _target_: ClassB
  hello: world

您可以结合使用 OmegaConf 的 variable interpolation with its custom resolvers

这是一个示例,其中 ClassA.__init__ 接收 modelmodelconf 作为参数。参数 modelconfcfg.model 的副本,它的 _target_ 字段已被删除。

# conf.yaml
_target_: app.ClassA
foo: bar
model:
  _target_: app.ClassB
  hello: world
modelconf: "${remove_target: ${.model}}"
# app.py
import hydra
from omegaconf import DictConfig, OmegaConf


class ClassB:
    def __init__(self, hello: str):
        print(f"ClassB.__init__ got {hello=}")


class ClassA:
    def __init__(self, foo: str, model: ClassB, modelconf: DictConfig) -> None:
        print(f"ClassA.__init__ got {foo=}, {model=}, {modelconf=}")


def remove_target_impl(conf: DictConfig) -> DictConfig:
    """Return a copy of `conf` with its `_target_` field removed."""
    conf = conf.copy()
    conf.pop("_target_")
    return conf


OmegaConf.register_new_resolver(
    "remove_target", resolver=remove_target_impl, replace=True
)


@hydra.main(config_path=".", config_name="conf.yaml")
def main(cfg: DictConfig) -> None:
    hydra.utils.instantiate(cfg)


if __name__ == "__main__":
    main()

在命令行:

$ python3 app.py
  ret = run_job(
ClassB.__init__ got hello='world'
ClassA.__init__ got foo='bar', model=<app.ClassB object at 0x10a125ee0>, modelconf={'hello': 'world'}

modelconf中删除_target_字段的动机如下: 如果 _target_ 而不是 删除,那么对 instantiate 的调用将导致 modelconf 被映射到 ClassB 的实例(而不是DictConfig)。

另请参阅 instantiate_convert_ 参数。使用 _convert_=="partial"_convert_=="all" 意味着 ClassA.__init__ 将接收 modelconf 类型的参数 dict 而不是类型 DictConfig.

def remove_target_and_add_convert_impl(conf: DictConfig) -> DictConfig:
    conf = conf.copy()
    conf.pop("_target_")
    conf["_convert_"] = "all"  # instantiate should now result in a dict rather than in a DictConfig
    return conf