游乐游手机版
首页/AI教程/文章详情

DataProto在RL训练流水线中的集装箱化应用

时间:2026-07-02 12:05
前四篇文章已经梳理了RLHF训练的核心脉络:RLHF不仅仅是一个简单的训练脚本,而是一条完整的训练推理闭环;HybridFlow 将这个闭环拆解为高层的数据流(dataflow);Single Controller 负责保持阶段的有序执行;ResourcePool 和 WorkerGroup 则将各

前四篇文章已经梳理了RLHF训练的核心脉络:RLHF不仅仅是一个简单的训练脚本,而是一条完整的训练推理闭环;HybridFlow 将这个闭环拆解为高层的数据流(dataflow);Single Controller 负责保持阶段的有序执行;ResourcePool 和 WorkerGroup 则将各个角色分配到 GPU 集群上执行。今天我们要深入一个更具体的问题:这些角色之间到底传输了什么数据?

许多人会本能地回答“tensor batch”。这个答案只说对了一半。后训练阶段中的样本远不止 input_idsattention_mask——它还会产生 response、reward、old logprob、ref logprob、value、advantage、return、uid、timing 以及各种运行元信息。verl 项目采用 DataProto 将这批不断“变胖”的训练证据打包成一个统一的协议。

核心洞察在于:DataProto 并不是一个普通的字典(dict),而是 controller、worker、rollout、reward、actor update 之间的数据契约。它使得 PPO 主循环能够清晰地组织成 repeat → union → dispatch → collect → update 模式,但同时也把字段增长、序列化、对象列以及样本对齐的风险集中到了这个协议边界上。

先看一张图,展示 DataProto 的三层结构。观察时请重点关注 batch 维度:tensor、object array 和 meta 信息都必须围绕同一批样本对齐。

\

DataProto 的三层结构

在源码中,DataProto 是一个 dataclass,核心字段包括 batch: TensorDictnon_tensor_batch: dictmeta_info: dict(定义在 verl/protocol.py:317-328)。check_consistency() 方法要求 batch 只有一个 batch 维度,且 non_tensor_batch 中的每个 np.ndarray 的第 0 维必须与 batch size 对齐(verl/protocol.py:454-478)。这正是 DataProto 最重要的隐含契约:无论字段来自 rollout、reward 还是 trainer,它们都必须描述同一批样本。

1. 三层结构分别应对三类数据

第一层 batch 存放 TensorDict,适合存储已 tensor 化且按样本对齐的数据:input_idsattention_maskresponsesresponse_maskold_log_probsref_log_probvaluesadvantagesreturns 等。from_dict() 会检查 tensor 的 batch 维度是否一致,然后再构造 TensorDict(verl/protocol.py:496-543)。

第二层 non_tensor_batch 存储按样本对齐但不适合 tensor 化的对象列。典型例子包括 uid、raw prompt、data source、多模态对象、reward 额外信息、工具或环境相关字段。from_single_dict() 会将 torch tensor 放入 batch,将 np.ndarray 放入 non_tensor_batchverl/protocol.py:479-493)。

第三层 meta_info 存放整批数据的控制信息和运行信息,例如 temperature、global step、global token number、timing、metrics、auto padding 标记等。这些信息不一定逐样本变化,但会影响后续阶段如何解释这批数据。

to_tensordict() 进一步说明了这三层如何接回 worker 侧执行:tensor batch 先转换成普通 dict,non-tensor 列会包装成 NonTensorStack,meta_info 会作为 non-tensor dict 合并进 TensorDict(verl/protocol.py:1102-1126)。因此,DataProto 是 controller 侧的协议,而 TensorDict 更接近于 worker 执行前的操作形态。

2. 一个 PPO batch 会在主循环中逐步“长大”

DataProto 只有放入 RayPPOTrainer.fit() 才真正发挥价值。主循环开始时,dataloader 产出的 batch_dict 被转为 DataProto.from_single_dict(batch_dict),然后写入 temperature,并为每条样本生成 uidverl/trainer/ppo/ray_trainer.py:1330-1349)。

接下来 rollout 过程让样本数量变多。trainer 先拿到 gen_batch,写入 global_steps,再根据 rollout.n 执行 repeat();如果是 REMAX 策略,还会将 sampled rollout 和 greedy baseline 拼接成一个 combined batch(verl/trainer/ppo/ray_trainer.py:1351-1370)。生成完成后,主 batch 也会按照 rollout.n 复制,再与 gen_batch_outputunion(),补上 responses 等新字段(verl/trainer/ppo/ray_trainer.py:1386-1407)。

下面这张图展示的是“batch 如何逐步扩展”,而不是单个字段的来源。重点在于:每个阶段都不是替换整批数据,而是在同一个 DataProto 语义空间里追加字段或更新 meta 信息。

\

一个 DataProto batch 在 PPO/GRPO 主循环中逐步长大

生成之后,DataProto 继续“变胖”:reward 阶段可能通过 union() 合并 reward model 输出,old logprob 阶段 union() old_log_probs,reference 阶段 union() ref_log_prob,critic 阶段 union() values,advantage 阶段写入 token_level_scorestoken_level_rewardsadvantagesreturns 等字段(verl/trainer/ppo/ray_trainer.py:1426-1541)。最终 actor/critic update 所消费的已经不再是原始 batch,而是一批携带完整训练证据的 DataProto。

这也解释了 uid 为何重要:一个 prompt 可能生成多条 response,样本顺序还可能被 balance 或 dispatch 改写。uid 是后续 advantage 计算、prefix grouping、诊断以及样本追踪能够继续识别“同一个原始 prompt”的关键列。

3. DataProto 的 API 是流水线操作,而非便利函数

union() 是 PPO 主循环中最常见的合箱动作。它会分别合并 tensor batch、non_tensor_batch 和 meta_info;如果已有同名字段但内容不一致,就会触发一致性检查(verl/protocol.py:109-122verl/protocol.py:188-199verl/protocol.py:781-798)。这能防止不同阶段将同一个字段写成语义不一致的数据。

repeat()slice()select_idxs()reorder() 负责样本级变换,确保 tensor 列和 non-tensor 列同步变换(verl/protocol.py:635-719verl/protocol.py:963-1013)。这一点在 RLHF 中非常实用:rollout.n 会扩展样本,batch balance 会重排样本,REMAX 会切出 baseline 区段,如果只处理 tensor 而不处理对象列,样本语义就会错位。

chunk()concat() 则直接服务于分布式边界。chunk() 按 batch 维度将 DataProto 切成 worker shard,并将 meta_info 传递给每个 shard;concat() 将多个 DataProto 沿 batch 维度拼接回来,并对 metrics 做合并处理(verl/protocol.py:864-961)。这是 DataProto 能够穿过 WorkerGroup 的基础。

4. 穿过 WorkerGroup 时,DataProto 必须可切、可合、可对齐

第三篇文章提到,WorkerGroup 的调用会经过 dispatch 和 collect。对于 DataProto 而言,dispatch/collect 不仅仅是传递对象引用,而是要在 controller 和 workers 之间保持 batch 语义。

decorator.py 中的 _split_args_kwargs_data_proto() 会通过 BatchData(arg).chunk(chunks) 切分输入;带有 auto padding 的版本会在 batch size 不能整除 worker 数时补齐样本,并将 padding size 放入 kwargs(verl/single_controller/base/decorator.py:71-117)。dispatch_dp_compute_data_proto() 按 WorkerGroup world size 切分,collect_dp_compute_data_proto() 再通过 BatchData(output).concat() 合并输出(verl/single_controller/base/decorator.py:167-199)。

下面这张图要展示的就是这个协议边界:controller 不仅将单个对象发送给 worker,而是先切成 shard;worker 返回后,collect 再合成一个 DataProto,以便 PPO 主循环能够继续按完整 batch 推进。

\

DataProto 如何在 controller 和 workers 之间切分与合并

当前训练 worker 常用的 ND dispatch 还会先查询 mesh 的 DP rank mapping,再按 DP 维度进行分发和收集(verl/single_controller/base/decorator.py:202-304)。这说明 DataProto 的“集装箱”属性并非比喻:它必须能够按 rank 拆箱、发货、收货、合箱,并且在合并后仍然保持样本对齐。

5. DataProto 的代价源于它日益像系统总线

DataProto 让代码更加清晰,但它并非免费的抽象。

第一类成本是字段增长。一个 batch 从 prompt 出发,经历 rollout、reward、logprob、value、advantage 之后,tensor 字段会越来越多,response length 也可能变得很长。print_size() 专门统计 TensorDict 和 non_tensor_batch 的大小,说明这不仅仅是语义问题(verl/protocol.py:436-452)。

第二类成本是序列化。__getstate__() 默认会将 TensorDict 合并后通过 torch.save 写入 buffer,也支持通过环境变量切换到 numpy 序列化(verl/protocol.py:377-424)。当 DataProto 频繁穿越 Ray object store 或 controller/worker 边界时,序列化和反序列化会转化为真实的系统成本。

第三类成本是对象列和对齐风险。non_tensor_batch 中可能包含 raw prompt、多模态对象、工具参数、reward 诊断信息等。这些字段很难像 tensor 那样被高效移动,但又必须与样本的第 0 维严格对齐。DataProto 的一致性检查能够捕获部分错误,但系统设计仍需避免将过重的对象长期挂在主 batch 上。

下面这张图汇总了这些代价。它补充说明:DataProto 解决了“数据语义统一”的问题,但也可能成为 controller 内存、Ray object store 以及字段对齐的压力点。

DataProto 的主要系统压力点

因此,优化 RLHF 数据流不能只问“这批 tensor 有多大”。更完整的追问应当是:哪些字段必须留在主 DataProto 中,哪些可以只在某个阶段临时存在,哪些对象列应该提前压缩或延迟加载,哪些 metric 应该只回传摘要。DataProto 让这些问题有了统一的落脚点。

小结:DataProto 是后训练系统的数据契约

至此,第一组的第 2-5 篇文章可以连贯起来看:

HybridFlow 解释阶段 → Single Controller 保留阶段顺序 → ResourcePool / WorkerGroup 放置执行角色 → DataProto 在角色之间搬运训练证据

DataProto 的价值在于将不断变化的 RL batch 转化为统一协议:tensor 字段、对象列和 meta 信息都围绕同一批样本流动。其代价也源于此:字段会增长,对象列会变重,dispatch/collect 必须保持可切分和可合并,controller 边界会承担序列化和聚合压力。

下一篇可以回到 PPO/GRPO step 本身:现在我们已经知道控制流在哪里、worker 放在哪里、数据如何流动,接下来就可以按照 fit() 逐段解释一轮 step 中每个阶段到底消费和产出什么。

本文源码索引

verl/protocol.py:317-328DataProto 的三层字段定义。
verl/protocol.py:454-478:batch 与 non-tensor 列的一致性检查。
verl/protocol.py:479-543from_single_dict()from_dict() 如何构造 DataProto。
verl/protocol.py:781-798union() 如何合并不同阶段产出的字段。
verl/protocol.py:864-961chunk()concat() 如何支撑分布式切分与合并。
verl/protocol.py:971-1013repeat() 如何复制 batch 和 non-tensor 列。
verl/protocol.py:1102-1126to_tensordict() 如何把 DataProto 转成 worker 可执行形态。
verl/trainer/ppo/ray_trainer.py:1330-1407:PPO 主循环如何从 dataloader batch 变成 rollout 后的 DataProto。
verl/trainer/ppo/ray_trainer.py:1426-1541:reward、logprob、value、advantage 如何继续给 batch 追加字段。
verl/single_controller/base/decorator.py:71-117:DataProto dispatch 前的切分和 auto padding。
verl/single_controller/base/decorator.py:167-199:DP DataProto dispatch/collect。
verl/single_controller/base/decorator.py:202-304:ND mesh 下的 DataProto dispatch/collect。

来源:https://cloud.tencent.com.cn/developer/article/2701611
上一篇如何用ResourcePool和WorkerGroup角色化GPU资源 下一篇深入解析PPO与GRPO一轮训练步骤究竟发生了什么
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
内网RPA离线部署从依赖打包到7×24无人值守踩坑与避坑方案
AI教程 · 2026-07-02

内网RPA离线部署从依赖打包到7×24无人值守踩坑与避坑方案

这三年,内网RPA项目接了不下二十个。每次开局都像闯关——断网、缺依赖、多机同步、定时执行、批量分发、源码保护、AI离线化,八个坑一个比一个深。今天把这些实战经验整理出来,希望能帮正在内网搞自动化的兄弟们少踩点雷。 一、内网无网络环境怎么部署RPA流程:先搞清楚什么叫“真离线” 很多工具宣传“支持本

水利工程师用WorkBuddy写洪水报告效率提升3倍
AI教程 · 2026-07-02

水利工程师用WorkBuddy写洪水报告效率提升3倍

WorkBuddy开发者分享季 水利工程师AI提效实战:用WorkBuddy撰写洪水影响评价报告,效率提升3倍 WorkBuddy 效率 人工智能 开发工具 一、我是谁,为什么需要AI 先介绍一下自己——我是一名水利工程师,在湖南长沙的一家小型水利设计公司任职。当前行业环境不太

日志服务数据加工规则洞察仪表盘使用指南
AI教程 · 2026-07-02

日志服务数据加工规则洞察仪表盘使用指南

数据加工诊断仪表盘 想实时掌握日志服务加工功能的运行状态?直接从加工列表页点击那个“规则洞察”按钮,仪表盘就会立刻呈现出来。入口就在那儿,不绕弯子。 跳转后,你可以按作业名称、实例ID或源LogStore来筛选任务状态。比如下边这张图,展示的是当前实例ID(90c9d47714dbb807d47c1

基于RFID的固定资产管理系统技术架构与工程实践
AI教程 · 2026-07-02

基于RFID的固定资产管理系统技术架构与工程实践

固定资产管理难题是众多企事业单位的普遍困扰,资产数量动辄数千件,且广泛分布于不同部门、楼层乃至园区。传统人工盘点方式在工程维度上始终面临三大关键瓶颈:采集效率低下、数据闭环中断、状态同步滞后。使用条码枪逐一扫描标签,识别距离通常不超过30厘米,操作人员需逐个寻找并扫描,盘点效率完全受限于人力。面对5

WorkBuddy实战用AI搭建A股智能盯盘助手省心高效
AI教程 · 2026-07-02

WorkBuddy实战用AI搭建A股智能盯盘助手省心高效

炒股的朋友们想必都深有体会——每天重复盯盘、查行情、分析板块轮动,这一整套流程下来耗费大量精力。手动翻查数据不仅身心俱疲,还很容易错过关键买卖节点。今天我们就来聊聊如何打造一款趁手的盯盘工具,借助AI替你分担这些重复性工作。 背景:盯盘的核心痛点 股民都有同感——每天不只要查询单只股票的实时行情,还