Prhub

#37476 [Feat][RL] IPC weight sync optimizations: multigpu support and chunked packed tensors

原始 PR 作者 hao-aaron 合并时间 2026-05-15 22:53 文件变更 10 提交数 23 评论 35 代码增减 +1595 / -459

执行摘要

IPC 权重同步优化:多 GPU 支持与分块打包传输

在大型同机 RLHF 场景(FSDP 训练 + vLLM 推理共享 GPU)中,原有 IPC 权重传输不支持多 GPU 且未对张量传输做内存上限控制,训练器可能因完整模型拷贝而 OOM。本 PR 旨在通过分块打包传输将训练端峰值内存控制在单缓冲区(默认 1GB),并引入多 GPU 全收集+句柄合并,使每个 FSDP worker 参与句柄收集而仅 rank 0 发送,以支持 FSDP 分片权重同步。

建议

该 PR 涉及权重传输核心路径的重要改造,值得 RLHF 开发者精读。重点关注:packed_tensor.py 的分块设计、ipc_engine.py 的多 GPU 全收集实现、以及 API 变更对下游的影响。建议后续 PR 跟进修复超大张量边界问题,并考虑增加正式 HTTP 分块端点。

讨论亮点

讨论亮点

  1. API 端点设计
    - kylesayrs 建议添加 POST /update_weights_chunkPOST /finalize_weight_update 新端点,避免与现有 is_checkpoint_format 混淆。
    - SumanthRH 提出三种方案,最终认同 Option 3:新端点并逐步废弃旧 API。
    - 当前 PR 未实现新端点,但通过 packed 参数和 callable send_mode 提供了扩展点。

  2. 张量引用提前释放风险
    - andakai 指出在非连续张量时,IPC 句柄可能因原张量被释放而失效,建议添加 weight_refs 保留引用。
    - hao-aaron 确认并立即修复。

  3. 分块缓冲大小保证
    - SumanthRH 担忧单个大张量可能导致打包缓冲区超出 buffer_size_bytes 上限,训练端内存可能翻倍。
    - hao-aaron 承认此问题,计划后续 PR 严格限制。

实现拆解

1. 重构 packed_tensor 工具模块

vllm/distributed/weight_transfer/packed_tensor.py 中,将原有的 NCCL 打包广播函数重构为模块级工具。提取 unpack_tensor()pack_tensors() 为独立函数,并新增 PackedChunkPackedIpcChunk 数据类。原有的 packed_broadcast_producer/consumer 重命名为 packed_nccl_broadcast_producer/consumer,以和 IPC 变体区分。nccl_engine.py 同步更新引用。

2. 扩展 IPC 引擎支持分块与多 GPU

vllm/distributed/weight_transfer/ipc_engine.py 中:

  • IPCTrainerSendWeightsArgs 新增 packedpacked_buffer_size_bytes 字段,mode 重命名为 send_mode 并支持 Callable 自定义发送。
  • IPCWeightTransferUpdateInfo 移除 ipc_handles_pickled 字段,串行化逻辑移入 parse_update_info(),句柄类型更改为 rebuild_cuda_tensor 参数元组。
  • 新增 _send_packed_send_unpacked_all_gather_and_merge_handles 等私有方法,实现多 GPU 全收集并仅在 rank 0 发送。分块模式下每块发送时设置正确的 run_initialize/finalize_layerwise_reload 标记,每块传输后释放缓冲区并触发 ipc_collect()

3. 新增端到端示例

examples/rl/rlhf_ipc_fsdp_ep.py 演示 4 GPU 上使用 FSDP2 训练 + vLLM 专家并行推理,通过 CUDA IPC 进行分块权重同步。使用 Qwen/Qwen3-30B-A3B 模型,展示 placement group 共置、DP SPMD 协调等关键模式。

4. 更新测试与文档

  • tests/distributed/test_packed_tensor.py 增加对 unpack_tensorpack_tensorspacked_ipc_producer 的单元测试,以及跨进程 IPC 往返集成测试。
  • tests/distributed/test_weight_transfer.py 适配 IPC 句柄格式变更,移除 pickle 相关测试,增加 parse_update_info 的多场景验证。
  • docs/training/weight_transfer/ipc.mdbase.md 更新新参数、分块用法及自定义 callable 模式说明。
文件 模块 状态 重要度
vllm/distributed/weight_transfer/ipc_engine.py IPC 引擎 modified 9.05
vllm/distributed/weight_transfer/packed_tensor.py 打包工具 modified 8.65
examples/rl/rlhf_ipc_fsdp_ep.py RL 示例 added 8.98
tests/distributed/test_packed_tensor.py 打包测试 modified 7.24
tests/distributed/test_weight_transfer.py 传输测试 modified 6.93

关键符号

pack_tensors unpack_tensor packed_ipc_producer packed_ipc_consumer packed_nccl_broadcast_producer packed_nccl_broadcast_consumer _send_packed _send_unpacked _all_gather_and_merge_handles parse_update_info gather_and_broadcast_weights_ipc _full_param_iter

关键源码片段

vllm/distributed/weight_transfer/ipc_engine.py core-logic

核心变更文件:实现多 GPU 同步、分块传输、API 重构。新增 packed 传输路径和 all-gather 逻辑。

@dataclass
class IPCTrainerSendWeightsArgs:
    """Arguments for IPC trainer send_weights method."""
    send_mode: str | Callable[['IPCWeightTransferUpdateInfo'], None]
    # send_mode 支持 'ray', 'http' 或自定义 callable
    llm_handle: Any = None
    """Ray actor handle or list of handles."""
    url: str | None = None
    """Base URL for HTTP endpoint."""
    packed: bool = False
    """启用分块打包传输,默认关闭"""
    packed_buffer_size_bytes: int = DEFAULT_PACKED_BUFFER_SIZE_BYTES
    """每块最大字节数,默认 1GB"""
​
    def __post_init__(self):
        if callable(self.send_mode):
            return # 自定义 callable 无需校验
        if self.send_mode == 'ray' and self.llm_handle is None:
            raise ValueError('llm_handle is required for ray send_mode')
        if self.send_mode == 'http' and self.url is None:
            raise ValueError('url is required for http send_mode')
        if self.send_mode not in ('ray', 'http'):
            raise ValueError(
                f'send_mode must be ray, http, or a callable, got {self.send_mode!r}'
            )

评论区精华

API 端点设计:新端点 vs 现有参数 设计

kylesayrs 建议添加 POST /update_weights_chunk 和 POST /finalize_weight_update 新端点,避免与现有 is_checkpoint_format 混淆。SumanthRH 提出三种方案,最终认同 Option 3(新端点 + 标记旧 API 废弃)。

结论:当前 PR 未实现新端点,但通过 packed 参数和 callable send_mode 提供了扩展点。计划后续 PR 添加正式端点。 · 已解决

非连续张量 IPC 句柄引用生命周期 正确性

andakai 指出接收端 rebuild_cuda_tensor 后,如果原张量非连续,返回值可能仅是视图,原存储释放会失效。建议添加 weight_refs 列表保持引用。

结论:hao-aaron 确认并添加了 weight_refs 机制。 · 已解决

分块缓冲区大小保证 性能

SumanthRH 指出当单个张量超过 buffer_size_bytes 时,pack_tensors 仅警告而不限制,可能导致训练端内存超出预期。

结论:hao-aaron 承认此问题,计划在后续 PR 中让 pack_tensors 严格尊重缓冲区大小限制。 · unresolved

风险与影响

风险分析

  • 多 GPU 全收集内存风险_all_gather_and_merge_handles 将所有 rank 的句柄收集到 rank 0,对大模型可能加剧 GPU 内存压力。但句柄数据量很小,实际风险较低,但需关注。
  • 超大张量边界问题pack_tensors 在单个张量超过 buffer_size_bytes 时仅警告,不限制,可能导致训练端实际分配双倍内存。
  • IPC 句柄生命周期:当前已使用 weight_refs 防止提前释放,但需确认所有路径均覆盖。
  • API 向后兼容性mode 字段重命名为 send_modeipc_handles_pickled 字段被移除,旧用户需要迁移。
  • 环境依赖:示例和测试依赖特定环境变量设置,可能影响可移植性。

影响分析

  • 用户:使用 IPC 权重传输的 RLHF 用户获得多 GPU 支持和分块传输能力,训练端峰值内存显著降低。需要适配新的 send_mode 参数,且暂不支持旧版 HTTP pickle 路径。
  • 系统:核心权重传输引擎的扩展性提升,为未来支持更灵活的发送方式奠定基础。
  • 团队:新增示例和测试提高了可测试性,但需维护 API 兼容性指引。
多 GPU 全收集内存风险 超大张量边界问题 IPC 句柄引用生命周期 API 向后兼容性 环境变量依赖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论