我在verl(一个RL后训练框架)里沉浸了数月,复刻了它,然后停止。写下了内部机制、复刻所需的工具开销以及一个棘手的NCCL错误。
摘要
深入探讨字节跳动verl强化学习后训练框架的内部机制,包括编排、单控制器模式以及一个棘手的NCCL错误修复。作者分享了复刻该框架和构建自定义工具的经验教训。
我不确定是否应该在这里发布这篇文章,但我朋友说很多研究者会浏览这个子版块,这篇文章可能对他们有帮助。我想它也可能帮助那些在家中尝试动手的人。我不知道这里有多少人在做后训练,但我确实看到有人发布蒸馏、微调、数据集和基准测试等内容,所以我觉得你可能会感兴趣。
为了提供背景,我从事Agent和工具使用能力的后训练工作。前一阵子,我几乎全身心投入在字节跳动的RL后训练框架verl中,持续了几个月。我阅读了大部分源码,吸收了几乎所有的知识。在与它一起工作的过程中,我开始想要一个“更好”的版本,一个更适合我的开发体验的版本。于是我对它进行了复刻(非公开,后来我放弃了),试图让它变得更好(在我看来)。虽然我推送了很多修复,并围绕它构建了工具,但到了某个时候,我不得不停下来,这让我心里空落落的,最终我把整个过程写了下来。作为对它的告别,同时也为了从中获得我所学到的所有知识和技能。
这是一篇对实际运行RLHF循环的部分的仔细解读,加上复刻带来的一些工程问题(不过没什么大不了的),以及一个我至今仍有点自豪的调试故事。
以下是博客文章内容的快速浏览:
- 编排层的内部机制:从每个阶段(rollout、reward、advantage、update)传递的数据结构(DataProto),以及API名称中未警告的陷阱。在其底层,还有一个半完成的向纯TensorDict的迁移。
- 单控制器模式:一个驱动进程持有调度,通过一个“魔法属性”分发系统将工作分发给GPU工作节点。这个模式很难缠,我花了很长时间才搞明白,但现在理解了,就觉得非常自然,并且帮助我以极大的信心和轻松感来构建自己的编排层小包。
- 资源池和协同定位,以及actor、critic、rollout和reference角色如何被融合到每个GPU上的单个Ray actor中。然后我简要谈谈复刻所需的工具,因为这仍然是verl的一个问题,而且我认为他们不太可能修复它,或者至少修复起来会很麻烦,因为他们需要支持这么多不同的架构等等。但主要问题是打包泄漏:torch不在核心依赖中,一个版本约束被复制粘贴了三次,requirements.txt和setup.py对所需依赖存在分歧,一个未维护的包仍然在活跃代码路径中被导入,其测试被跳过。还有,测试没有标准化,我浪费了很多精力试图让测试套件干净整洁,甚至构建了一个GPU感知的测试调度器,将测试装箱到空闲的卡片上,而不是让一些GPU闲置。我还加了一个小彩蛋,因为我看到同事遇到了一个NCCL问题。一个多GPU测试挂起,没有错误,没有超时,没有崩溃。CPU屏障通过了,但第一个NCCL集合操作挂起了。原因是NCCL为它的bootstrap套接字选择了一个绑定的网络接口,其IP无法路由回自身,因此rank 0在一个没有其他进程能到达的地址上监听。修复方法是一个环境变量(单节点上设置为`NCCL_SOCKET_IFNAME=lo`)。找到这个原因需要拆解TCPStore、Gloo和NCCL层,并阅读NCCL自己的调试输出。
但是,正如你所料,我停止了,因为我关心的每个重构(对编排层而言,如果你读了博客就会明白有太多间接层和魔法,很难理解,而且我认为它不是一个好的开发基础)都必须跟上几乎每天都在发布变化的框架,保持同步的成本超过了工作本身。我现在正在构建自己的小型爱好编排层。显然,这类知识可能会过时,但我认为编排部分作为基础原理是值得了解和理解的,而且无论实现如何,我觉得抽象层或多或少都是一样的,除非你改变范式(例如从单控制器到SPMD)。而且我认为,如果你有兴趣为verl做贡献,你将从这篇博客中获得很好的想法,但我不确定他们是否会接受这些领域的贡献。
好了,抱歉啰嗦了,哈哈,这是完整文章:[https://reinforcedknowledge.com/posts/verl-retrospective/](https://reinforcedknowledge.com/posts/verl-retrospective/)
相似文章
@adithya_s_k: https://x.com/adithya_s_k/status/2054961319179420035
分析为什么强化学习在编程任务中因可验证奖励而受到青睐,以及新兴框架Harbor如何解决RL训练中环境复杂度的瓶颈。
我从零重建了一个Claude Code风格的编程代理——整个代理循环只有6行代码。20章,约5000行代码,无框架,也支持本地模型
一位开发者分享了一个20章的教程,从头重建了一个Claude Code风格的编程代理,展示了整个代理循环(约6行代码),并支持本地模型和多种LLM API。
@charles_irl: 恰当的后训练强化学习,广泛部署,是迈向未来软件系统能悄然自我改进、适应人类需求的关键一步。
Modal 在其平台上宣布了一个开源的强化学习库,通过可扩展的部署解决后训练强化学习中的基础设施挑战。
我为 PyTorch 训练循环构建调试器所学到的东西,以及它如何改变我对故障诊断的思考 [D]
作者分享了构建 NeuralDBG 的经验,这是一个针对 PyTorch 训练循环的开源调试器,通过监测逐层梯度范数的变化而非全局损失来检测局部故障,如梯度消失/爆炸。文中包含实用代码片段和社区问题。
@_djdumpling: Luke 是在 RL 基础设施方面最出色的人之一,绝对值得一读!
Luke J. Huang 的新博客文章调研了异步强化学习理论与基础设施,涵盖 8 家开放权重前沿实验室,并讨论了算法技术以及针对训练-推理不匹配的系统修复方案。