一键导入
model-infer-prefetch
为模型添加 torch_npu.npu_prefetch 优化特性时使用,当 profiling 显示 MatMul/QBMM/GMM 算子存在 memory-bound 热点时使用,或将 prefetch 模式迁移到新模型时使用
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
为模型添加 torch_npu.npu_prefetch 优化特性时使用,当 profiling 显示 MatMul/QBMM/GMM 算子存在 memory-bound 热点时使用,或将 prefetch 模式迁移到新模型时使用
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
infer 仓模型量化适配改造技能。分析并接入既有 compressed-tensors 量化方案和权重,完成量化产物契约检查、结构参考匹配、量化 runtime 映射、权重加载、post-load 处理、融合算子量化冲突回退、真实生效验证和收益评估。用于模型优化流程中的量化初评估和量化改造任务;不重新设计上游量化算法,不实现 compressed-tensors 之外的量化路线。
NPU 多流技术知识技能。提供整网模块 / 算子 DAG 拆解、模块间与模块内并行性判断、多流候选编排派生、TorchAir(Ascend IR/GE) 与 npugraph_ex/aclgraph 的多流 API 路由、切流 / 同步 / 控核实现,以及假并行(overlap_pct)排查与 Profile 验证等技术规则。供两类工作引用:形成多流优化候选 plan,以及实施 / review 多流改造。触发场景包括:多流、双流、stream overlap、控核、limit_core_num、整网 DAG、模块拆解、npu_stream_switch、npu_wait_tensor、TorchAir 多流、record_stream、多流假并行排查。本技能只提供多流技术规则,不做 Plan / round 编排。
基于 PyTorch 框架的昇腾 NPU 模型推理融合算子优化技能。分析模型代码,识别可替换为 torch_npu 融合算子的计算模式,生成替换方案。触发场景:torch_npu 融合算子替换、MoE/Attention/FFN/Norm 等模块的推理算子适配、torch_npu API 使用咨询。基于仓库已有模型的融合算子经验,按计算语义推荐最佳方案。
NPU 性能数据拆解技能。把 kernel_details.csv 按用户描述的模型结构切成 component 实例(每层 attn / ffn / moe…),再按用户给的 cluster 规则把 component 内部算子 分桶,生成 wall_ms / bubble_ms 中位数 + 异常 layer 的单页 HTML。 触发场景:分析 NPU prof / 拆解大模型性能 / 找抖动 layer。
NPU 性能分析数据采集技能。用于华为昇腾NPU上的 PyTorch 模型性能分析。 触发场景: - 用户需要采集 NPU 性能数据 - 用户提到 profiling、性能分析、tensorboard - 用户需要分析模型推理性能瓶颈 - 用户使用 torch_npu.profiler - 用户遇到 profiler 解析失败或 JSON 截断问题 关键要求:必须用 ExperimentalConfig(Level1 + PipeUtilization),否则 kernel_details.csv 只有 9 列、op_statistic/api_statistic 不生成。采集前先判断仓库有无轻框架内置 prof(enable_profiler):有则用框架只调参数、无则注入。
通用模型推理优化编排技能。用于从推理场景、精度基线、profiling 采集与性能分析开始,拉起多个方向的 subagent 生成不限于多流的优化候选,再按 Plan / round 编排 implementer 和 reviewer subagent 实施、验收、派生新 Plan,并最终判断哪些 Plan 保留、哪些淘汰。适用于融合算子、prefetch、图模式、多流、KVCache、量化、并行等优化项的统一调测编排。
| name | model-infer-prefetch |
| description | 为模型添加 torch_npu.npu_prefetch 优化特性时使用,当 profiling 显示 MatMul/QBMM/GMM 算子存在 memory-bound 热点时使用,或将 prefetch 模式迁移到新模型时使用 |
| user-invocable | true |
提供手动指定和自动化分析两种方式确定预取位置,覆盖方案设计、大小计算、代码实现和性能验证。
torch_npuenable_prefetch 开关保护,默认 Falsemax_size 从保守值开始,根据 profiling 结果逐步调整npu-roofline-analysis 从 profiling 数据中识别候选位置max_sizeenable_prefetch 开关torch_npu.npu_prefetch 调用max_size 和 dependency 的具体取值等待用户确认方案后再进行开发。有修改意见则返回第一步。
按照确认的设计方案逐步实施代码修改:
enable_prefetch 开关torch_npu.npu_prefetch 调用max_size 和 dependency 参数由 Agent 实际执行以下测试,记录真实结果:
重要:必须实际运行测试并生成性能优化报告,包括:
在开始实施前先确定使用哪种方式。如果用户未指定,优先采用自动化分析。
| 方式 | 输入要求 | 输出结果 | 适用场景 |
|---|---|---|---|
| 手动指定位置 | 用户提供目标算子和依赖窗口 | 直接进入大小确定阶段 | 已有明确优化目标,熟悉模型结构 |
| 自动化分析 | profiling 数据或模型代码 | 候选位置列表 + 理论预取大小 | 需要从数据中发现机会,不确定优化点 |
用户直接提供:
直接跳转到"预取大小确定"章节。
通过调用 npu-roofline-analysis skill 和分析模型代码自动识别候选位置。
开始
│
├─→ 步骤 1:调用 npu-roofline-analysis
│ ↓
│ 获取 memory-bound top 10 算子列表
│ ↓
├─→ 步骤 2:对每个 memory-bound 算子
│ ├── 分析前序算子
│ ├── 判断前序是否访存密集
│ │
│ ├─→ 前序是访存密集 ──→ 无预取空间 ──→ 跳过该算子
│ │
│ └─→ 前序非访存密集 ──→ 有预取空间 ──→ 标记为候选
│ ↓
├─→ 步骤 3:计算理论预取大小
│ ├── 获取权重张量维度
│ ├── 获取数据类型(bf16/int8)
│ └── 计算 max_size = 维度 × 字节数
│ ↓
└─→ 输出:候选位置列表 + 理论预取大小
| 步骤 | 检查项 | 结果 | 下一步 |
|---|---|---|---|
| 1 | 调用 npu-roofline-analysis | 获取 memory-bound top 10 算子 | 进入步骤 2 |
| 2 | 调用 npu-roofline-analysis分析每个算子的前序算子(前2-3个) | 判断前序是否访存密集 | 进入步骤 3 |
| 3a | 前序算子是访存密集(大 MatMul/通信)但其输出可用 | 有预取空间(使用前序输出作为依赖窗口) | 计算理论预取大小 |
| 3b | 前序算子非访存密集(LayerNorm/ROPE/SwiGLU/小算子) | 有预取空间(使用前序输出作为依赖窗口) | 计算理论预取大小 |
| 3c | 前序算子是通信或无合适窗口 | 无预取空间 | 跳过该算子 |
| 4 | 计算权重大小 | 理论 max_size | 输出候选列表 |
访存密集定义:指 memory-bound 算子,即内存带宽成为瓶颈的算子。
| 算子类型 | 是否访存密集(memory-bound) | 说明 |
|---|---|---|
| 大型 MatMul, BatchMatMul, QBMM, GMM | 是 | 权重搬运密集,memory-bound,但其输出可作为依赖窗口 |
| 通信算子(send, recv, all_reduce) | 是 | 带宽密集,不适合作为依赖窗口 |
| 大型数据搬运(大 transpose, 大 concat) | 是 | 数据搬运量大,会争抢带宽 |
| LayerNorm, RMSNorm | 否 | 虽是访存类算子,但不是 memory-bound,可作为依赖窗口 |
| ROPE, cast, reshape, 小 transpose | 否 | 计算或搬运量小,可作为依赖窗口 |
| SwiGLU, GELU, Silu, npu_dequant_swiglu_quant | 否 | 计算密集,可作为依赖窗口 |
| router topk, dispatch, combine | 否 | 计算密集,可作为依赖窗口 |
| router.classifier(小型 MatMul) | 否 | 权重较小,输出可作为依赖窗口 |
场景:LongCat-Flash 模型优化
调用 npu-roofline-analysis:
分析 gate_up_proj 前序算子:
分析 down_proj 前序算子:
分析 q_a_proj 前序算子:
分析 router.classifier 前序算子:
计算理论预取大小:
hidden_size × intermediate_size × 2 × 2 字节(bf16)输出候选列表:
详细的 roofline 分析方法参见
npu-roofline-analysisskill
根据权重张量维度和数据类型计算 max_size,遵循"先保守后激进"原则。
基本公式:
max_size = 权重维度乘积 × 数据类型字节数 × 保守系数
数据类型字节数:
bf16 / fp16: 2 字节int8: 1 字节fp32: 4 字节保守系数:
| 算子类型 | 权重维度 | 数据类型 | 理论 max_size | 保守 max_size(50%) |
|---|---|---|---|---|
| MatMul(q_proj) | hidden_size × hidden_size | bf16 | H × H × 2 | H × H |
| MatMul(o_proj) | hidden_size × hidden_size | bf16 | H × H × 2 | H × H |
| MatMul(gate_up_proj) | hidden_size × intermediate_size × 2 | bf16 | H × I × 4 | H × I × 2 |
| MatMul(down_proj) | intermediate_size × hidden_size | bf16 | I × H × 2 | I × H |
| QBMM | hidden_size × hidden_size | int8 | H × H | H × H / 2 |
| GMM(MoE) | hidden_size × intermediate_size × 2 / moe_tp_size × experts_per_rank | bf16/int8 | 见下方 | 见下方 |
# 数据类型字节数
dtype_bit = 1 if quant_mode == "w8a8" else 2 # int8: 1 字节, bf16: 2 字节
# GMM1(gate_up_proj)预取大小
gmm1_prefetch_size = hidden_size * intermediate_size * 2 * dtype_bit // moe_tp_size * experts_per_rank // 2
# GMM2(down_proj)预取大小
gmm2_prefetch_size = hidden_size * intermediate_size * dtype_bit // moe_tp_size * experts_per_rank
| 场景 | 调整方向 | 说明 |
|---|---|---|
| 目标算子加速明显,依赖窗口稳定 | 增大 max_size | 从 50% → 70% → 100% |
| 目标算子加速不明显 | 保持或减小 max_size | 可能预取收益有限 |
| 依赖窗口明显退化 | 减小 max_size | 从 50% → 30% → 10% |
| 依赖窗口严重退化 | 调整位置或放弃 | 前移 prefetch 或选择其他依赖窗口 |
| 位置 | 目标算子 | 依赖窗口 | max_size | 说明 |
|---|---|---|---|---|
| Line 1244 | router classifier | o_proj | 18 MB | 固定值 |
| Line 1259 | q_a_proj | dense MLP output | 18 MB | 保守值 |
| Line 1260 | q_b_proj | dense MLP output | 36 MB | 中等值 |
| Line 1261 | kv_a_proj_with_mqa | dense MLP output | 7 MB | 保守值 |
| Line 1286 | next layer attention | down_proj | 计算值 | 动态计算 |
参考文件:
models/longcat-flash/models/modeling_longcat_flash.py,models/longcat-flash/models/ffn.py
| 优先级 | 算子类型 | 说明 |
|---|---|---|
| 高 | MatMul, BatchMatMul, QBMM, GMM | 主要预取目标,权重搬运密集 |
| 高 | 大型 MLP/FFN 线性层 | q_proj, k_proj, v_proj, o_proj, up_proj, down_proj, gate_up_proj |
| 高 | MoE 相关 MatMul | router.classifier, experts.w13_weight, experts.w2_weight |
| 高 | 融合前置大搬运算子 | 如 MLAProlog(需 roofline 支持) |
| 低 | LayerNorm, RMSNorm, ROPE | 通常作为依赖窗口,不是预取目标 |
| 低 | cast, reshape, transpose, concat | 同上 |
| 低 | router topk, dispatch, combine | 同上 |
| 低 | SwiGLU, GELU, Silu | 同上 |
开始选择依赖窗口
│
├─→ 找到目标算子的紧邻前驱
│ ↓
│ 检查:是否 memory-bound?
│ ├─→ 是 ──→ 前移到更早的前驱 ──→ 重新检查
│ │
│ └─→ 否 ──→ 检查:是否有足够执行时间?
│ ├─→ 是 ──→ 选择为依赖窗口 ✓
│ │
│ └─→ 否 ──→ 前移到更早的前驱 ──→ 重新检查
│
└─→ 所有前驱都不合适 ──→ 报告"无安全窗口" ──→ 放弃该目标
从目标算子向前找同一关键路径上的前序算子,优先选择:
npu-roofline-analysis 判断为非 memory-bound重要:即使前序算子本身是大型 MatMul(如 o_proj),其输出仍可作为依赖窗口,因为该算子执行完成后带宽空闲,可以开始预取下一个算子的权重。
| 目标算子 | 依赖窗口 | 代码位置 | 说明 |
|---|---|---|---|
| router.classifier | o_proj 输出 | modeling_longcat_flash.py 的 attention forward | o_proj 完成后预取 router 权重 |
| gate_up_proj | o_proj 输出 | modeling_longcat_flash.py 的 dense MLP forward | o_proj 完成后预取 MLP 权重 |
| down_proj | gate_up_proj 输入 x | modeling_longcat_flash.py 的 dense MLP forward | 在 gate_up_proj 执行时预取 down_proj 权重 |
| q_a_proj / q_b_proj / kv_a_proj(下一层) | down_proj 输出 | modeling_longcat_flash.py 的 layer forward 末尾 | down_proj 完成后预取下一层 attention 权重 |
| experts.w2_weight | router_logits 输出 | models/longcat-flash/models/ffn.py 的 MoE forward | router 完成后预取 GMM2 权重 |
| router.classifier(下一层) | gmm2_out 输出 | models/longcat-flash/models/ffn.py 的 MoE forward 末尾 | GMM2 完成后预取下一层 router 权重 |
| experts.w13_weight(下一层) | gmm2_out 输出 | models/longcat-flash/models/ffn.py 的 MoE forward 末尾 | GMM2 完成后预取下一层 GMM1 权重 |
关键观察:
如果所有合理前驱都表现为重搬运或重通信窗口,则明确说明"当前阶段没有安全窗口",不要为了"有改动"而硬插 prefetch。
检查开关传递链路:YAML → InferenceConfig → 模型类 __init__(通过 infer_config.model_config.custom_params 或专用字段)→ forward/decode/prefill
配置文件示例(config.yaml):
model_config:
enable_prefetch: true # 默认 false
enable_multi_stream: 2 # prefetch 需要多流支持
模型初始化示例:
class YourModel:
def __init__(self, config):
self.enable_prefetch = config.get("enable_prefetch", False)
# prefetch 需要图模式 + 多流
assert not self.enable_prefetch or config.get("enable_multi_stream", 0) > 0
推荐:使用 wrapper 函数(executor/utils/common_utils.py):
def npu_prefetch(switch_flag, weight, depend, size, offset=0):
if switch_flag:
return torch_npu.npu_prefetch(weight, depend, size, offset)
else:
return None
在模型中调用:
from executor.utils.common_utils import npu_prefetch
class YourModel:
def forward(self, x):
# 计算依赖窗口
dependency_output = self.some_layer(x)
# 预取下一个算子的权重
npu_prefetch(
self.enable_prefetch,
weight=self.next_layer.weight,
depend=dependency_output,
size=self.prefetch_size,
offset=0
)
# 执行目标算子
output = self.next_layer(dependency_output)
return output
dependency 必须是明确的 tensor 节点正确示例:
# 依赖节点是目标算子的直接前驱
attn_output = self.attention(x) # 依赖窗口
npu_prefetch(self.enable_prefetch, self.mlp.weight, attn_output, size)
mlp_output = self.mlp(attn_output) # 目标算子
错误示例:
# 依赖节点与目标算子不在同一路径
attn_output = self.attention(x)
npu_prefetch(self.enable_prefetch, self.mlp.weight, x, size) # 错误:x 不是 mlp 的直接前驱
mlp_output = self.mlp(attn_output)
优先:
max_size避免:
| 场景 | 经验 |
|---|---|
| LongCat-Flash | 优先看 QBMM、MLAProlog、Matmul;对更重的后续算子,可提前预取更早权重 |
| AFD/FFN 分离 | Attention 提速后 FFN 成瓶颈时,优先看 GMM/Matmul;仅在通信间隙和非重搬运窗口存在时尝试 |
| MoE | 专家计算常见候选是 grouped_matmul 和大专家线性层;dispatch/combine/router 通常不是 prefetch 目标 |
| Dense MLP | gate_up_proj/down_proj/o_proj 常是候选;但其前序窗口若已被另一个 MatMul 占满,不要硬加 |
在 prefetch 前后运行 profiling,按以下清单逐一检查:
至少满足其中两项:
| 失败信号 | 根因分析 | 调整策略 |
|---|---|---|
| 目标算子没快,前序窗口反而变慢 | max_size 过大,争抢带宽 | 减小 max_size:50% → 30% → 10% |
| 关键路径没有缩短,只是等待位置挪动 | 依赖窗口选择不当 | 前移或后移 prefetch 位置 |
| 多流上出现新的长拖尾 | prefetch 引入新的同步点 | 调整依赖节点或放弃该位置 |
| 图模式下依赖关系不合法 | 依赖节点与目标算子不匹配 | 修正依赖节点或改为 eager 模式测试 |
max_size:从 50% → 70% → 100% 或 50% → 30% → 10%max_size,微调 dependency 位置:前移或后移依赖窗口| 错误现象 | 根因 | 修复方案 |
|---|---|---|
| 不先跑 roofline 就选目标 | 缺少 profiling 数据支持 | 必须先用 npu-roofline-analysis 确认 memory-bound |
| 选了 LayerNorm/ROPE 作为预取目标 | 误判目标算子 | 这些通常是依赖窗口,不是预取目标 |
| dependency 窗口也是 memory-bound | 依赖窗口选择不当 | 选非 memory-bound 的前驱,或前移 prefetch |
| 一次性预取全量权重 | max_size 过大 | 先保守 max_size(50%),后续再调优 |
| 多处同时加 prefetch | 改动范围过大 | 先单个目标,验证后再扩展 |
| 没有开关保护 | 缺少回退机制 | 所有 prefetch 必须有 enable_prefetch 开关 |
| 前序窗口退化但不调整 | 未根据 profiling 调整 | 缩小 max_size 或调整位置,必要时回退 |
| 图模式下编译失败 | 依赖节点不合法 | 确保依赖节点与目标算子在同一路径 |
完成后必须汇报:
max_size 取值依据:权重维度、数据类型、保守系数或用户指定值必须交付的文件:
如果无法运行实际测试(如缺少模型权重):
| 主题 | 文件路径 |
|---|---|
| npu_prefetch wrapper 函数 | executor/utils/common_utils.py(搜索 npu_prefetch) |
| LongCat-Flash prefetch 实现 | models/longcat-flash/models/modeling_longcat_flash.py(搜索 npu_prefetch 调用点) |
| FFN prefetch 大小计算 | models/longcat-flash/models/ffn.py(搜索 prefetch_size 计算) |
| 配置验证逻辑 | executor/core/config/inference_config.py(InferenceConfig._validate)+ 模型自身 __init__ 中的额外语义校验 |
| 配置示例 | models/longcat-flash/config/README.md |
| Roofline 分析 | 调用 npu-roofline-analysis skill |
| 图模式适配 | 调用 model-infer-graph-mode skill |