# PR #2402 完整报告

- 仓库：`radixark/miles`
- 标题：scripts: download the DAPO dataset the NPU recipe trains on
- 合并时间：2026-08-12 08:00
- 原文链接：http://prhub.com.cn/radixark/miles/pull/2402

---

# 执行摘要

- 一句话：修复 NPU 训练脚本的数据 / 模型路径错位，统一到 DAPO
- 推荐动作：值得快速精读（约 10 分钟）：这是一个典型的『从示例复制脚本后未同步常量』的修复案例，prepare() 与 execute() 路径不一致的审计思路对维护各类 recipe/launch 脚本很有参考价值。建议审阅时关注两点：一是 TRAIN_DATA_PATH 作为单一事实源的做法是否可推广到其他 NPU 脚本；二是是否应为这类路径一致性补一个 snapshot 或静态检查，避免再次回归。

# 功能与动机

这是 #2398/#2399 数据集下载审计的后续跟进。PR body 明确指出：scripts/run_qwen3_4b_npu.py 的 prepare() 和 execute() 对运行时使用的数据与模型路径说法不一致，'the recipe could not run end to end as written'；脚本疑似从 geo3k VLM multi-turn 示例复制而来，'several of its constants were never updated'。需要让数据集下载与实际训练消费对齐、模型路径与下载目录对齐，使 NPU recipe 真正可运行。

# 实现拆解

变更集中在 scripts/run_qwen3_4b_npu.py，分四步完成：
1. **数据集常量对齐**：DATASET_NAME 从 VeraIsHere/geo3k_imgurl_processed 改为 zhuzilin/dapo-math-17k；DATA_ROOT 从 /root/dataset/geo3k_imgurl_processed（单数）改为 /root/datasets/dapo-math-17k（复数，与 prepare() 中 mkdir 创建的目录一致）；TRAIN_DATA_PATH 改为根级 dapo-math-17k.jsonl。该数据集顶层即为 prompt + 扁平 label 字段，正好匹配训练参数 --input-key prompt --label-key label，无需额外转换。
2. **训练数据引用统一**：rollout_args 中的 --prompt-data 由硬编码字符串改为 f"--prompt-data {TRAIN_DATA_PATH} "，使 prepare() 里的 os.path.exists(TRAIN_DATA_PATH) 检查真正守护训练读取的文件。
3. **模型路径统一**：ckpt_args（--hf-checkpoint）与 megatron_args（--load）由硬编码 /root/model/Qwen3-4B-Instruct-2507/ 改为 f"/root/models/{MODEL_NAME}/"，与 prepare() 的 hf download 目标目录一致，并让 MILES_SCRIPT_MODEL_NAME 环境变量覆盖能够传导到训练参数。
4. **清理 geo3k 残留命名**：wandb group 由 geo3k_vlm_multi_turn 改为 qwen3-4b-npu，被注释的 eval 桩数据集标签由 geo3k_eval 改为 dapo_eval。
配套验证：作者在 Test plan 中声明已通过 python -m py_compile 与 black 24.3.0 检查，并计划在 NPU 节点跑通 prepare() + execute()；本 PR 未新增自动化测试文件。

关键文件：
- `scripts/run_qwen3_4b_npu.py`（模块 启动脚本；类别 source；类型 core-logic；符号 prepare, execute）: 唯一变更文件，修复 prepare() 与 execute() 在数据集和模型路径上的不一致，使 NPU recipe 可端到端运行

关键符号：prepare, execute

## 关键源码片段

### `scripts/run_qwen3_4b_npu.py`

唯一变更文件，修复 prepare() 与 execute() 在数据集和模型路径上的不一致，使 NPU recipe 可端到端运行

```python
import os

import miles.utils.external_utils.exec_command as U
from miles.utils.external_utils.command_utils import execute_train_npu

# 模型名允许通过环境变量覆盖，prepare() 与 execute() 必须引用同一来源，
# 否则会出现 " 下载的是 A、训练读的是 B" 的路径错位
MODEL_NAME = os.environ.get("MILES_SCRIPT_MODEL_NAME", "Qwen3-4B-Instruct-2507")

NUM_GPUS = int(os.environ.get("MILES_SCRIPT_NUM_GPUS", "4"))
EXTERNAL_RAY = int(os.environ.get("MILES_SCRIPT_EXTERNAL_RAY", "0"))
TRAIN_BACKEND = os.environ.get("MILES_SCRIPT_TRAIN_BACKEND", "fsdp").lower()
assert TRAIN_BACKEND in {"fsdp", "megatron"}

# 数据集常量：修复前 prepare() 下载 VeraIsHere/geo3k_imgurl_processed，
# execute() 却读取 dapo-math-17k 的 jsonl，二者毫无交集，recipe 无法端到端运行。
# 现在统一指向 zhuzilin/dapo-math-17k 根级 dapo-math-17k.jsonl，
# 顶层字段为 prompt + 扁平 label，正好匹配 --input-key prompt --label-key label
DATASET_NAME = "zhuzilin/dapo-math-17k"
DATA_ROOT = "/root/datasets/dapo-math-17k"          # 与 prepare() 的 mkdir 目录对齐（复数 datasets）
TRAIN_DATA_PATH = os.path.join(DATA_ROOT, "dapo-math-17k.jsonl")


def prepare():
    # 下载目录统一为 /root/models/{MODEL_NAME}，execute() 中的
    # --hf-checkpoint 与 --load 也指向这里，权重只有一个事实来源
    U.exec_command_cpu("mkdir -p /root/models /root/datasets")
    U.exec_command_cpu(f"hf download Qwen/{MODEL_NAME} --local-dir /root/models/{MODEL_NAME}")

    # 数据缺失时才下载；下载后再次确认存在性，
    # TRAIN_DATA_PATH 现在就是训练真正读取的路径
    data_missing = not os.path.exists(TRAIN_DATA_PATH)
    if data_missing:
        U.exec_command_cpu(f"hf download --repo-type dataset {DATASET_NAME} --local-dir {DATA_ROOT}")
    if not os.path.exists(TRAIN_DATA_PATH):
        raise FileNotFoundError(f"Dataset not found. Expected local dataset at {TRAIN_DATA_PATH}; ")

```

```python
def execute():
    # 模型路径统一：修复前硬编码为 /root/model/Qwen3-4B-Instruct-2507/，
    # 与 prepare() 的 /root/models/{MODEL_NAME} 不一致，且环境变量覆盖失效
    ckpt_args = f"--hf-checkpoint /root/models/{MODEL_NAME}/ "

    wandb_args = (
        (
            "--use-wandb "
            "--wandb-project miles-dev "
            "--wandb-group qwen3-4b-npu "          # 清理 geo3k_vlm_multi_turn 残留
            f"--wandb-key '{wandb_api_key}' "
        )
        if (wandb_api_key := os.environ.get("WANDB_API_KEY"))
        else ""
    )

    rollout_args = (
        # 训练数据引用 TRAIN_DATA_PATH 而非硬编码字符串，
        # prepare() 的存在性检查由此真正守护训练输入
        f"--prompt-data {TRAIN_DATA_PATH} "
        "--input-key prompt "
        "--label-key label "
        "--apply-chat-template "
        "--rm-type math "
        # ... 其余 rollout / GRPO / 优化器参数保持不变
    )

    megatron_args = (
        "--train-backend megatron "
        f"--load /root/models/{MODEL_NAME}/ "      # 与 prepare() 下载目录一致
        # ... 其余 Megatron 并行与重计算参数保持不变
    )

```

# 评论区精华

本 PR 无任何 review 评论（review_comments_count = 0），合并人 Zhichenzzz 以空评论直接 APPROVED。核心讨论实际沉淀在 PR body 中：作者明确点出 prepare() 与 execute() 的路径分歧是根因——数据集下载了 geo3k 而训练读取 dapo-math-17k、模型硬编码 /root/model 与下载目录 /root/models 不一致，并解释该脚本源自 geo3k 示例的复制残留。这些表述等同于评审证据，说明了路径统一的目标与合理性。

- prepare() 与 execute() 路径一致性问题 (correctness): Zhichenzzz 以空评论 APPROVED，接受统一 DATA_ROOT/TRAIN_DATA_PATH 与 /root/models/{MODEL_NAME} 的修复方案，prepare() 的存在性检查现在能守护训练实际读取的文件。

# 风险与影响

- 风险：
 - 外部数据集未锁定版本：zhuzilin/dapo-math-17k 未指定 revision，上游若更新内容或顶层字段结构，prompt/label 字段可能变化，影响 --input-key/--label-key 匹配。
 - 目标路径变更影响存量环境：/root/model → /root/models/{MODEL_NAME} 与 /root/dataset → /root/datasets 均属破坏性路径调整，旧环境需重新下载权重与数据，且可能遗留旧目录占用磁盘。
 - 缺少自动化测试：PR 只靠 py_compile、black 和手动 NPU 验证，未在 tests/fast 或 snapshot 中固化路径一致性，同类复制粘贴错误仍可能回归。
 - 影响面收敛：仅涉及单脚本 scripts/run_qwen3_4b_npu.py，核心训练 / 推理代码路径未改动，回归风险限定在 NPU Qwen3-4B recipe 的启动环节。
 - 影响：对用户：使用 Ascend NPU 跑 Qwen3-4B GRPO 数学 RL 的团队从此可按文档零修改跑通 prepare() → execute()，不再卡在缺失数据和路径错位上；wandb 分组名从 geo3k_vlm_multi_turn 改为 qwen3-4b-npu 后，指标归类更准确。对系统：变更仅是脚本常量与参数串改写，不触碰 miles 训练框架核心，无运行时行为外溢。对团队：修复了 #2398/#2399 审计暴露的 recipe 一致性问题，为后续 NPU recipe 的复制模板留下正确基线；但需留意存量子环境中路径迁移的沟通。由于修复前脚本本就无法端到端运行，本次调整基本没有可用性回退。
 - 风险标记：缺少自动化测试 , 外部数据源未锁定 revision, 路径调整影响存量环境

# 关联脉络

- PR #2377 fix(kimi): align YaRN parameters with checkpoints: 同属『脚本配置与外部实体（checkpoint/ 数据集）不一致』的修复模式，且该 PR 配套了 fast 测试与 snapshot 更新，可作为本 PR 补充测试的参照。
- PR #2300 scripts: enable the Miles dashboard in the quick-start launcher: 同为 scripts 目录的启动脚本变更，维护同一条 Qwen3-4B recipe 启动线。
- PR #2279 Run the launch script snapshot tests by hand instead of in CI: 定义了 launch 脚本的手动快照测试流程，本 PR 的 run_qwen3_4b_npu.py 属于该测试体系覆盖范围，后续可在此补充路径一致性用例。