Hydra instantiate处理嵌套配置中OmegaConf自定义tuple解析器报错如何解决?
OmegaConf自定义tuple解析器嵌套配置问题说明
基础实现
OmegaConf支持注册自定义解析器,以下是实现tuple类型解析的示例代码:
def resolve_tuple(*args): return tuple(args) OmegaConf.register_new_resolver("tuple", resolve_tuple)
该解析器可以将配置文件中${tuple:1,2}格式的插值语句解析为tuple类型(1, 2),结合hydra.utils.instantiate可直接创建包含tuple类型属性的对象。
单文件配置运行正常示例
配置文件 config.yaml
obj: tuple: ${tuple:1,2}
测试代码 test.py
import hydra import hydra.utils as hu from omegaconf import OmegaConf def resolve_tuple(*args): return tuple(args) OmegaConf.register_new_resolver('tuple', resolve_tuple) @hydra.main(config_path='conf', config_name='config_test') def main(cfg): obj = hu.instantiate(cfg.obj, _convert_='partial') print(obj) if __name__ == '__main__': main()
运行输出
$ python test.py {'tuple': (1, 2)}
嵌套配置报错场景
当使用defaults字段引入其他独立配置文件的内容,通过二次插值引用tuple解析结果时,运行相同逻辑会报错。
独立配置文件 tuple/base.yaml
tuple: ${tuple:1,2}
主配置文件 config.yaml
defaults: - tuple: base - _self_ obj: tuple: ${tuple}
报错信息
$ python test.py Error executing job with overrides: [] Traceback (most recent call last): File "test.py", line 16, in main obj = hu.instantiate(cfg.obj, _convert_='partial') File "/Users/me/anaconda3/envs/my_env/lib/python3.7/site-packages/hydra/_internal/instantiate/_instantiate2.py", line 175, in instantiate OmegaConf.resolve(config) omegaconf.errors.UnsupportedValueType: Value 'tuple' is not a supported primitive type Set the environment variable HYDRA_FULL_ERROR=1 for a complete stack trace.
问题排查与疑问
排查OmegaConf源码发现:单文件运行正常的场景下,配置对象的allow_objects标志为True;嵌套配置报错场景下该标志为None,虽然_instantiate2.py中调用Omegaconf.resolve(config)前已将allow_objects设为True,但依然触发报错。
疑问点:
- 从独立文件填充的插值/解析值会覆盖该标志是否为预期行为?
- 如果是预期行为,有没有方法可以确保所有解析和插值的值的
allow_objects标志保持为True?
解答
问题原因
该行为是OmegaConf的预期设计:每个OmegaConf节点都有独立的allow_objects属性,通过defaults字段加载的独立配置文件,其节点默认的allow_objects属性为None(即未开启自定义对象支持)。在插值解析时,解析动作会优先使用值来源节点的allow_objects属性,而非上层引用节点的属性,因此即使在instantiate前给上层节点设了allow_objects=True,来源节点提前解析时触发的类型校验依然会报错。
解决方案
最简单的适配方案是在进入main函数后、调用instantiate前,手动给整个根配置树开启allow_objects支持,修改后的main函数如下:
@hydra.main(config_path='conf', config_name='config_test') def main(cfg): # 给全量配置树开启自定义对象支持 OmegaConf.allow_objects(cfg, True) obj = hu.instantiate(cfg.obj, _convert_='partial') print(obj)
如果上述方案不生效,可在注册解析器时添加use_cache=False参数,避免解析结果被提前缓存到无object权限的节点上下文中:
OmegaConf.register_new_resolver('tuple', resolve_tuple, replace=True, use_cache=False)
内容的提问来源于stack exchange,提问作者Grr
相关产品推荐
相关产品推荐

