多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

EdgeLM/fairseq Hydra 配置集成指南:基于 Dataclass 的分层配置与 fairseq-hydra-train 训练实战

EdgeLM/fairseq Hydra 配置集成指南:基于 Dataclass 的分层配置与 fairseq-hydra-train 训练实战 EdgeLM/fairseq Hydra 配置集成指南基于 Dataclass 的分层配置与 fairseq-hydra-train 训练实战【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm导读本文以 edgelm/docs/hydra_integration.md 为骨架系统讲解 EdgeLM 项目所依赖的 fairseq 框架如何通过 Hydra 与 Python dataclass 重构其配置体系从旧的全局args命名空间迁移到组件自带配置 dataclass 分层 YAML 覆盖的新模式并给出fairseq-hydra-train的三种实战用法命令行覆盖、外部配置替换、外部配置目录叠加。读完本文你将掌握如何为新组件声明配置 dataclass、如何利用II()实现跨节点参数继承、如何用 YAML 分层组织并复用训练配置以及如何结合仓库源码fairseq/dataclass、fairseq_cli/hydra_train.py理解配置从 dataclass 默认值到最终生效值的完整链路。Hydra 是什么Hydra 是一个开源 Python 框架旨在简化研究类及其他复杂应用的开发。其核心能力是动态构建层级化配置通过组合composition生成配置并允许通过配置文件与命令行对其进行覆盖override。Hydra 这个名字取自多头九头蛇的寓意——它天然支持同时运行多个相似任务例如超参扫描就像多头蛇同时伸出多个头一样。在 EdgeLM/fairseq 中Hydra 与 OmegaConf 配合使用dataclass 定义配置结构YAML 文件提供默认值与覆盖值命令行提供最终覆盖。动机为什么 fairseq 需要 Hydra旧模式的问题共享 args 命名空间直到引入 Hydra 之前fairseq 的所有组件都通过一个在应用启动时创建的全局限性args命名空间来配置。每个组件通过声明自己的add_args方法向 argparse parser 注册参数并寄希望于参数名不会与其他组件的参数冲突。这种模式在小规模应用中尚可工作但随着 fairseq 不断壮大并被集成进其他应用问题逐渐暴露难以追踪参数来源要弄清楚某个组件如何被配置需要 a) 检查该组件注册了哪些参数b) 阅读源码找出它使用了哪些在其他地方注册的共享参数。复现成本高复现一个模型往往需要共享一条包含几十个命令行开关的长命令。命名空间互相污染组件间参数名冲突的风险随规模增长。新模式dataclass 封装配置旧模式出于向后兼容仍然支持但未来会被弃用。新组件应遵循以下约定创建一个 dataclass 封装配置该组件所需的全部参数该 dataclass 随组件一起注册传给register_*()函数fairseq 负责构造配置对象并将其传给组件的构造函数组件之间共享参数是可选的但必须显式指向真相来源source of truth见下文II()继承示例。这一改变使 fairseq 组件更独立、更易被其他应用复用要创建某个组件只需要初始化其 dataclass 并覆盖部分默认值即可。配置方式的升级路径虽然通过命令行配置 fairseq无论是旧的 argparse 入口还是新的 Hydra 入口依然完全受支持但你现在可以完全或逐段地通过层级化 YAML 配置文件来配置 fairseq。这些 YAML 文件还可以作为示例随仓库发布供他人以完全一致的配置复现任务。此外Hydra 拥有丰富且持续增长的插件库提供超参扫描包括通过 Ax 库实现贝叶斯优化、跨平台任务分发等功能。这些能力让fairseq-hydra-train天然具备跑实验矩阵的能力。创建或迁移组件dataclass 配置规范基本规则每个新建或改造后的组件都应提供一个配套 dataclass。这些 dataclass 通常与组件位于同一文件中并作为参数传给register_*()函数。所有 fairseq 应用都必须包含的顶层配置放在 global 配置文件 中并加入FairseqConfig对象。每个 dataclass 是一个类似NamedTuple的纯数据对象plain-old-data object。其特点使用dataclass装饰器修饰通常继承自FairseqDataclass它提供了一些向后兼容的功能每个字段必须有类型注解通常带有 metadata如 help 字符串和默认值字段的数据类型只能是原始类型或其他配置对象。FairseqDataclass在 edgelm/fairseq/dataclass/configs.py 中定义它提供了_get_all_attributes()、_get_meta()、_get_default()、_get_type()、_get_help()、_get_choices()等元数据访问方法以及from_namespace()用于从旧 argparse Namespace 转换——这是向后兼容机制的核心。示例InteractiveConfigfrom dataclasses import dataclass, field from fairseq.dataclass import FairseqDataclass dataclass class InteractiveConfig(FairseqDataclass): buffer_size: int field( default0, metadata{ help: read this many sentences into a buffer before processing them }, ) input: str field( default-, metadata{help: file to read from; use - for stdin}, )这正是 edgelm/fairseq/dataclass/configs.py 中InteractiveConfig的真实定义对应fairseq-interactive的交互式推理入口。继承值II()与${...}插值有些组件需要共享同一个值。例如学习率调度器lr scheduler和优化器optimizer都需要知道初始学习率。可以通过声明一个字段使其默认值继承自同一配置层级中的另一个配置节点dataclass class FairseqAdamConfig(FairseqDataclass): ... lr: List[float] II(optimization.lr) ...II(optimization.lr)是${optimization.lr}的语法糖后者是在 YAML 配置文件或命令行中实现同样效果的写法。注意这要求根配置中存在一个名为optimization的配置对象且其中包含名为lr的字段。在 edgelm/fairseq/dataclass/configs.py 中OptimizationConfig的lr字段默认值为[0.25]而DatasetConfig中的max_tokens_valid、batch_size_valid分别通过II(dataset.max_tokens)、II(dataset.batch_size)继承CheckpointConfig与DistributedTrainingConfig也大量使用了II(common.*)这类插值读者可以在同一文件中找到大量真实用例。Tasks 和 ModelsTask 和 Model 的创建方式与以往相同区别仅在于旧实现现在继承LegacyFairseq*基类而新组件继承FairseqTask和FairseqModel并向register_*()函数提供 dataclass。Task 示例dataclass class LanguageModelingConfig(FairseqDataclass): data: Optional[str] field( defaultNone, metadata{help: path to data directory} ) ... register_task(language_modeling, dataclassLanguageModelingConfig) class LanguageModelingTask(FairseqTask): ... classmethod def setup_task(cls, cfg: LanguageModelingConfig): ...注意setup_task的签名直接接收LanguageModelingConfig类型类型即文档。Model 示例dataclass class TransformerLanguageModelConfig(FairseqDataclass): activation_fn: ChoiceEnum(utils.get_available_activation_fns()) field( defaultrelu, metadata{help: activation function to use} ) dropout: float field(default0.1, metadata{help: dropout probability}) ... register_model(transformer_lm, dataclassTransformerLanguageModelConfig) class TransformerLanguageModel(FairseqLanguageModel): ... classmethod def build_model(cls, cfg: TransformerLanguageModelConfig, task: FairseqTask): ...仓库中的真实实现位于 edgelm/fairseq/models/transformer_lm.pyTransformerLanguageModelConfig定义了dropout、decoder_embed_dim、decoder_layers等字段register_model(transformer_lm, dataclassTransformerLanguageModelConfig)将两者绑定build_model(cls, args, task)负责按配置构建模型。同文件下方还通过register_model_architecture(transformer_lm, transformer_lm_wiki103)、transformer_lm_gpt、transformer_lm_big等注册了大量预置架构见 edgelm/fairseq/models/transformer_lm.py这些名称正是modeltransformer_lm/transformer_lm_gpt这种 Hydra 组选择语法的来源。其他组件tokenizer / bpe / criterion 等其他组件的工作方式不变但现在将配置 dataclass 作为唯一的构造函数参数dataclass class MosesTokenizerConfig(FairseqDataclass): source_lang: str field(defaulten, metadata{help: source language}) ... register_tokenizer(moses, dataclassMosesTokenizerConfig) class MosesTokenizer(object): def __init__(self, cfg: MosesTokenizerConfig): ...为新增组件类型注册扩展 FairseqConfig如果你要为一类全新组件添加新的注册表需要将其添加到 edgelm/fairseq/dataclass/configs.py 中的FairseqConfig对象dataclass class FairseqConfig(object): ... my_new_registry: Any NoneFairseqConfig目前包含common、common_eval、distributed_training、dataset、optimization、checkpoint、bmuf、generation、eval_lm、interactive、ema等固定 dataclass 字段以及modelMISSING即必选、task、criterion、optimizer、lr_scheduler、scoring、bpe、tokenizer等Any类型的注册表字段。新增注册表只需在末尾加一个Any None字段即可。注册机制背后的实现注册与构建的底层实现在 edgelm/fairseq/registry.py 中setup_registry()为每个注册名维护REGISTRY类注册表、DATACLASS_REGISTRYdataclass 注册表和REGISTRIES全局注册表索引。register_x(name, dataclassNone)装饰器会做三项关键工作校验 dataclass 必须继承FairseqDataclass将 dataclass 实例node._name name通过ConfigStore.instance().store(...)注册进 Hydra 的配置存储指定groupregistry_name——这正是 Hydra 能通过modelxxx、taskxxx选择组件的根源将类挂到REGISTRY[name]。build_x()则负责在运行时根据cfg._name从DATACLASS_REGISTRY找到对应 dataclass用merge_with_parent(dc(), cfg)见 edgelm/fairseq/dataclass/utils.py把 YAML/命令行提供的覆盖值与 dataclass 默认值合并再构造组件。使用fairseq-hydra-train训练要充分利用 Hydra 提供的配置灵活性建议使用fairseq-hydra-train入口训练新模型。旧的 CLI 工具如fairseq-train在可预见的未来仍受支持但最终会被弃用。该入口在 edgelm/fairseq_cli/hydra_train.py 中实现并通过 edgelm/setup.py 的console_scripts注册为命令行程序。其启动流程为hydra_main上的hydra.main(config_pathos.path.join(.., fairseq, config), config_nameconfig)指明配置搜索路径为仓库内 edgelm/fairseq/config 目录、主配置名为configHydra 启动时创建一个层级配置对象其中包含所有必要的 dataclass 及其代码内默认值默认值被 edgelm/fairseq/config 目录中 YAML 文件的值覆盖目前只设置最小默认值再被命令行参数的值进一步覆盖add_defaults(cfg)见 edgelm/fairseq/dataclass/initialize.py针对 Hydra 不知道的动态注册组件task/model/criterion/optimizer/lr_scheduler 等从各*_DATACLASS_REGISTRY查出对应 dataclass 并执行merge_with_parent把注册表中的默认值补进配置最后调用distributed_utils.call_main(cfg, pre_main, **kwargs)进入与fairseq-train相同的训练主流程。hydra_init()edgelm/fairseq/dataclass/initialize.py在启动时把FairseqConfig及每个顶层字段的默认实例存入 Hydra 的 ConfigStore保证config.yaml中的defaults列表能按名称解析。主配置 edgelm/fairseq/config/config.yaml 内容如下# package _group_ hydra: run: dir: . defaults: - _self_ - task: null - model: null - criterion: cross_entropy - optimizer: null - lr_scheduler: fixed - bpe: null - tokenizer: null - scoring: null - generation: null - common_eval: null - eval_lm: null注意criterion与lr_scheduler分别默认指向cross_entropy与fixed其余注册表默认置空由用户在命令行或 YAML 中指定。1. 通过命令行覆盖默认值$ fairseq-hydra-train \ distributed_training.distributed_world_size1 \ dataset.batch_size2 \ task.datadata-bin \ modeltransformer_lm/transformer_lm_gpt \ tasklanguage_modeling \ optimization.max_update5000要点形如dataset.batch_size2的参数使用点号路径定位层级配置中的具体字段modeltransformer_lm/transformer_lm_gpt除了显式提供参数值外还指示 Hydra 将 edgelm/fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml 中的配置叠加到 dataclass 默认值之上如果不想指定特定架构可以直接写modeltransformer_lm只对已迁移的 task/model 生效。以transformer_lm_gpt.yaml为例它给出了 GPT 风格 LM 的完整参数activation_fn: gelu、dropout: 0.1、decoder_embed_dim: 768、decoder_ffn_embed_dim: 3072、decbegin▁of▁sentence#oder_layers: 12、decoder_attention_heads: 12、decoder_normalize_before: true等完整字段见 edgelm/fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml。仓库还内置了 wiki103、big、gbw、gpt2 系列等多种预置架构配置edgelm/fairseq/config/model/transformer_lm 目录。2. 用外部配置替换内置配置$ fairseq-hydra-train \ --config-dir /path/to/external/configs \ --config-name wiki103其中/path/to/external/configs/wiki103.yaml内容如下# package _group_ model: _name: transformer_lm distributed_training: distributed_world_size: 1 dataset: batch_size: 2 task: _name: language_modeling data: /path/to/data add_bos_token: false max_target_positions: 1024 optimization: max_update: 50000 lr: [ 0.25 ] criterion: cross_entropy optimizer: adam lr_scheduler: _name: cosine要点此时不使用edgelm/fairseq/config 中的内置配置但每个 dataclass 的默认值依然生效除非被你的外部配置覆盖顶层字段如model、task、optimization对应FairseqConfig的顶层节点组件节点通过_name指定注册名如model._name: transformer_lm、lr_scheduler._name: cosineHydra 据此从 ConfigStore 找到对应 dataclasslr: [ 0.25 ]展示了列表类型字段在 YAML 中的写法对应OptimizationConfig.lr的List[float]类型。此外你还可以在同目录下按顶层字段名如model、dataset建子目录并放置有意义的配置文件将主配置拆分为多个片段。例如可以同时维护model/small_transformer_lm.yaml、model/big_transformer_lm.yaml然后通过命令行、主配置的 defaults 来选用甚至把多个配置一次性全部作为 sweep 启动参见 Hydra 文档中的 sweep 用法。3. 将外部配置目录加入 Hydra 搜索路径这种方式可以在保留内置默认配置包括所有 bundled config 文件的同时只对部分组件使用你自己的配置文件$ fairseq-hydra-train \ distributed_training.distributed_world_size1 \ dataset.batch_size2 \ task.data/path/to/data/ \ modeltransformer_lm/2_layers \ tasklanguage_modeling \ optimization.max_update5000 \ --config-dir /path/to/external/configs其中/path/to/external/configs的目录结构如下. -- model | -- transformer_lm | | -- 2_layers.yaml2_layers.yaml是transformer_lm_gpt.yaml的副本但将decoder_layers改为 2。这样modeltransformer_lm/2_layers就会命中外部配置目录中你自定义的架构文件而其他部分如tasklanguage_modeling、criterion默认值等仍使用内置配置。你也可以用同样的方式为其他组件添加自定义配置。三种方式的取舍总结方式命令行内置 YAML外部 YAML适用场景1. 命令行覆盖逐个字段指定使用不使用快速实验、微调个别参数2. 外部主配置仅--config-dir/--config-name不使用仅 dataclass 默认值使用完整复现、分享实验配置3. 外部配置目录正常覆盖 --config-dir使用按组件叠加在默认配置上做局部定制与旧 argparse 入口的兼容与迁移fairseq 为平滑迁移提供了完整的兼容层旧的add_args式组件仍可通过LegacyFairseq*基类运行edgelm/fairseq/dataclass/utils.py 中的gen_parser_from_dataclass()可将任意 dataclass 展开为 argparse 参数支持前缀、别名、枚举选项、${}插值字段跳过等convert_namespace_to_omegaconf()则能把旧的扁平argparse.Namespace反向转换成结构化DictConfig期间通过_override_attr()/migrate_registry()把命名空间中的值转成 Hydra override 字符串FairseqDataclass.from_namespace()支持从 Namespace 直接构造配置对象。因此无论你的组件是新的还是旧的都可以在两种入口之间平滑过渡。常见问题与排查建议modeltransformer_lm不生效仅对已迁移带 dataclass 注册的 task/model 生效旧式add_args组件请继续使用 legacy 入口。II(...)插值报错检查根配置中是否存在对应节点与字段如optimization.lr插值路径必须与FairseqConfig顶层结构一致。新增注册表后fairseq-hydra-train找不到组件确认已在FairseqConfig中追加Any None字段并重启进程让 ConfigStore 重新注册。外部配置覆盖不生效确认 YAML 中使用了正确的_name组件注册名且层级字段名与 dataclass 字段名一致--config-dir指向的是包含配置文件的目录方式二或包含分片子目录的目录方式三注意二者结构差异。训练崩溃排查可在配置中设置common.suppress_crashestrue对应 edgelm/fairseq/dataclass/configs.py 中CommonConfig.suppress_crashes使hydra_main吞掉异常并返回指标值便于 sweep 场景下收集结果。小结通过 Hydra dataclass 的配置体系fairseq以及基于它的 EdgeLM 项目将配置组件从解析长串命令行参数简化为声明一个带默认值的 dataclass 用 YAML/命令行做分层覆盖。掌握本文介绍的组件迁移方法、II()值继承、FairseqConfig扩展方式以及fairseq-hydra-train的三种配置组合策略你就可以在复现实验、管理多架构对比、分享可复现配置时游刃有余。相关核心实现可进一步查阅 edgelm/fairseq/dataclass/configs.py、edgelm/fairseq/dataclass/initialize.py、edgelm/fairseq/dataclass/utils.py、edgelm/fairseq_cli/hydra_train.py 与 edgelm/fairseq/registry.py。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表