# PR #6398 完整报告

- 仓库：`verl-project/verl`
- 标题：[ci] fix: the qwen3 model replaces the qwen25 model
- 合并时间：2026-05-22 23:32
- 原文链接：http://prhub.com.cn/verl-project/verl/pull/6398

---

# 执行摘要

- 一句话：替换 Qwen2.5 测试用例为 Qwen3
- 推荐动作：该 PR 为常规的 CI 模型升级与清理，技术复杂度较低，但展示了测试脚本演变和 CI 配置管理方式。建议阅读以了解 Ascend 测试用例的组织结构，并留意 reviewer 提出的配置优化建议（如移除冗余 critic 参数）。重点关注 `test_check_profiler_output.py` 中移除计数检查的权衡——在简洁性和严格性之间需根据实际输出特点取舍。

# 功能与动机

PR 正文明确说明 'Remove some test cases for the qwen25 model and use the qwen3 model instead'，旨在跟随模型版本演进，保持 CI 覆盖最新模型，并清理过时的测试用例。

# 实现拆解

1. **重写 Qwen3 性能分析测试脚本**：将 `tests/special_npu/run_qwen2_5_05b_grpo.sh` 重命名为 `run_qwen3_8b_grpo_profiling.sh`，并大幅调整超参数，包括增大 batch size、sequence length、启用 dynamic bsz 和 sequence parallelism，同时添加了 critic 配置（尽管 GRPO 不用）。
2. **轻量替换 MindSpeed 测试脚本**：将 `run_qwen2_5_05b_grpo_mindspeed.sh` 重命名为 `run_qwen3_06b_grpo_mindspeed.sh`，仅修改模型名称和 checkpoint 路径。
3. **删除两个旧的 nightly CI 入口**：移除 `run_grpo_qwen25-vl-3b-instruct_fsdp_npu.sh` 和 `run_grpo_qwen25-7b-instruct_fsdp_npu.sh`，对应 Qwen2.5-VL 和 Qwen2.5-7B 的 GRPO 测试。
4. **更新 CI 工作流配置文件**：在 `.github/workflows/nightly_ascend.yml` 中删除与上述两个脚本对应的 job，并调整注释；同时小幅修改 `.github/workflows/e2e_ascend.yml`。
5. **简化 profiler 输出校验**：在 `tests/utils/test_check_profiler_output.py` 中移除 `_validate_stage_dirs` 方法中的目录计数检查，因为 NPU 场景下始终只产生一个 profiler 输出目录。
6. **更新 CI 文档**：在 `docs/ascend_tutorial/contribution_guide/ascend_ci_guide_zh.rst` 中添加 Qwen3-8B 和 Qwen3-0.6B 的映射路径。

关键文件：
- `tests/special_npu/run_qwen3_8b_grpo_profiling.sh`（模块 性能分析；类别 test；类型 rename-or-move）: 核心替换脚本：从 Qwen2.5-0.5B 改为 Qwen3-8B，大幅调整训练超参数，并添加了 critic 配置（尽管 GRPO 中冗余），是 PR 中最主要的新测试入口。
- `tests/special_npu/nightly_ci_ascend/run_grpo_qwen25-vl-3b-instruct_fsdp_npu.sh`（模块 测试脚本；类别 test；类型 deletion）: 被删除的 Qwen2.5-VL-3B GRPO 测试入口，对应 CI 配置中的对应 job 也被移除。
- `tests/special_npu/nightly_ci_ascend/run_grpo_qwen25-7b-instruct_fsdp_npu.sh`（模块 测试脚本；类别 test；类型 deletion）: 被删除的 Qwen2.5-7B GRPO 测试入口，对应 CI 配置中的对应 job 也被移除。
- `.github/workflows/nightly_ascend.yml`（模块 CI 流水线；类别 infra；类型 infrastructure）: CI 配置主文件：移除了两个 Qwen2.5 的 nightly job，仅保留 Qwen3-8B profiling job，并调整了注释。
- `tests/utils/test_check_profiler_output.py`（模块 测试工具；类别 test；类型 test-coverage；符号 _validate_stage_dirs）: 测试工具修改：移除 `_validate_stage_dirs` 中的目录计数检查，导致 reviewer 质疑测试严格性。该文件是讨论焦点。
- `tests/special_npu/run_qwen3_06b_grpo_mindspeed.sh`（模块 测试脚本；类别 test；类型 rename-or-move）: 轻量替换脚本：仅将模型名从 Qwen2.5-0.5B 改为 Qwen3-0.6B，并更新 checkpoint 路径。

关键符号：未识别

## 关键源码片段

### `tests/special_npu/run_qwen3_8b_grpo_profiling.sh`

核心替换脚本：从 Qwen2.5-0.5B 改为 Qwen3-8B，大幅调整训练超参数，并添加了 critic 配置（尽管 GRPO 中冗余），是 PR 中最主要的新测试入口。

```bash
# Qwen3-8B GRPO profiling test script ( 替换 Qwen2.5-0.5B 版本 )
# 关键变更：模型变大、参数调整、启用 dynamic bsz 和 ulysses parallelism

set -x

# vllm ascend 会对某些模型做优化，但在 RLHF 训练中可能不适用，设为 0 禁用

MODEL_ID=${MODEL_ID:-Qwen/Qwen3-8B}
MODEL_PATH=${MODEL_PATH:-${HOME}/.cache/models/${MODEL_ID}}

SAVE_PATH=tests/utils/ci/profiler_data
rm -rf "$SAVE_PATH"

# Profiler 配置（NPU 级别 0）
LEVEL="level0"
CONTENTS=['npu','cpu']
ANALYSIS=False
PROFILE_STEPS=[1]
PROFILE_RANKS_ALL=False
PROFILE_RANKS=[0]
DISCRETE=True

python3 -m verl.trainer.main_ppo \
    algorithm.adv_estimator=grpo \
    data.train_files=$HOME/data/gsm8k/train.parquet \
    data.val_files=$HOME/data/gsm8k/test.parquet \
    # Batch size 从 16 增加到 32，序列长度从 512/128 增加到 1024/2048
    data.train_batch_size=32 \
    data.max_prompt_length=1024 \
    data.max_response_length=2048 \
    data.shuffle=False \
    actor_rollout_ref.model.path="${MODEL_PATH}" \
    actor_rollout_ref.model.use_remove_padding=True \
    actor_rollout_ref.model.enable_gradient_checkpointing=True \
    actor_rollout_ref.actor.optim.lr=1e-6 \
    actor_rollout_ref.actor.ppo_mini_batch_size=32 \
    actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=1 \
    # 开启参数 / 优化器 offload，减少显存占用
    actor_rollout_ref.actor.fsdp_config.param_offload=True \
    actor_rollout_ref.actor.fsdp_config.optimizer_offload=True \
    actor_rollout_ref.actor.use_kl_loss=False \
    # 启用 ulysses sequence parallelism（新增）
    actor_rollout_ref.actor.ulysses_sequence_parallel_size=2 \
    actor_rollout_ref.actor.use_dynamic_bsz=True \
    actor_rollout_ref.rollout.tensor_model_parallel_size=1 \
    actor_rollout_ref.rollout.name=vllm \
    actor_rollout_ref.rollout.gpu_memory_utilization=0.9 \
    actor_rollout_ref.rollout.max_num_batched_tokens=4000 \
    actor_rollout_ref.rollout.max_num_seqs=64 \
    actor_rollout_ref.rollout.checkpoint_engine.update_weights_bucket_megabytes=4096 \
    actor_rollout_ref.rollout.log_prob_use_dynamic_bsz=True \
    actor_rollout_ref.rollout.enable_chunked_prefill=True \
    # critic 配置在 GRPO 下冗余，可能浪费资源（reviewer 指出）
    critic.optim.lr=1e-5 \
    critic.model.use_remove_padding=True \
    critic.model.path="${MODEL_PATH}" \
    ... # 其余参数略

```

### `tests/utils/test_check_profiler_output.py`

测试工具修改：移除 `_validate_stage_dirs` 中的目录计数检查，导致 reviewer 质疑测试严格性。该文件是讨论焦点。

```python
# test_check_profiler_output.py 修改后的 _validate_stage_dirs 方法
# 移除了步骤 3（目录计数验证），仅保留 PROF 文件验证

def _validate_stage_dirs(self, stage: str) -> bool:
    dirs = glob.glob(os.path.join(self._base_dir, stage))
    if not dirs:
        logger.error(f"[{stage}] No directories found.")
        return False
    for d in dirs:
        logger.info(f"[{stage}] Found: {d}")
    # 注意：原目录计数检查（检查 dirs 长度是否符合预期）被移除了
    # 原因：NPU 场景下始终只生成一个输出目录，无需检查
    # 但风险：若 profiler 失败未生成输出，glob 返回空列表，但空列表已在上面被拦截止（返回 False），
    # 所以更安全的是保留 bool(dirs) 检查，而原逻辑是若为空则 for 循环直接跳过并 return True？
    # 实际上面有 if not dirs return False，所以空会被捕获，移除计数检查影响有限。
    # reviewer 担忧的是当仅有一个目录但内容不完整时，无法通过计数发现异常。
    for target_dir in dirs:
        if not self.config.prof_validator(target_dir):
            logger.error(f"[{stage}] PROF not found in {target_dir}")
            return False
    return True

```

# 评论区精华

> **关于目录计数验证的移除**：
> - gemini-code-assist[bot] 指出此举降低了测试严格性，若 profiler 未生成输出，`glob` 返回空列表会导致函数误返回 `True`，且 `dir_count_validator` 仍保留在配置中，造成不一致。
> - yyyy2000 追问：“为什么把这里 profiling 文件个数检查删除”。
> - daikang6 回应：“npu 下的个数就是 1，没有多个”，表明该检查在 NPU 场景下多余。
> - 尽管有争议，最终 PR 仍保留了删除，未恢复该检查。

> **关于脚本配置不一致**：
> - gemini-code-assist[bot] 指出 Qwen3-8B profiling 脚本使用了 `algorithm.adv_estimator=grpo` 却包含完整的 critic 配置，认为冗余且可能导致 OOM；同时项目名错误地使用 `verl_example_ppo_gsm8k`，KL 惩罚也未启用。这些建议未被作者采纳或进一步修改。

- 移除 profiler 输出目录计数检查 (correctness): daikang6 回应 NPU 场景下目录数始终为 1，无需检查。最终未恢复该检查，PR 合并。
- Qwen3-8B profiling 脚本配置不一致 (design): 作者未采纳或进一步修改这些意见，PR 直接合并。

# 风险与影响

- 风险：
 1. **测试严格性风险 **（`tests/utils/test_check_profiler_output.py`）：移除目录计数后，若 profiler 故障未生成输出，校验可能静默通过，导致 CI 假阳性。
 2. **资源浪费风险 **（`tests/special_npu/run_qwen3_8b_grpo_profiling.sh`）：GRPO 脚本包含冗余 critic 配置，可能初始化多余模型副本，占用 NPU 显存。
 3. **旧脚本不可逆**：两个 Qwen2.5 测试脚本被直接删除，如需回退需从 Git 历史恢复。
 - 影响：**影响范围**：仅影响 Ascend NPU 的 CI 流水线（nightly 和 e2e）。**用户**：普通用户无感知；开发者若在 Ascend 上运行测试，需使用新脚本并配合 Qwen3 模型权重。**团队**：CI 维护者需确保新脚本参数正确，并关注 profiler 校验的假阳性问题。**程度**：中等，涉及多个配置文件和脚本的修改，但未改动核心训练代码。
 - 风险标记：测试严格性降低 , 配置冗余 , 旧脚本不可逆 , 脚本安全合规

# 关联脉络

- 暂无明显关联 PR