TRL 中的 Delta Weight Sync 实现极低带宽下的万亿参数模型训练
TRL 中的 Delta Weight Sync 实现极低带宽下的万亿参数模型训练
1 TB 问题
异步 RL 训练需要每一步都将整个模型从训练器发送到推理引擎,以保持策略同步。对于 bf16 格式的 7B 模型,每一步需要 14 GB。对于前沿的 1T 参数模型,每一步大约需要 1 TB。这种传输处于关键路径上,会导致 GPU 在不生成 token 时出现计算空闲。
为什么 bf16 RL 权重几乎总是稀疏的
在连续的 RL 优化器步骤之间,大约 99% 的 bf16 权重保持位一致(在最坏情况下也不低于 98%)。这是因为 bf16 的精度有限:如果更新的幅度低于权重周围可表示值之间间距的一半,更新就会被舍入吸收。在典型的 RL 学习率下(例如 3×10⁻⁶),大多数权重的更新大小都小于这个阈值,因此 bf16 表示不会发生变化。这种稀疏性是由算术逻辑保证的,而不是偶然的测量结果。
HF Buckets 与架构
什么是 Bucket?
Bucket 是 Hugging Face Hub 上的一种用于高频对象存储的 repo 类型。它不需要 commit 仪式或 PR 工作流。文件通过两个函数进行添加、列出或下载:用于上传的 batch_bucket_files 和用于下载的 download_bucket_files。在底层,Buckets 使用 Xet,即 Hub 的基于内容的分块存储层,它根据内容对分块进行去重。
三个框
该架构由三个组件和一个共享基质组成:
Trainer: 拥有模型权重,运行优化器并发出稀疏 deltas(可以位于任何地方:单个 GPU、多个 GPU 或笔记本电脑)。
HF Bucket: 一个包含
anchors/(用于完整快照)和deltas/(用于稀疏补丁)的单一 repo;这是双方达成共识的唯一媒介。vLLM rollout server: 从 bucket 拉取数据,应用 deltas,并提供 rollout 服务(不一定与 trainer 位于同一位置)。
Environment: 通过 HTTP 或函数调用连接到 rollout server。
Trainer 和 rollout server 从不直接交换权重数据;它们只共享一个带有 bucket 坐标的微小 POST 请求。所有的字节传输都发生在每一方与 bucket 之间,且是并行的。
协议
使用 safetensors 作为传输格式
我们使用 safetensors 作为磁盘和传输格式。bucket 中存在两种文件类型:
- Anchors: 带有完整 bf16 权重的常规 checkpoint(每 N 步写入一次,默认 N=10)。
- Deltas: 对于每个更改的参数,存储一个包含元素索引的 int32 tensor 和一个包含这些索引处数值的 bf16 tensor。
元数据指示文件是稀疏的还是 anchor,从而使接收方能够进行相应的分支处理。
Trainer 端:来自优化器 Hook 的布尔掩码
BF16ChangeDetector 在优化器上注册 pre-step 和 post-step hooks,以便在步骤前后对 bf16 权重进行快照。通过比较这些快照来计算已更改元素的布尔掩码。使用这种 ground-truth 方法是因为从 Adam 统计数据预测掩码的召回率很低(约 30%)。
vLLM 端:30 行扩展
我们实现了一个 DeltaWeightTransferEngine,通过 --worker-extension-cls 标志接入 vLLM(无需 fork)。在接收到权重更新时:
- 从 bucket 下载 delta safetensors 文件。
- 对于 anchors:加载所有 tensor 并为未来的 deltas 进行快照。
- 对于 deltas:对于每个更改的参数,检索索引和数值,将其应用到本地 bf16 快照,并将重建的完整 tensor 喂给 vLLM 的
load_weights。
在 Spaces 上真正落地
我们运行了一次完全解耦的训练,没有共享网络:
- Trainer: 一个 GPU 节点。
- vLLM rollout server: 安装了我们扩展的 Hugging Face Space (Docker SDK, L4 GPU)。
- Wordle environment: 第二个 Hugging Face Space (CPU),具有 256 个并发会话容量。
- Hub bucket: 用于权重 deltas 和 anchors 的中央 repo。
设置仅涉及几次 hf CLI 调用。vLLM Space 的 Dockerfile 从 delta-weight-sync 分支安装 TRL 并设置 worker extension class。训练可以从任何可以通过 HTTPS 访问 Spaces 和 bucket 的地方启动。
这究竟释放了什么潜力?
- 无需集群的异步 RL 训练: 单个 GPU trainer 可以使用 Spaces 进行 rollout 和环境模拟,权重通过 bucket 传输。
- 免费的多副本推理: 多个 vLLM Spaces 从同一个 bucket 拉取数据;Xet 对存储的分块进行去重,Hub 的边缘缓存可以廉价地处理重复下载。
- 可调试的传输格式: Deltas 是可以使用 Python 中的
safe_open检查的 safetensors 文件。 - 通往前沿规模之路: 对于 Qwen3-0.6B 模型,每一步的负载从 1.2 GB 降至 20–35 MB。对于 Llama-3.1-405B 模型(bf16 下为 810 GB),根据简单计算,每一步的 deltas 约为 6 GB(相比之下全量为 810 GB),将推理暂停时间从约 8 秒(使用 100 GB/s NCCL)减少到几秒钟。在 1 GB/s 带宽的跨云环境下,全量广播需要 13 分钟;而 delta 仅需 6 秒。
我们仍需解决的问题
- 两个 CPU bf16 快照: Trainer 保留一个用于变化检测;rollout server 保留一个用于为 vLLM 的
load_weights重建完整 tensor。当 vLLM 获得稀疏load_weightsAPI 时,后者将被移除。 - 固定的 anchor 周期: 目前每 N 步生成一个 anchor;采用自适应策略(当累积漂移超过阈值时生成 anchor)可能会降低成本。
- 多节点 FSDP2 训练器:
BF16ChangeDetector是为单进程优化器 hook 构建的;多节点 FSDP2 的支持尚未经过测试。 - 接入优化器: 由于存在非平凡的交互,从 Adam 统计数据预测掩码仍然具有挑战性。
- 与传输压缩叠加: 稀疏 safetensors 和逐块 gzip 是正交的,但尚未结合使用。
尝试一下
- PR: huggingface/trl#5417 (branch:
delta-weight-sync)。 - 完整的 Wordle 示例:
examples/scripts/openenv/async_wordle.py。 - Spaces Dockerfiles:
examples/scripts/openenv/vllm_space/和examples/scripts/openenv/wordle_space/。 - 背景阅读: 我们的 async RL landscape post,Fireworks 1 TB post,以及 Cursor Composer 2 report。