Train-Infer Operator Diff Scanner(RL 训推算子一致性扫描 )

SkillAI & models

Scans for operator differences between the RL training and inference (rollout) paths. Use this skill when the user provides a training launch script path and asks to compare operator differences between the Megatron training path and the vLLM inference path (especially fused operators vs. individual

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Train-Infer Operator Diff Scanner(RL 训推算子一致性扫描 ) skill

What this skill tells your AI

The instructions your AI receives, as published by kali20gakki/msagent in skills/accuracy/train-infer-op-diff-scanner/SKILL.md and read by ahel’s review.

面向 Ascend NPU 的 RL 训推算子差异性运行时扫描技能。

核心原则

  1. 必须运行完整 RL 脚本:算子采集必须通过运行完整 RL 训练脚本(集成 verl profiler)完成。禁止编写独立脚本分离运行 Megatron 训练和 vLLM 推理来分别采集算子数据
  2. 运行时采集(非静态扫描):所有算子信息必须来自真实 NPU 运行时 profiling,静态源码扫描结果不作为最终结论
  3. profiler 集成到 RL 脚本:通过 global_profiler + 各组件 profiler 配置在 RL 脚本中开启 profiling(训练路径用 e2e profiler,推理路径用 discrete=True 分离采集)
  4. 代码栈贴入报告:每个差异算子需附对应的代码调用栈(从 profiler DB 的 MSTX/CPU callstack 提取或从源码路径标注)

触发条件

  • 对比 RL 训练(Megatron)和推理(vLLM)的算子差异
  • 扫描训练和推理路径中的融合算子差异
  • 生成训推算子一致性报告
  • 用户提供了 RL 训练启动脚本路径

不适用场景

  • 运行时 dump 数据的逐值对比(应使用 rl-consistency-analysis skill)
  • 纯性能 profiling 分析(应使用 msprof-analyze-cli skill)
  • 无法执行脚本或 NPU 不可用的环境

工作流程(5 阶段)

阶段 1:环境与配置解析(预计 2-3 分钟)

1.1 解析训练脚本

必须先读取用户提供的 RL 脚本,提取以下配置项:

解析项脚本字段示例
训练后端actor_rollout_ref.actor.strategymegatron
推理引擎actor_rollout_ref.rollout.namevllm
模型路径MODEL_PATH 或 actor_rollout_ref.model.path/workspace/models/Qwen3-0.6B
模型 IDMODEL_IDQwen/Qwen3-0.6B
TP/PP/EPtensor_model_parallel_size 等1
max_prompt_lengthdata.max_prompt_length512
max_response_lengthdata.max_response_length1
train_batch_sizedata.train_batch_size4
total_training_stepstrainer.total_training_steps1
NPU 设备ASCEND_RT_VISIBLE_DEVICES1
rollout 配置enforce_eager, calculate_log_probs, nTrue, True, 2
1.2 环境检查(必须全部通过,失败则告知用户并停止)
python -c "import torch; import torch_npu; print(torch.npu.device_count(), 'NPUs available')"
which msprof
pip show megatron-core vllm vllm-ascend mbridge 2>/dev/null | grep -E "^(Name|Version):"
ls -la ${MODEL_PATH}/config.json
1.3 备份原始脚本
cp <script_path> <script_path>.bak_$(date +%Y%m%d_%H%M)

阶段 2:集成 Profiler 到 RL 脚本(预计 2-3 分钟)

目的:修改 RL 训练脚本,嵌入 profiling 配置,使单次运行即可同时采集训练和推理路径的 NPU 算子。

2.1 检查脚本是否已含 profiler 配置

搜索脚本中是否存在 global_profiler 或 PROFILER 相关配置块。若已存在则跳过 2.2。

2.2 在脚本中添加 Profiler 配置块

在脚本中 launch 命令之前插入以下配置,(参考 references/run_qwen3_0_6b_megatron_vllm_ascend.sh 的实际实现):

PROFILER_OUTPUT_DIR=${PROFILER_OUTPUT_DIR:-<脚本目录>/profiler_output}
rm -rf ${PROFILER_OUTPUT_DIR} 2>/dev/null || true
mkdir -p ${PROFILER_OUTPUT_DIR}

# 关键:训练路径用 e2e profiler,推理路径用 discrete=True 分离采集
PROFILER=(
    global_profiler.tool=npu
    global_profiler.steps=[1]
    global_profiler.save_path=${PROFILER_OUTPUT_DIR}
    actor_rollout_ref.actor.profiler.enable=True
    actor_rollout_ref.actor.profiler.tool_config.npu.contents="['npu','cpu','shapes']"
    actor_rollout_ref.actor.profiler.tool_config.npu.level=level1
    actor_rollout_ref.ref.profiler.enable=True
    actor_rollout_ref.ref.profiler.tool_config.npu.contents="['npu','cpu','shapes']"
    actor_rollout_ref.ref.profiler.tool_config.npu.level=level1
    actor_rollout_ref.rollout.profiler.enable=True
    actor_rollout_ref.rollout.profiler.tool=npu
    actor_rollout_ref.rollout.profiler.tool_config.npu.contents="['npu','cpu','shapes']"
    actor_rollout_ref.rollout.profiler.tool_config.npu.level=level1
    actor_rollout_ref.rollout.profiler.tool_config.npu.discrete=True
)

在 launch 命令参数末尾追加 "${PROFILER[@]}"。

2.3 配置说明
配置项说明
global_profiler.tool=npu全局开启 NPU profiling
global_profiler.steps=[1]仅采集 step 1(节省时间)
actor.profiler.enable=True训练 actor 路径采集
ref.profiler.enable=True训练 ref 路径采集
rollout.profiler.enable=True推理 rollout 路径采集
rollout.profiler.tool_config.npu.discrete=True关键:触发 vLLM 侧独立 torch_npu.profiler 采集,产出 raw *_ascend_pt 目录(非 DB),须事后 analyse() 才落 DB(见阶段 3.3)
level=level1采集 CANN 算子级别数据
2.4 输出路径约定(训练/推理采集后端不同,产物形态不同)

运行完成后,profiler 输出目录结构如下。关键:训练与推理两条路径的 profiler 后端不同,产物形态也不同:

profiler_output/
├── e2e/                                              # 训练路径(Megatron actor+ref)
│   └── <hostname>_<pid>_<ts>_ascend_pt/
│       └── ASCEND_PROFILER_OUTPUT/
│           └── ascend_pytorch_profiler_0.db          # ← 训练算子(msprof,已自动解析)
└── agent_loop_rollout_replica_0/                     # 推理路径(vLLM rollout)
    └── <hostname>_<pid>_<ts>_ascend_pt/              # ← vllm-ascend torch_npu profiler 原始目录
        └── (需执行 analyse() 离线解析后才生成 ASCEND_PROFILER_OUTPUT/*.db)

机制差异(决定后续流程):

路径profiler 后端export_type是否自动解析产物
训练(e2e)CANN msprof(verl)Db✅ 自动直接生成 ascend_pytorch_profiler_0.db
推理(discrete=True)torch_npu.profiler(vllm-ascend)Text❌ 需手动只落 *_ascend_pt 目录,须 analyse() 后才有 DB

推理侧的 discrete=True 由 vLLM 引擎触发 profiler,走 vllm_ascend/worker/worker.py 的 _init_profiler()(export_type=ExportType.Text),不会像训练侧那样自动解析出 DB。


阶段 3:运行 RL 脚本采集算子数据(预计 5-15 分钟)

3.1 运行完整 RL 训练脚本
cd <脚本所在目录>
bash <脚本名> 2>&1 | tee profiler_output/run.log

注意:必须等待脚本完整执行完毕。此脚本同时运行 Megatron 训练和 vLLM rollout,运行时间取决于模型大小(0.6B 模型约 5-10 分钟)。

3.2 验证采集产物

训练路径(已自动解析为 DB):

find profiler_output/e2e -name "ascend_pytorch_profiler_0.db" -type f

确认存在 profiler_output/e2e/*/ASCEND_PROFILER_OUTPUT/ascend_pytorch_profiler_0.db。

推理路径(原始目录,尚未解析):

find profiler_output/agent_loop_rollout_replica_0 -maxdepth 2 -type d -name "*_ascend_pt"

确认存在 profiler_output/agent_loop_rollout_replica_0/<hostname>_<pid>_<ts>_ascend_pt/ 目录(这是 vllm-ascend torch_npu.profiler 的原始输出,不是 DB,目录内含 FRAMEWORK/torch.op_range 与 PROF_*/host/data)。

3.3 对推理侧 ascend_pt 目录执行离线解析(关键步骤,不可跳过)

推理侧 profiler 走 vLLM-Ascend 的 torch_npu.profiler(export_type=Text),默认不自动解析。必须手动调用 analyse() 生成 DB,否则推理侧拿不到 device 算子:

INFER_PT_DIR=$(find profiler_output/agent_loop_rollout_replica_0 -maxdepth 2 -type d -name "*_ascend_pt" | head -1)
python3 -c "
from torch_npu.profiler.profiler import analyse
analyse('${INFER_PT_DIR}')
"

解析完成后,推理侧会生成 ASCEND_PROFILER_OUTPUT/ascend_pytorch_profiler_0.db(含 COMPUTE_TASK_INFO 表 = device 侧 AI Core 真实执行算子),同时 text 模式还会额外产出 api_statistic.csv / operator_details.csv / trace_view.json(host 侧备选)。验证 DB 已生成:

find profiler_output/agent_loop_rollout_replica_0 -name "ascend_pytorch_profiler_0.db" -type f

机制说明(关键):analyse() 不带 export_type 时,会从 profiler_info_*.json 读取采集时的 _export_type。由于 vllm-ascend 采集时是 ["text"],本应只走 text 解析;但 CANN 8.5.0 的 msprof 支持 text(which will also export the database) 默认行为(torch_npu 内部 CannPackageManager.is_support_default_export_db() 检测),因此会自动补上 db parser,从而同时产出 DB 与 CSV。若某 CANN 版本不支持该默认行为(msprof --help 输出无 text(which will also export the database)),则须显式传 export_type=['db']:

python3 -c "
from torch_npu.profiler.profiler import analyse
analyse('${INFER_PT_DIR}', export_type=['db'])
"

告警说明:analyse 过程中出现的 Failed to get acl to npu flow events、Failed to get task data from db、no such table: TASK 等告警是 export_type=Text 模式的正常现象(推理侧 msprof 格式的 device 二进制 device_*/data/ 为空),不影响最终 COMPUTE_TASK_INFO 中 device 算子的解析——真实算子来自 host 侧 CANN api_event 记录(CANN_API 表),analyse 会将其还原为 device 侧算子。

3.4 验证推理侧 device 算子已落地(证据闭环)

解析完成后,必须用 SQL 确认 COMPUTE_TASK_INFO 表非空(该表 = device 侧 AI Core 真实执行算子),不能只确认 DB 文件存在:

python3 -c "
import sqlite3, glob
dbs = glob.glob('profiler_output/agent_loop_rollout_replica_0/*/ASCEND_PROFILER_OUTPUT/ascend_pytorch_profiler_0.db')
assert dbs, '推理侧 DB 缺失'
c = sqlite3.connect(dbs[0])
n = c.execute('SELECT COUNT(*) FROM COMPUTE_TASK_INFO').fetchone()[0]
print('COMPUTE_TASK_INFO rows =', n)
"
  • ✅ n > 0:推理侧 device 算子已落地,进入阶段 4。
  • ❌ DB 缺失或 n == 0:按以下顺序兜底:
兜底触发条件操作
1. 显式导出 DBanalyse() 后无 ascend_pytorch_profiler_0.db(CANN 不支持默认 text 同时导 db)analyse('${INFER_PT_DIR}', export_type=['db']) 后重新验证
2. host 侧 CSV 备选DB 存在但 COMPUTE_TASK_INFO 为空改用 ASCEND_PROFILER_OUTPUT/api_statistic.csv(或 operator_details.csv)中的 CANN 算子名统计,报告中标注「host 侧备选,非 device 侧」
3. 终止扫描1、2 兜底操作失败跳过阶段 4、5,直接输出报告,记录已进行的操作与结果

阶段 4:算子提取与对比分析(预计 3-5 分钟)

4.1 从 Profiler DB 提取算子列表

使用 ascend_pytorch_profiler_db_explorer skill 或直接 SQL 查询 DB。

重要:COMPUTE_TASK_INFO 表中算子名字段是 name(INTEGER 外键),真实算子名字符串在 STRING_IDS 字典表中,必须 JOIN 查询,不能直接查 task_name(该列不存在)。

训练路径算子提取(从 profiler_output/e2e/*/ASCEND_PROFILER_OUTPUT/ascend_pytorch_profiler_0.db):

-- 提取训练路径所有唯一 CANN 算子名及调用次数(device 侧真实执行算子)
SELECT s.value AS task_name, COUNT(*) AS cnt
FROM COMPUTE_TASK_INFO t
JOIN STRING_IDS s ON t.name = s.id
GROUP BY s.value
ORDER BY cnt DESC;

推理路径算子提取(从 profiler_output/agent_loop_rollout_replica_0/*/ASCEND_PROFILER_OUTPUT/ascend_pytorch_profiler_0.db,即 3.3 解析后产物):

-- 同上,提取推理路径所有唯一 CANN 算子(device 侧真实执行算子)
SELECT s.value AS task_name, COUNT(*) AS cnt
FROM COMPUTE_TASK_INFO t
JOIN STRING_IDS s ON t.name = s.id
GROUP BY s.value
ORDER BY cnt DESC;

将结果分别保存为:

  • profiler_output/megatron_runtime_ops.json
  • profiler_output/vllm_runtime_ops.json
4.2 构建算子全量对比表

按 Transformer 层结构逐模块对比,生成标准对比表:

维度训练路径 (Megatron)推理路径 (vLLM)差异类型差异等级
注意力列出运行时算子(如 FlashAttentionScore)列出运行时算子(如 FusedInferAttentionScore)算子不同 / 融合vs非融合🔴
残差+归一化Add + RmsNormAddRmsNormBias融合程度不同🟠
激活函数Swish(独立 SiLU)SwiGlu(SiLU+Gate 融合)融合程度不同🟠
RoPESin + Cos(独立)_triton_rope(融合)后端实现不同🟠
MatMul(线性层)MatMulV2MatMulV2相同🟢
KV Cache无ReshapeAndCacheNdKernel推理独有🟡
反向传播RmsNormGrad, FlashAttentionScoreGrad 等无训练独有🟡
4.3 差异等级判定规则
标记颜色判定条件精度风险
🔴红一方使用融合 kernel,另一方使用多个独立 kernel(如 Attention:分离 MatMul+Softmax+MatMul vs 单 kernel FusedInferAttentionScore)高
🟠橙同类操作但融合程度不同(如 Add+RMSNorm vs AddRmsNormBias),或不同后端实现同一数学运算(如 NPU RoPE vs Triton RoPE)中
🟡黄实现方式不同但数学语义等价,或仅单侧存在且另一侧有等价替代低
🟢绿相同基本算子,或训练/推理单侧独占且无等价替代极低
4.4 提取代码调用栈(关键)

对每个 🔴 和 🟠 差异算子,从以下源码路径标注代码调用栈:

算子类别训练路径关键源码推理路径关键源码
Attentionmegatron/core/transformer/dot_product_attention.py → FlashAttentionScorevllm_ascend/attention/ → FusedInferAttentionScore
RMSNormmegatron/core/transformer/torch_norm.pyvllm_ascend/layers/layernorm.py → AscendRMSNorm
SwiGLUmegatron/core/transformer/mlp.pyvllm_ascend/layers/activation.py → AscendSiluAndMul
RoPEmegatron/core/transformer/attention.py → Sin/Cosvllm_ascend/layers/rotary_embedding.py → _triton_rope

提取方式(优先使用 MSTX 标记):

  1. 查询 DB 中 MSTX 表获取算子与 Python 调用栈的对应关系
  2. 若 MSTX 不可用,则标注算子对应的源码文件路径和关键函数名
  3. 在报告中以 call stack 形式展示:上层调用路径 → 算子类/函数 → CANN 算子名

阶段 5:生成最终产物(预计 3-5 分钟)

必须生成以下 3 个文件:

产物 1:完整报告 (Markdown) → <工作目录>/train_infer_op_diff_report.md

必须包含以下章节(参考 references/report_template.md):

  1. 标题 + 元信息(模型名、配置、脚本路径、采集方式、生成时间)
  2. 算子证据来源(表格:路径、数据源、DB 文件、算子数)
  3. 训练路径算子全量列表(运行时采集的 CANN 算子 TOP30+,含调用次数和用途分类)
  4. 推理路径算子全量列表(同上)
  5. 核心差异:训练 vs 推理算子对比表(含差异类型和 🔴🟠🟡🟢 等级标记)
  6. 代码调用栈(每个 🔴🟠 差异算子附源码路径和调用链)
  7. 结论与建议(P0-P3 优先级,含具体操作)

格式要求:

  • 使用 HTML 颜色标记差异等级:<span style="color:red">🔴 高差异</span>、<span style="color:orange">🟠 中差异</span>、<span style="color:gold">🟡 低差异</span>、<span style="color:green">🟢 无差异</span>
  • 代码调用栈使用折叠块 <details><summary>调用栈详情</summary>...</details>
产物 2:算子对比表 (CSV UTF-8 BOM) → <工作目录>/operator_diff_table.csv
操作,训练算子,推理算子,训练调用次数,推理调用次数,差异类型,差异等级,训练代码路径,推理代码路径
注意力,FlashAttentionScore,FusedInferAttentionScore,672,224,算子不同,🔴,megatron/core/transformer/dot_product_attention.py,vllm_ascend/attention/ascend_attention.py
残差+归一化,Add(6484)+RmsNorm(2712),AddRmsNormBias(448),6484+2712,448,融合vs非融合,🟠,megatron/core/transformer/transformer_layer.py,vllm_ascend/layers/layernorm.py

保存格式:文件开头写入 UTF-8 BOM \xef\xbb\xbf


执行顺序约束

阶段 1 (配置解析 + 备份脚本)
  └─→ 阶段 2 (集成 Profiler 到脚本)
        └─→ 阶段 3 (运行 RL 脚本采集算子)  ← 最耗时
              └─→ 阶段 4 (提取算子 + 对比分析)
                    └─→ 阶段 5 (生成报告)
  • 各阶段严格串行,不可跳过
  • 阶段 3 运行期间需等待脚本执行完成
  • 每个阶段完成后立即整理中间结果,避免丢失

时间控制

阶段预计耗时说明
阶段 12-3 min纯文本解析 + 环境检查
阶段 22-3 min修改脚本(文本操作)
阶段 35-15 min运行 RL 脚本(取决于模型大小)
阶段 43-5 minSQL 查询 + 对比分析
阶段 53-5 min生成报告和 CSV

重要约束

  1. 绝对禁止独立分离运行:不允许编写独立脚本分别运行 Megatron 训练和 vLLM 推理来采集算子数据
  2. 绝对禁止跳过运行时采集:不允许仅凭源码静态扫描生成最终对比表
  3. 备份优先:修改脚本前必须先备份
  4. 证据闭环:每个结论必须附 profiler DB 提取的运行时算子证据

注意事项

  • 脚本运行时间可能较长(0.6B 模型约 5-10 分钟),需在开始前告知用户预计等待时间
  • 如果 profiler DB 表结构不同(如 ge_task_merge vs ge_summary),需先查询 schema
  • 推理侧必须先 analyse() 离线解析:推理 profiler 产物是 *_ascend_pt 目录(vllm-ascend torch_npu.profiler,export_type=Text),不解析就没有 DB。device_*/data 为空(无 ffts_profile.data/stars_soc.data)是该模式的正常现象,不影响 device 算子提取——analyse() 会从 host 侧 CANN_API(api_event 记录)还原出 COMPUTE_TASK_INFO(device 侧算子);仅在 COMPUTE_TASK_INFO 仍为空时才需要走 3.4 的兜底(export_type=['db'] 或 api_statistic.csv)
  • CSV 文件必须使用 UTF-8 with BOM 编码(\xef\xbb\xbf 文件头)

References

  • references/report_template.md — 报告模板
  • references/run_qwen3_0_6b_megatron_vllm_ascend.sh — Qwen3-0.6B GRPO 训练脚本

Signals

GitHub stars
31
Forks
8
Last commit
Sep 2026

ahel review

  • K5info
    obfuscation

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
train-infer-op-diff-scanner
Source
github.com/kali20gakki/msagent