ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hydra 实验性功能深度指南:Callback 事件机制与基于配置 Pickle 的任务重跑

Hydra 实验性功能深度指南:Callback 事件机制与基于配置 Pickle 的任务重跑 Hydra 实验性功能深度指南Callback 事件机制与基于配置 Pickle 的任务重跑【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydraHydra 的 experimental 目录聚合了尚在演进中的前沿能力其 API 尚未完全稳定。本指南以 experimental/intro.md 为总纲完整展开其中两大核心实验特性——Callback 事件回调机制与基于 Pickle 配置的任务重跑--experimental-rerun并结合仓库源码与测试用例说明其接口定义、调用顺序、配置方法与限制边界。读完本文你将能够自定义 Hydra 回调以挂载生命周期钩子如任务结束后上传文件、远程集群错误日志采集并利用官方回调实现任意历史任务的一键复现。实验性功能可用但 API 仍在演进Hydra 将一批新特性标记为实验性experimental其准入门槛在 version-1.3 文档的 Introduction 中有着明确表述这些功能可以正常工作Those features should all work但其 API 可能尚未稳定依赖它们的代码可能在未来的版本升级中发生变化code relying on them may break in future versions as they evolve当功能被认为足够稳定和完整后会被移出实验性目录并正式转正。从仓库结构看实验性功能集中在两处核心实现位于 hydra/experimentalcallback.py、callbacks.py配套演示应用位于 examples/experimental/rerun。文档侧version-1.3则由 intro、callbacks、rerun 三页构成完整篇章对应 sidebar 配置。Callback 接口六个生命周期事件Callback 机制允许自定义代码在 Hydra 的各种事件发生时被触发。使用前需导入基类from hydra.experimental.callback import Callback然后创建Callback的子类重写其中任意一个或多个方法并将子类注册到hydra.callbacks配置节中方法便会在恰当的时机被调用。Callback类定义于 hydra/experimental/callback.py共暴露六个事件方法覆盖 RUN 与 MULTIRUN 两种模式事件方法触发时机附加参数on_run_start(config)RUN 模式下应用代码开始执行前被调用。此时config已完成组合含 overrides但部分hydra.runtime配置尚未填充无on_run_end(config)RUN 模式下应用代码返回后被调用无on_multirun_start(config)MULTIRUN 模式下任何任务开始前被调用使用 launcher 时在本机执行先于任何 Sweeper/Launcher 初始化无on_multirun_end(config)MULTIRUN 模式下所有任务返回后被调用使用 launcher 时在本机执行无on_job_start(config, *, task_function)RUN 与 MULTIRUN 模式下每个 Hydra 任务开始前调用一次在hydra.core.utils.run_job内部触发。远程启动时会在远端随应用代码执行。task_function即被hydra.main装饰的函数task_functionon_job_end(config, job_return)RUN 与 MULTIRUN 模式下每个任务结束后调用一次同样在run_job内部触发。job_return携带对日志或后处理有用的信息参见hydra.core.utils.JobReturnjob_return值得注意的是on_job_end拿到的job_return是完整的任务返回记录。仓库测试 tests/test_callbacks.py 验证了即使在应用被KeyboardInterrupt中断时on_job_end与on_run_end也恰好各触发一次且JobReturn携带statusFAILED excKeyboardInterrupt的完整信息后中断仍会正常向外传播。配置 Callback注册与完整示例以每次任务结束后将某文件上传到 S3 桶为例。为简洁起见回调类直接写在应用文件内生产环境建议独立成文件class MyCallback(Callback): def __init__(self, bucket: str, file_path: str) - None: self.bucket bucket self.file_path file_path def on_job_end(self, config: DictConfig, **kwargs: Any) - None: print(fJob ended,uploading...) # uploading... hydra.main(version_baseNone, config_pathconf, config_nameconfig) def my_app(cfg: DictConfig) - None: print(OmegaConf.to_yaml(cfg)) if __name__ __main__: my_app()运行python my_app.py输出中可以看到自定义的on_job_end被调用$ python my_app.py foo: bar Job ended,uploading...回调的注册通过配置完成目录结构与三个配置文件如下conf ├── config.yaml └── hydra └── callbacks └── my_callback.yamldefaults: - /hydra/callbacks: - my_callback foo: bar# package _global_ hydra: callbacks: my_callback: _target_: my_app.MyCallback bucket: my_s3_bucket file_path: ./test.pt这段配置体现了 Hydra 的核心机制hydra.callbacks是一个 config group通过defaults列表引用my_callbackmy_callback.yaml中_target_指向回调类的导入路径bucket、file_path则是传入__init__的构造参数由 Hydra 的实例化机制完成对象创建。多回调注册与调用顺序在hydra.callbacks配置节中可以使用列表注册多个回调。start类事件按最终组合后的顺序依次调用end类事件按逆序调用。假设组合后的配置如下# package hydra.callbacks my_callback1: _target_: my_app.MyCallback1 param1: val1 my_callback2: _target_: my_app.MyCallback2 param2: val2则每个任务开始前先调用MyCallback1.on_job_start再调用MyCallback2.on_job_start任务结束后先调用MyCallback2.on_job_end再调用MyCallback1.on_job_end类似栈的后进先出。整体生命周期顺序为on_run_start/on_multirun_start→每个任务on_job_start→on_job_end→ 应用退出前on_run_end/on_multirun_end各调用一次。内置示例 Callback 的源码实现官方提供了两个开箱即用的回调实现位于 hydra/experimental/callbacks.pyLogJobReturnCallback—— 任务结束时记录返回值或错误对运行在远程集群如 slurm上排查失败任务尤为有用。其核心逻辑根据job_return.status分支处理class LogJobReturnCallback(Callback): def on_job_end(self, config, job_return, **kwargs): if job_return.status JobStatus.COMPLETED: self.log.info(fSucceeded with return value: {job_return.return_value}) elif job_return.status JobStatus.FAILED: self.log.error(, exc_infojob_return._return_value)PickleJobInfoCallback—— 将任务配置与返回值以 pickle 序列化保存用于复现 Hydra 任务即下一节的重跑功能。on_job_start时把组合后的config保存为${output_dir}/.hydra/config.pickleon_job_end时把JobReturn保存为${output_dir}/.hydra/job_return.pickleclass PickleJobInfoCallback(Callback): def on_job_start(self, config, **kwargs): self.output_dir Path(config.hydra.runtime.output_dir) / Path(config.hydra.output_subdir) self._save_pickle(objconfig, filenameconfig.pickle, output_dirself.output_dir) def on_job_end(self, config, job_return, **kwargs): self._save_pickle(objjob_return, filenamejob_return.pickle, output_dirself.output_dir) def _save_pickle(self, obj, filename, output_dir): output_dir.mkdir(parentsTrue, exist_okTrue) with open(str(output_dir / filename), wb) as file: pickle.dump(obj, file, protocol4)两个回调的 pickle 产物是否与真实任务一致由 tests/test_callbacks.py 严格验证测试断言config.pickle与应用中保存的任务配置完全相等、job_return.pickle的返回值与状态JobStatus.COMPLETED符合预期且 RUN 与 MULTIRUN 两种模式下都成立。重跑历史任务--experimental-rerun--experimental-rerun命令行选项允许从一个先前任务保存的 config pickle 直接恢复运行其演示应用位于 examples/experimental/rerun。第一步保存任务配置在config.yaml中注册PickleJobInfoCallbackhydra: callbacks: save_job_info: _target_: hydra.experimental.callbacks.PickleJobInfoCallback应用函数仅打印输出目录与配置值hydra.main(config_path., config_nameconfig) def my_app(cfg: DictConfig) - None: log.info(foutput_dir{HydraConfig.get().runtime.output_dir}) log.info(fcfg.foo{cfg.foo})首次运行$ python my_app.py [2022-03-16 14:51:30,905][hydra.experimental.pickle_job_info_callback][INFO] - Saving job configs in .../outputs/2022-03-16/14-51-30/.hydra/config.pickle [2022-03-16 14:51:30,906][__main__][INFO] - Output_dir.../outputs/2022-03-16/14-51-30 [2022-03-16 14:51:30,906][__main__][INFO] - cfg.foobar [2022-03-16 14:51:30,906][hydra.experimental.pickle_job_info_callback][INFO] - Saving job_return in .../outputs/2022-03-16/14-51-30/.hydra/job_return.pickleconfig.pickle即重跑所需的输入。第二步从 Pickle 重跑$ OUTPUT_DIR/path/to/outputs/2022-03-16/14-51-30/.hydra/ $ python my_app.py --experimental-rerun $OUTPUT_DIR/config.pickle .../hydra/main.py:23: UserWarning: Experimental rerun CLI option. warnings.warn(msg, UserWarning) [2022-03-16 14:59:21,666][__main__][INFO] - Output_dir/path/to/outputs/2022-03-16/14-51-30 [2022-03-16 14:59:21,666][__main__][INFO] - cfg.foobar注意两点启动时会输出 Experimental rerun CLI option 的用户警告my_app.log会追加第二次运行的日志但本次不会触发任何 Callback。命令行参数的源码实现从源码可以确认该选项的真实行为。选项注册位于 hydra/_internal/utils.pyparser.add_argument( --experimental-rerun, helpRerun a job from a previous config pickle, )其处理逻辑在 hydra/main.py 的decorated_main中def decorated_main(cfg_passthrough: Optional[DictConfig] None) - Any: if cfg_passthrough is not None: return task_function(cfg_passthrough) else: args args_parser.parse_intermixed_args() if args.experimental_rerun is not None: cfg _get_rerun_conf(args.experimental_rerun, args.overrides) task_function(cfg) _flush_loggers() else: _run_hydra(...)可以推断出实现要点--experimental-rerun分支绕过了完整的_run_hydra流程直接反序列化 pickle 得到cfg后调用task_function(cfg)——这解释了为什么重跑时不改变工作目录、不调用回调、也基本不执行其他hydra.main的辅助逻辑。重要限制与注意事项官方文档明确列出了该实验功能的边界仅支持单次运行single run不支持 multirun 场景--experimental-rerun不能与其他命令行选项或 overrides 同时使用额外的参数会被直接忽略。测试 test_experimental_rerun 印证了这一点传入x1时同样会发出 Config overrides are not supported as of now 的警告重跑通过cfg_passthrough将配置直接传给应用因此除日志外其余hydra.main功能如切换工作目录、调用回调均不会执行配置以尽力而为best efforts的方式保存与重建只能保证hydra.main传入的cfg对象本身跨运行保持一致。由于配置是惰性求值的若应用在运行时才解析配置其解析结果无法保证一致。例如配置time_now: ${now:%H-%M-%S}在应用内通过cfg.time_now访问时每次运行都会解析出不同的时间值。适用场景与使用建议综合文档与源码这两项实验特性最典型的落地场景包括远程集群slurm 等失败排查通过LogJobReturnCallback在任务结束时集中记录返回值或异常堆栈任务可复现性通过PickleJobInfoCallback持久化完整组合配置配合--experimental-rerun对任意历史任务做精确复现与调试生命周期钩子扩展基于Callback六个事件方法实现上传产物、发送通知、资源清理等与运行模式RUN/MULTIRUN及本地/远端环境正交的横切逻辑。由于这些功能仍处于实验阶段依赖时需注意锁定 Hydra 版本并关注后续版本中 API 的演进与转正公告。【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表