引言
Verl太火了,最近很多篇宣传的文章。看了一下Verl中的源代码,个人感觉要比OpenRLHF要更容易懂一些。对于大部分人来只需要会用就可以,所以我今天就结合我看到的代码,详细说说Verl中关于batch size的事情。
先放上一个verl中示例的运行脚本
https://github.com/volcengine/verl/blob/main/examples/grpo_trainer/run_deepseek7b_llm.sh
set -x
python3 -m verl.trainer.main_ppo \
algorithm.adv_estimator=grpo \
data.train_files=$HOME/data/gsm8k/train.parquet \
data.val_files=$HOME/data/gsm8k/test.parquet \
data.train_batch_size=1024 \
data.max_prompt_length=512 \
data.max_response_length=1024 \
data.filter_overlong_prompts=True \
data.truncation='error' \
actor_rollout_ref.model.path=deepseek-ai/deepseek-llm-7b-chat \
actor_rollout_ref.actor.optim.lr=1e-6 \
actor_rollout_ref.model.use_remove_padding=True \
actor_rollout_ref.actor.ppo_mini_batch_size=256 \
actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=80 \
actor_rollout_ref.actor.use_kl_loss=True \
actor_rollout_ref.actor.kl_loss_coef=0.001 \
actor_rollout_ref.actor.kl_loss_type=low_var_kl \
actor_rollout_ref.model.enable_gradient_checkpointing=True \
actor_rollout_ref.actor.fsdp_config.param_offload=False \
actor_rollout_ref.actor.fsdp_config.optimizer_offload=False \
actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=160 \
actor_rollout_ref.rollout.tensor_model_parallel_size=2 \
actor_rollout_ref.rollout.name=vllm \
actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \
actor_rollout_ref.rollout.n=5 \
actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=160 \
actor_rollout_ref.ref.fsdp_config.param_offload=True \
algorithm.kl_ctrl.kl_coef=0.001 \
trainer.critic_warmup=0 \
trainer.logger=['console'] \
trainer.project_name='verl_grpo_example_gsm8k' \
trainer.experiment_name='deepseek_llm_7b_function_rm' \
trainer.n_gpus_per_node=8 \
trainer.nnodes=1 \
trainer.save_freq=-1 \
trainer.test_freq=5 \
trainer.total_epochs=15 $@
batchsize相关的参数有
- data.train_batch_size
- actor_rollout_ref.actor.ppo_mini_batch_size
- actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu
这三处,参数里提到了三种不同的batch
- train_batch
- mini_batch
- micro_batch
这三处有什么区别呢?我们结合代码来看
train_batch
https://github.com/volcengine/verl/blob/db1d3251c534a772e22bac3ec20541fc0209e91e/verl/trainer/ppo/ray_trainer.py#L318C7-L318C98
real_train_batch_size = config.data.train_batch_size * config.actor_rollout_ref.rollout.n
train_batch_size * num_generations = total_batch_size
我们不难发现, train_batch 其实就是从原始数据集中prompt, total_batch则是对于train_batch的rollout集合
配置文件中train_batch_size为1024,rollout.n=5 。则total_batch_size=1024*5=5120
mini_batch
一个mini_batch就更新一次模型参数
https://github.com/volcengine/verl/blob/db1d3251c534a772e22bac3ec20541fc0209e91e/verl/workers/actor/dp_actor.py#L248C13-L248C70
dataloader = batch.split(self.config.ppo_mini_batch_size)
这里的batch是处理好的total_batch,按照mini_batch_size的大小切分
及为
total_batch_size // mini_batch_size = 5120 // 256 =20
对于一个total_batch_size 来说,模型要更新参数total_batch_size // mini_batch_size = 5120 // 256 = 20次
micro_batch
继续拆分mini_batch
self.gradient_accumulation = self.config.ppo_mini_batch_size // self.config.ppo_micro_batch_size_per_gpu
# split batch into micro_batches
micro_batches = mini_batch.split(self.config.ppo_micro_batch_size_per_gpu)
256 // 80 = 3 每个mini batch中forward三次,这三个micro相当于梯度累积的作用