fb-hydra:如何获取内部配置以继承外部配置字段?
fb-hydra: How to get inner configurations to inherit outer configuration fields?
我正在尝试编写分层配置结构,以便内部目录中的配置文件继承外部目录中的配置文件。例如,在下面的场景中
upper_config
|
|-middle_config
| |
| |-lower_config
我希望 middle_config
能够继承和覆盖 upper_config
的参数,并且 lower_config
能够继承和覆盖 middle_config
的参数] 和 upper_config
.
一个解决方案是编写一个配置解析器,以便首先读取外部模块,当读取内部模块时,它们会覆盖外部模块中的字段。
但是,我想使用 Hydra(或其他一些工具,接受建议)以获得所有额外的便利。我已经从头到尾阅读了几次文档,虽然感觉配置组或包指令应该能够处理这个问题,但我无法将它们拼凑起来。
我相信 post 问了一个非常相似的问题,但答案没有启发我,而且问问题的人似乎决定实施一个版本的配置我上面描述的解析器。
我希望有一种方法可以将内部配置文件的 package
指令更改为指向父配置,并以某种方式继承其默认列表。
假设我们有以下文件:
my_app.py
outer/conf1.yaml
outer/middle/conf2.yaml
outer/middle/inner/conf3.yaml
为了使事情具体化,这里是my_app.py
的内容:
import hydra, omegaconf
@hydra.main(config_path="outer", config_name="conf1")
def my_app(cfg) -> None:
print(omegaconf.OmegaConf.to_yaml(cfg))
my_app()
TLDR
如果您的 yaml
文件只包含纯数据(即没有默认列表或包指令),在命令行动态组合配置的最灵活方法如下所示:
$ python my_app.py +middle@_global_=conf2 +middle/inner@_global_=conf3
这将在 outer/conf1.yaml
之上合并 outer/middle/conf2.yaml
,然后在其之上合并 outer/middle/inner/conf3.yaml
。 @_global_
关键字表示输入配置应在顶层合并,而不是根据其包含目录的名称嵌套。
现在了解详情...
在回答这个问题时,我可能会使用 Hydra 1.1 的最新候选版本中的一些功能:
>>> import hydra
>>> hydra.__version__
'1.1.0.rc1'
我们可以采用一些方法来使用 middle/inner 配置覆盖我们的外部配置:
- 使用默认列表指定包。
- 使用包header指定包
- 使用 command-line 包替代来指定包(这是上面 TLDR 部分中使用的方法)
以下是每种方法的详细信息:
使用默认列表指定包。
假设我们有以下内容:
在 outer/conf1.yaml
:
defaults:
- _self_
- middle@_here_: conf2
a: 1
b: 2
在outer/middle/conf1.yaml
中:
defaults:
- _self_
- inner@_here_: conf3
b: 3
c: 4
在outer/middle/inner/conf3.yaml
中:
c: 5
d: 6
使用这些 yaml 文件,运行 my_app.py
给出以下结果:
$ python my_app.py
a: 1
b: 3
c: 5
d: 6
如您所见,conf1
被 conf2
覆盖,后者又被
被 conf3
覆盖。那么,这是如何工作的呢? defaults list用于指定每个配置的顺序object
被创作。在 conf1
中, @_here_
包关键字用于指定
conf2
应该合并到当前配置组的信息而不是
包含在 middle
包中。这记录在 Default List 包中
关键字。
@_global_
关键字也很有趣。请注意,可以 just-as-well
在默认列表中写入 - middle@foo: conf2
而不是 - middle@_here_: conf2
,在这种情况下
"foo"
键将出现在输出配置中,内容为 conf2
嵌套在它下面。
正如在 conf1.yaml
中一样,conf2.yaml
使用默认列表来指定
conf3
应该合并到 conf2
而不是合并到
名为 "inner"
的包(这将是默认行为,因为
记录在案
here).
- _self_
关键字有什么作用?
在默认列表中,此关键字允许控制
当前配置与默认值中指定的其他输入配置合并
列表。例如,在 conf2.yaml
默认值列表中,写入 - _self_
before - inner@_here_: conf3
确保 conf3
将被合并到
conf2
,而不是相反。此 _self_
关键字已记录
here。如果 - _self_
中没有指定
默认列表,然后是默认与当前合并的顺序
配置是:
- 使用 Hydra 1.0:从
默认列表已合并到当前配置中
- 使用 Hydra 1.1:最后合并当前配置,覆盖默认列表中指定的其他配置
如需参考,请参阅 这些迁移
说明
从 1.0 版移动到 1.1 版。
使用包header指定包
使用包
指令
在yaml文件的顶部可以达到类似的结果:
在outer/conf1.yaml
中:
defaults:
- _self_
- middle: conf2
a: 1
b: 2
在outer/middle/conf2.yaml
中:
# @package _global_
defaults:
- _self_
- inner: conf3
b: 3
c: 4
在outer/middle/inner/conf3.yaml
# @package _global_
c: 5
d: 6
# @package <PACKAGE>
指令指定
应放置当前输入配置。
$ python my_app.py
a: 1
b: 3
c: 5
d: 6
这与在默认值中使用 @<PACKAGE>
关键字的方式大致相同
列表(如前一节所述),command-line 处的结果是
完全相同的。这两种方法之间的一个区别是包 header
适用于给定输入配置的所有内容,而使用
@<PACKAGE>
默认列表中的关键字提供了更细粒度的
控制应将哪些输入配置放入哪些包中。
仍然需要在默认列表中使用 - _self_
关键字以确保
合并以正确的顺序发生(请参阅上一节的注释
在 _self_
).
Hydra 对包 headers 的处理在 Hydra 1.0 与 中有所不同
1.1.
使用 command-line 包替代来指定包
获得所需结果的最优雅、最灵活的方法是使用 command-line 包覆盖:
给定 outer/conf1.yaml
如下:
a: 1
b: 2
而outer/middle/conf2.yaml
因此:
b: 3
c: 4
和outer/middle/inner/conf3.yaml
:
c: 5
d: 6
我们可以利用九头蛇的强大command-lineoverride syntax
组成输出配置:
$ python my_app.py +middle@_global_=conf2 +middle/inner@_global_=conf3
a: 1
b: 3
c: 5
d: 6
使用此方法不需要使用 _self_
关键字,因为
+<group>@<package>=<option>
具有 附加 到默认值的效果
列表(here 是一个
参考)而不是前置。
我正在尝试编写分层配置结构,以便内部目录中的配置文件继承外部目录中的配置文件。例如,在下面的场景中
upper_config
|
|-middle_config
| |
| |-lower_config
我希望 middle_config
能够继承和覆盖 upper_config
的参数,并且 lower_config
能够继承和覆盖 middle_config
的参数] 和 upper_config
.
一个解决方案是编写一个配置解析器,以便首先读取外部模块,当读取内部模块时,它们会覆盖外部模块中的字段。
但是,我想使用 Hydra(或其他一些工具,接受建议)以获得所有额外的便利。我已经从头到尾阅读了几次文档,虽然感觉配置组或包指令应该能够处理这个问题,但我无法将它们拼凑起来。
我相信
我希望有一种方法可以将内部配置文件的 package
指令更改为指向父配置,并以某种方式继承其默认列表。
假设我们有以下文件:
my_app.py
outer/conf1.yaml
outer/middle/conf2.yaml
outer/middle/inner/conf3.yaml
为了使事情具体化,这里是my_app.py
的内容:
import hydra, omegaconf
@hydra.main(config_path="outer", config_name="conf1")
def my_app(cfg) -> None:
print(omegaconf.OmegaConf.to_yaml(cfg))
my_app()
TLDR
如果您的 yaml
文件只包含纯数据(即没有默认列表或包指令),在命令行动态组合配置的最灵活方法如下所示:
$ python my_app.py +middle@_global_=conf2 +middle/inner@_global_=conf3
这将在 outer/conf1.yaml
之上合并 outer/middle/conf2.yaml
,然后在其之上合并 outer/middle/inner/conf3.yaml
。 @_global_
关键字表示输入配置应在顶层合并,而不是根据其包含目录的名称嵌套。
现在了解详情...
在回答这个问题时,我可能会使用 Hydra 1.1 的最新候选版本中的一些功能:
>>> import hydra
>>> hydra.__version__
'1.1.0.rc1'
我们可以采用一些方法来使用 middle/inner 配置覆盖我们的外部配置:
- 使用默认列表指定包。
- 使用包header指定包
- 使用 command-line 包替代来指定包(这是上面 TLDR 部分中使用的方法)
以下是每种方法的详细信息:
使用默认列表指定包。
假设我们有以下内容:
在 outer/conf1.yaml
:
defaults:
- _self_
- middle@_here_: conf2
a: 1
b: 2
在outer/middle/conf1.yaml
中:
defaults:
- _self_
- inner@_here_: conf3
b: 3
c: 4
在outer/middle/inner/conf3.yaml
中:
c: 5
d: 6
使用这些 yaml 文件,运行 my_app.py
给出以下结果:
$ python my_app.py
a: 1
b: 3
c: 5
d: 6
如您所见,conf1
被 conf2
覆盖,后者又被
被 conf3
覆盖。那么,这是如何工作的呢? defaults list用于指定每个配置的顺序object
被创作。在 conf1
中, @_here_
包关键字用于指定
conf2
应该合并到当前配置组的信息而不是
包含在 middle
包中。这记录在 Default List 包中
关键字。
@_global_
关键字也很有趣。请注意,可以 just-as-well
在默认列表中写入 - middle@foo: conf2
而不是 - middle@_here_: conf2
,在这种情况下
"foo"
键将出现在输出配置中,内容为 conf2
嵌套在它下面。
正如在 conf1.yaml
中一样,conf2.yaml
使用默认列表来指定
conf3
应该合并到 conf2
而不是合并到
名为 "inner"
的包(这将是默认行为,因为
记录在案
here).
- _self_
关键字有什么作用?
在默认列表中,此关键字允许控制
当前配置与默认值中指定的其他输入配置合并
列表。例如,在 conf2.yaml
默认值列表中,写入 - _self_
before - inner@_here_: conf3
确保 conf3
将被合并到
conf2
,而不是相反。此 _self_
关键字已记录
here。如果 - _self_
中没有指定
默认列表,然后是默认与当前合并的顺序
配置是:
- 使用 Hydra 1.0:从 默认列表已合并到当前配置中
- 使用 Hydra 1.1:最后合并当前配置,覆盖默认列表中指定的其他配置
如需参考,请参阅 这些迁移 说明 从 1.0 版移动到 1.1 版。
使用包header指定包
使用包 指令 在yaml文件的顶部可以达到类似的结果:
在outer/conf1.yaml
中:
defaults:
- _self_
- middle: conf2
a: 1
b: 2
在outer/middle/conf2.yaml
中:
# @package _global_
defaults:
- _self_
- inner: conf3
b: 3
c: 4
在outer/middle/inner/conf3.yaml
# @package _global_
c: 5
d: 6
# @package <PACKAGE>
指令指定
应放置当前输入配置。
$ python my_app.py
a: 1
b: 3
c: 5
d: 6
这与在默认值中使用 @<PACKAGE>
关键字的方式大致相同
列表(如前一节所述),command-line 处的结果是
完全相同的。这两种方法之间的一个区别是包 header
适用于给定输入配置的所有内容,而使用
@<PACKAGE>
默认列表中的关键字提供了更细粒度的
控制应将哪些输入配置放入哪些包中。
仍然需要在默认列表中使用 - _self_
关键字以确保
合并以正确的顺序发生(请参阅上一节的注释
在 _self_
).
Hydra 对包 headers 的处理在 Hydra 1.0 与 中有所不同 1.1.
使用 command-line 包替代来指定包
获得所需结果的最优雅、最灵活的方法是使用 command-line 包覆盖:
给定 outer/conf1.yaml
如下:
a: 1
b: 2
而outer/middle/conf2.yaml
因此:
b: 3
c: 4
和outer/middle/inner/conf3.yaml
:
c: 5
d: 6
我们可以利用九头蛇的强大command-lineoverride syntax 组成输出配置:
$ python my_app.py +middle@_global_=conf2 +middle/inner@_global_=conf3
a: 1
b: 3
c: 5
d: 6
使用此方法不需要使用 _self_
关键字,因为
+<group>@<package>=<option>
具有 附加 到默认值的效果
列表(here 是一个
参考)而不是前置。