开源Hugging Face Blog·原文 2026年9月10日本站收录 2026年9月15日

AsyncGRPOTrainer支持跨HF Jobs只同步LoRA适配器,500 步训练从 3 小时 27 分缩至 53 分

TRL v1.14的异步GRPO训练器现在可以只训练LoRA适配器并仅把它同步给vLLM。一个rank-1适配器只有几MB,可以经Storage Bucket在多个Hugging Face Job之间传递,绕开需要共享节点或NCCL的全权重同步。

AI解读:TRL的AsyncGRPOTrainer现在能只训练LoRA适配器,并把适配器而不是完整模型同步给vLLM,这个能力在PR #7017 中合入,随TRL v1.14发布。

在此之前,异步训练器和vLLM推理服务通常要跑在同一节点或共享文件系统上;Hugging Face Jobs一个Job就是一个容器、跑在一台虚拟机上,跨节点无法用NCCL通信,全权重同步走不通。LoRA把这个限制绕开了:1.5B模型的rank-1适配器只有几MB,完整模型约 3 GB,适配器可以走Storage Bucket挂载的共享目录。

对做RL后训练的人来说,这意味着训练和生成可以放到不同机器、不同Job上,各自按自己的速度跑。但这条路径有明确前提:只有vLLM能直接服务的普通LoRA配置才走适配器同步,DoRA、modules_to_save或rank超过 --max-lora-rank的配置会回退到合并权重同步。

多副本推理还得自己加一层代理:Job暴露的端口需要Authorization头,而且vLLM的 /v1/load_lora_adapter在data-parallel-size大于 1 时只作用于应答的那个rank。代理负责加头、把每次适配器加载广播到所有副本,并按KV前缀亲和性把同一prompt的多个rollout路由到已缓存其前缀的副本。

项目作者报告,同样的配方跑 500 步,五次运行从 3 小时 27 分降到 53 分。需要注意的是,这是作者在公开博客中给出的单次项目结果,没有第三方复现或跨配置的对比数据。

这套方案不依赖TRL或vLLM的代码改动,靠的是HF Jobs的卷挂载和已有的运行时LoRA加载接口。它的适用范围仍是单节点内最多 8 张H200的Job规模,而不是替代大规模多节点训练集群。

TRL v1.14的AsyncGRPOTrainer现在可以只训练LoRA适配器,并仅把适配器同步给vLLM,而不是同步完整模型权重。这一能力由PR #7017 合入,随TRL v1.14发布。

一篇Hugging Face博客介绍了建立在该能力上的实际项目:训练器和vLLM推理副本不再共享同一台机器,而是作为各自独立的Hugging Face Jobs运行。作者用它把同一套 500 步训练配方在五次运行中从 3 小时 27 分压缩到 53 分钟。

博客说明,之前异步训练器和vLLM若不在同一节点,全权重同步每次更新都要在机器之间搬运数GB数据,需要NCCL组或共享文件系统;而Hugging Face Jobs一个Job就是一个容器、跑在一台虚拟机上,无法跨节点通信。LoRA把每次同步的数据量降到几MB,使这条路径可行。

LoRA适配器经Storage Bucket在Job间传递

新的适配器同步路径不通过tensor传输。训练器每隔几个优化步把适配器保存到 /.vllm_lora/trl-policy-v{N},用原子重命名发布目录,然后把这个路径发给vLLM的 /v1/load_lora_adapter端点;vLLM从磁盘读取文件,rollout worker随后可以请求model="trl-policy-v{N}"。

这要求训练器和vLLM服务共享文件系统。在Slurm集群上这是网络文件系统;在Hugging Face Jobs上,作者把Storage Bucket作为卷挂载到每个Job的同一路径,底层用hf-mount把bucket暴露为容器内的POSIX文件系统。TRL和vLLM都不需要为此改动。

作者指出,rank-1适配器对 1.5B模型只有几MB,完整模型约 3 GB。博客还引用Thinking Machines的LoRA Without Regret,称LoRA在策略梯度RL中可以匹配全量微调,即使rank为 1,原因是优势函数每轮只给出约O(1) 比特信息,rank-1适配器的容量足以吸收。

参与这套设置的包括三个Job:一个跑AsyncGRPOTrainer加LoRA和FSDP的训练器Job,两个各用一张GPU的vLLM Job,以及挂载在三个Job同一路径的Storage Bucket。适配器目录经bucket从训练器传到服务器。检查点和最终适配器也存入bucket,Job被抢占后训练器可以恢复。

  • 训练器不向vLLM发送tensor,而是发布适配器目录路径并调用 /v1/load_lora_adapter。
  • vLLM副本使用vllm/vllm-openai:v0.27.1镜像,开启VLLM_ALLOW_RUNTIME_LORA_UPDATING=1 和VLLM_SERVER_DEV_MODE=1。
  • max_staleness=4 时需要 --max-loras 6,即保留当前策略加前四个版本再留一个交换槽位。
  • 适配器名带版本号,避免vLLM前缀缓存跨权重版本命中导致rollout的prefill与decode来自不同策略。
  • HF Jobs是临时的,但适配器始终持久化到bucket,抢占后不会丢失。

代理负责认证、广播适配器加载和按KV前缀路由

训练器和vLLM Job之间需要一个代理,原因有两个:Job暴露的端口要求每个请求带Authorization: Bearer头,代理负责加上这个头,TRL无需感知;同时作者想要不止一张GPU做生成。

单个vLLM服务器通常用 --data-parallel-size大于 1 来扩展,但TRL拒绝在该模式下使用适配器同步,因为 /v1/load_lora_adapter只会到达应答的那个DP rank,其他rank会继续用基础模型响应新策略名。在HF Jobs上每个副本是独立机器,数据并行被放到上一层,由代理把适配器加载广播到所有副本。

代理还负责路由。vLLM按 16 token的块存储前缀KV缓存;由于GRPO的rollout worker会对同一prompt发G个请求(示例中G=8),如果它们都到同一个副本,第一个请求计算prefill,其余七个直接复用。博客称,用轮询路由时大约一半请求会落到没有缓存该前缀的副本,需要重做prefill。

路由器按块哈希链跟踪哪个副本见过哪些块,并用适配器名作为哈希种子,因为KV缓存依赖生成它的适配器:策略v3缓存的前缀对v4无用。路由时统计每个副本匹配的前导块数量,去掉所有副本都有的公共块后,如果某副本有该prompt特有的块且负载不超过最轻副本 8 个请求,就发给它,称为affinity hit;超过则放弃缓存发给最轻副本,称为spill;没有副本有特有块时按负载轮询,称为unmatched。

博客给出的例子中,同一prompt的第二次rollout命中已缓存全部 8 个块的副本A;新prompt发到负载更轻的副本B;当A领先超过 8 个请求时,第四次rollout溢出到B,B补做一次prefill后该问题对所有副本都变成公共块。

  • 代理在训练器Job的 127.0.0.1:8000 上运行,TRL把它当作单个vLLM服务器。
  • 每个副本用一张GPU和官方vllm/vllm-openai镜像,只开启运行时LoRA加载并预留足够适配器槽位。
  • 所有会改变状态的请求,例如适配器加载、pause、resume,都要广播到每个副本。
  • 路由按块哈希的链式匹配,哈希以适配器名作为种子。
  • 公共块不参与路由判断,因为它们不指向某个具体prompt。

数据集与超参数来自精度相关论文,500 步实测从 3 小时 27 分降到 53 分

作者选用sail/Sanity-Test-R1D-1.5B,来自论文Defeating the Training-Inference Mismatch via FP16(Qi等,2025),复现代码在sail-sg/Precision-RL。论文作者用DeepSeek-R1-Distill-Qwen-1.5B为每道MATH题生成 40 个答案,保留成功率在 20% 到 80% 之间的题目,得到 1,460 道题。

作者表示该数据集适合RL验证,因为题目对该模型既非已解决也非完全无望,模型能获得早期训练信号;同时数据集足够小,两小时内可以跑完一轮,适合做端到端测试,例如某个vLLM副本在新适配器名下静默返回基础模型时几十步内就能从曲线看出。

超参数取自论文的LoRA脚本oat/scripts/lora:Qwen/Qwen2.5-Math-1.5B,LoRA rank 1、alpha 2,学习率 4e-5,每个prompt 8个样本,每步 128 个补全,最多生成 3,000 token,上下文 4,096 token。训练器使用与副本相同的镜像并额外安装TRL,配置里weight_sync_steps=4,即每 4 个优化步发布一次适配器,save_steps=50 存检查点。

初始化时TRL调用 /server_info,如果发现lora_config就使用适配器同步;vLLM无法直接服务的配置,例如DoRA、modules_to_save或rank超过 --max-lora-rank,会带着警告回退到合并权重同步,日志中会出现Adapter-only vLLM sync enabled。

作者报告同一配方跑 500 步的五次运行从 3 小时 27 分降到 53 分钟。这是作者博客中的项目结果,没有提供跨硬件配置或第三方复现的数据。方案本身仍受HF Jobs单Job一台虚拟机、最多 8 张H200的规模限制。

  • vLLM固定使用v0.27.1,作者把版本视为配方的一部分。
  • 训练脚本是普通的AsyncGRPOTrainer脚本,唯一Job特有的值是输出目录和服务器URL。
  • 输出目录指向bucket,适配器、检查点和最终适配器都落在那里。
  • 该方案不要求TRL或vLLM代码改动,依赖已有的运行时LoRA加载端点和hf-mount。

信息来源

Hugging Face Blog原始来源