Prhub

#6323 [veomni] feat: add veomni qwen3-30b and fix ep

原始 PR 作者 wangshuyang31 合并时间 2026-05-19 16:29 文件变更 2 提交数 12 评论 9 代码增减 +135 / -1

执行摘要

新增 Qwen3-30B VeOmni 训练脚本并修复 EP 参数获取 bug

PR body 指出需要为 VeOmni 后端添加 Qwen3-30B 和 Qwen3-1.7B 的 NPU 训练脚本,并修复 EP 参数访问 bug,确保专家并行在 VeOmni 引擎下正常工作。同时响应 Review 意见,将脚本从 ascend_extras 移至公共目录,合并 GPU/NPU 配置。

该 PR 值得单读以了解 VeOmni 后端训练脚本的标准结构和 EP 参数修复方式。特别注意 extra_parallel_sizes 初始化的一致性问题,建议在其相关 PR (#6346 等) 中确认修复。

讨论亮点
  1. extra_parallel_sizes 类型风险gemini-code-assist 指出 ps.extra_parallel_sizes 初始化为元组((self.engine_config.expert_parallel_size,)),字典访问将导致 TypeError。建议在同一 PR 中修复初始化。该评论未被回复,但 PR 已合并,需注意初始化是否已改为字典。
  2. 脚本目录迁移wuxibin89 建议将 NPU 脚本从 ascend_extras 移至公共 examples/grpo_trainer。作者采纳并删除原有位置的文件。
  3. 命名规范和硬件合并wucong25 要求脚本命名遵循 run_<model>_<train-backend>.sh 格式,并合并 NPU/GPU 配置,通过 DEVICE 变量区分。作者添加了 USE 判断和头部注释。

实现拆解

  1. 创建初始脚本:在 examples/ascend_extras/grpo_trainer/ 下为 NPU 创建 run_qwen3-30b_veomni_npu.shrun_qwen3_1_7b_npu.sh
  2. 根据 Review 重构:删除小模型脚本(避免为每个模型保留),将 30B 脚本移至 examples/grpo_trainer/ 并重命名为 run_qwen3_30b_veomni.sh
  3. 脚本完善:添加 DEVICE 自动检测逻辑(若可导入 torch_npu 则为 npu,否则为 gpu),在 NPU 分支中设置 HCCL、VLLM 等环境变量,并在头部注释说明算法、硬件、推理后端。
  4. 修复 EP 参数:在 verl/workers/engine/veomni/transformer_impl.pyget_per_tensor_param 方法中,将 Expert Parallel 的 gather 维度从 ps.ep_size 改为 ps.extra_parallel_sizes['ep'],以匹配新的并行状态字典结构。
  5. 配套调整:未新增测试,因功能依赖特定硬件环境。
文件 模块 状态 重要度
examples/grpo_trainer/run_qwen3_30b_veomni.sh 训练脚本 added 5.65
verl/workers/engine/veomni/transformer_impl.py 引擎 modified 4.93

关键符号

get_per_tensor_param

关键源码片段

examples/grpo_trainer/run_qwen3_30b_veomni.sh core-logic

新增的 VeOmni 训练脚本,是 PR 核心产物,支持 GPU/NPU 自动切换,结构规范。

#!/usr/bin/env bash
# GRPO | Qwen3-30B-A3B (MoE) | VeOmni training | NVIDIA GPUs or Ascend NPU
# Knobs:
# INFER_BACKEND controls rollout backend: vllmset -x
ENGINE=${1:-vllm}
# 检测硬件类型:如果能导入 torch_npu 则识别为 npu,否则为 gpu
DEVICE=${DEVICE:-$(python3 -c 'import torch_npu' 2>/dev/null && echo npu || echo gpu)}TRAIN_FILE=dapo-math-17k.parquet
TEST_FILE=aime-2024.parquet
max_prompt_length=$((1024 * 2))
max_response_length=$((1024 * 8))
rollout_max_num_seqs=$((128))
n_devices_per_node=$((8))
actor_ppo_max_token_len=$(((max_prompt_length + max_response_length) * 1))
infer_ppo_max_token_len=$(((max_prompt_length + max_response_length) * 3))case "${DEVICE}" in
  gpu)
    # GPU 环境无需额外配置
    ;;
  npu)
    # Ascend NPU 专用环境变量:启用任务队列、VLLM 后端、关闭 NZ 格式等
    export TASK_QUEUE_ENABLE=1
    export HCCL_OP_EXPANSION_MODE="AIV"
    export VLLM_USE_V1=1
    export VLLM_VERSION=0.13.0
    export VLLM_ASCEND_ENABLE_NZ=0
    export HCCL_BUFFSIZE=610
    export CKPT_DIR="./ckpt30b"
    export PYTORCH_NPU_ALLOC_CONF=max_split_size_mb:1024
    export CUDA_DEVICE_MAX_CONNECTIONS=1
    n_devices_per_node=16
    ;;
  *)
    echo "Unsupported DEVICE=${DEVICE}. Expected 'gpu' or 'npu'." >&2
    exit 1
    ;;
esac# 后续参数省略 ...
verl/workers/engine/veomni/transformer_impl.py core-logic

核心 bug 修复:修正专家并行参数访问方式,影响所有使用 VeOmni 引擎的 MoE 模型训练。

# verl/workers/engine/veomni/transformer_impl.py
# 在 get_per_tensor_param 方法的内部闭包 param_generator 中def param_generator():
    for name, param in params.items():
        unsharded_tensor = param.full_tensor() if isinstance(param, DTensor) else param
​
        is_expert_layer = "mlp.experts." in name
        is_proj = any(p in name for p in ["down_proj", "gate_proj", "up_proj", "gate_up_proj"])
​
        if is_expert_layer and is_proj and ps.ep_enabled:
            output_shape = list(unsharded_tensor.shape)
            # 修复:原使用 ps.ep_size,现改为从 extra_parallel_sizes 字典中获取 EP 大小
            # 注意:需确保 extra_parallel_sizes 已被初始化为字典(如 {'ep': N}),
            # 否则访问 ['ep'] 会引发 TypeError
            output_shape[0] *= ps.extra_parallel_sizes["ep"]
            stacked_tensor = torch.empty(output_shape, dtype=unsharded_tensor.dtype, device=device)
​
            # all gather expert tensors [32, H, I] -> [128, H, I]
            torch.distributed.all_gather_into_tensor(stacked_tensor, unsharded_tensor, group=ps.ep_group)
            yield from process_func(name, stacked_tensor)
            del stacked_tensor
        else:
            if is_expert_layer:
                yield from process_func(name, unsharded_tensor)
            else:
                yield name, unsharded_tensor

评论区精华

extra_parallel_sizes 类型错误风险 正确性

gemini-code-assist 指出 extra_parallel_sizes 初始化为元组 (self.engine_config.expert_parallel_size,),字典访问 'ep' 会引发 TypeError,建议同一 PR 修复初始化。

结论:作者未公开回复,PR 已合并;需确认初始化已改为字典。 · unresolved

脚本目录和命名规范 设计

wuxibin89 建议将脚本从 ascend_extras 移至公共 examples/grpo_trainer;wucong25 要求命名符合 run_<model>_<train-backend>.sh 并合并 GPU/NPU。

结论:作者采纳:删除原始位置文件,在 examples/grpo_trainer/run_qwen3_30b_veomni.sh 中加入 DEVICE 判断。 · 已解决

脚本增加硬件注释和参数参考 documentation

wucong25 要求在脚本头部注明算法、模型、训练后端、支持硬件和推理后端,参数格式参考其他脚本。

结论:作者添加头部注释和 DEVICE 逻辑,并调整参数格式。 · 已解决

风险与影响

  1. 类型错误风险transformer_impl.py 修改依赖 ps.extra_parallel_sizes 被正确初始化为字典。若初始化仍为元组(如行 107),则运行时在 param_generator 中访问 ps.extra_parallel_sizes['ep'] 会触发 TypeError。需确认该初始化已在同系列 PR 中修复。
  2. 配置兼容性:脚本中设置的 NPU 环境变量(如 VLLM_USE_V1=1VLLM_VERSION=0.13.0)可能随 VLLM 版本变化而失效,需持续维护。
  3. 无测试覆盖:改动依赖特定硬件(NPU),未添加单元测试或 CI 步骤,回归风险仅靠人工验证。

对用户:新增可直接使用的 Qwen3-30B VeOmni 训练脚本,支持 GPU 和 Ascend NPU 自动切换,降低了 NPU 用户的使用门槛。删除了小模型脚本,用户若需训练 Qwen3-1.7B 需自行适配。对系统:修改了 VeOmni 引擎中 EP 参数的获取方式,影响所有使用 MoE 模型且开启 EP 的训练流程。对团队:规范了脚本命名和组织结构,便于后续维护。

潜在类型错误风险 缺少对应测试覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论