
Hydra 输出与工作目录完全指南从hydra.job.chdir到hydra.output_subdir【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra导读本篇技术指南聚焦 Hydra 框架的输出/工作目录机制为什么每次运行都需要一个新的输出目录、输出目录里到底存放了什么、如何让 Python 应用自动切换到该目录以及如何在chdir开启后仍能访问原始工作目录。文章以官方教程 website/docs/tutorials/basic/running_your_app/3_working_directory.md 为核心骨架并结合仓库中hydra/core/utils.py、hydra/conf/hydra/output/default.yaml、示例应用 examples/tutorials/basic/running_your_hydra_app/3_working_directory 等源码与配置帮助你在实际项目中正确使用、定制与迁移 Hydra 的目录管理能力。一、为什么需要每个运行一个输出目录在没有 Hydra 时每次运行实验你都要手动指定一个新的输出目录--output_dir 2019-09-25/15-16-17之类的命令行参数既繁琐又容易忘记覆盖上一次的结果。Hydra 的核心思路是为每一次运行自动创建一个新的输出目录并把你的代码执行环境放到这个输出目录中。每次运行应用Hydra 都会生成一个新的输出目录默认情况下该目录同时用于存放 Hydra 自身产生的输出配置快照、日志等。这意味着你无需操心目录命名也不必担心不同运行之间互相覆盖文件。从源码结构看这个能力由三层机制协同实现默认目录模板默认的run.dir与sweep.dir模板定义在 hydra/conf/hydra/output/default.yaml单次运行hydra.core.utils.run_job()负责计算输出目录、写入配置快照并可选地执行os.chdir见 hydra/core/utils.py批量运行multirunBasicLauncher.launch()依据hydra.sweep.dir与hydra.sweep.subdir为每个 job 计算目录见 hydra/_internal/core_plugins/basic_launcher.py。下面先用一个最小示例观察它的实际行为。二、最小示例查看工作目录与输出目录官方示例应用位于 examples/tutorials/basic/running_your_hydra_app/3_working_directory/my_app.py内容如下import os from omegaconf import DictConfig import hydra from hydra.core.hydra_config import HydraConfig hydra.main() def my_app(_cfg: DictConfig) - None: print(fWorking directory : {os.getcwd()}) print(fOutput directory : {HydraConfig.get().runtime.output_dir}) if __name__ __main__: my_app()运行两次观察输出$ python my_app.py Working directory : /home/omry/dev/hydra Output directory : /home/omry/dev/hydra/outputs/2019-09-25/15-16-17 $ python my_app.py Working directory : /home/omry/dev/hydra Output directory : /home/omry/dev/hydra/outputs/2019-09-25/15-16-19关键观察点每次运行都会生成一个全新的输出目录两次运行的时间戳目录不同15-16-17vs15-16-19互不干扰在默认配置下Hydra 1.2 或chdirFalse当前工作目录不变仍是你启动应用的目录输出目录的完整路径可以通过Hydra Config 中的hydra.runtime.output_dir获取——这是应用内访问输出目录的标准方式。关于如何访问 Hydra Config可参考 website/docs/configure_hydra/Intro.md 中 Accessing the Hydra config 一节。提示上述示例同时存放在 website/docs/tutorials/basic/running_your_app/3_working_directory.md 与示例目录中两者是同一份代码的文档与实体两面。三、输出目录里到底有什么查看其中一个输出目录$ tree outputs/2019-09-25/15-16-17 outputs/2019-09-25/15-16-17 ├── .hydra │ ├── config.yaml │ ├── hydra.yaml │ └── overrides.yaml └── my_app.log目录内容分两部分Hydra 输出子目录默认名为.hydra文件含义config.yaml用户指定配置合成后的完整配置的 YAML 快照hydra.yamlHydra 自身配置的 YAML 快照overrides.yaml本次运行使用的命令行覆盖overrides列表主输出目录文件含义my_app.log本次运行生成的日志文件这套快照机制让每个输出目录自包含、可复现只要保留outputs/...目录事后就能精确得知当时用了什么配置、覆盖了什么参数、Hydra 的配置是怎样的。从源码角度这些文件由run_job()统一写入。在 hydra/core/utils.py 中可以看到实际写盘逻辑if config.hydra.output_subdir is not None: hydra_output Path(config.hydra.runtime.output_dir) / Path( config.hydra.output_subdir ) _save_config(task_cfg, config.yaml, hydra_output) _save_config(hydra_cfg, hydra.yaml, hydra_output) _save_config(config.hydra.overrides.task, overrides.yaml, hydra_output)其中_save_config()hydra/core/utils.py会先mkdir(parentsTrue, exist_okTrue)再以OmegaConf.to_yaml()序列化写入。注意config.hydra.output_subdir若为None则整个.hydra目录都不会被创建——这正是下一节禁用输出子目录的机制入口。四、让应用自动切换到输出目录hydra.job.chdir很多应用希望把输出文件如数据库 dump、模型 checkpoint直接写在输出目录里而不是手动拼接绝对路径。Hydra 从 v1.2 起提供了hydra.job.chdir开关。4.1 行为对比hydra.job.chdir的默认值定义在 hydra/conf/init.py# Change current working dir to the output dir. chdir: bool False即Hydra v1.2 起默认False工作目录保持不变。将其设为True后hydra.main装饰器会在调用你的主函数之前执行os.chdir把 Python 的工作目录切换到本次运行的输出目录。实测效果# check current working dir $ pwd /home/jasha/dev/hydra # for Hydra 1.2, working dir remains unchanged by default $ python my_app.py Working directory : /home/jasha/dev/hydra Output directory : /home/jasha/dev/hydra/outputs/2023-04-18/13-43-24 # working dir changed to output dir $ python my_app.py hydra.job.chdirTrue Working directory : /home/jasha/dev/hydra/outputs/2023-04-18/13-43-17 Output directory : /home/jasha/dev/hydra/outputs/2023-04-18/13-43-17 # output dir and files are still created even if chdir is disabled: $ tree -a outputs/2023-04-18/13-43-24/ outputs/2023-04-18/13-43-24/ ├── .hydra │ ├── config.yaml │ ├── hydra.yaml │ └── overrides.yaml └── my_app.log三个要点chdirTrue后os.getcwd()与hydra.runtime.output_dir指向同一个目录此时直接写相对路径文件即可落在输出目录内即使不开启chdir输出目录和其中的文件照常创建.hydra与my_app.log依旧存在只是你的进程还在原目录该开关既可以在命令行以hydra.job.chdirTrue传入也可以写进配置文件的hydra.job节点。4.2 源码实现chdir的切换逻辑在 hydra/core/utils.py_chdir hydra_cfg.hydra.job.chdir if _chdir: os.chdir(output_dir) ret.working_dir output_dir else: ret.working_dir os.getcwd()并且使用try/finally保证任务结束包括异常中断后恢复原始工作目录hydra/core/utils.py。仓库测试也对chdirTrue的场景做了覆盖验证例如 hydra/test_utils/launcher_common_tests.py 中通过overrides [hydra.job.chdirTrue]断言os.getcwd()指向预期目录。需要留意切换工作目录的行为会影响应用对相对路径的解析。如果你在代码里读取了启动时所在目录下的资源文件请参考下一节的两个工具函数否则在chdirTrue下会定位到错误位置。五、访问原始工作目录get_original_cwd()与to_absolute_path()当hydra.job.chdirTrue时os.getcwd()已指向输出目录但你依然可以拿到启动应用时所在的原始工作目录。官方示例 examples/tutorials/basic/running_your_hydra_app/3_working_directory/original_cwd.py 演示了这两种用法import os from omegaconf import DictConfig import hydra from hydra.utils import get_original_cwd, to_absolute_path hydra.main() def my_app(_cfg: DictConfig) - None: print(fCurrent working directory : {os.getcwd()}) print(fOrig working directory : {get_original_cwd()}) print(fto_absolute_path(foo) : {to_absolute_path(foo)}) print(fto_absolute_path(/foo) : {to_absolute_path(/foo)}) if __name__ __main__: my_app()运行结果$ python examples/tutorial/8_working_directory/original_cwd.py Current working directory : /Users/omry/dev/hydra/outputs/2019-10-23/10-53-03 Original working directory : /Users/omry/dev/hydra to_absolute_path(foo) : /Users/omry/dev/hydra/foo to_absolute_path(/foo) : /foo两个函数的语义见 hydra/utils.py函数行为get_original_cwd()返回启动 Hydra 应用时的原始工作目录即HydraConfig.get().runtime.cwd见 hydra/utils.py。未初始化 HydraConfig 时调用会抛出ValueErrorto_absolute_path(path)相对路径按原始工作目录为基准转为绝对路径绝对路径原样返回见 hydra/utils.py典型用法应用需要读取位于项目根目录下的数据文件或预训练模型时用to_absolute_path(data/foo)而非裸的相对路径这样无论chdir是否开启都能正确定位。六、改变或禁用 Hydra 输出子目录hydra.output_subdir默认情况下 Hydra 输出子目录名为.hydra。你可以通过覆盖hydra.output_subdir来改变或禁用它的创建# 改变子目录名例如改为 custom_hydra_output python my_app.py hydra.output_subdircustom_hydra_output # 禁用子目录创建不生成 .hydra 目录 python my_app.py hydra.output_subdirnull结合上一节源码可以看到run_job()在写快照前先判断config.hydra.output_subdir is not Nonehydra/core/utils.py为null时直接跳过整个.hydra目录的创建。注意禁用.hydra后本次运行将不再保留config.yaml/hydra.yaml/overrides.yaml快照会损失可复现性请按需使用。七、定制输出目录命名hydra.run.dir与hydra.sweep.dir7.1 单次运行run目录模板默认的单次运行模板定义在 hydra/conf/hydra/output/default.yamlrun: dir: outputs/${now:%Y-%m-%d}/${now:%H-%M-%S}即outputs/日期/时分秒的树形结构。你可以在配置文件中覆盖hydra.run.dir来实现自己的命名策略website/docs/configure_hydra/workdir.md 给出了三种常见模式按日期分组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}模板中支持${now:...}时间格式化、${hydra.job.name}任务名以及用户自定义配置项插值实现目录名自描述实验内容的效果。7.2 批量运行multirun目录模板multirun 场景下涉及两个键键默认值含义hydra.sweep.dirmultirun/${now:%Y-%m-%d}/${now:%H-%M-%S}整个 sweep 的根目录hydra.sweep.subdir${hydra.job.num}每个 job 的子目录job 序号默认配置同样位于 hydra/conf/hydra/output/default.yaml。在底层BasicLauncher.launch()会为每个 job 调用run_job()并传入job_dir_keyhydra.sweep.dir与job_subdir_keyhydra.sweep.subdir见 hydra/_internal/core_plugins/basic_launcher.py而run_job()则在 hydra/core/utils.py 中先取sweep.dir再延迟求值sweep.subdir因为hydra.job.num这类值只在客户端执行时可用最终拼成output_dir os.path.join(dir, subdir)。因此multirun 的目录同样支持时间、job 名等插值hydra: sweep: dir: ${hydra.job.name} subdir: ${hydra.job.num}运行python my_app.py --multirun aa1,a2,a3后将得到类似my_app/0、my_app/1、my_app/2的目录结构。7.3 用hydra_override_dirname生成描述性目录名如果希望子目录名直接体现本次 job 的命令行参数如batch_size32,learning_rate0.1可以使用内置的hydra_override_dirname解析器它从命令行 override 推导目录名通常与hydra.sweep.subdir配合使用详见 website/docs/configure_hydra/workdir.mdhydra: sweep: dir: multirun subdir: ${hydra_override_dirname:}运行python my_app.py --multirun batch_size32 learning_rate0.1,0.01会得到multirun ├── batch_size32,learning_rate0.01 └── batch_size32,learning_rate0.1解析器还支持在调用处定制分隔符与排除键例如将随机种子排除在目录名之外hydra: sweep: dir: multirun subdir: ${hydra_override_dirname:{exclude_keys: [seed]}}/seed${seed}运行python my_app.py --multirun batch_size32 learning_rate0.1,0.01 seed1,2将生成multirun ├── batch_size32,learning_rate0.01 │ ├── seed1 │ └── seed2 └── batch_size32,learning_rate0.1 ├── seed1 └── seed2也可自定义键值分隔符kv_sep、条目分隔符item_sep甚至通过element_resolver挂载一个自定义 OmegaConf 解析器对每个元素做预处理例如把/与\替换为_以保证目录名在不同平台可用。相关示例配置与配套应用见仓库中的 examples/configure_hydra/job_override_dirname 目录。八、配套资源与进一步阅读本文核心教程 website/docs/tutorials/basic/running_your_app/3_working_directory.md可运行的示例代码examples/tutorials/basic/running_your_hydra_app/3_working_directory/my_app.py 与 original_cwd.py工作目录定制模式详解website/docs/configure_hydra/workdir.md输出目录定制配套示例examples/configure_hydra/workdir 与 examples/configure_hydra/job_override_dirnameHydra Config 访问方式HydraConfig.get()website/docs/configure_hydra/Intro.md关键实现源码hydra/core/utils.pyrun_job/_save_config、hydra/utils.pyget_original_cwd/to_absolute_path、hydra/conf/init.pyhydra.job.chdir默认值、hydra/conf/hydra/output/default.yaml默认目录模板相关测试hydra/test_utils/launcher_common_tests.pychdir行为验证使用建议在 Hydra 1.2 及以上版本中如果应用需要把产物写进输出目录推荐显式开启hydra.job.chdirTrue并使用get_original_cwd()/to_absolute_path()读取启动目录下的资源同时保留默认的.hydra快照以维持可复现性。升级或迁移到新版本时务必确认chdir默认值是否影响了你对相对路径的既有假设。【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考