通义千问3是该系列最新一代大语言模型,提供稠密模型与混合专家(MoE)模型的完整解决方案。基于海量训练构建的Qwen3在推理能力、指令遵循、智能体功能及多语言支持方面实现突破性进展,主要特性包括:
模型huggingface链接:Qwen/Qwen3-4B
本案例使用昇腾A3机器上,基于VeRL 框架完成Qwen3-4B-GRPO算法强化学习实践。
| 硬件名称 | 配置信息 | 备注 |
|---|---|---|
| 机器型号 | A3 超节点 | |
| 测试集群 | 8卡Pod | 单机 |
安装完成后版本概览
| 软件 | 版本 | 部署方式 |
|---|---|---|
| Driver | AscendHDK 25.2.0 | 宿主机 |
| Firmware | AscendHDK 25.2.0 | 宿主机 |
| CANN | 8.2.RC1 (文档:8.1.RC1) | 容器 |
| Python | 3.10.18 | 容器 |
| torch | 2.5.1 | 容器 |
| torch_npu | 2.5.1 | 容器 |
| transformers | 4.52.4 | 容器 |
| torchvision | 0.20.1 | 容器 |
| ray | 2.46.0 | 容器 |
MindspeedLLM 镜像已发布,使用方法请参考:昇腾训练镜像构建指导 中 VERL镜像。镜像下载链接:Ascend-SACT/ascend_train_image
GSM8K(小学8千数学题)是一个包含8,500道高质量、语言多样的小学数学文字题的数据集。该数据集的创建旨在支持对需要多步推理的基础数学问题进行问答的任务。
这些问题需要2到8个步骤来解决。解决方案主要涉及使用基本算术运算(+ − ×÷)进行一系列基础计算,以得出最终答案。
一个聪明的中学生应该能够解决每一个问题:根据论文所述,"这些问题所需的概念不超过初级代数水平,绝大多数问题无需显式定义变量即可解决。
解决方案以自然语言形式提供,而非纯粹的数学表达式。论文中指出:"我们认为这是最普遍有用的数据格式,并期望它能揭示大型语言模型内部独白的特性。

测试过程中我们采用open/gsm8k,下载数据集并将数据集预处理为parquet格式,以便包含计算RL奖励所需的必要字段。
source /usr/local/Ascend/ascend-toolkit/set_env.sh
cd /src/verl_code/verl
python3 examples/data_preprocess/gsm8k.py --local_dir /data/private/datasets/gsm8k

下载HuggingFace权重到指定目录下:

export VLLM_USE_V1=1
trainer_n_gpus_per_node=8
trainer_nnodes=1
exp_num=13
trainer_project_name='verl_grpo_example_gsm8k'
trainer_experiment_name="qwen3_4b_grpo_8ka_${exp_num}"
use_dynamic_bsz=True
python3 -m verl.trainer.main_ppo \
algorithm.adv_estimator=grpo \
data.train_files=/mnt/bn/llm-lr-hl/shared/data/gsm8k/train.parquet \
data.val_files=/mnt/bn/llm-lr-hl/shared/data/gsm8k/test.parquet \
data.train_batch_size=512 \
data.max_prompt_length=1024 \
data.max_response_length=1024 \
data.filter_overlong_prompts=True \
data.truncation='error' \
actor_rollout_ref.model.path=/mnt/bn/llm-lr-hl/shared/models/Qwen3-4B \
actor_rollout_ref.actor.optim.lr=5e-7 \
actor_rollout_ref.model.use_remove_padding=True \
actor_rollout_ref.actor.entropy_coeff=0.001 \
actor_rollout_ref.actor.ppo_mini_batch_size=256 \
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.actor.use_torch_compile=False \
actor_rollout_ref.actor.use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.actor.ppo_max_token_len_per_gpu=3000 \
actor_rollout_ref.model.enable_gradient_checkpointing=True \
actor_rollout_ref.actor.fsdp_config.param_offload=True \
actor_rollout_ref.actor.fsdp_config.optimizer_offload=True \
actor_rollout_ref.rollout.enforce_eager=True \
actor_rollout_ref.rollout.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.rollout.log_prob_max_token_len_per_gpu=4096 \
actor_rollout_ref.rollout.enable_chunked_prefill=False \
actor_rollout_ref.rollout.tensor_model_parallel_size=2 \
actor_rollout_ref.rollout.name=vllm \
actor_rollout_ref.rollout.gpu_memory_utilization=0.9 \
actor_rollout_ref.rollout.n=5 \
actor_rollout_ref.ref.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.ref.log_prob_max_token_len_per_gpu=8192 \
actor_rollout_ref.ref.fsdp_config.param_offload=True \
actor_rollout_ref.ref.use_torch_compile=True \
algorithm.kl_ctrl.kl_coef=0.001 \
trainer.critic_warmup=0 \
trainer.project_name=${trainer_project_name} \
trainer.experiment_name=${trainer_experiment_name} \
trainer.logger=['console','wandb'] \
trainer.default_local_dir=/data/private/outputs/ckpt/rl/${trainer_project_name}/${trainer_experiment_name} \
trainer.n_gpus_per_node=$trainer_n_gpus_per_node \
trainer.nnodes=$trainer_nnodes \
trainer.save_freq=-1 \
trainer.test_freq=5 \
trainer.total_epochs=15 \
trainer.val_before_train=Falsejemalloc(由Facebook优化)和tcmalloc(Google的线程缓存分配器)在内存分配效率、碎片控制、多线程性能等方面显著优于传统的malloc(如glibc的ptmalloc2)。
# 要求Ubuntu版本>=20.04
# 安装 jemalloc
sudo apt update
sudo apt install libjemalloc2source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
source ~/.bashrc
cd /data/private/code/verl_code/verl
set -xeuo pipefail
# export VLLM_ATTENTION_BACKEND=XFORMERS
export VLLM_USE_V1=1
export VLLM_VERSION=0.9.1
trainer_n_gpus_per_node=16
trainer_nnodes=1
exp_num="compare_h20_1"
trainer_project_name='verl_grpo_example_gsm8k'
trainer_experiment_name="qwen3_4b_grpo_8ka_${exp_num}"
export TENSORBOARD_DIR="/data/private/outputs/rl/tensorboard_dir/${trainer_project_name}/${trainer_experiment_name}"
mkdir -p /data/private/outputs/rl/${trainer_project_name}
log_path=/data/private/outputs/rl/${trainer_project_name}/${trainer_experiment_name}.log
use_dynamic_bsz=True
# 开启二级流水
export TASK_QUEUE_ENABLE=2
export CPU_AFFINITY_CONF=1
# 内存分配优化
if [ -f "/usr/lib/aarch64-linux-gnu/libjemalloc.so.2" ]; then
export LD_PRELOAD="/usr/lib/aarch64-linux-gnu/libjemalloc.so.2${LD_PRELOAD:+:$LD_PRELOAD}"
echo "jemalloc enabled"
else
echo "Running without jemalloc - consider installing it for better performance"
echo "sudo apt-get install libjemalloc2"
fi
echo "当前 LD_PRELOAD 值: $LD_PRELOAD"
python3 -m verl.trainer.main_ppo \
algorithm.adv_estimator=grpo \
data.train_files=/data/private/datasets/gsm8k/train.parquet \
data.val_files=/data/private/datasets/gsm8k/test.parquet \
data.train_batch_size=512 \
data.max_prompt_length=1024 \
data.max_response_length=1024 \
data.filter_overlong_prompts=True \
data.truncation='error' \
actor_rollout_ref.model.path=/data/share/1950833868382666752/hw/weights/Qwen3-4B \
actor_rollout_ref.actor.optim.lr=5e-7 \
actor_rollout_ref.model.use_remove_padding=True \
actor_rollout_ref.actor.entropy_coeff=0.001 \
actor_rollout_ref.actor.ppo_mini_batch_size=256 \
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.actor.use_torch_compile=False \
actor_rollout_ref.actor.use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.actor.ppo_max_token_len_per_gpu=3000 \
actor_rollout_ref.model.enable_gradient_checkpointing=True \
actor_rollout_ref.actor.fsdp_config.param_offload=True \
actor_rollout_ref.actor.fsdp_config.optimizer_offload=True \
actor_rollout_ref.rollout.enforce_eager=True \
actor_rollout_ref.rollout.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.rollout.log_prob_max_token_len_per_gpu=4096 \
actor_rollout_ref.rollout.enable_chunked_prefill=False \
actor_rollout_ref.rollout.tensor_model_parallel_size=2 \
actor_rollout_ref.rollout.name=vllm \
actor_rollout_ref.rollout.gpu_memory_utilization=0.9 \
actor_rollout_ref.rollout.n=5 \
actor_rollout_ref.ref.log_prob_use_dynamic_bsz=${use_dynamic_bsz} \
actor_rollout_ref.ref.log_prob_max_token_len_per_gpu=8192 \
actor_rollout_ref.ref.fsdp_config.param_offload=True \
actor_rollout_ref.ref.use_torch_compile=True \
algorithm.kl_ctrl.kl_coef=0.001 \
trainer.critic_warmup=0 \
trainer.project_name=${trainer_project_name} \
trainer.experiment_name=${trainer_experiment_name} \
trainer.logger=['console','tensorboard'] \
trainer.default_local_dir=/data/private/outputs/ckpt/rl/${trainer_project_name}/${trainer_experiment_name} \
trainer.n_gpus_per_node=$trainer_n_gpus_per_node \
trainer.nnodes=$trainer_nnodes \
trainer.save_freq=-1 \
trainer.test_freq=5 \
trainer.total_epochs=15 \
trainer.val_before_train=False \
trainer.device=npu 2>&1 | tee $log_path| 组件 | NPU | GPU |
|---|---|---|
| 卡数 | 8 | 8 |
| 机器 | A3 | H20 |
| CANN | 25.2.0 | - |
| HDK | 25.2.0 | - |
| python | 3.10.18 | 3.10.18+ |
| torch | 2.5.1 | 2.7.1+cu126 |
| torch-npu | 2.5.1.post1 | - |
| ray | 2.49.1 | 2.50.0 |
| transformers | 4.52.4 | 4.53.0 |
| vllm | 0.9.1 | 0.9.2 |
| vllm_ascend | 0.9.1 | - |
| verl | 0.5.0 br 796871d7d a4d8952edc6653e9661bbe37722ede13f2a7b0c7 | 0.5.0 cb809d66e46dfd3342d008628891a14a054fa424 |




| 指标 | 对比H20 |
|---|---|
| 端到端时间 | 1.58倍 |
| 平均生成时间(秒) | 0.80倍 |
| 平均演员更新时间(秒) | 2.35倍 |
| 平均步骤时间(秒) | 1.53倍 |