昇腾上跑 RL:DeepSeek-R1 和 Qwen2.5 的训练优化实录
仓库 cann-recipes-train 里是两个可以直接复用的 RL 训练样例,分别针对 DeepSeek-R1 和 Qwen2.5。不是抽象文档,而是你在昇腾 NPU 上实际跑得起来的代码。我们基于 verl 框架,把 CANN 平台的底层优化能力落在了这两个模型上。
环境准备
- 计算资源:1 张 NPU 910B,32vCPU + 64GB 内存
- 容器镜像:
ubuntu22.04-py3.11-cann8.2.rc1-sglang-main-notebook
启动后用 npu-smi 看状态:910B3 温度 46℃,HBM 显存占用 3.3G/64G,功耗 96.5W,空闲待命。
克隆仓库后,rl_train 目录下是模型对应的 RL 训练样例:
deepseek:DeepSeek-R1 的 RL 训练优化qwen2_5:基于 Qwen2.5-1.5B 的 RL 入门
DeepSeek-R1 RL 训练优化
硬件与依赖
最低 128 张 Atlas A3。样例运行时需拉取指定 commit 的 Verl、vLLM v0.9.1、vLLM-Ascend 补丁,以及 Megatron-LM、MindSpeed 等依赖,全部放到 cann-recipes-train/rl_train/deepseek/ 下。
然后要改一點 verl 源码,好让补丁生效。
![图片:性能效果对比]
在 Atlas A3 SuperPoD 128 卡集群上,分别加载真实权重和随机初始化权重,跑出来的性能效果如上图。
让 verl 和 vLLM-Ascend 兼容
vLLM-Ascend 社区已经做了 DeepSeek-R1 的昇腾适配,推理部分不用担心。但要和 verl 对接,得动几个关键地方,主要在 vllm_rollout_spmd.py:
- 初始化 vLLM 前,先手动引入 vLLM-Ascend 的 patch,避免类或函数不匹配。
- 设置
VLLM_DP_MASTER_PORT和对应 IP,每个 DP 组有独立通信端口,适应多机环境。 - 关掉 NPU 多机下会出问题的 sleep 模式。不关的话,显存释放不掉,还会被 vLLM 内存池接管,后续手动卸载就失效了。
- 加载真实权重时,默认
max_num_batched_token=8192容易 OOM,改成 1024 并启用 chunked_prefill 就能避免。
训推切换:参数重排与权重搬运
大模型强化学习的一个麻烦事:训练和推理时,模型在卡上的分片方式不一样。训练时 8 张卡分成 EP4(两组各 4 卡),流水线还分 PP2;推理时要合成 EP8,流水线不分段(PP1)。所以每次训完要更新参数时,必须把参数从训练分片改到推理分片(reshard),这里我们用的是 alltoallv 通信,定向传递参数,没有冗余广播,单卡增量内存从 14G 压到 0.05G。
另外,Actor、Rollout、Ref 三个模型挤在同一批卡里。切换模型时,前一个占着显存,得先把它挪到主机内存(offload),再把下一个加载进来。昇腾团队针对显存管理和数据迁移做了细节优化,切换时间降了不少。
两个优化配合,训推迭代顺畅了很多。
![图片:Reshard 优化核心]
- Reshard 优化核心:专家参数用 AlltoAllV 定向传,只给目标推理 rank,不做全量广播。PP 域通信调整顺序,先在 TP 域聚合参数,再用 PP 域 AlltoAll 广播,减少通信量。
- Offload 优化核心:替换 vLLM 多机下有问题的 wake_up/sleep 机制,改用自定义的
onload/offload_model_weight和init/free_cache_engine。去掉训练完成到推理开始前的冗余卸载/加载步骤,并且把推理的 放在 reshard 和卸载训练权重之后,降低内存峰值。


