torchtitan-npu Swap Optimizer 完整指南:3步显存流水线破解大模型训练显存瓶颈
【免费下载链接】torchtitan-npuAscend Extension for torchtitan项目地址: https://gitcode.com/cann/torchtitan-npu
在 Ascend NPU 上进行大模型训练时,torchtitan-npu 提供的Swap Optimizer是一种显存优化技术:它把 Adam/AdamW 优化器的状态(动量、方差)卸载到 CPU 内存,仅在参数更新阶段分块换入 NPU,以“按块加载 → 异步更新 → 及时卸载”的 3 步流水线,在不损失训练精度的前提下大幅降低显存占用,让更大规模模型的训练变得可行。
为什么优化器状态是大模型训练的显存黑洞 💡
训练大模型时,显存主要被三样东西占据:模型权重、激活值、优化器状态。以 AdamW 为例,每个参数都要维护一阶动量exp_avg和二阶动量exp_avg_sq,状态量级与参数量相当,往往成为显存占用的最大头。
而问题在于:
- 静态驻留浪费:优化器状态在前向、反向传播全程都占着 NPU 显存,却只在最后的参数更新(
optimizer.step())时才被用到; - 朴素卸载太慢:简单的 CPU Offload 方案会让主机与加速卡之间的大块同步传输阻塞主计算流,训练吞吐量急剧下降。
Swap Optimizer 正是针对这两个痛点设计:前向/反向期间优化器状态完全不在显存里,只在更新时以小块流水线方式换入换出,用“多流通信与计算重叠”换显存空间。
原理拆解:Load、Update、Offload 三步流水线 🔧
第 1 步:Load —— 零显存占位,异步换入
初始化时,系统会在 CPU 侧(pin_memory=True)为每个参数分配固定内存存放优化器状态,同时在 NPU 端把状态的底层物理显存清空,只保留 Tensor 元数据。因此在漫长的前向/反向传播期间,优化器状态占用显存为0。
进入optimizer.step()后,独立的加载流swap_to_device_stream开始异步地把下一块参数的状态从 CPU 拷贝到 NPU 并恢复其显存大小。
第 2 步:Update —— 事件同步,Fused 算子更新
主计算流通过事件(Event)等待当前块状态加载完成后,立即调用底层 Fused Adam 算子完成参数更新。由于加载的是“下一块”、更新的是“当前块”,两者在时间上完全错开、并行推进。
第 3 步:Offload —— 及时卸载,显存立即复用
更新完成后记录事件,卸载流swap_to_host_stream把最新状态异步写回 CPU,同时再次清空该块的设备侧显存,供下一个参数块使用。整个过程对训练逻辑完全透明,step()的调用方式不变。
核心实现位于 swap_optimizer.py,其中的
SwapOptimizersContainer无缝拦截了原生Adam/AdamW的step方法。
快速上手:2 行配置开启 Swap Optimizer ⚡
Swap Optimizer 的配置统一收敛在 configs.py 的OptimizerConfig中。在模型的config_registry.py里只需两个字段:
from torchtitan_npu.config.configs import OptimizerConfig optimizer = OptimizerConfig( name="AdamW", lr=3e-4, weight_decay=0.01, swap_optimizer=True, # 开启 Swap 显存流水线 swap_optimizer_times=16, # 参数状态切分为 16 块 )也可以不改代码,启动训练时直接用 CLI 覆盖:
bash scripts/run_train.sh \ --optimizer.swap-optimizer \ --optimizer.swap-optimizer-times 16关键参数怎么选
| 配置项 | 默认值 | 说明 |
|---|---|---|
swap_optimizer | false | true启用 Swap 流水线;false回退到上游基础优化器 |
swap_optimizer_times | 16 | 状态切块数。值越大,单次峰值显存越小,但流调度开销可能略增 |
name | "AdamW" | Swap 特性当前支持Adam和AdamW |
实践建议:默认 16 块已经是很好的起点;如果显存仍然紧张,把它调大到 32 或 64,反之可以适当调小。DeepSeek-V3 系列模型的官方 recipe 即采用了swap_optimizer=True, swap_optimizer_times=16的组合,见 deepseek_v3/config_registry.py。
与 Checkpoint 及 Muon 的兼容性 ✅
- Checkpoint 无缝配合:保存 DCP checkpoint 时会自动等待未完成的 swap/offload 操作,并从 CPU cache 保存真实的 Adam 状态;加载时恢复 CPU cache 并重建设备侧零显存占位符,可直接继续训练。全程不需要把 CPU cache 搬回 NPU。
- Muon 混合优化器:当
name="Muon"且swap_optimizer=true时,会进入 Muon + Swap 混合分支,Muon 的momentum_buffer也按同样的流水线卸载与换入。
功能验证可参考 test_swap_optimizer.py 与 test_swap.py。
相关显存优化特性一览 🧩
torchtitan-npu 在 Optimizer 卸载增强方向 还提供了一族互补技术,可按需组合:
| 特性 | 适用场景 | 文档 |
|---|---|---|
| Swap Optimizer | 前向/反向期间优化器状态零显存,更新时分块流水线换入 | swap_optimizer.md |
| Virtual Optimizer | 流水线并行(PP)场景下按 stage 精细分配动量显存 | virtual_optimizer.md |
| Muon Optimizer | 矩阵型参数的高效优化 | muon_optimizer.md |
总结
用一句话概括:Swap Optimizer 让大模型训练“把优化器状态搬进 CPU 仓库,用到哪块取哪块”。
- 收益:前向/反向期间优化器状态显存占用归零,峰值显存大幅下降;
- 代价极小:分块 + 双流异步重叠,通信与计算并行,吞吐损失远低于朴素 Offload;
- 开启成本极低:一行
swap_optimizer=True,checkpoint 保存/加载、Muon 联用均开箱即用。
如果你正在 Ascend NPU 上训练 DeepSeek 等超大模型并被显存卡住,不妨优先尝试这个特性。
【免费下载链接】torchtitan-npuAscend Extension for torchtitan项目地址: https://gitcode.com/cann/torchtitan-npu
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考