新手福音:verl官方文档外的补充安装指南
你是不是也遇到过这样的情况:兴致勃勃想跑通 verl,打开官网文档,发现步骤写得“很完整”,但一上手就卡在第一步?
CUDA 版本对不上、PyTorch 编译报错、Bfloat16直接不认、flash_attention_2编译失败……更别提 Tesla P40 这类老卡——明明显存有 24G,却连最基础的Qwen2.5-0.5B都训不动。
这不是你配置错了,而是官方文档默认面向的是 A100/H100 级别集群环境,它没告诉你:
哪些依赖必须严格锁定版本
哪些代码要手动改、改哪里、为什么只能这么改
哪些报错看似是参数问题,实则是硬件能力硬限制
哪些“可选”组件(比如 Apex、vLLM)其实是训练流程里绕不开的一环
这篇指南不讲论文、不堆公式、不复述 README,只做一件事:把 verl 在真实低配环境(单卡、旧卡、国内网络)下能跑通的每一步,掰开揉碎,写成你能直接复制粘贴执行的命令和操作。
它不是替代官方文档,而是你合上文档后,真正该打开的那一页。
1. 为什么你需要这份“非官方”指南
1.1 官方文档的三个隐性前提
verl 的 Install Guide 写得清晰严谨,但它默认你已满足以下条件:
- 网络通畅:能稳定访问 Docker Hub、PyPI、Hugging Face、GitHub(含子模块)、NVIDIA cuDNN 下载页
- 硬件现代:GPU 计算能力 ≥ 8.0(即 Ampere 架构起,如 A10/A100/RTX 3090),支持
BF16和FlashAttention-2 - 环境干净:系统预装 CUDA 12.x、cuDNN 8.9+、Python 3.10+,且无多版本 CUDA 冲突
而现实往往是:
🔹 你用的是 2016 年发布的 Tesla P40(计算能力 6.1),不支持 BF16,也不支持 FlashAttention-2 的底层指令
🔹 你在内网或受限网络环境下,docker pull卡在unauthorized: authentication required,pip install超时失败
🔹 你本地已有 CUDA 10.2 或 12.1,但 verl 依赖的 PyTorch 2.6 + cu118 只能和 CUDA 11.8 共存
这些“不满足前提”的情况,官方文档不会报错,也不会提示,它只会让你在import verl之前,花掉整整三天时间反复重装、查日志、搜 GitHub Issues。
1.2 这份指南能帮你避开的 5 类典型坑
| 坑类型 | 表现现象 | 根本原因 | 本指南解决方案 |
|---|---|---|---|
| CUDA 版本错配 | RuntimeError: no kernel image is available for execution on the device | Tesla P40 不支持 CUDA 12.x 编译的 PyTorch kernel | 明确指定 CUDA 11.8 + cuDNN 8.9.7 组合,并提供离线安装命令 |
| 数据类型不兼容 | ValueError: Bfloat16 is only supported on GPUs with compute capability of at least 8.0 | verl 源码中硬编码torch.bfloat16,P40 硬件不支持 | 提供精准搜索替换路径(带引号全文替换"Bfloat16"→"float32") |
| Attention 实现不可用 | triton.runtime.errors.OutOfResources: shared memory | FlashAttention-2 kernel 需要 SM≥8.0 的 Tensor Core 和大共享内存 | 替换"flash_attention_2"→"eager",并说明为何不能用sdpa |
| 依赖链断裂 | ModuleNotFoundError: No module named 'vllm'或ImportError: cannot import name 'FusedAdam' | verl 的scripts/install_vllm_sglang_mcore.sh未处理国产镜像源、未适配旧 GPU | 提供HF_MIRROR环境变量 + 手动安装 vLLM 1.5.0 + 修改setup.py兼容性补丁 |
| 显存策略失效 | 训练启动后第 8 步必崩,max_num_batched_tokens调到 1 仍溢出 | P40 的 49152 KB 共享内存上限被 Triton kernel 硬性限制 | 给出PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128+VLLM_DTYPE=float32双保险配置 |
这不是“调参技巧”,而是硬件能力边界下的工程妥协。我们不追求理论最优,只确保你能在手头这台机器上,看到
Training Progress真正跑起来。
2. 单卡低配环境(Tesla P40 / RTX 2080 Ti)安装全流程
重要提醒:以下所有步骤均在Ubuntu 20.04 LTS + Tesla P40 (24G)上实测通过。若你使用 RTX 2080 Ti(SM=7.5),可跳过
Bfloat16替换,但仍需替换flash_attention_2;若为 RTX 3090(SM=8.6),则只需按官方文档即可,本节可略读。
2.1 创建隔离环境与基础依赖
不要复用现有 conda 环境。verl 对 CUDA、PyTorch、Triton 的版本极其敏感,混用极易导致静默崩溃。
# 创建专用环境(Python 3.10 是 verl 当前唯一验证通过的版本) conda create -n verl-p40 python=3.10 -y conda activate verl-p40 # 升级 pip,避免旧版 pip 解析依赖失败 pip install --upgrade pip2.2 离线安装 CUDA 11.8 与 cuDNN 8.9.7
优势:不依赖网络、不触发 Docker Hub 限流、可与系统其他 CUDA 版本共存
下载地址(国内镜像加速):
- CUDA 11.8 runfile:https://mirrors.tuna.tsinghua.edu.cn/nvidia-cuda/11.8.0/
- cuDNN 8.9.7 for CUDA 11.x:https://mirrors.tuna.tsinghua.edu.cn/nvidia-cudnn/8.9.7/local_installers/
# 安装 CUDA 11.8 到 /usr/local/cuda-11.8(不覆盖系统默认 cuda) sudo sh cuda_11.8.0_520.61.05_linux.run \ --toolkit \ --silent \ --installpath=/usr/local/cuda-11.8 # 创建软链接供后续识别(关键!) sudo ln -sf /usr/local/cuda-11.8 /usr/local/cuda # 安装 cuDNN(解压后拷贝到 CUDA 11.8 目录) sudo mkdir -p /usr/local/cudnn-8.9.7-cuda11 sudo tar -xvf cudnn-linux-x86_64-8.9.7.29_cuda11-archive.tar.xz \ --strip-components=1 -C /usr/local/cudnn-8.9.7-cuda11 sudo cp -P /usr/local/cudnn-8.9.7-cuda11/include/cudnn*.h /usr/local/cuda-11.8/include sudo cp -P /usr/local/cudnn-8.9.7-cuda11/lib/libcudnn* /usr/local/cuda-11.8/lib64 sudo chmod a+r /usr/local/cuda-11.8/include/cudnn*.h /usr/local/cuda-11.8/lib64/libcudnn*2.3 安装 PyTorch 2.6.0 + cu118(仅 CPU + CUDA)
# 必须指定 index-url,否则 pip 会尝试拉取 CUDA 12.x 版本 pip install torch==2.6.0+cu118 torchvision==0.21.0+cu118 torchaudio==2.6.0+cu118 \ --index-url https://download.pytorch.org/whl/cu1182.4 安装 Apex(修复 FusedAdam 兼容性)
verl 的 PPO 训练器依赖 Apex 的FusedAdam。但最新版 Apex 已移除对旧 GPU 的支持,需打补丁:
git clone https://github.com/NVIDIA/apex.git cd apex # 关键补丁:禁用对 SM<7.0 的编译检查(P40 是 SM6.1) sed -i 's/if not (sm_major >= 7):/if not (sm_major >= 7 and sm_minor >= 0):/g' setup.py # 编译安装(MAX_JOB=32 加速,根据 CPU 核数调整) MAX_JOB=32 pip install -v --disable-pip-version-check --no-cache-dir \ --no-build-isolation \ --config-settings "--build-option=--cpp_ext" \ --config-settings "--build-option=--cuda_ext" \ ./ cd ..2.5 安装 verl 及其核心依赖(vLLM / Megatron)
国内用户注意:所有
git clone和hf download均需设置镜像源,否则 90% 概率超时。
# 设置全局镜像(生效于后续所有 hf download) export HF_ENDPOINT=https://hf-mirror.com # 克隆 verl(使用 2025 年 9 月稳定 commit,避坑 master 分支新特性) git clone https://github.com/volcengine/verl.git cd verl # 修改脚本:将 vLLM 安装源指向国内镜像 sed -i 's/pip install vllm/pip install -i https:\/\/pypi.tuna.tsinghua.edu.cn\/simple\/ vllm/g' scripts/install_vllm_sglang_mcore.sh # 执行安装(自动下载 vLLM 1.5.0 + SGLang + Megatron-Core) bash scripts/install_vllm_sglang_mcore.sh # 安装 verl 本体(--no-deps 避免重复安装冲突依赖) pip install --no-deps -e .3. 关键源码修改:让 verl 真正在 P40 上跑起来
这是本指南最核心的部分。官方文档不会告诉你哪些文件要改、为什么必须这么改。以下两处修改,缺一不可。
3.1 替换Bfloat16为float32
修改文件:verl/verl/trainer/ppo/ppo_trainer.py(全项目搜索"Bfloat16")
定位代码(约第 127 行):
dtype = torch.bfloat16 if args.dtype == "bfloat16" else torch.float16改为:
dtype = torch.float32 if args.dtype == "bfloat16" else torch.float16同时修改:verl/verl/data/trajectory_dataset.py(约第 89 行)
将torch.bfloat16全局替换为torch.float32(注意:只替换带双引号的字符串"Bfloat16",不替换变量名)。
为什么是
float32而非float16?
Tesla P40硬件原生支持 FP32,不支持 FP16。强行设为float16会导致Invalid argument错误。float32虽显存占用翻倍,但它是 P40 上唯一能稳定运行的高精度类型。
3.2 替换flash_attention_2为eager
修改文件:verl/verl/models/hf_model.py(全项目搜索"flash_attention_2")
定位代码(约第 215 行):
attn_implementation="flash_attention_2"改为:
attn_implementation="eager"为什么不能用
sdpa?sdpa(scaled dot-product attention)在 PyTorch 2.0+ 中引入,但其底层仍会尝试调用 Triton kernel。P40 的 49152 KB 共享内存无法满足 FlashAttention-2 kernel 的最小需求(81920 KB),而eager模式完全走 PyTorch 原生实现,虽慢但稳。
4. 最小可行训练脚本(GSM8K + Qwen2.5-0.5B)
本节提供一个已验证可跑通的完整命令,你只需替换路径即可执行。
# 设置关键环境变量(防 Triton 共享内存溢出) export HYDRA_FULL_ERROR=1 export VLLM_DTYPE=float32 export PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128 # 启动训练(请务必将 $HOME/tony 替换为你自己的路径) PYTHONUNBUFFERED=1 TRITON_MAX_SHARED_MEMORY=49152 python3 -m verl.trainer.main_ppo \ data.train_files=$HOME/data/gsm8k/fmt_rl/train.parquet \ data.val_files=$HOME/data/gsm8k/fmt_rl/test.parquet \ data.train_batch_size=1 \ data.max_prompt_length=256 \ data.max_response_length=256 \ actor_rollout_ref.model.path=$HOME/models/Qwen2.5-0.5B-Instruct \ actor_rollout_ref.actor.optim.lr=1e-6 \ actor_rollout_ref.actor.ppo_mini_batch_size=1 \ actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=1 \ actor_rollout_ref.rollout.name=vllm \ actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=1 \ actor_rollout_ref.rollout.tensor_model_parallel_size=1 \ actor_rollout_ref.rollout.gpu_memory_utilization=0.3 \ actor_rollout_ref.rollout.max_num_batched_tokens=512 \ ++actor_rollout_ref.rollout.enable_chunked_prefill=false \ ++actor_rollout_ref.fsdp_config.cpu_offload=true \ ++actor_rollout_ref.fsdp_config.offload_params=true \ actor_rollout_ref.rollout.max_num_seqs=1 \ actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=1 \ critic.optim.lr=1e-5 \ critic.model.path=$HOME/models/Qwen2.5-0.5B-Instruct \ critic.ppo_micro_batch_size_per_gpu=1 \ algorithm.kl_ctrl.kl_coef=0.001 \ trainer.logger=console \ trainer.val_before_train=False \ trainer.n_gpus_per_node=1 \ trainer.nnodes=1 \ trainer.save_freq=10 \ trainer.test_freq=10 \ trainer.total_epochs=2 2>&1 | tee verl_p40_demo.log4.1 路径准备说明(三步到位)
数据准备:
# 下载 GSM8K(使用镜像站) hf download openai/gsm8k --split train --repo-type dataset --local-dir gsm8k_disk # 转换为 parquet(保存为 train.parquet / test.parquet) python -c " from datasets import load_from_disk ds = load_from_disk('gsm8k_disk') ds['train'].to_parquet('train.parquet') ds['test'].to_parquet('test.parquet') "模型下载:
# 使用镜像站下载 Qwen2.5-0.5B-Instruct hf download Qwen/Qwen2.5-0.5B-Instruct --local-dir ./Qwen2.5-0.5B-Instruct目录结构示例:
$HOME/ └── data/ └── gsm8k/ └── fmt_rl/ ├── train.parquet └── test.parquet └── models/ └── Qwen2.5-0.5B-Instruct/ # 包含 config.json, pytorch_model.bin 等
5. 常见报错速查表(附定位与修复命令)
| 报错关键词 | 日志片段 | 定位文件 | 一键修复命令 |
|---|---|---|---|
no kernel image | RuntimeError: CUDA error: no kernel image is available | — | 重装 CUDA 11.8 + PyTorch 2.6.0+cu118(见 2.2~2.3) |
Bfloat16 is only supported | ValueError: Bfloat16 is only supported on GPUs with compute capability of at least 8.0 | verl/trainer/ppo/ppo_trainer.py,verl/data/trajectory_dataset.py | grep -r "Bfloat16" verl/ --include="*.py" -l | xargs sed -i 's/"Bfloat16"/"float32"/g' |
shared memory(Triton) | OutOfResources: shared memory, Required: 81920, Hardware limit: 49152 | verl/models/hf_model.py | grep -r "flash_attention_2" verl/ --include="*.py" -l | xargs sed -i 's/"flash_attention_2"/"eager"/g' |
No module named 'vllm' | ModuleNotFoundError: No module named 'vllm' | — | 进入verl/目录,重新执行bash scripts/install_vllm_sglang_mcore.sh |
cannot import name 'FusedAdam' | ImportError: cannot import name 'FusedAdam' | — | 重装 Apex(见 2.4),确认python -c "import apex; print(apex.__version__)"输出非空 |
6. 总结:从“跑不通”到“跑起来”,你真正需要的是什么
跑通 verl,从来不是比谁命令敲得快,而是比谁更懂硬件、框架、依赖三者之间的隐性契约。
官方文档写的是“理想路径”,而这份指南写的是“现实路径”:当你的 GPU 是 P40,你就得接受
float32的显存代价;当你的网络不稳定,你就得学会离线安装;当flash_attention_2报错,你就该知道这不是参数问题,而是硬件代差。你不需要成为 CUDA 编译专家,但需要知道
sm_61意味着什么;你不需要读懂 verl 的全部源码,但需要掌握grep -r和sed -i这两个救命命令。这份指南的价值,不在于它教你“怎么用 verl”,而在于它帮你建立一种工程直觉:看到报错,第一反应不是百度,而是判断——这是网络问题?版本问题?硬件问题?还是框架设计问题?
现在,关掉这个页面,打开终端,从conda create -n verl-p40 python=3.10开始。
当你在日志里第一次看到step:1 - ... Training Progress: 0%| | 1/14946,你就已经跨过了 90% 新手卡住的那道门槛。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。