知乎:不关岳岳的事(已授权)
链接:https://zhuanlan.zhihu.com/p/27676081245
编辑:「深度学习自然语言处理」公众号
背景
强化学习(RL)对大模型复杂推理能力提升有关键作用,然而,RL 复杂的计算流程以及现有系统局限性,也给训练和部署带来了挑战。VeRL(https://github.com/volcengine/verl)是字节跳动seed团队和香港大学开发的强化学习仓库。该框架采用混合编程模型,融合单控制器(Single-Controller)的灵活性和多控制器(Multi-Controller)的高效性,可更好实现和执行多种RL算法,显著提升训练吞吐量,降低开发和维护复杂度。
本文会先简单介绍VeRL框架涉及的一些概念,并且简单阅读整理VeRL框架的一些核心算法逻辑,以方便开发者对该框架加深了解。除了VeRL以外,还有OpenRLHF(https://github.com/OpenRLHF/OpenRLHF)等非常优秀的国产开源训练框架,设计理念都非常简洁,且各有一些独特的优势。
相关资料
VeRL框架的论文(HybridFlow):https://arxiv.org/pdf/2409.19256
论文解读:https://zhuanlan.zhihu.com/p/24682036412
VeRL框架的官方解读:https://mp.weixin.qq.com/s/JYQQs2vqnhRz82rtDI-1OQ
仓库地址:https://github.com/volcengine/verl
Docs:Welcome to verl’s documentation! (https://verl.readthedocs.io/en/)
知乎上的一些阅读笔记:
https://zhuanlan.zhihu.com/p/26833089345
https://zhuanlan.zhihu.com/p/25763072556
核心概念
尽可能用通俗的话解释一下和本文相关的一些概念:
General Concepts
RL:RL即强化学习,最近因为o1/r1的缘故,是大模型领域的当红技术。VeRL就是一个主要面向RL的训练框架。个人(从NLP的视角)觉得RL和传统的SFT技术有几点不同:
1)引入了惩罚信号。众所周知,SFT只是模仿学习正例。而RL不仅对好的样本奖励,也要对坏的样本惩罚。无论是简单的策略梯度,还是GRPO、Reinforce、PPO这些算法,原理都是一致的,本质上只是在设计不同的奖励/惩罚的粒度(token/macro action/seq等等)和力度(需不需要引入baseline,要不要考虑KL限制,要不要clip等等)。
2)允许使用当前模型在线产出的样本训练自身。SFT一般学习的都是人工标注或者其他模型生成的样本(即蒸馏)。而RL允许当前模型实时采样样本,并依据这些样本训练自身。
online强调当前策略模型是否能和环境进行交互(比如遇到新的一批数学题目,是否可以做完后实时拿到正确与否的信号),在一些其他场景(如GUI Agent,自动驾驶),允许online需要搭建复杂的simulator;
on-policy强调当前的RL训练数据一定是最新的策略模型实时生成的,在一些时候,会预先采样生成大量的经验数据,然后分mini批次更新,在这种场景下,除了第一个mini-batch是on-policy的,后面的其实是off-policy的;
所以目前大家用的GRPO/Reinforce/PPO这些一定是online的,但不一定是on-policy(主要看mini-batch num是否大于1);
其实从这个角度来看,RS技术更像是RL,只不过没有惩罚信号(也可以引入负例进一步做DPO);
Rejection Sampling技术也是自己采样训练自己,为什么一般用在SFT阶段?
on-policy vs. online:
Ray:Ray 是一个分布式计算框架,现在流行的RL框架如VeRL和OpenRLHF都依托Ray管理RL中复杂的Roles(比如PPO需要四个模型)和分配资源。以下是一些核心的概念:
Ray Actor:有状态的远程计算任务,一般是被ray.remote装饰器装饰的Python类,运行时是一个进程(和PPO等Actor-Critic算法的Actor不要混淆了);
Ray Task:无状态的远程计算任务,一般是被ray.remote装饰器装饰的Python函数,创建的局部变量仅在当前可见,对于任务的提交者不可见,因此可以视作无状态;
资源管理:Ray可以自动管理CPU、GPU、Mem等资源的分配(通过ray.remote装饰器或者启动的options参数可以指定指定的ray actor所需的计算资源),并且还可以设计资源组(placement group),将不同的ray actor指定放置在相同或者不同的资源位置(bundle);
通过使用ray,verl可以方便地实现各种角色、各种并行策略的资源分配,并且实现hybrid engine等colocate策略;
异步执行:ray的计算是异步的,一般执行一个ray的计算任务后,ray会立刻返回任务的执行句柄Object reference,用户的代码不会阻塞,可以自行使用ray.get/ray.wait进行阻塞式/轮询式的结果获取;
PS: 在RL训练中引入异步的概念,可以方便actor/critic/generator/rm之间互相overlap掉一些处理时间(比如actor在更新上一个batch的时候,generator已经可以生成下一个batch了)。由于o1-liked rl的主要时间卡点在rollout位置,因此将rollout 更好地aynsc化(例如充分利用线上serving集群的夜晚空闲时间)是未来 rl infra优化的方向之一;
并行策略:
3D并行:目前的LLM训练(如megatron-lm)和推理引擎(vllm, sglang)都支持了各种并行策略,以加大训推吞吐和减少显存占用,包括:数据并行(DP)、张量并行(TP,层内部切分并行)、流水线并行(PP,层间串行执行) 等;
VeRL的新版本也支持了基于ulysess的序列并行(SP,在序列长度的维度切分并行,对长文RL训练很有必要);
不同角色在不同阶段的3D并行策略可能会灵活变化,因此VeRL的hybrid engind为做了很多优化,如零冗余的模型参数re-sharding;
FSDP:是meta提出的,和megatron不同的另一套distributed training framework。核心思想非常直观,将模型参数(权重、优化器状态等)在所有GPU之间分片存储,计算时,仅当某个GPU需要其他GPU上的参数时才进行通信,并且还进行了计算通信重叠的优化;
verl同时支持和适配两套训练引擎,即FSDP和Megatron,前者逻辑清晰,且方便支持新的模型结构,research友好;而后者对超大规模(如100B以上)的模型训练更友好,并且参数resharding的开销更小,工程友好;
VeRL-related Concepts
Hybrid Flow:RL的训练逻辑和Pretrain/SFT不一样,涉及到多个模型之间的交互和协作。VeRL将LLM RL训练逻辑的dataflow建模成一个两层的hybrid flow问题,进行了解耦,包括:
控制流:位于high-level,描述了多个模型角色之间的交互逻辑,如actor make experience结束后,Critic、RM、reference开始计算分数,完成后计算GAE和相应loss;
计算流:位于low-level,描述了单个模型角色内部的计算流程(如前向反向传播、优化器更新、自回归生成等),管理模型的训练和推理具体过程;

Single controller vs. Multiple controller: 单控制器和多控制器是两种不同的设计模式;
Single controller:单控制器模式使用一个中央控制器来统一管理所有子模块。
优点:架构清晰,容易理解,所有逻辑集中在一处,便于维护和管理;
⭐️NOTE:VeRL通过single controller pattern来实现前述的RL算法的控制流,这就非常方便新算法的开发和实现(利好算法同学),比如笔者之前曾在全局multi-controller的框架上设计&改动过一些新算法(如agent的multi-turn rl),经常会遇到各种nccl集合通信hang住的问题,以及一点细微的改动需要在多个角色之间同步,非常折磨人;
Multi-controller:将控制逻辑分散到多个专门的控制器中,每个控制器负责处理特定的模块。
VeRL通过设计多层级的worker(RayWorkerGroup → WorkerDict → ModelWorker → ParallelWorker),实现计算流的multi-controller封装;
优点:single controller,如果所有数据都需要经过中央控制器,可能通信开销过大,而multi controller缓解了这一问题;
靠集合通信实现各个角色的同步控制(控制流),逻辑比较复杂且分散;
⭐️NOTE:VeRL在计算流维度使用了multi-controller模式,避免了single controller实现计算流潜在的通信开销过高问题,目前主流的训练引擎(FSDP、Megatron)都是基于该设计模式,而主流的推理引擎(vLLM、sglang)也有适配该模式进一步减少通信开销的计划;
Hybrid Engine:
训练引擎 vs. 推理引擎:顾名思义,训练引擎主要负责训练,推理引擎主要负责推理(废话),前者主要参与Actor、Critic的训练,后者主要参与Generator生成样本的过程。此外,一些仅涉及到前向传播的推理过程,一般也会使用训练引擎(Critic、RM、reference打分计算logits和score等),因为现代训练引擎的结果精度一般会比推理引擎更高(因为kernel fusion等底层因素)。
模型放置策略:
常见分组:
该方案是目前VeRL主要采用的方案;
Actor/Ref一组,Critic/RM一组,Generator单独;
Actor/Generator一组(因为二者的具体参数需要实时同步),其余单独放置;
分开放置:所有角色放置在不同的设备上,可以异步overlap掉执行时间,但会有GPU资源在训练过程中空闲;
分组放置:将角色分组,按组分配在同样的设备上,也可以overlap,且减少了GPU idle time;
一起放置:所有角色放置在同样的设备上,GPU始终被占用,但是只能串行执行;
VeRL的hybrid engine设计:
仅在Micro DP Group All gather参数;
worker_dict:每张卡(driver)调度一个worker_dict,它是不同worker的一个分片,主要方便ray管理和角色切换,具体的函数实现是worker_dict内部承载的worker class实现的(各种ModelWorker、ParallelWorker);
worker_group:当前colocate的角色所占据的所有设备的worker_dict共同组成的worker_group,在这一级别统一管理数据resharding、任务执行等分布式逻辑;
通过实现resource pool,灵活支持各种模型放置策略,以colocate为主,将actor的训练和推理引擎放置在一起,动态切换角色;
设计了worker_dict概念,实现了worker角色的灵活切换。这样,不同角色可以放置在相同的设备上,但是通过method的rebind进行转换,并通过reload和offload params来切换参数;
由于模型在不同角色之间切换(例如从actor切换为generator),需要不同的参数切分逻辑,所以VeRL也设计了一套高效切换的策略,名为Zero redundancy model resharding,具体可以参考论文5.3节。
此外,VeRL的3D hybrid engine也通过优化显著减少了参数resharding过程中的通信开销:

数据传输协议:VeRL中的worker可以动态切换具体的角色(例如从actor切换为generator),为了适配不同角色和方法所需的数据划分细节(例如在dp维度切分数据、在3d维度切分数据等),VeRL设计了一套数据传输协议(Data Transfer Protocol),主要包括数据的分发(Dispatch)和收集(Collect),具体的细节如下所示:

VeRL将上述数据传输协议以及方法执行(execute,包括全部执行和rank0单独执行)协议,设计为Python的装饰器,通过定义decorator绑定给各个worker类的具体方法。这样在每个workergroup调用内部的workerdict时,便可以得知如何分发和收集数据。

上图表述了VeRL训练的具体数据传输&执行流程:
RayPPOTrainer 向 RayWorkerGroup 发起方法调用;
在 RayWorkerGroup 内部:
首先执行数据分发逻辑(dispatch protocol)
然后执行逻辑判断哪些 worker 需要运行任务(可能是所有 WorkerDicts 或仅 rank0)
带有数据的任务被分发给指定的 WorkerDicts(先是定义角色的ModelWorkerDict,然后是定义计算的ParallelWorkerDict)
任务执行:
每个 WorkerDict 通过 Ray 远程执行接收其任务
完成任务后,结果返回给 RayWorkerGroup
结果处理:
结果通过收集逻辑进行处理(collect protocol)
最终,处理后的结果返回给 RayPPOTrainer
主要代码阅读
代码结构
VeRL仓库的核心代码逻辑(verl:https://github.com/volcengine/verl/)树如下所示:
Project Root
├── models # 模型定义
│ ├── llama
│ │ └── megatron
│ ├── registry.py
│ ├── transformers
│ │ ├── llama.py
│ │ ├── monkey_patch.py
│ │ └── qwen2.py
│ └── weight_loader_registry.py
├── protocol.py # 数据协议
├── single_controller # single controller的实现逻辑
│ ├── base
│ │ ├── decorator.py
│ │ ├── megatron
│ │ ├── register_center
│ │ ├── worker_group.py
│ │ └── worker.py
│ ├── ray
│ │ ├── base.py
│ │ └── megatron.py
│ └── version
│ └── version
├── third_party # 第三方库,主要是vllm的定制化修改
│ └── vllm
├── trainer # 训练器
│ ├── config
│ │ ├── evaluation.yaml
│ │ ├── generation.yaml
│ │ ├── ppo_megatron_trainer.yaml
│ │ ├── ppo_trainer.yaml
│ │ └── sft_trainer.yaml
│ ├── fsdp_sft_trainer.py
│ ├── main_eval.py
│ ├── main_generation.py
│ ├── main_ppo.py
│ ├── ppo
│ │ ├── core_algos.py
│ │ └── ray_trainer.py
│ └── runtime_env.yaml
├── utils # 工具类
│ ├── config.py
│ ├── dataset
│ │ ├── rl_dataset.py
│ │ ├── rm_dataset.py
│ │ └── sft_dataset.py
│ ├── debug
│ │ ├── performance.py
│ │ └── trajectory_tracker.py
│ ├── distributed.py
│ ├── flops_counter.py
│ ├── fsdp_utils.py
│ ├── fs.py
│ ├── hdfs_io.py
│ ├── import_utils.py
│ ├── logger
│ │ └── aggregate_logger.py
│ ├── logging_utils.py
│ ├── megatron
│ │ ├── memory.py
│ │ ├── optimizer_config.py
│ │ ├── optimizer.py
│ │ ├── pipeline_parallel.py
│ │ ├── sequence_parallel.py
│ │ └── tensor_parallel.py
│ ├── megatron_utils.py
│ ├── memory_buffer.py
│ ├── model.py
│ ├── py_functional.py
│ ├── ray_utils.py
│ ├── rendezvous
│ │ └── ray_backend.py
│ ├── reward_score
│ ├── seqlen_balancing.py
│ ├── tokenizer.py
│ ├── torch_dtypes.py
│ ├── torch_functional.py
│ ├── tracking.py
│ └── ulysses.py
├── version
│ └── version
└── workers # Worker定义和实现
├── actor
│ ├── base.py
│ ├── dp_actor.py
│ └── megatron_actor.py
├── critic
│ ├── base.py
│ ├── dp_critic.py
│ ├── __init__.py
│ └── megatron_critic.py
├── fsdp_workers.py
├── megatron_workers.py
├── reward_model
│ ├── base.py
│ └── megatron
├── rollout
│ ├── base.py
│ ├── hf_rollout.py
│ ├── naive
│ ├── tokenizer.py
│ └── vllm_rollout
└── sharding_manager
├── base.py
├── fsdp_ulysses.py
├── fsdp_vllm.py
└── megatron_vllm.py
Trainer组件
https://verl.readthedocs.io/en/latest/workers/ray_trainer.html
trainer文件下主要放置了核心的训练逻辑,主要封装了整体RL算法的控制流程。PPO Ray Trainer - verl documentation(https://verl.readthedocs.io/en/latest/workers/ray_trainer.html)trainer文件下主要放置了核心的训练逻辑,主要封装了整体RL算法的控制流程。PPO Ray Trainer - verl documentation trainer文件下主要放置了核心的训练逻辑,主要封装了整体RL算法的控制流程。PPO Ray Trainer - verl documentation trainer文件下主要放置了核心的训练逻辑,主要封装了整体RL算法的控制流程。
目前支持的训练逻辑包括:
SFT:
基本上就是一个Torch-native的FSDP标准Trainer的实现;
基于ulysess实现了sft训练时对超长序列的序列并行支持;
Devicemesh:torch2.2引入的新机制,用于管理设备&进程组之间的NCCL数据通信。Verl借用了该机制简化了对于数据传输的控制逻辑。
文档:https://pytorch.org/tutorials/recipes/distributed_device_mesh.html
Devicemesh对于管理各种并行(模型、数据并行)时设备之间的通信非常有用,不再需要手撸进程组,以及手动管理rank和拓扑了,方便很多;
fsdp_sft_trainer.py:基于FSDP(dpsd zero3)实现的SFT训练逻辑,verl支持在RL训练前通过sft来cold-start policy;
PPO/GRPO/Reinforce++/RLOO等RL算法:
初始化RL中的各个Role:RL算法中本身涉及较多角色(Actor、Critic、RM、Ref)的协作,需要预先定义好各个模型的角色,涉及resource_pool的定义和分配、workerdict和workergroup的初始化和分配;
WorkerGroup机制支持了每类colocate model group的具体实现,包含:
ResourcePoolManager:资源池管理,封装ray的placement_group,将指定的角色合理分配到设备上;
实现了一些PPO算法计算loss所需要的函数,如:
实现了一些timer,metric计算的函数(compute_data_metrics、compute_timing_metrics),以及save/load等断点续训和ckpt保存的逻辑(_save_checkpoint、_load_checkpoint),还有validate的逻辑(_validate)和dp负载均衡的逻辑(_balance_batch)的逻辑等等;
fit方法实现了rl算法的完整的training loop,调用了各个worker进行实际的计算;
actor_rollout_wg:支持actor、generator二者互相切换(通过reload/offload params和reshard)的hybrid engine;
critic_wg(可选):支持critic角色,仅ppo需要;
ref_policy_wg(可选):支持reference角色,开启kl需要;
rm_wg(可选):支持RM角色,model based reward需要;
由init_workers方法初始化资源池和各个worker group;
apply_kl_penalty:计算PPO的token-level kl reward;
KL loss是在core_algos.py里面实现的;
compute_advantage:计算优势函数的逻辑,核心算法依然是在core_algos.py里面实现的;
VeRL同时支持PPO/GRPO/Reinforce++/RLOO/Remax等算法,这些RL算法的核心区别点在于advantage是如何计算的(critic预测baseline,group计算baseline,batch内留一法等等),因此VeRL选择将adv_estimator单独出一套逻辑,主体同样是放在core_algos.py内部;
需要注意,fit方法是在单进程运行的,因此如果是在ray cluster上运行,尽可能不要把trainer调度在head节点上,可能负载压力会比较大;
选择奖励函数(model-based or rule-based),基于Reward Manager以及用户自定义的打分规则(一般定义在utils/reward_score目录下);
选择训练后端(FSDP or Megatron):
调用RayPPOTrainer进行具体的训练流程;
可以根据数据集中每条样本指定的reward_style,选择针对性的reward func;
Verl支持基于FSDP和Megatron两套后端进行模型的训练和前向传播推理,后者主要在模型规模特别大的时候,有一定的性能优势,但是自定义的修改比较麻烦,支持新架构比较麻烦,一般学术界FSDP后端就够用了。工业界追求极致性能时会需要megatron,可以进行许多定制化的优化来提升训练吞吐;
先调用trainer的init_workers函数初始化各个rl角色的workergroup,然后调用fit函数执行实际的训练;
main_ppo.py:RL算法的入口程序,主要有以下几个主要功能:
RayPPOTrainer.py:
还有main_generation.py和main_eval.py的逻辑,分别适用于离线生成与评估;
core_algos.py文件也是一个非常重要的文件,包含了:
各种loss的计算逻辑:
policy_loss(训练policy model,即actor), value_loss(训练value model,即critic),entropy_loss(policy model训练的额外trick loss,通过熵正则提升采样多样性),kl_loss(grpo等算法会把kl loss外置);
各种advantage的计算逻辑:
如前所述,各个rl算法的核心区分点主要在adv如何实现,这里实现了各种rl算法的adv estimation;
各类RL训练过程中的工程和算法超参可以参考doc:Config Explanation
(https://verl.readthedocs.io/en/latest/examples/config.html)
Workers组件
workers文件夹下定义了RL中各个角色的worker(high-level,主要负责描述逻辑),以及各个角色计算时实际依赖的worker(low-level,主要负责描述运算);
这里再回顾一下:worker被workerdict封装后,每个设备(GPU)会运行一个。一个colocate的RL 角色依托WorkerGroup进行管理,每个workergroup下管理着一组远程运行的 workers。WorkerGroup 作为single controller与 workers 之间的中介。我们将 worker 的方法绑定到 WorkerGroup 的方法上,通过装饰器实现具体的方法执行/数据分发的逻辑。

fsdp_workers.py:基于FSDP训练后端,定义了一系列RL训练过程中可能使用的Worker。这些workers是基于实际负责运算的worker(后面会介绍)所进行的进一步封装;
基于模型的RM打分实现;
和ActorRolloutRefWorker逻辑大体一致,只不过基于的后端是DataParallelPPOCritic;
不需要rollout,且额外多出了compute_values这个操作,通过value head计算token-level value以便PPO计算Adv;
可以选择扮演单独的RL中的Actor(Policy Model)、Rollout(负责generate response)、Reference(负责提供ref_log_prob计算KL);
可以选择基于hybrid engine,同时扮演多个角色,然后verl通过参数的offload/reload/reshard进行灵活的切换;
目前支持了Data Parallelism(fsdp)和Sequence Parallelism(context维度,基于ulysess实现);
关键方法:
指定optim_config一般是actor,需要基于FSDP进行训练,需要初始化fsdp wrap的模型(进一步传给DataParallelPPOActor封装)、optimizer和lr_scheduler;
不指定optim_config一般是ref,统一推理引擎和训练引擎,确保KL计算的数值准确性;
基于vllm封装的rollout引擎,推理生成数据,使用rollout_sharding_manager管理数据的形状,match rollout引擎的切分;
compute_log_prob:基于actor的训练引擎,同步计算old_logprobs,方便进行importance sampling;
基于DataParallelPPOActor的update_policy,计算policy-Loss并更新Policy模型的权重;
基于ulysses_sharding_manager支持sequence parallel的数据前处理和后处理,从而实现序列并行;
init_model:根据config指定的model类型,来初始化当前worker:
update_actor:
generate_sequences:
compute_ref_log_prob: 基于训练引擎,计算ref_logprobs,方便计算kl constraint;
save_checkpoint/load_checkpoint:实现模型参数的offload/reload,以及保存到外部硬盘;
_build_model_optimizer:
所有的涉及运算的函数,都有dispatch_mode装饰器,以实现workergroup内部的数据传输逻辑(single-controller的设计模式);
ActorRolloutRefWorker:
CriticWorker:
RewardModelWorker:
megatron_workers.py:基于megatron后端实现的RL workers;
基于megatron支持4D并行,DP、TP、SP、PP;
核心逻辑基本和FSDP版本一致,但是底层逻辑需要适配megatron框架;
接下来,我们看看具体的Actor运算Worker,它们被放置在当前目录的子文件夹下,默认都有fdsp(torch-native)和megatron两个写法的版本,以兼容两套训练引擎:
Actor:
compute_log_prob:为了计算KL或者Importance Sampling,前向传播推理得到各token位置的logits和对数概率;
update_policy:基于预先计算好的advantage,计算policy loss、entropy loss和kl loss,然后更新policy model;
RL算法(如PPO)中扮演Actor角色的Worker(Reference model也可以借用);
核心功能有:
Critic:
compute_values:计算Values,参与计算PPO算法的advantage;
update_critic:计算value loss,然后更新value model;
Actor-Critic-based RL算法(如PPO)中扮演Critic角色的Worker;
核心功能有:
Reward_model:
基于Model-based的打分模型,计算response-level reward;
核心功能主要就是compute_reward;
rule-based reward不需要;
Rollout:
原生的rollout逻辑,最简单的从logits->softmax->sampling的逻辑;
huggingface TGI后端的rollout逻辑;
vllm的rollout逻辑;
目前开源版本的推理引擎以vllm为主,但sglang也在接入中;
基于third_party中修改的vllm engine进行推理;
repreat采样没有使用n_samples参数而是直接repeat_interleave输入,多次生成;
old_log_probs没有使用vllm引擎得到的结果,为了确保importance sampling和kl divergence计算的准确性,要用训练引擎(FSDP或者Megatron)统一计算,避免引擎不同带来的误差;
核心功能就是在训练时候rollout response,主要函数为generate_sequences;
支持不同的生成引擎后端:
此外,该文件夹下还有sharding_manager,主要是负责管理不同的parallelism下的sharding,包括:
data sharding(preprocess_data,postprocess_data);
device mesh的管理;
模型参数的reload & offload逻辑(基于上下文管理器);
Single Controller组件
https://verl.readthedocs.io/en/latest/hybrid_flow.html#
实现verl的核心混合编程模型的重点,即基于single controller机制去管理RL的控制流;
Worker:方便管理worker进程在workergroup进程组内部的信息(如rank_id和world_size),以及资源分配的信息;
ResourcePool:管理某个资源池,包括池内节点信息和进程信息;
Workergroup:管理多个worker所组成的workergroup,如负责管理data parallelism。最重要的函数是 _bind_worker_method:
将用户定义的方法bind到WorkerGroup实例上;
处理被@register装饰器修饰的方法;
配置数据分发/收集模式和执行模式;
同步执行当前group内所有worker的该方法,并且根据分发&执行模式正确管理执行逻辑和数据传输逻辑;
Decorator:主要定义了各种worker的数据分发和函数执行模式的装饰器,装饰后,workergroup在执行worker的方法时,将会通过装饰器自动配置数据分发和执行的模式;
Ray:该处代码主要是基于ray后端,去管理worker(WorkerDict)和workergroup(RayWorkerGroup)。通过Python语法糖,实现了worker的method rebind,以让同一个workergroup在不同的rl角色之间灵活切换;
Models组件
主要包含常见模型结构(主要是llama结构和qwen2结构,允许用户集成更多的结构)的定义,包括:
Transformers版本的模型结构定义:
FSDP版本的RL训练推理、Rollout引擎、导出模型权重需要使用;
自定义新的模型结构:Add models with the FSDP backend(https://verl.readthedocs.io/en/latest/advance/fsdp_extension.html)
Megatron版本的模型结构定义:
Megatron版本的RL训练推理需要使用;
Megatron版本需针对4D Parallelism做较多的适配;
自定义新的模型结构:Add models with the Megatron-LM backend(https://verl.readthedocs.io/en/latest/advance/megatron_extension.html)
Utils组件
在utils文件夹下定义了一些重要的工具和组件,包括:
Dataset:
主要包括:rl、sft和rm的dataset;
处理数据集中的各个key,包括取出了制作好的parquet里面的prompt列,apply_chat_ml + tokenize后设为input_ids;
VeRL的dataset和dataloader没有和训练过程强绑定,可以在训练过程中比较轻松地做到dataloader的重载或者修改,所以实现一些功能会比较方便,如动态的课程学习等;
Debug:
主要包括:监控Performance(如GPU usage)和Trajectory(即保存rollout结果)的逻辑;
Logger:
顾名思义,主要是将一些监控指标输出到指定的位置(console或者wandb)的逻辑;
Megatron:
主要是为了在verl中使用megatron所编写的一些utils,以及对原有megatron实现适配verl所进行的一些patch;
Reward_score:
这里主要存着适配不同的rule-grader所编写的逻辑,包括各种parse answer的逻辑和compare answer的逻辑;
其他:如checkpoint管理的工具、hdfs文件管理的工具、支持ulysess/seq_balancing等feature的工具等;
third_party组件
目前主要是对开源的推理引擎vLLM,做了一些针对verl进行的定制化适配和封装(如SPMD); 之前支持4个版本:031,042,054,063,最近应该刚刚支持了07版本(Upgrading to vllm >= 0.7:https://verl.readthedocs.io/en/latest/README_vllm0.7.html);
主要是继承了原始的vllm,以支持verl所需要的一些功能,比如取出特定计算结果、更好地支持hybrid engine(如sync/offload params,device mesh管理,weight loader的兼容...)等;
sglang的接入也在wip;
Protocol组件
https://verl.readthedocs.io/en/latest/data.html
为了支持RL过程中更好的数据管理和传输,verl设计了DataProto这一数据结构,主要包括:
基于TensorDict所实现的batch,用于管理a dictionary of tensors;
基于Dict所实现的meta_info,用于管理当前DataProto的信息;
其余non-tensor数据,存在non_tensor_batch中;
以及DataProto使用所需要的各类数据管理逻辑,如pop、chunk、union、concat、rename、reorder等等;
DataProtoFuture则是为了支持DataProto的异步处理而构造的,支持负责reduce的collect_fn和负责scatter的dispatch_fn,从而方便worker的非阻塞执行;
工程性能调优
https://verl.readthedocs.io/en/latest/perf/perf_tuning.html
备注:昵称-学校/公司-方向/会议(eg.ACL),进入技术/投稿群
id:DLNLPer,记得备注呦