使用 vLLM 加速 RLHF,来自 OpenRLHF 的最佳实践

5 分钟阅读
OpenRLHF 团队

随着训练具备推理能力的大语言模型(LLM)需求的增长,基于人类反馈的强化学习(RLHF)已成为核心技术。然而,传统的 RLHF 流水线——尤其是使用近端策略优化(PPO)的流水线——往往受到巨大的计算开销阻碍。对于擅长复杂推理任务的模型(如 OpenAI-o1 和 DeepSeek-R1)而言,这一挑战尤为突出。在这些模型中,生成长思维链(CoT)输出的时间可能占总训练时间的 90%。这些模型必须产生详细的、分步骤的推理过程,可能跨越数千个 token,使得推理阶段比训练阶段更加耗时。作为领先的推理框架,vLLM 为生成 RLHF 样本和更新模型权重提供了一个用户友好的接口。

OpenRLHF 的设计

为了在 RLHF 框架的性能和易用性之间取得平衡,OpenRLHF 被设计为一个高性能且用户友好的解决方案,集成了 Ray、vLLM、零冗余优化器(ZeRO-3)和自动张量并行(AutoTP)等关键技术。

Ray 是 OpenRLHF 分布式架构的支柱。凭借强大的调度和编排功能,Ray 可以高效管理复杂的数据流和计算,包括跨多个节点分发基于规则的奖励模型。

带有 Ray Executor 和 AutoTP 的 vLLM 在加速推理方面发挥着核心作用。通过内置对 Ray Executors 的支持以及与 HuggingFace Transformers 的集成,它能够通过 AutoTP 实现高效的权重更新,从而带来高吞吐量和内存高效的 LLM 生成。

带有 HuggingFace Transformers 的 ZeRO-3 是一种来自 DeepSpeed 的内存优化方法,使 OpenRLHF 能够训练大模型,而无需使用 Megatron 等重量级框架。这种与 HuggingFace 的无缝集成,允许轻松加载和微调预训练模型。

Ray、vLLM、ZeRO-3 和 HuggingFace Transformers 共同构成了一个尖端且精简的 RLHF 训练加速解决方案。该架构还影响了诸如 veRL 等其他框架,它们采用了类似的范式来实现可扩展且高效的 RLHF 训练。OpenRLHF 也是第一个基于 Ray、vLLM 和 ZeRO-3 开发的开源 RLHF 框架,已被 Google、字节跳动、阿里巴巴、美团、Berkeley Starling 团队等使用。

Ray and vLLM in OpenRLHF
OpenRLHF 中的 Ray 和 vLLM
如上图所示,OpenRLHF 使用 Ray 的放置组(Placement Group)API 来灵活调度 RLHF 流水线的各个组件,包括 vLLM 引擎、Actor、Critic、Reference 和 Reward 模型。尽管表现形式上是分开的,但这些组件可以放在共享的 Ray 放置组中,以最大化资源效率。例如,所有模块都可以在混合引擎配置中的同一 GPU 组内运行,或者特定组件(如 Actor 和 Critic)可以组合在一起。所有模块由一个中央 Ray Actor 编排,该 Actor 管理整个训练生命周期。Actor 和 vLLM 引擎之间的权重同步通过高性能通信方法处理,例如 NVIDIA 集体通信库 (NCCL) 或混合引擎设置中的 CUDA 进程间通信 (IPC) 内存传输。

使用 vLLM Ray Executor 实现 RLHF 加速

OpenRLHF 和 vLLM 提供了一套简洁高效的 API,简化了 RLHF 流水线内的交互。通过实现自定义的 WorkerExtension 类,用户可以处理训练和推理组件之间的权重同步。环境变量 VLLM_RAY_PER_WORKER_GPUSVLLM_RAY_BUNDLE_INDICES 允许对每个 Worker 进行细粒度的 GPU 资源分配,从而实现多个组件共享一个 GPU 组的混合引擎配置。

# rlhf_utils.py
class ColocateWorkerExtension:
    """
    Extension class for vLLM workers to handle weight synchronization.
    This class ensures compatibility with both vLLM V0 and V1.
    """
    def report_device_id(self) -> str:
        """Report the unique device ID for this worker"""
        from vllm.platforms import current_platform
        self.device_uuid = current_platform.get_device_uuid(self.device.index)
        return self.device_uuid
 
    def update_weights_from_ipc_handles(self, ipc_handles):
        """Update model weights using IPC handles"""
        handles = ipc_handles[self.device_uuid]
        device_id = self.device.index
        weights = []
        for name, handle in handles.items():
            func, args = handle
            list_args = list(args)
            list_args[6] = device_id  # Update device ID for current process
            tensor = func(*list_args)
            weights.append((name, tensor))
        self.model_runner.model.load_weights(weights=weights)
        torch.cuda.synchronize()
 
# main.py
class MyLLM(LLM):
    """
    Custom LLM class to handle GPU resource allocation and bundle indices.
    This ensures proper GPU utilization and placement group management.
    """
    def __init__(self, *args, bundle_indices: list, **kwargs):
        # Prevent Ray from manipulating CUDA_VISIBLE_DEVICES at the top level
        os.environ.pop("CUDA_VISIBLE_DEVICES", None)
        # Configure GPU utilization per worker
        os.environ["VLLM_RAY_PER_WORKER_GPUS"] = "0.4"
        os.environ["VLLM_RAY_BUNDLE_INDICES"] = ",".join(map(str, bundle_indices))
        super().__init__(*args, **kwargs)
 
 
# Create Ray's placement group for GPU allocation
pg = placement_group([{"GPU": 1, "CPU": 0}] * 4)
ray.get(pg.ready())
 
# Create inference engines
inference_engines = []
for bundle_indices in [[0, 1], [2, 3]]:
    llm = ray.remote(
        num_gpus=0,
        scheduling_strategy=PlacementGroupSchedulingStrategy(
            placement_group=pg
        )
    )(MyLLM).remote(
        model="facebook/opt-125m",
        tensor_parallel_size=2,
        distributed_executor_backend="ray",
        gpu_memory_utilization=0.4,
        worker_extension_cls="rlhf_utils.ColocateWorkerExtension",
        bundle_indices=bundle_indices
    )
    inference_engines.append(llm)

完整的 RLHF 示例详细介绍了如何初始化指定 GPU 数量的 Ray,创建放置组来管理资源,并定义训练 Actor 和推理引擎。训练 Actor 管理模型初始化和权重更新,而推理引擎则通过 vLLM 提供模型服务。权重同步使用 CUDA IPC 或 NCCL 执行,确保在整个 RLHF 流水线中保持一致性和高效性。

致谢

我们要向 vLLM 的贡献者们表示诚挚的感谢,包括 Kaichao YouCody YuRui Qiao 等人,没有他们的帮助,OpenRLHF 与 vLLM 的集成将无法实现。来自 vLLM 团队的 Kaichao You 领导了这次 RLHF 集成工作。

OpenRLHF 项目是第一个基于 Ray 和 vLLM 的开源 RLHF 框架。我们要感谢 Jian HuSonglin JiangZilin ZhuXibin Wu 等人,他们对 OpenRLHF 项目的 Ray、vLLM Wrapper 和混合引擎组件做出了重大贡献。Jian Hu 领导了该开发工作。