Hydra 配置系统完全指南:掌握hydra.*配置节点与内置 Resolver
【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra
Hydra 作为"优雅配置复杂应用"的框架,其自身同样高度可配置:启动器(Launcher)、扫描器(Sweeper)、日志、输出目录模式以及应用帮助信息都可通过配置定制。本篇指南以 Hydra 1.2 版本文档 configure_hydra/Intro.md 为骨架,系统梳理 Hydra 配置的组成结构、hydra.*各配置节点的字段语义,以及内置 Resolver 的用法,并结合仓库源码(hydra/conf/init.py、hydra/core/hydra_config.py、hydra/core/utils.py 等)深入其实现原理。读完本文,你将能够在自己的配置文件中熟练覆盖 Hydra 行为、在代码中读取运行时信息、并用hydra、now、python_version等 Resolver 编写动态配置。
Hydra 自身是如何被配置的
Hydra 的一个核心设计理念是:Hydra 的配置与你应用的配置使用同一套机制。这意味着你可以用教程中已经熟悉的三种方式定制 Hydra 自身:
- 在自有配置中直接覆盖:将一段 Hydra 配置片段写进你的 config,直接覆盖对应键值;
- 组合不同插件或自定义代码提供的配置:通过
defaults列表引入不同来源的配置组; - 命令行覆盖:在命令行中像覆盖自己的配置一样覆盖 Hydra 的一切,例如
hydra.job.chdir=True、hydra.run.dir=...。
Hydra 配置本身由多个配置文件组合而成,其defaults列表定义在 hydra/conf/init.py 的HydraConf数据类中:
# hydra/config(defaults 列表示意) defaults: - output: default # 输出目录 - launcher: basic # 启动器配置 - sweeper: basic # 扫描器配置 - help: default # 应用 --help - hydra_help: default # --hydra-help - hydra_logging: default # Hydra 自身日志 - job_logging: default # Job 日志 - callbacks: null # 回调(实验特性) - env: default # 环境相关覆盖这些配置组对应的真实文件位于 hydra/conf/hydra/ 目录下,例如:
output/default.yaml:定义默认的 run/sweep 输出目录模式;launcher/basic.yaml、sweeper/basic.yaml:默认插件配置;job_logging/、hydra_logging/:日志相关配置(default、disabled、stdout、none等变体);help/default.yaml、hydra_help/default.yaml:帮助模板。
其中 hydra/conf/hydra/output/default.yaml 的内容即为运行时输出目录的默认值:
# @package hydra run: dir: outputs/${now:%Y-%m-%d}/${now:%H-%M-%S} sweep: dir: multirun/${now:%Y-%m-%d}/${now:%H-%M-%S} subdir: ${hydra.job.num}用--cfg hydra查看完整的 Hydra 配置
要查看 Hydra 配置的真实组成,可以给应用加上--cfg hydra标志:
$ python my_app.py --cfg hydra输出会展示一个大型配置树,其顶层大致如下(省略了日志等细节):
hydra: run: dir: outputs/${now:%Y-%m-%d}/${now:%H-%M-%S} sweep: dir: multirun/${now:%Y-%m-%d}/${now:%H-%M-%S} subdir: ${hydra.job.num} launcher: _target_: hydra._internal.core_plugins.basic_launcher.BasicLauncher sweeper: _target_: hydra._internal.core_plugins.basic_sweeper.BasicSweeper max_batch_size: null hydra_logging: version: 1 formatters: ...从源码看,--cfg hydra的实现位于 hydra/_internal/hydra.py:get_sanitized_hydra_cfg()先深拷贝完整配置,删除除hydra外的所有键,再剔除hydra_help与help节点,随后由show_cfg()输出 YAML。这也是 Hydra 官方推荐用来"查看配置结构"的调试入口。
访问 Hydra 配置的两种方式
Hydra 配置体积较大。为避免污染你的应用配置,Hydra 在把配置对象传递给@hydra.main()装饰的函数之前,会从配置对象中删除hydra节点。这一点在源码中有两处印证:
- hydra/core/utils.py 中
del task_cfg["hydra"]; - hydra/_internal/hydra.py 的
get_sanitized_cfg()在cfg_type == "job"时同样删除hydra。
因此你需要通过以下两种方式显式访问 Hydra 配置。
方式一:在配置中使用hydraResolver
在你的 YAML 配置里,通过${hydra:key}语法引用 Hydra 配置节点:
config_name: ${hydra:job.name}注意语法细节:Resolver 的名字是hydra,key跟在冒号之后。该 Resolver 的底层实现是 hydra/core/utils.py 中注册的OmegaConf.register_resolver("hydra", lambda path: OmegaConf.select(HydraConfig.get(), path)),即对HydraConfig单例做一次 OmegaConf 路径选择。
方式二:在代码中使用HydraConfig单例
from hydra.core.hydra_config import HydraConfig @hydra.main() def my_app(cfg: DictConfig) -> None: print(HydraConfig.get().job.name)HydraConfig定义在 hydra/core/hydra_config.py,是一个单例类:
set_config(cfg)将配置中hydra节点置为只读,并通过OmegaConf.masked_copy(cfg, "hydra")拷贝出该节点;拷贝后仍把父节点挂回去,从而允许从用户配置向hydra节点做插值引用;get()返回self.cfg.hydra,若尚未初始化会抛出ValueError: HydraConfig was not set;initialized()用于判断 Hydra 配置是否已经设置。
下文列出的运行时变量,正是通过这两种方式读取的。
hydra.job:Job 配置节点
hydra.job节点用于配置 Job 的若干行为。其完整字段定义(Structured Config)在 hydra/conf/init.py 的JobConf数据类中,各字段说明如下:
| 字段 | 含义 | 默认值 |
|---|---|---|
name | Job 名称,默认取 Python 文件名(去掉后缀),可被覆盖 | 自动填充 |
override_dirname | 由命令行覆盖派生出的路径名,常用于输出目录 | ${hydra_override_dirname:} |
chdir | 为True时,Hydra 在调用用户 main 函数前执行os.chdir(output_dir) | False(1.2 起) |
id | 底层任务系统中的 Job ID(如 SLURM Job ID) | 自动填充 |
num | 扫描(sweep)中 Job 的序号 | 自动填充 |
config_name | 该 Job 使用的配置名(只读输出) | 自动填充 |
env_set | 为启动的 Job 设置的环境变量(Dict[str, str]) | {} |
env_copy | 从启动机器拷贝的环境变量列表(List[str]) | [] |
config | Job 的细粒度配置(目前用于override_dirname格式化) | — |
hydra.job.name:Job 名称
Job 名用于多种场景,例如日志文件名${hydra.job.name}.log。默认派生自 Python 文件名(train.py的 Job 名为train),可通过命令行或配置文件覆盖。可参考示例 examples/configure_hydra/job_name/。
hydra.job.chdir:是否切换到输出目录
chdir控制 Hydra 是否在每个 Job 运行前把当前工作目录切换到输出目录。从 Hydra 1.2 开始默认值为False,即工作目录保持不变;设置为True后可方便地把数据库导出等产物直接写到输出目录:
# 默认行为(Hydra >= 1.2):工作目录不变 $ python my_app.py Working directory : /home/user/dev/myapp Output directory : /home/user/dev/myapp/outputs/2023-04-18/13-43-24 # 开启 chdir 后:工作目录变为输出目录 $ python my_app.py hydra.job.chdir=True Working directory : /home/user/dev/myapp/outputs/2023-04-18/13-43-17 Output directory : /home/user/dev/myapp/outputs/2023-04-18/13-43-17即使关闭chdir,输出目录及其中文件(.hydra/config.yaml、.hydra/hydra.yaml、.hydra/overrides.yaml、my_app.log)仍会照常创建。若在chdir=True下仍需访问原始工作目录,可使用hydra.utils.get_original_cwd()与to_absolute_path(),详见 tutorials/basic/running_your_app/3_working_directory.md。
hydra.job.override_dirname:由覆盖派生的目录名
该字段根据命令行参数自动填充,通常用作输出目录模式的一部分,尤其在hydra.sweep.subdir中。其格式可由hydra.job.config.override_dirname下的三项配置定制:
kv_sep:键值分隔符,默认=;item_sep:条目分隔符,默认,;exclude_keys:要从override_dirname中排除的命令行键列表。
一个典型场景是排除随机种子:
hydra: run: dir: output/${hydra.job.override_dirname}/seed=${seed} job: config: override_dirname: exclude_keys: - seed运行python my_app.py --multirun batch_size=32 learning_rate=0.1,0.01 seed=1,2会生成形如multirun/batch_size=32,learning_rate=0.01/seed=1的目录结构。注意:源码 hydra/core/utils.py 表明hydra.job.override_dirname已弃用,推荐使用${hydra_override_dirname:}Resolver(见下文"内置 Resolver"一节)。更多示例见 workdir.md。
hydra.job.id与hydra.job.num
id:由当前生效的 Launcher 填充。基础启动器BasicLauncher只把 Job ID 设为序号;SLURM 等调度型 Launcher 会填入真实任务 ID。从源码 hydra/_internal/core_plugins/basic_launcher.py 可以看到,基础启动器在每次launch循环中执行sweep_config.hydra.job.id = idx与num = idx。num:当前扫描运行中的 Job 序号(0 到 n-1)。
hydra.job.config_name:Job 使用的配置名
自动填充为@hydra.main()中指定的配置名,仅作输出用途。
hydra.job.env_set与hydra.job.env_copy:环境变量控制
env_set(Dict[str, str])用于设置运行 Job 的环境变量,常见用途是影响底层库的行为,例如禁用 Intel IPP/MKL 的多线程:
hydra: job: env_set: OMP_NUM_THREADS: 1也可以用插值把 PyTorch Distributed 的RANK自动设置为扫描序号:
hydra: job: env_set: RANK: ${hydra:job.num}env_copy(List[str])用于把本地环境变量拷贝到运行 Job 的环境,对远程运行尤其有用:
hydra: job: env_copy: - AWS_KEY更完整的字段说明见 configure_hydra/job.md。
hydra.run与hydra.sweep:输出目录模式
这两个节点分别对应单次运行(未加--multirun)与多任务扫描(加了--multirun)的输出目录,详见 workdir.md。
hydra.run:单次运行
dir:指定输出目录,默认outputs/${now:%Y-%m-%d}/${now:%H-%M-%S}。
按日期分组的示例:
hydra: run: dir: ./outputs/${now:%Y-%m-%d}/${now:%H-%M-%S}按 Job 名分组:
hydra: run: dir: outputs/${hydra.job.name}/${now:%Y-%m-%d_%H-%M-%S}目录模式中还可以引用用户配置变量:
hydra: run: dir: outputs/${now:%Y-%m-%d_%H-%M-%S}/opt:${optimizer.type}hydra.sweep:多任务扫描
dir:所有扫描 Job 共享的公共输出目录,默认multirun/${now:%Y-%m-%d}/${now:%H-%M-%S};subdir:每个 Job 专属子目录模式,默认${hydra.job.num}。
例如对python my_app.py --multirun a=a1,a2,a3,默认会生成0/、1/、2/三个子目录。也可以结合override_dirname让子目录携带覆盖信息:
hydra: sweep: dir: multirun subdir: ${hydra.job.override_dirname}运行python my_app.py --multirun batch_size=32 learning_rate=0.1,0.01将生成:
multirun ├── batch_size=32,learning_rate=0.01 └── batch_size=32,learning_rate=0.1hydra.runtime:运行时信息节点
hydra.runtime下的字段在运行时自动填充,不应被覆盖:
version:Hydra 版本号;cwd:应用启动时的原始工作目录;output_dir:Hydra 为保存日志与 YAML 配置而创建的目录(由 workdir.md 描述的模式决定);choices:最终各配置组选择的字典;config_sources:组合配置所用到的最终配置源列表。
RuntimeConf的 Structured Config 同样定义在 hydra/conf/init.py,其中config_sources的每个元素是ConfigSourceInfo(path, schema, provider)三元组。
hydra.overrides:命令行覆盖记录
hydra.overrides同样由运行时自动填充,不应覆盖:
task:除hydra配置覆盖之外的命令行覆盖列表,与.hydra/overrides.yaml文件内容一致;hydra:命令行中使用的hydra配置覆盖列表。
其数据类OverridesConf见 hydra/conf/init.py。
hydra.mode:运行模式
hydra.mode指示当前运行模式(RUN 或 MULTIRUN),由 hydra/types.py 中的RunMode枚举定义。更多说明见 tutorials/basic/running_your_app/2_multirun.md。
顶层其他 Hydra 设置
以下字段位于 Hydra 配置顶层,同样可通过配置或命令行覆盖:
| 字段 | 作用 | 默认/说明 |
|---|---|---|
searchpath | Hydra 查找配置的路径列表 | 只能在主配置中设置 |
job_logging/hydra_logging | 日志配置 | 对应 hydra/conf/hydra/job_logging/ 与 hydra/conf/hydra/hydra_logging/,详见 logging.md |
sweeper | Sweeper 插件设置 | 默认 basic sweeper(hydra/_internal/core_plugins/basic_sweeper.py) |
launcher | Launcher 插件设置 | 默认 basic launcher(hydra/_internal/core_plugins/basic_launcher.py) |
callbacks | 实验性回调支持 | 默认{},详见 experimental/callbacks.md |
help | 配置应用--help标志 | 模板位于 hydra/conf/hydra/help/default.yaml,详见 app_help.md |
hydra_help | 配置--hydra-help标志 | 模板位于 hydra/conf/hydra/hydra_help/default.yaml |
output_subdir | 配置.hydra子目录名 | 默认.hydra,设为null可禁用创建,详见 3_working_directory.md |
verbose | 按文件配置 DEBUG 级日志 | 可为布尔值、字符串或字符串列表,详见 4_logging.md |
其中verbose的三种取值形式在 hydra/conf/init.py 的HydraConf中有明确注释:布尔true将根 logger 设为 debug;字符串视为单元素列表;列表中的每个元素表示一个要设为 debug 的 logger。典型命令行为hydra.verbose=true或hydra.verbose=[hydra,__main__]。
此外,hydra/conf/init.py 的末尾通过ConfigStore.instance().store(group="hydra", name="config", node=HydraConf(), provider="hydra")将整个HydraConf注册进 ConfigStore,这也是 Hydra 自身配置能被插件与用户配置覆盖的机制基础。
Hydra 内置 Resolver
Hydra 默认注册了若干 OmegaConf Resolver,注册逻辑集中在 hydra/core/utils.py 的setup_globals()中。
hydra:向hydra配置节点插值
用法为${hydra:path},例如${hydra:job.name}取 Hydra Job 名。其实现为OmegaConf.select(HydraConfig.get(), path)。
now:当前时间字符串
基于strftime格式化当前时间:
# 例如用于输出目录的时间戳 ${now:%H-%M-%S}默认输出目录模式outputs/${now:%Y-%m-%d}/${now:%H-%M-%S}正是它的典型应用。实现为lambda pattern: datetime.now().strftime(pattern),并启用了use_cache=True。
python_version:运行时 Python 版本
通过sys.version_info返回版本字符串,可选参数为major、minor或micro:
default: ${python_version:} # 3.8 major: ${python_version:major} # 3 minor: ${python_version:minor} # 3.8 micro: ${python_version:micro} # 3.8.2注意:源码中实际返回键为major/minor/micro(文档中"macro"应为micro之误)。其实现根据sys.version_info构造版本字典并查询。
hydra_override_dirname:推荐使用的覆盖目录名 Resolver
除文档明确列出的三个 Resolver 外,hydra/core/utils.py 还注册了hydra_override_dirname,它根据hydra.job.config.override_dirname的kv_sep、item_sep、exclude_keys配置生成覆盖派生目录名,用于取代已弃用的hydra.job.override_dirname字段。在hydra.sweep.subdir中使用${hydra_override_dirname:}是当前推荐的写法。
若你需要自定义 Resolver,可在应用代码中调用OmegaConf.register_resolver(Hydra 测试中有现成示例,见 hydra/test_utils/launcher_common_tests.py)。
实践建议小结
- 想快速查看 Hydra 配置全貌,优先使用
python my_app.py --cfg hydra; - 在配置文件或命令行中覆盖
hydra.run.dir、hydra.sweep.dir、hydra.sweep.subdir即可完全掌控输出目录布局,配合${now:...}、${hydra:job.name}等插值可做到按日期、按 Job 名、按覆盖参数组织目录; - 需要读取 Hydra 运行时信息时,配置内用
${hydra:...},代码内用HydraConfig.get(); - 涉及环境变量传递,使用
hydra.job.env_set/hydra.job.env_copy;涉及远程调度(如 SLURM),留意 Launcher 对hydra.job.id的填充行为; hydra.job.override_dirname已弃用,新代码请使用${hydra_override_dirname:}Resolver,并通过hydra.job.config.override_dirname.exclude_keys排除种子等无需进入目录名的键。
【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考