ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

fairseq Optimizers 优化器模块全解析:从 FairseqOptimizer 基类到混合精度训练(IAD/fairseq 实战指南)

fairseq Optimizers 优化器模块全解析:从 FairseqOptimizer 基类到混合精度训练(IAD/fairseq 实战指南) fairseq Optimizers 优化器模块全解析从 FairseqOptimizer 基类到混合精度训练IAD/fairseq 实战指南【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm导读本文以 decoding/IAD/fairseq/docs/optim.rst 为骨架深入剖析本仓库 IAD 项目所携带的 fairseq 训练框架中的fairseq.optim优化器模块。文章将依次讲解优化器的注册与构建机制、FairseqOptimizer基类的核心能力、Adam/Adagrad/Adadelta/SGD/NAG/Adafactor 等内置优化器的参数与底层实现以及 FP16 混合精度优化器与动态损失缩放的完整工作流。读完本文你将掌握--optimizer命令行选型方法、各优化器关键超参数的语义与默认值并能理解梯度裁剪、学习率调度与优化器之间的协作关系为 IAD 项目中的模型训练与调参提供可落地的依据。一、文档定位一个 Sphinx autodoc 索引页背后是完整的优化器体系optim.rst本身是 fairseq 文档体系中负责自动生成 API 文档的 Sphinx 源文件。它通过automodule:: fairseq.optim与 8 个autoclass指令声明性地列出整个优化器模块的公开 API包括fairseq.optim.FairseqOptimizer所有优化器的统一基类fairseq.optim.adadelta.Adadelta、fairseq.optim.adagrad.Adagrad经典自适应学习率算法fairseq.optim.adafactor.FairseqAdafactor面向超大规模模型的低显存自适应优化器fairseq.optim.adam.FairseqAdam训练中最常用的 Adam/AdamWfairseq.optim.fp16_optimizer.FP16Optimizer混合精度训练的优化器包装层fairseq.optim.nag.FairseqNAG与fairseq.optim.sgd.SGD带动量的随机梯度下降族。也就是说这份“几乎只有一行正文”的文档实质上是优化器模块的目录页真正的技术细节全部沉淀在 fairseq/optim 源码目录 中。本文将以该目录下的实现为准把文档声明的每个类逐一展开。二、模块全景与注册机制--optimizer是如何生效的fairseq/optim/init.py 是整个优化器体系的入口其核心是registry注册表机制( _build_optimizer, register_optimizer, OPTIMIZER_REGISTRY, OPTIMIZER_DATACLASS_REGISTRY, ) registry.setup_registry(--optimizer, base_classFairseqOptimizer, requiredTrue)该调用创建了以--optimizer为入口参数的注册表base_class被限定为FairseqOptimizer且requiredTrue意味着训练时必须显式指定优化器名称。随后__init__.py会扫描optim/目录下所有以.py结尾且不以_开头的文件并自动导入使各优化器通过register_optimizer(adam)之类的装饰器完成注册见 adam.py。build_optimizer是面向训练器的唯一工厂函数init.pydef build_optimizer(cfg: DictConfig, params, *extra_args, **extra_kwargs): if all(isinstance(p, dict) for p in params): params [t for p in params for t in p.values()] params list(filter(lambda p: p.requires_grad, params)) return _build_optimizer(cfg, params, *extra_args, **extra_kwargs)它做了两件事把字典形式的参数组扁平化为张量列表只保留requires_gradTrue的参数避免把冻结层的参数交给优化器维护。因此在训练命令行中使用--optimizer adam或sgd、adafactor、nag、adagrad、adadelta、lamb、adamax等即可完成选型注册表中还包含composite多优化器组合与bmufBMUF 分布式训练用但这两个未出现在optim.rst的 autoclass 清单中。三、FairseqOptimizer基类优化器与训练器的契约fairseq_optimizer.py 定义了FairseqOptimizer它不直接继承torch.optim.Optimizer而是通过.optimizer属性持有底层的 torch 优化器实例从而在 torch 之上附加 fairseq 训练所需的统一接口。其关键成员如下成员作用实现要点add_args向命令行解析器注入优化器专属参数若子类声明了__dataclass则用gen_parser_from_dataclass从 dataclass 自动生成参数fairseq_optimizer.pyoptimizer_config返回用于重建/覆盖优化器参数的 kwargs各子类必须实现训练器借此在恢复 checkpoint 时用新配置覆盖旧配置从而支持“换学习率继续训练”fairseq_optimizer.pyget_lr/set_lr读写当前学习率直接操作第一个或全部param group 的lr字段state_dict/load_state_dict优化器状态存取加载时支持optimizer_overrides参数覆盖旧状态fairseq_optimizer.pybackward反向传播入口默认loss.backward()FP16 包装层会在此处叠加损失缩放multiply_grads梯度乘以常数供损失缩放反向折算使用clip_grad_norm梯度范数裁剪委托utils.clip_grad_norm_step(closure, scale, groups)执行一步参数更新若底层优化器supports_step_with_scale则直接把 scale 传入否则先multiply_grads(1.0/scale)再 stepfairseq_optimizer.pyzero_grad清空梯度将p.grad置为None后调用optimizer.zero_grad()average_params参数平均默认空实现Adam 子类在 BMUF 场景下重写为跨卡 all-reduce 一阶/二阶矩adam.py基类还暴露了一组能力探测属性supports_memory_efficient_fp16、supports_step_with_scale、supports_groups、supports_flat_params。这些属性决定了 FP16 包装层能否采用内存高效方案、梯度能否被压平成单块连续张量等优化路径是后续混合精度章节的关键前置条件。四、Adam / AdamW--optimizer adam的默认首选adam.py 中的FairseqAdam是训练配置中使用最频繁的优化器。其 dataclass 配置FairseqAdamConfig定义了以下命令行参数adam.py参数默认值含义--adam-betas(0.9, 0.999)一阶、二阶矩的指数衰减系数以字符串元组形式传入内部用eval解析--adam-eps1e-8分母稳定性常数--weight-decay--wd0.0权重衰减系数--use-old-adamFalse强制使用本文件内的纯 PythonAdam实现而不走融合内核--lr继承自optimization.lr列表学习率取lr[0]传给优化器一个非常关键的实现事实写在FairseqAdam的 docstring 中该优化器的权重衰减行为对应的是 Adam 的 AdamW 变体最接近 PyTorch 的torch.optim.AdamW。也就是说--optimizer adam实际做的是 AdamW 的权重衰减decoupled weight decay而不是把 L2 惩罚混入梯度。FairseqAdam.__init__的选路逻辑adam.py若--tpu开启使用本文件内的Adam实现因为它会自动把 FP16/BF16 梯度提升到 FP32 计算否则若存在融合 Adam 内核fused_adam通过get_fused_adam_class()获取且 CUDA 可用则使用FusedAdam并打印using FusedAdam日志兜底使用纯 PythonAdam。仓库自带的 fused_adam.py 提供了可选的融合 CUDA 版本可显著降低 kernel launch 开销同时还有 fused_lamb.py 注册了--optimizer lamb参数--lamb-betas、--lamb-eps、--weight-decay适合需要逐层自适应缩放学习率的大规模预训练场景。关于纯 PythonAdam的实现adam.py有几点值得注意梯度为 FP16/BF16 时先在内部提升为 FP32 计算更新完成后再拷贝回低精度参数——这是它能声明supports_memory_efficient_fp16True的原因显式支持amsgrad变体维护二阶矩历史最大值权重衰减以p_data_fp32.add_(p_data_fp32, alpha-weight_decay * lr)的方式解耦施加再次印证其 AdamW 语义偏差修正系数bias_correction1/2按步数动态计算保证训练初期步长不过大。五、SGD 与 NAG经典动量优化器sgd.py 中的SGD直接包装torch.optim.SGD注册名为sgd。它暴露两个命令行参数--momentum动量因子默认0.0--weight-decay--wd权重衰减默认0.0。optimizer_config返回{lr: args.lr[0], momentum: ..., weight_decay: ...}并声明supports_flat_paramsTrue支持参数压平加速。SGD 因显存占用低无二阶矩在批量受限的微调场景中仍有实用价值。nag.py 中的FairseqNAG注册名为nag实现 Nesterov 加速梯度法。它同样基于 dataclassFairseqNAGConfig自动生成参数核心仍是动量思想但更新方向使用了“前瞻”位置的梯度收敛轨迹比标准动量更平稳。从源码结构看NAG类继承自torch.optim.Optimizer的自定义实现适合需要经典一阶方法对照实验的场景。六、Adagrad 与 Adadelta自适应学习率的早期代表adagrad.py 的Adagrad注册名为adagrad仅暴露--weight-decay参数其余使用torch.optim.Adagrad默认值。Adagrad 按每个参数的历史梯度平方和自适应地缩小学习率在稀疏梯度如词嵌入上效果好但累积平方和无上限会导致学习率单调递减。adadelta.py 的Adadelta注册名为adadelta其命令行参数均带默认值参数默认值含义--adadelta-rho0.9梯度平方指数衰减的系数--adadelta-eps1e-6分母稳定性常数--weight-decay/--wd0.0权重衰减--anneal-epsFalse是否对eps进行退火Adadelta 不依赖全局学习率用参数增量平方的运行均值来归一化更新步长解决了 Adagrad 学习率单调衰减的问题--anneal-eps开关则是 fairseq 针对特定训练稳定性的扩展。七、Adafactor低显存自适应优化器adafactor.py 的FairseqAdafactor注册名为adafactor基于论文《Adafactor: Adaptive Learning Rates with Sublinear Memory Cost》。它的核心思想是把二阶矩的维护拆成行、列两个低秩向量对二维及以上参数用外积近似平方梯度_approx_sq_grad从而把显存占用从 O(n) 降到 O(√n) 量级adafactor.py特别适合训练参数量极大的模型。命令行参数与默认值adafactor.py参数默认值含义--adafactor-eps(1e-30, 1e-3)平方梯度正则项与参数尺度正则项--clip-threshold1.0对更新量的 RMS 做裁剪的阈值--decay-rate-0.8二阶矩的衰减率步数幂次--beta1None一阶矩系数可选为None时不维护一阶矩--weight-decay/--wd0.0权重衰减--scale-parameterFalseCLI 为 store_true是否按参数 RMS 缩放学习率--relative-stepFalseCLI 为 store_true是否用步数的逆平方根作为学习率--warmup-initFalse相对步长模式下是否启用 warmup 初始化底层Adafactor构造函数默认scale_parameterTrue、relative_stepTrue与 CLI 默认相反——源码 docstring 明确提示若想使用外部手动学习率调度必须显式设置scale_parameterFalse且relative_stepFalse同时lr与relative_step互斥warmup_init依赖relative_stepTrue否则会抛ValueErroradafactor.py。因此在使用--optimizer adafactor配合 fairseq 的 lr scheduler 时务必加上--scale-parameter --relative-step之外的正确组合避免学习率被内部逻辑覆盖。值得注意的是optimizer_config的 docstring 中有一条实战警告fp16 下 Adafactor 存在经验上的收敛问题可能需要仔细搜索合适的配置组合。八、FP16 混合精度优化器FP16Optimizer 与 MemoryEfficientFP16Optimizeroptim.rst中专门列出的FP16Optimizer位于 fp16_optimizer.py它并不是独立优化算法而是包装层对任意FairseqOptimizer做混合精度改造。同文件中还有未在 autoclass 清单中列出的MemoryEfficientFP16Optimizer。8.1 经典 FP16Optimizer维护 FP32 参数主副本FP16Optimizer.build_optimizerfp16_optimizer.py的流程用build_fp32_params为全部模型参数创建 FP32 副本默认flattenTrue压平成连续张量可通过--fp16-no-flatten-grads关闭BF16 下强制不压平因为 TPU 上未压平更快用这些 FP32 参数构建真正的底层优化器若底层优化器不支持扁平参数supports_flat_paramsFalse却要求压平直接抛RuntimeError提示改用--fp16-no-flatten-grads。训练周期中的关键同步点对应backward/step/zero_grad的重写backward先经DynamicLossScaler放大 loss 再反传防止 FP16 梯度下溢_sync_fp16_grads_to_fp32把 FP16 梯度拷入 FP32 主副本clip_grad_norm先同步梯度、计算范数再根据max_norm更新缩放系数并调用 scaler 的check_overflow检测上溢step若底层优化器支持step(scale...)则直接传入1/_multiply_factor否则先_unscale_grads还原梯度再 step随后scaler.update()动态调整损失缩放_sync_fp32_params_to_fp16把更新后的 FP32 参数拷回 FP16 模型。8.2 内存高效版本不维护 FP32 副本MemoryEfficientFP16Optimizerfp16_optimizer.py的 docstring 明确其取舍不再为模型维护一份 FP32 主副本而是要求底层优化器在 step 内部自行把梯度提升为 FP32 并同步回 FP16 参数大幅节省显存但略微增加优化器耗时。正因如此只有声明supports_memory_efficient_fp16True的优化器如本文的Adam、Adafactor才能被包装否则构造时抛ValueError。8.3 DynamicLossScaler动态损失缩放动态损失缩放器 配合上述两个包装层工作。默认的fp16_scale_window由公式自动推导fp16_optimizer.pyscale_window int(2 ** 14 / data_parallel_size / update_freq[0])即默认窗口 16384 步按数据并行规模与梯度累积步数折算使用自定义--update-freq调度时必须显式给出--fp16-scale-window。相关控制参数包括--fp16-init-scale初始缩放、--fp16-scale-tolerance、--threshold-loss-scale阈值下限与--min-loss-scale。特别地使用 BF16 时scaler被置为None完全禁用损失缩放——因为 BF16 的指数位宽足够大不需要缩放即可避免下溢。九、优化器与学习率调度、梯度裁剪的协作优化器只负责“根据梯度更新参数”学习率由独立的lr_scheduler模块管理。本仓库对应的调度器实现位于 fairseq/optim/lr_scheduler 目录包括cosine_lr_scheduler、inverse_square_root_schedule预训练常用、polynomial_decay_schedule、tri_stage_lr_scheduler、triangular_lr_scheduler、reduce_lr_on_plateau、fixed_schedule、manual_lr_scheduler等。调度器通过FairseqOptimizer.set_lr在每个 step 前写入lr字段具体关系可参考 lr_scheduler.rst。典型完整训练命令行示例参数均可在源码中找到对应定义fairseq-train contenteditable="false">【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表