尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Hydra 插件机制完全指南:四大插件类型与自动发现扩展框架

Hydra 插件机制完全指南:四大插件类型与自动发现扩展框架 Hydra 插件机制完全指南四大插件类型与自动发现扩展框架【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydraHydra 是一个用于优雅配置复杂应用的开源框架其核心扩展能力来自插件体系通过Sweeper、Launcher、SearchPathPlugin与ConfigSource四类插件接口开发者可以把超参数搜索、作业调度、配置仓库等能力自由组合进 Hydra。本文以 website/docs/advanced/plugins/intro.md 为骨架结合仓库内抽象接口、内置实现与完整示例插件的源码系统讲解每一类插件的职责、抽象方法、注册与自动发现原理并给出可直接复用的开发模板帮助你从使用 Hydra进阶到扩展 Hydra。插件机制总览一切皆可插拔Hydra 的插件机制建立在统一的Plugin基类之上。hydra/plugins/plugin.py 中的定义极为简洁——它只是一个空的ABC抽象基类所有插件类型都从它派生# hydra/plugins/plugin.py from abc import ABC class Plugin(ABC): ...运行时Hydra 通过 hydra/core/plugins.py 中PLUGIN_TYPES列表维护所有受支持的插件类型PLUGIN_TYPES: List[Type[Plugin]] [ Plugin, ConfigSource, CompletionPlugin, Launcher, Sweeper, SearchPathPlugin, ]也就是说除原文档详细介绍的 Sweeper、Launcher、SearchPathPlugin、ConfigSource 四类插件外CompletionPlugin命令补全插件也属于官方插件接口之一其抽象接口定义在 hydra/plugins/completion_plugin.py内置实现包括hydra/_internal/core_plugins/下的 bash、zsh、fish 三个补全插件。插件类的生命周期分两阶段发现与注册Hydra 启动时扫描已安装的插件包把其中所有满足Plugin且非抽象的类收集进Plugins单例plugin_type_to_subclass_list/class_name_to_class。实例化根据配置中hydra.sweeper、hydra.launcher等节点的_target_字段定位具体插件类并通过instantiate构造实例后调用其setup()完成初始化。Sweeper把命令行参数展开成一批作业职责定义原文档对 Sweeper 的定义是负责把命令行参数列表转换为多个作业job。以内置 basic sweeper 为例给定如下 multirun 参数batch_size128 optimizernesterov,adam learning_rate0.01,0.1它会生成 4 个作业每个作业使用一组具体参数batch_size128 optimizernesterov learning_rate0.01 batch_size128 optimizernesterov learning_rate0.1 batch_size128 optimizeradam learning_rate0.01 batch_size128 optimizeradam learning_rate0.1这就是对配置组做笛卡尔积展开。从 hydra/_internal/core_plugins/basic_sweeper.py 的源码可以看到其实现方式split_arguments先把每个带逗号的覆盖项拆成独立的 override 列表再调用itertools.product(*lists)生成全部组合非 sweep 覆盖项如batch_size128会被原样保留到每个组合中这正是上面示例中batch_size128出现在所有 4 个作业里的原因。该源码模块头的注释还揭示了 basic sweeper 的另一个能力它同时支持range()语法下面两条命令是等价的python foo.py a1,2,3 b10,20 python foo.py arange(1,4) b10,20两者都会生成 6 个作业。BasicSweeper 同时支持通过配置节点max_batch_size控制每批提交的作业数量——当作业总量很大时sweeper 会调用split_overrides_to_chunks按该上限分批把批次交给 launcher 逐批执行避免一次性提交过多作业。抽象接口Sweeper 的抽象接口定义在 hydra/plugins/sweeper.py任何自定义 Sweeper 都必须实现两个抽象方法setup(*, hydra_context, task_function, config) - None初始化 sweeper接收 Hydra 上下文、任务函数与组装好的完整配置用于保存状态并准备 launcher。sweep(arguments: List[str]) - Any执行一次完整的多作业运行arguments是描述本次 sweep 行为的字符串列表具体结构由 Sweeper 实现决定返回值是所有已启动作业的返回对象集合结构与具体实现相关。此外基类还提供了一个非抽象方法validate_batch_is_legal(batch)它会对整批 override 逐条调用config_loader.load_sweep_config预校验组合能否成功组装。源码注释明确指出launcher 可能在另一个进程甚至另一台机器上执行因此 sweeper 必须在此处提前做同样的校验以便尽早发现组装错误——basic_sweeper.py 的sweep()在调用self.launcher.launch(batch, ...)之前就会先执行这一步并打印校验吞吐量的 debug 日志。从源码结构看一个典型的sweep()流程是合并配置中的params与命令行参数 → 用OverridesParser解析 → 展开为批量 override → 逐批校验 → 交给 launcher 执行 → 收集JobReturn结果。Launcher把作业启动到指定环境职责定义Launcher 的职责是把一批参数列表启动到特定环境。原文档的描述是Launcher 接收像上文那样的一批参数列表并为其中每一个启动一个作业作业使用这些参数组装自己的配置内置 basic launcher 只是在本地启动作业。Sweeper 与 Launcher 的分工十分清晰Sweeper 决定跑什么负责参数的展开、分批与校验Launcher 决定在哪里跑、怎么跑负责把已确定的每个作业调度到本地进程、集群、云环境等目标。这也是 Hydra 能实现同一套配置在不同环境运行的关键解耦设计换一个 Launcher 插件例如仓库中plugins/目录下的hydra_joblib_launcher、hydra_submitit_launcher、hydra_ray_launcher、hydra_rq_launcher就能在不修改业务代码的前提下把作业分发到多进程、Slurm 集群、Ray 或 Redis 队列等环境。抽象接口Launcher 接口定义在 hydra/plugins/launcher.py同样只有两个抽象方法setup(*, hydra_context, task_function, config) - None初始化 launcher 实例。launch(job_overrides: Sequence[Sequence[str]], initial_job_idx: int) - Sequence[JobReturn]job_overrides是一批作业参数每个内层列表对应一个作业的 overrideinitial_job_idx是起始作业编号——sweeper 分多批执行时用它保证各批次的作业编号连续。返回该批所有作业的JobReturn序列。从basic_sweeper.py的调用点可以看到 launcher 的使用方式sweeper 在setup()中通过Plugins.instance().instantiate_launcher(...)按hydra.launcher配置实例化 launcher随后每取出一批作业就调用一次launcher.launch(batch, initial_job_idx...)。官方示例插件examples/plugins/example_launcher_plugin的 README.md 给出了一个自定义 launcher 的实际运行效果$ python example/my_app.py --multirun dbpostgresql,mysql [2019-10-22 19:45:05,060] - Example Launcher(foo10, barabcde) is launching 2 jobs locally [2019-10-22 19:45:05,060] - Sweep output dir : multirun/2019-10-22/19-45-05 [2019-10-22 19:45:05,060] - #0 : dbpostgresql db: driver: postgresql pass: drowssap timeout: 10 user: postgres_user ...这个示例 launcher 从自己的配置节点读取了foo和bar两个参数foo10, barabcde展示了插件配置随插件一起打包、在初始化时注入实例的完整链路。SearchPathPlugin在配置组装前改写搜索路径职责定义SearchPathPlugin 是一种配置路径插件它可以操纵配置搜索路径search path。原文档指出了它的两种典型用途影响默认 Hydra 配置让 Hydra 的默认行为更适配特定环境例如替换内置的hydra配置组追加新的搜索路径条目让更多配置对 Hydra 应用可见。SearchPathPlugin 插件会被 Hydra自动发现并在配置组装之前被调用以操纵搜索路径许多其他插件如 sweeper、launcher 插件在被安装后也会实现 SearchPathPlugin把自己的配置目录追加进搜索路径从而无需用户手动指定配置路径。抽象接口与示例实现SearchPathPlugin 接口定义在 hydra/plugins/search_path_plugin.py只有一个抽象方法class SearchPathPlugin(Plugin): abstractmethod def manipulate_search_path(self, search_path: ConfigSearchPath) - None: ...它接收一个ConfigSearchPath对象实现者通过append、prepend等操作调整搜索路径。官方示例 example_searchpath_plugin.py 展示了最典型用法——把插件自带的配置目录追加到搜索路径末尾class ExampleSearchPathPlugin(SearchPathPlugin): def manipulate_search_path(self, search_path: ConfigSearchPath) - None: # Appends the search path for this plugin to the end of the search path # Note that foobar/conf is outside of the example plugin module. # There is no requirement for it to be packaged with the plugin, it just needs # be available in a package. search_path.append( providerexample-searchpath-plugin, pathpkg://arbitrary_package/conf )该示例特意用pkg://scheme 指向arbitrary_package/conf包——源码注释强调被追加的配置目录不要求和插件打包在同一模块里只要它存在于某个可导入的包中即可同时提醒开发者在构建 sdist 后检查包内容、确认MANIFEST.in正确保证配置确实被打进了分发包。provider参数用于标记搜索路径条目的来源便于调试与覆盖判断pkg://与file://等 scheme 由 ConfigSource 体系解析见下文。ConfigSource从非标准位置读取配置职责定义ConfigSource 插件用于在组装配置时让 Hydra 能够访问非标准位置上的配置。原文档给出的典型场景包括接入公司内部的私有配置仓库从公共来源如 GitHub 或 S3读取配置。正因为配置读取被抽象成了可插拔的 ConfigSourceHydra 才能做到配置在哪里、怎么读完全与组装逻辑解耦。抽象接口ConfigSource 接口定义在 hydra/plugins/config_source.py是四个接口中方法最多的一个抽象方法包括scheme() - str静态方法返回该配置源的 scheme 标识例如内置的file://或pkg://ConfigSource.__init__会校验传入路径必须以该 scheme 开头。load_config(config_path: str) - ConfigResult加载指定路径的配置返回一个ConfigResult数据类包含provider、path、config、header、defaults_list、is_schema_source等字段。is_group(config_path) - bool判断路径是否是一个配置组目录。is_config(config_path) - bool判断路径是否是一个配置文件。available() - bool判断该配置源当前是否指向有效位置。list(config_path, results_filter) - List[str]列出指定配置路径下的条目results_filter取None全部、ObjectType.GROUP仅组或ObjectType.CONFIG仅配置返回排序且去重的组/配置标识列表。基类还提供了一些可复用/可覆盖的通用行为值得注意_normalize_file_name(filename)只接受.yaml扩展名——遇到.yml会直接抛出ConfigLoadErrorHydra config files must use the .yaml extension.无扩展名时自动补.yaml_get_header_dict(config_text)解析 YAML 文件头部形如# package ...的注释头用于读取package等元信息遇到第一个非注释头行即停止exists(config_path)默认实现为is_group(...) or is_config(...)子类可按需覆盖以提升性能。一个完整的示例实现官方示例 example_configsource_plugin.py 用内存字典模拟了一个自定义配置源可作为实现参考。它scheme()返回example即该源以example://前缀寻址available()返回self.path valid_path即仅当路径合法时才认为可用在load_config中通过self._normalize_file_name(config_path)规范化文件名、查表、用OmegaConf.create构造DictConfig并附带header含package信息组装ConfigResultis_group/is_config/list分别基于硬编码的组、配置与两级目录结构如dataset/imagenet、level1/level2/nested1返回结果list支持按results_filter过滤。该插件还演示了 ConfigSource 对defaults list 与 package header 的完整支持示例数据中包含带defaults列表的配置如config_with_defaults_list.yaml、configs_with_defaults_list/global_package.yaml以及package: _global_、package: _group_、package: _name_、package: foo._group_._name_等各类 package 头——这意味着自定义 ConfigSource 提供的配置与文件系统上的 YAML 具备同等的组、包与 defaults 语义能力。插件发现与注册机制自动扫描hydra_plugins包要让插件生效Hydra 需要能在启动时找到它们。其核心实现位于 hydra/core/plugins.py 的Plugins单例类关键流程如下_initialize()导入两个顶层模块并作为扫描根hydra._internal.core_plugins内置插件如 basic_launcher、basic_sweeper、bash/fish/zsh completion、file/pkg/structured config sourcehydra_plugins所有第三方安装插件约定的顶层包名。_scan_all_plugins()用pkgutil.walk_packages递归遍历这两个包跳过以_开头但__开头除外的模块逐个导入模块后用inspect.getmembers找出所有_is_concrete_plugin_type(obj)为真的类——即Plugin的子类且非抽象。_register()把每个插件类按继承关系挂到plugin_type_to_subclass_list[plugin_type]下若是ConfigSource子类还会额外注册进SourcesRegistry。这里的SourcesRegistry定义在 hydra/_internal/sources_registry.py维护着 scheme → ConfigSource 类的映射register时若同一 scheme 已被不同类注册会抛错resolve(scheme)用于按 scheme 取回对应类未注册的 scheme 会得到包含全部受支持类型的报错信息。Plugins类还通过is_in_toplevel_plugins_module强制了一个重要约束所有插件类必须定义在hydra_plugins.或hydra._internal.core_plugins.开头的模块中否则_instantiate会抛出RuntimeError。这保证了插件命名空间可控、可扫描、可预测。插件配置的注入方式插件实例并非凭空创建而是通过 Hydra 的配置系统实例化的。以内置 sweeper 为例basic_sweeper.py 在模块加载时就把自己的默认配置注册进了ConfigStoredataclass class BasicSweeperConf: _target_: str hydra._internal.core_plugins.basic_sweeper.BasicSweeper max_batch_size: Optional[int] None params: Optional[Dict[str, str]] None ConfigStore.instance().store( grouphydra/sweeper, namebasic, nodeBasicSweeperConf, providerhydra )_target_指向插件类的完全限定名其余字段作为构造参数注入。运行时Plugins.instantiate_sweeper/instantiate_launcher读取config.hydra.sweeper/config.hydra.launcher节点通过_instantiate用instantiate(config, _target_clazz, _recursive_False)构造插件实例再调用setup(...)。因此替换插件 替换hydra.sweeper/hydra.launcher配置节点的_target_与参数这正是 examples/plugins/example_launcher_plugin 中用hydra/launcher/example.yaml覆盖内置 launcher的机制基础。动手开发你的第一个 Hydra 插件仓库 examples/plugins 目录下提供了 6 个可直接借鉴的完整示例插件工程按类型分布为示例工程演示的插件类型参考入口example_sweeper_pluginSweeper自定义 sweeper 与配套配置example_launcher_pluginLauncher自定义 launcher 及运行输出见 READMEexample_searchpath_pluginSearchPathPlugin把pkg://配置追加进搜索路径example_configsource_pluginConfigSource内存版自定义配置源example_generic_plugin通用 Plugin最简插件骨架example_registered_plugin手动注册演示Plugins.instance().register(...)手动注册方式每个示例工程的目录结构高度一致也是发布第三方插件时应遵循的标准布局example_xxx_plugin/ ├── hydra_plugins/ # 约定的顶层插件包必需 │ └── example_xxx_plugin/ │ ├── __init__.py │ ├── example_xxx_plugin.py # 插件实现 │ └── py.typed # PEP 561 类型标记 ├── tests/ # 插件单元测试 ├── setup.py # 打包配置entry point 或包发现 ├── MANIFEST.in # 确保非 .py 资源如 conf/*.yaml被打入 sdist └── README.md开发步骤要点如下继承对应抽象类按上文各接口实现Sweeper、Launcher、SearchPathPlugin或ConfigSource或直接继承Plugin写通用扩展类必须定义在hydra_plugins包内。用配置节点携带参数插件参数通过ConfigStore注册或随插件打包的conf/hydra/{sweeper,launcher}/xxx.yaml提供_target_指向插件类。需要提供配置的插件同时实现 SearchPathPlugin如原文档所说这是被广泛采用的做法——安装插件后其配置自动进入搜索路径。校验打包产物参考example_searchpath_plugin源码注释的建议构建 sdist 后确认MANIFEST.in把配置 YAML 一并包含。结语Hydra 的插件体系用一个极简的Plugin基类承载了完整的扩展生态Sweeper负责把命令行参数展开为作业批、Launcher负责把作业派发到目标环境、SearchPathPlugin在组装前改写配置搜索路径、ConfigSource则打通任意位置读取配置的能力。这四类接口相互配合构成了组合配置—生成作业—调度执行的完整扩展链路。理解 hydra/core/plugins.py 中的自动扫描与hydra_plugins包约定再对照 examples/plugins 中的六个示例工程实践即可快速把自定义能力接入 Hydra实现真正可插拔的复杂应用配置方案。【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表