ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Hydra 1.0 到 1.1 默认组合顺序变更解析:主配置与 Defaults List 的覆盖优先级迁移指南

Hydra 1.0 到 1.1 默认组合顺序变更解析:主配置与 Defaults List 的覆盖优先级迁移指南 Hydra 1.0 到 1.1 默认组合顺序变更解析主配置与 Defaults List 的覆盖优先级迁移指南【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydraHydra 1.1 调整了配置组合composition的默认执行顺序这是一次影响所有用户的行为变更在 1.0 中Defaults List 中的配置会覆盖主配置文件config.yaml而从 1.1 起规则颠倒为主配置覆盖 Defaults List 中的配置。本文围绕官方升级文档展开结合仓库源码与测试用例完整讲解变更前后的行为差异、_self_的三种使用场景、主配置三种形态YAML 文件、纯 Structured Config、Structured Config Schema 配置文件下的迁移做法以及如何用--cfg job验证迁移结果、如何让同一份配置同时兼容 Hydra 1.0 与 1.1。变更背景Defaults List 与主配置的覆盖关系反转一个最简示例同样的输入不同的输出假设应用目录下存在两个配置文件主配置文件config.yaml包含一个 Defaults List引入配置组foo的选项bar以及一个键值对foo.x 10配置组选项文件foo/bar.yaml通过# package _group_头部声明自己的包位置为配置组路径foo内容为x: 20。defaults: - foo: bar foo: x: 10# package _group_ x: 20两者的区别在于主配置为foo.x定义了10而 Defaults List 引入的foo/bar.yaml为foo.x定义了20。最终输出中foo.x取哪个值完全取决于组合顺序。Hydra 1.0 的行为Defaults List 中的配置覆盖主配置因此foo/bar.yaml的x: 20胜出输出为foo: x: 20Hydra 1.1 起的行为主配置覆盖 Defaults List 中的配置因此config.yaml的x: 10胜出输出为foo: x: 10底层原理组合顺序与“后出现者胜出”规则Hydra 的组合过程本质上是把所有参与组合的输入配置按深度优先顺序展开成一颗 Defaults 树再依次合并到输出配置节点中后出现的配置覆盖先出现的配置。因此“谁覆盖谁”完全取决于当前配置在 Defaults List 中的相对位置。在源码中这个位置由_self_条目显式控制。_self_表示“包含当前 Defaults List 的这份配置自身”在列表中的插入位置它在解析后会被转换为一个ConfigDefault(path_self_)元素相关实现见 hydra/_internal/defaults_list.py 中的_validate_self()函数而is_self()的判定逻辑self.path _self_见 hydra/core/default_element.py。在 1.0 时代即使主配置未显式书写_self_其内容也被隐式放置在 Defaults List 的最前面因此列表中后续出现的foo: bar会覆盖主配置。1.1 改变了这个隐式默认位置使主配置的内容在语义上位于列表末尾从而反过来覆盖列表中的配置。组合顺序的完整定义_self_的两种语义位置要正确迁移先要理解_self_的定位规则。以主配置文件为例_self_放在 Defaults List 第一位主配置的内容先被合并随后列表中的每一项依次覆盖它。此时行为等同于 Hydra 1.0Defaults List 覆盖主配置。_self_放在 Defaults List 最后一位主配置的内容最后被合并覆盖列表中所有先出现的配置。此时是 Hydra 1.1 的新默认行为。未书写_self_Hydra 1.1 会在列表末尾自动追加一个_self_。仓库测试 tests/defaults_list/test_defaults_list.py 中的test_missing_self_is_appended_without_warning直接验证了这一行为当列表只有GroupDefault(groupgroup1, valuefile1)时_validate_self()返回后列表变为[GroupDefault(...), ConfigDefault(path_self_)]。需要注意_self_在列表中只能出现一次重复定义会抛出ConfigCompositionExceptionDuplicateselfdefined ...且_self_PACKAGE这种带包的写法不被支持ValueError: _self_PACKAGE is not supported详见 hydra/_internal/defaults_list.py 与 hydra/core/default_element.py。从 Hydra 1.1 开始官方在调试输出中提供了观察该顺序的直接手段运行python my_app.py --info defaults会打印一张表格其中专门有一列_self_用于标记每一行配置是否就是当前配置自身相关日志代码见 hydra/_internal/hydra.py。迁移方案一主配置是 YAML 文件1.1 的警告机制为避免用户在升级时“悄悄”踩中行为变化Hydra 1.1 设置了告警条件当主配置的 Defaults List 中缺少_self_且主配置中除 Defaults List 外还包含其他配置值时会发出警告提示你明确声明组合顺序。换句话说一个只有defaults:键、没有其他内容的主配置不会触发警告因为此时顺序问题无关紧要。两种修复选择接受新行为推荐面向未来把_self_追加到 Defaults List 的末尾。此时主配置覆盖 Defaults List 中的配置符合 1.1 及以后版本的默认语义defaults: - foo: bar - _self_ foo: x: 10保留旧行为兼容 1.0把_self_作为 Defaults List 的第一项defaults: - _self_ - foo: bar foo: x: 10输出结果中foo.x将被foo/bar.yaml的x: 20覆盖与 Hydra 1.0 完全一致foo: x: 20关于 Defaults List 的完整语法CONFIG、GROUP_DEFAULT、override、optional、null、PACKAGE 等元素与组合规则官方文档见 website/versioned_docs/version-1.2/advanced/defaults_list.md。迁移方案二主配置是 Structured Config当主配置不是 YAML 文件、而是 Python 中的 Structured Configdataclass时同样需要显式声明_self_以表达组合顺序。典型场景是把主配置声明为一个 dataclass并在其中通过defaults字段引用配置组。由于 dataclass 字段的限制defaults需要借助field(default_factory...)来初始化defaults [ _self_, {db: mysql} ] dataclass class Config: # this is unfortunately verbose due to dataclass limitations defaults: List[Any] field(default_factorylambda: defaults) # Hydra will populate this field based on the defaults list db: Any MISSING在这种形态下官方建议将_self_放在列表第一项。理由是Structured Config 的字段是应用逻辑的一部分通常应保持较低的优先级让配置组如db: mysql中的实际取值来填充或覆盖这些字段如果把_self_放在最后dataclass 中的字段默认值反而会覆盖配置组的取值这通常不是用户想要的结果。MISSING的使用也值得注意它表示该字段“必须由组合过程提供值”。当db标记为MISSING且 Defaults List 提供了db: mysql时最终配置中的db内容来自配置组选项mysql若组合后仍为MISSINGHydra 会在组合校验阶段报错。迁移方案三主配置是带 Structured Config Schema 的 YAML 文件第三种形态是“混合式”主配置仍然是一个 YAML 文件但它的结构由一个通过cs.store(namebase_config, nodeConfig)注册的 Structured Config 作为 Schema 来约束。此时必须把_self_放在 Schema 的后面即列表顺序为“Schema 在前_self_在后”。dataclass class Config: host: str localhost port: int 8080 cs.store(namebase_config, nodeConfig)defaults: - base_config # schema - _self_ # after schema port: 3306组合结果为host: localhost # schema port: 3306 # config.yaml这里的顺序逻辑是base_configSchema最先合并提供host: localhost与port: 8080两个字段及其默认值主配置config.yaml在_self_处合并其port: 3306覆盖 Schema 的默认值8080host未被覆盖保留 Schema 提供的localhost。如果误把_self_放到base_config之前Schema 反而会覆盖主配置导致port被重置回8080。这是该形态下最常见的迁移错误务必注意顺序Schema 在前_self_紧随其后。验证迁移是否改变你的配置行为变更可能以不易察觉的方式影响线上任务配置官方提供了两条验证路径使用hydra.main的应用分别在新旧两个 Hydra 版本上运行python my_app.py --cfg job对比输出的完整 job 配置。只要两份输出逐字节一致即可确认升级没有改变任务的实际配置。使用 Compose API 的应用由于没有命令行入口建议为组合后的配置补充全面的单元测试锁定关键字段的期望值防止升级静默改变组合结果。Compose API 的用法可参考仓库中的 hydra/compose.py。双版本兼容让同一份配置同时跑在 Hydra 1.0 与 1.1如果你维护的配置需要同时兼容 Hydra 1.0 与 1.1例如处于分批升级的过渡期做法与“保留旧行为”一致把_self_插入到 Defaults List 的第一项。Hydra 1.0.7 及之后发布的 1.0 系列版本会直接忽略Defaults List 中的_self_条目因此配置在 1.0 下行为不变Hydra 1.1 在_self_位于第一项时会组合出与 Hydra 1.0 完全相同的配置。两者叠加即可实现一份配置在两个大版本下产生一致结果。从源码看_self_在 1.1 中是被当作普通ConfigDefault参与组合的见 hydra/_internal/defaults_list.py其is_self()判定与排序逻辑在 hydra/core/default_element.py 中定义而 1.0 则是将其过滤忽略——这正是双版本兼容得以成立的基础。小结迁移决策速查场景_self_位置行为接受 1.1 新行为Defaults List 末尾主配置覆盖 Defaults List保留 1.0 旧行为 / 双版本兼容Defaults List 第一项Defaults List 覆盖主配置主配置为 Structured Config第一项推荐配置组取值覆盖 dataclass 字段默认值主配置为 YAML Structured Config SchemaSchema 之后配置文件覆盖 Schema 默认值Schema 提供缺失字段迁移时请记住三件事先运行python my_app.py --cfg job在新旧版本上对比输出为 Compose API 场景补充单元测试最后在所有主配置无论 YAML、Structured Config 还是混合形态中显式书写_self_让组合顺序可读、可控、可审计。【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表