作者:昇腾实战派 x 安佐

一、背景

自DeepSeek模型发布之后,类GRPO的RLHF训练方法已经逐渐成为大模型后训练的范式,而VeRL作为大模型RL领域泛用性最强的框架,受到社区广泛关注。

出于强化学习性能考虑,考虑将多模态大模型的强化学习任务从SWIFT切换至VeRL框架。模型选型为Qwenvl系列最新的Qwen3vl-8B。

本文记录在VeRL上穿刺Qwen3vl-8B的适配流程与精度对比数据。

Qwen3vl-8B模型介绍

Qwen3-VL-8B 是阿里通义千问系列推出的多模态模型,具备强大的视觉理解和文本生成能力,适用于复杂场景下的图像识别、图文对话和视觉推理等任务。

GRPO算法介绍

GRPO算法流程不再赘述,示意图与损失函数如下:
在这里插入图片描述

在这里插入图片描述

需注意,在当前VeRL的实现中,损失函数在默认情况下已使用DAPO中的token-mean形式,而非原始GRPO中的seq-mean-token-mean。

二、环境版本信息

软件依赖版本

组件 版本 备注
CANN 8.2.RC1
torch 2.7.1+cpu
torch_npu 2.7.1.dev20250724
vLLM 0.11.0 可选择pip安装或本地编译安装
vLLM-ascend 0.11.rc0 可选择pip安装或本地编译安装
veRL 0.7.0.dev0 commit id: 65eb019a81012317b98afc17ce8fd36342a5e786

Qwen3vl-dense模型的VeRL版本依赖于https://github.com/volcengine/verl/pull/3838 等PR,所以直接选择了较新版本。

三、环境搭建

1. 容器环境配置
  1. 如果不是以root身份登录设备,在登录后先切换到root
sudo su - root
  1. 在home下面创建个人目录
mkdir /home/<name>
  1. 创建容器

docker_start.sh:

CONTAIN_NAME=$1
IMAGES_NAME=$2

docker run -it -u root --ipc=host --net=host --privileged=True \
--device=/dev/davinci0 \
--device=/dev/davinci1 \
--device=/dev/davinci2 \
--device=/dev/davinci3 \
--device=/dev/davinci4 \
--device=/dev/davinci5 \
--device=/dev/davinci6 \
--device=/dev/davinci7 \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /usr/local/sbin/:/usr/local/sbin/ \
-v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \
-v /var/log/npu/slog/:/var/log/npu/slog \
-v /var/log/npu/profiling/:/var/log/npu/profiling \
-v /var/log/npu/dump/:/var/log/npu/dump \
-v /var/log/npu/:/usr/slog \
-v /usr/lib/jvm/:/usr/lib/jvm \
-v /home/:/home/ \
--name $CONTAIN_NAME $IMAGES_NAME /bin/bash

启动命令:

bash docker_start.sh contain_name image_name:version
  1. 进入容器
docker exec -it contain_name bash
2. 软件安装流程
(1)安装CANN
(2)安装vLLM和vLLM-ascend

用git下载并安装vLLM和vLLM-ascend。

# 安装vllm
cd ../
git clone https://github.com/vllm-project/vllm.git
cd vllm
git checkout v0.11.0
VLLM_TARGET_DEVICE=empty pip install -v -e .

# 安装vllm-ascend
cd ../
git clone https://github.com/vllm-project/vllm-ascend
cd vllm-ascend
git checkout v0.11.0rc0
pip install -v -e .
(3)下载VeRL与安装相关依赖
cd ../
git clone https://github.com/volcengine/verl.git
cd verl
git checkout 65eb019a81012317b98afc17ce8fd36342a5e786
pip install -r  requirements-npu.txt

四、模型适配流程

1. 数据集处理

本次实验使用Geo3k训练数据集,数据集下载地址:https://huggingface.co/datasets/hiyouga/geometry3k

原始数据需数据处理后使用,数据处理脚本见:verl/examples/data_preprocess/geo3k.py

python examples/data_preprocess/geo3k.py --local_dir=""

默认处理后数据集保存位置为~/data/geo3k
数据集格式为:

$~/data/geo3k
├── train.parquet
├── test.parquet
2. 源代码修改项

由于qwen3vl系列模型优化暂未合入veRL主线,部分优化需要手动添加:

verl/models/transformers/npu_patch.py

line 25:
-from transformers.modeling_utils import PretrainedConfig, PreTrainedModel
+from transformers.configuration_utils import PretrainedConfig
+from transformers.modeling_utils import PreTrainedModel
+from transformers.models.qwen3_vl import modeling_qwen3_vl
+from transformers.models.qwen3_vl_moe import modeling_qwen3_vl_moe

line 205:
+modeling_qwen3_vl_moe.Qwen3VLMoeTextRMSNorm.forward = rms_norm_forward
+modeling_qwen3_vl_moe.apply_rotary_pos_emb = apply_rotary_pos_emb_qwen3_npu
+modeling_qwen3_vl.Qwen3VLTextRMSNorm.forward = rms_norm_forward
+modeling_qwen3_vl.Qwen3VLTextMLP.forward = silu_forward

verl/workers/fsdp_workers.py (用于vllm_ascend部分特性启用)

line 92:
+import vllm
+import vllm_ascend.patch.worker
3. 环境变量与训练脚本

verl/trainer/runtime_env.yaml

working_dir: ./
excludes: ["/.git/"]
env_vars:
  TASK_QUEUE_ENABLE: "1"
  HCCL_EXEC_TIMEOUT: "3600"
  HCCL_CONNECT_TIMEOUT: "3600"
  VLLM_ASCEND_ENABLE_MATMUL_ALLREDUCE: "1"

训练脚本:

MODEL_PATH=/data/weight/Qwen3-VL-8B-Instruct
time=$(date +"%m%d")

WORKING_DIR=${WORKING_DIR:-"${PWD}"}
RUNTIME_ENV=${RUNTIME_ENV:-"${WORKING_DIR}/verl/trainer/runtime_env.yaml"}

RAY_API_SERVER_ADDRESS='http://127.0.0.1:8260' ray job submit --no-wait --runtime-env="${RUNTIME_ENV}" \
    --working-dir "${WORKING_DIR}" \
    -- python3 -m verl.trainer.main_ppo \
    algorithm.adv_estimator=grpo \
    data.train_files=/data/l00906151/geo3k/dataset/train.parquet \
    data.val_files=/data/l00906151/geo3k/dataset/test.parquet \
    data.train_batch_size=512 \
    data.max_prompt_length=1024 \
    data.max_response_length=2048 \
    data.filter_overlong_prompts=True \
    data.truncation='error' \
    data.image_key=images \
    actor_rollout_ref.model.path=${MODEL_PATH} \
    actor_rollout_ref.actor.optim.lr=1e-6 \
    actor_rollout_ref.model.use_remove_padding=True \
    actor_rollout_ref.actor.ppo_mini_batch_size=32 \
    actor_rollout_ref.actor.use_kl_loss=True \
    actor_rollout_ref.actor.kl_loss_coef=0.01 \
    actor_rollout_ref.actor.kl_loss_type=low_var_kl \
    actor_rollout_ref.actor.entropy_coeff=0 \
    actor_rollout_ref.actor.use_torch_compile=False \
    actor_rollout_ref.actor.loss_agg_mode='seq-mean-token-mean' \
    actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=2 \
    actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=4 \
    actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=4 \
    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.actor.fsdp_config.forward_prefetch=False \
    actor_rollout_ref.ref.fsdp_config.forward_prefetch=False \
    actor_rollout_ref.rollout.tensor_model_parallel_size=4 \
    actor_rollout_ref.rollout.name=$ENGINE \
    +actor_rollout_ref.rollout.engine_kwargs.vllm.disable_mm_preprocessor_cache=True \
    actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \
    actor_rollout_ref.rollout.enable_chunked_prefill=True \
    actor_rollout_ref.rollout.enforce_eager=True \
    actor_rollout_ref.rollout.free_cache_engine=True \
    actor_rollout_ref.rollout.n=5 \
    actor_rollout_ref.ref.fsdp_config.param_offload=True \
    algorithm.use_kl_in_reward=False \
    trainer.critic_warmup=0 \
    trainer.logger=console \
    trainer.project_name='verl_grpo_example_geo3k' \
    trainer.experiment_name='qwen3_vl_8b_function_rm' \
    trainer.n_gpus_per_node=8 \
    trainer.nnodes=1 \
    trainer.save_freq=25 \
    trainer.test_freq=10 \
    trainer.total_epochs=1 \
    trainer.device=npu $@ 2>&1 | tee qwen3_${time}.log

五、适配过程问题与解决方案

1. 端口占用导致ray job submit失败

启动ray进程,提交ray job过程中出现报错,打屏信息包括"No available agent to submit job, please try again later."。实际是因为残留进程导致的端口占用

查询下述日志可确定具体冲突的端口

vim /tmp/ray/session_xxxxxx/logs/dashboard_agent.log

在这里插入图片描述

附linux 端口查询命令:

lsof -i:8000
COMMAND   PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
nodejs  26993 root   10u  IPv4 37999514      0t0  TCP *:8000 (LISTEN)
2. 内存申请失败

拉起过程中报错"Failed to apply for memory"。安装jemalloc2后解决。
在这里插入图片描述

操作系统源安装jemalloc:

Ubuntu:
sudo apt install libjemalloc2

OpenEuler:
yum install jemalloc

安装完成后通过命令 find /usr -name libjemalloc.so.2 确认动态链接库位置。

环境变量导入jemalloc:

export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2   # arm默认路径
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2    #  x86默认路径
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐