verl 大模型强化学习后训练入门:Qwen2.5-0.5B - GSM8K
本文深度解析了大模型强化学习框架 verl 的使用细节,以 Qwen2.5-0.5B 模型和 GSM8K 数学推理数据集为例,提供了一份完整的 Post-Training(后训练)实战教程,分为五个部分:1. 环境配置,详细记录了 FlashAttention 和 vLLM 的手动安装避坑指南。2. 数据和模型下载准备3. 训练命令参数解析4. verl_demo.log 训练日志解析5. Che
本文深度解析了大模型强化学习框架 verl 的使用细节,以 Qwen2.5-0.5B 模型和 GSM8K 数学推理数据集为例,
提供了一份完整的 Post-Training(后训练)实战教程,分为五个部分:
1. 环境配置,详细记录了 FlashAttention 和 vLLM 的手动安装避坑指南。
2. 数据和模型下载准备
3. 训练命令参数解析
4. verl_demo.log 训练日志解析
5. Checkpoint 断点续训与模型验证
https://github.com/verl-project/verl verl 的 github 源码。
https://verl.readthedocs.io/en/latest/start/quickstart.html quickstart 以及技术文档
目录
1. 安装
根据显卡和CUDA,安装对应版本的 verl。
5090 CUDA13.0 配置下 可以安装最新版的。
https://verl.readthedocs.io/en/latest/start/install.html
官方的指令(如果顺利的话下面几行就完成安装了)
# 创建虚拟环境
conda create -n verl python==3.12
conda activate verl
git clone git@github.com:volcengine/verl.git(多来几次 有概率下不了)
cd verl
pip install --no-deps -e .
bash scripts/install_vllm_sglang_mcore.sh
# FSDP会装,如果你不想装 MEGATRON 就设置一下
# USE_MEGATRON=0 bash scripts/install_vllm_sglang_mcore.sh
作用是 安装 rollout generation:SGLang(会自动安装2.8的torch), vLLM;
还有一些适应 verl 的依赖 transformers、numpy。
比如会出现 把之前下的 numpy 2.2.6 降级为 numpy<2.0.0 去适配版本的操作。
plus:.sh 脚本如果报错;需要手搓安装
但是:如果你出现卡在 echo "3. install FlashAttention and FlashInfer"
因为 wget 下载flash-attn的whl 在服务器不好下载,于是如下按照脚本 手搓一步一步安装。
csdn 参考 - flash-attn 下载预编译的,无需长时间等待配置
备注:需要安装 flash-attention 加速;但直接 pip install flash-attn
会导致可能两个小时以上的系统配置时间,官方的 .sh 文件里 也是下载预编译的
需要根据自身配置选用版本 如:
" flash_attn-2.8.1+cu12torch2.8cxx11abiFALSE-cp312-cp312-linux_x86_64.whl "
代表适用于 cuda12 torch2.8 python12;
ABI(Application Binary Interface):定义程序组件如何二进制交互的接口规范;FALSE代表旧版
python -c "import torch;print(torch._C._GLIBCXX_USE_CXX11_ABI)"
预编译的版本: https://github.com/Dao-AILab/flash-attention/releases
注意先在这里找到对应版本的,下载之后上传到服务器可以安装的位置,再进行下一步手搓。
按照 install_vllm_sglang_mcore.sh 把脚本一步一步。
# 1. 两个 rollout
pip install "sglang[all]==0.5.2" --no-cache-dir && pip install torch-memory-saver --no-cache-dir
pip install --no-cache-dir "vllm==0.11.0"
# 2. verl 的一些依赖 注意 zsh 要 \[ 转义
pip install "transformers[hf_xet]>=4.51.0" accelerate datasets peft hf-transfer \
"numpy<2.0.0" "pyarrow>=15.0.0" pandas "tensordict>=0.8.0,<=0.10.0,!=0.9.0" torchdata \
ray\[default\] codetiming hydra-core pylatexenc qwen-vl-utils wandb dill pybind11 liger-kernel mathruler \
pytest py-spy pre-commit ruff tensorboard
pip install "nvidia-ml-py>=12.560.30" "fastapi[standard]>=0.115.0" "optree>=0.13.0" "pydantic>=2.9" "grpcio>=1.62.1"
# 3. FlashAttention and FlashInfer
pip install --no-cache-dir flash_attn-2.8.1+cu12torch2.8cxx11abiFALSE-cp312-cp312-linux_x86_64.whl
pip install --no-cache-dir flashinfer-python==0.3.1
# 4. fix opencv
pip install opencv-python
pip install opencv-fixer
python -c "from opencv_fixer import AutoFix; AutoFix()"
'''
5. 如果你需要装 MEGATRON 则还有如下
pip install "onnxscript==0.3.1"
NVTE_FRAMEWORK=pytorch pip3 install --no-deps git+https://github.com/NVIDIA/TransformerEngine.git@v2.6
pip3 install --no-deps git+https://github.com/NVIDIA/Megatron-LM.git@core_v0.13.1
pip install nvidia-cudnn-cu12==9.10.2.21
'''
2. gsm8k数据准备
需要实现 提取答案函数 extract_solution 和 批量处理数据函数 make_map_fn() ;
github代码 /examples/data_preprocess/gsm8k.py
gsm8k 对应论文 7473道训练集;1319道测试集。
gsm8k 数据集为,answer 先是推理过程,然后最后结尾有答案。 #### + 答案
提取answer 中 #### 之后的数字:
import re
def extract_solution(solution_str):
# 使用正则表达式匹配 "####" 后面的数字(可能包含负号、小数点、逗号)
solution = re.search("#### (\\-?[0-9\\.\\,]+)", solution_str)
# 确保匹配成功
assert solution is not None
# 获取匹配到的整个字符串(包含"#### ")
final_solution = solution.group(0)
# 移除"#### ",并去掉数字中的逗号(用于千位分隔符)
final_solution = final_solution.split("#### ")[1].replace(",", "")
return final_solution
把 question + answer 转换为 适合模型训练的数据格式,prompt + ability + reward_model
def make_map_fn(split):
# 返回实际用于处理数据集每条记录的函数
def process_fn(example, idx):
# 获取原始问题并从example字典中移除
question_raw = example.pop("question")
# 在原始问题后添加指令跟随提示
question = question_raw + " " + instruction_following
# 获取原始答案并从example字典中移除
answer_raw = example.pop("answer")
# 从原始答案中提取最终答案
solution = extract_solution(answer_raw)
# 构建新的数据格式
data = {
"data_source": data_source, # 数据来源
"prompt": [ # 对话格式的提示
{
"role": "user", # 用户角色
"content": question, # 添加指令后的问题
}
],
"ability": "math", # 能力分类:数学
"reward_model": { # 奖励模型相关信息
"style": "rule", # 使用规则风格
"ground_truth": solution, # 正确答案(用于评估)
},
"extra_info": { # 额外信息,保留原始数据
"split": split, # 数据集划分(train/test)
"index": idx, # 数据索引
"answer": answer_raw, # 原始答案(包含推理过程)
"question": question_raw, # 原始问题
},
}
return data
return process_fn
加载数据集 并对训练测试集 分别处理 + 保存
import datasets
# 加载数据集
data_source = "openai/gsm8k"
dataset = datasets.load_dataset(data_source, "main")
# 获取训练集和测试集
train_dataset = dataset["train"]
test_dataset = dataset["test"]
# prompt 要求模型逐步思考并输出最终答案
instruction_following = 'Let\'s think step by step and output the final answer after "####".'
# 进行预处理 with_indices=True 会为每个数据项提供索引idx
train_dataset = train_dataset.map(function=make_map_fn("train"), with_indices=True)
test_dataset = test_dataset.map(function=make_map_fn("test"), with_indices=True)
# 保存为Parquet格式
train_dataset.to_parquet("train.parquet")
test_dataset.to_parquet("test.parquet")
3. 模型准备 - Qwen2.5-0.5B
执行后下载到 D:\huggingface_cache\hub
python -c "import transformers; transformers.pipeline('text-generation', model='Qwen/Qwen2.5-0.5B-Instruct')"
models--Qwen--Qwen2.5-0.5B-Instruct\snapshots\ 哈希目录下 有一些文件:
1. 最大的 模型权重文件:model.safetensors
2. 分词器相关文件:tokenizer、vocab 词汇表;merges.txt 字符对合并;tokenizer_config 分词器配置
3. 推理生成配置:generation_config.json;温度、top-p等
4. 模型结构配置:config.json;层数、隐藏层大小、注意力头等
4. 命令行训练 参数设置示例(只是单卡情形)
https://rfqmivel9n.feishu.cn/wiki/BoRlwTaXniXiOXkyEZhcgmzcn8f
# 环境变量:保证日志实时输出,不缓存(避免训练过程中看不到实时日志)
export PYTHONUNBUFFERED=1
python3 -m verl.trainer.main_ppo \
data.train_files=$HOME/data/gsm8k/train.parquet \ # 训练数据集
data.val_files=$HOME/data/gsm8k/test.parquet \ # 验证数据集
data.train_batch_size=256 \ # 每一步迭代读取256道数学题
data.max_prompt_length=512 \ # 题目最大长度
data.max_response_length=512 \ # 答案最大长度
actor_rollout_ref.model.path=Qwen/Qwen2.5-0.5B-Instruct \ # Actor模型路径
actor_rollout_ref.actor.optim.lr=1e-6 \ # Actor学习率
actor_rollout_ref.actor.ppo_mini_batch_size=64 \ # 迷你批次(一次加载64个 加载256个容易炸内存 但256个才进行梯度更新 相当于off-policy)
actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=4 \ # 每个GPU加载几个(比迷你批次还小)
actor_rollout_ref.rollout.name=vllm \ # vllm 采样器 生成回答
actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=8 \ # rollout时 每个GPU同时算几个 策略的对数概率
actor_rollout_ref.rollout.tensor_model_parallel_size=1 \ # 张量并行
actor_rollout_ref.rollout.gpu_memory_utilization=0.4 \ # 采样的GPU 显存利用率限额
actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=4 \ # 旧策略ref 每个GPU同时算几个 策略的对数概率
critic.optim.lr=1e-5 \ # Critic学习率
critic.model.path=Qwen/Qwen2.5-0.5B-Instruct \ # Critic模型路径
critic.ppo_micro_batch_size_per_gpu=4 \ # Critic 每个GPU微批次每次处理4个样本
algorithm.kl_ctrl.kl_coef=0.001 \ # KL系数
trainer.logger=console \ # 训练过程中实时在终端打印日志信息
trainer.val_before_train=False \ # 训练前是否验证
trainer.n_gpus_per_node=1 \ # 每个节点的GPU数量
trainer.nnodes=1 \ # 训练节点数量
trainer.save_freq=10 \ # checkpoint 保存频率
trainer.test_freq=10 \ # 测试频率
trainer.total_epochs=15 \ # 完整遍历15遍训练数据集
2>&1 | tee verl_demo.log # 保存日志的位置;正常信息和报错都写入
每个batch 256题,7473 ÷ 256 = 29.19 一轮29批次;15epoch 共 29*15 = 435 steps;
训练时计算步骤:
1. 准备完整样本输入:「题目(prompt)+ Actor生成的初始答案(response)」
2. Critic 网络接收完整输入,预测价值(values/vpred_mean)
3. (可选,多轮任务用)Actor基于当前答案,决定下一步动作(GSM8K单步任务,此步骤跳过)
4. 奖励函数接收「题目+Actor最终答案」,计算即时奖励/得分(rewards/score)
5. 用「rewards(实际奖励)+ Critic终端价值」计算累计回报(returns)
6. 用「returns(真实累计回报)- values(Critic预测价值)」计算优势值(advantages)
7. 用advantages 优化Actor
8. 用「returns(真实标签)- values(预测价值)」的差值优化Critic(让Critic的预测更精准)
5. verl_demo.log 日志信息
1. Actor 信息:
lr=1e-6 学习率; entropy 熵; ppo_kl 和 kl_loss kl散度和损失;
pg_loss 策略梯度损失; grad_norm 梯度范数; pg_clipfrac 策略裁剪比例;
2. Critic 信息:
lr=1e-5 学习率;grad_norm 梯度范数;vf_loss 价值预测损失;
真实值 衡量 Actor 表现:score(0/1对错) rewards 奖励值 (Actor 正确率)
预测值:vpred_mean:单步预测; values:全局价值均值预测;
returns:真实累计回报; advantages:优势函数;
3. 题目&回答长度:
prompt_length 题目长度/ num_turns 对话轮数 / response_length答案长度 分别 mean/max/min;
aborted_ratio 中断比例 clip_ratio 太长 截断比例
4. timing_s 时间信息:
step 单步总时间;gen 生成答案耗时;update_critic update_actor 两个网络更新耗时;
reward 计算奖励耗时;old_log_prob 计算概率对数耗时;values 价值计算耗时;adv 优势值计算耗时;
6. checkpoint 信息
checkpoints/verl_examples/gsm8k 中不同时间步的 checkpoint 保存
子文件夹中有 actor文件夹;critic 文件夹;
data.pt 包含训练过程快照数据,是框架用于 “断点续训” 和 “步骤恢复” 的辅助文件。
actor 文件夹:


7. 利用 checkpoint 进行 test
trainer.val_before_train=True \
trainer.val_only=True \
trainer.resume_mode=resume_path \
trainer.resume_from_path='' # 填目标导入的checkpoint路径
主要 导入了checkpoints/verl_examples/gsm8k/actor 里面的 model_world_size_1_rank_0.pt
结果:正确率由 0% -> 53%

更多推荐


所有评论(0)