关于 model-compute-simulation
用于估算已知模型或配置计算特征的模拟工具,面向研究模型执行流、张量形状、FLOPs 或 MFU 的开发与性能分析人员。它可结合并行配置及实测延迟,生成算子级或内核级计算分析。
主要功能
- 01生成算子顺序、张量形状和 FLOPs
- 02估算前向计算的总体 MFU
- 03支持内核到算子的映射分析
- 04比较不同并行配置的计算量
适用场景
- 01检查指定推理形状的计算流程
- 02估算给定延迟下的 MFU
- 03分析内核级计算利用率
- 04比较并行配置对 FLOPs 的影响
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bbuf/ ai-infra-auto-driven-skills --skill model-compute-simulation安装后在 Claude Code 中输入/model-compute-simulation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/gpu-specs.jsonmodel-config-index.jsonscripts/config_normalization.pyextract_compute_flow_from_trace.pymodel_compute_simulator.py详细介绍
模型计算模拟
概述
当问题涉及算子顺序、张量维度、FLOPs、MFU 或并行性检查时,请使用此工具。模拟器会加载模型配置、构建代表性的算子序列、打印张量形状和 FLOPs,并可根据测得的延迟估算 MFU。
输入
运行模拟前,请收集或核实以下输入:
| 项目 | 重要性 | 获取方式 | 用户未提供时的默认值 |
|---|---|---|---|
| 模型名称 | 用于在 model-config-index.json 中查找配置;决定完整架构 | 询问用户,或根据跟踪上下文推断 | —(必填) |
| 配置准确性 | 索引中的值可能与实际服务配置不同(例如 routed_expert_intermediate_size、compress_ratios) | 请用户提供 config.json,或对照 HuggingFace 核实关键参数 | 使用索引中的值,并注明可能存在差异 |
| GPU 类型 | 决定 MFU 分母中的峰值 FLOPS | 询问用户 | —(计算 MFU 时必填) |
| dtype(bf16 / fp8) | 影响峰值 FLOPS 的选择;fp8 会使峰值翻倍 | 询问用户 | bf16 |
| 批量大小和序列长度 | 直接影响 FLOPs 和张量形状 | 询问用户 | B=1,S=1(解码) |
| TP / DP / EP | TP 会将 GEMM FLOPs 分摊到多块 GPU;EP 会拆分专家 FLOPs | 询问用户 | 读取运行清单;否则明确报告所采用的假设 |
| 实测延迟(ms) | 计算 MFU 分子所必需;必须是每块 GPU 的前向传播墙钟时间 | 询问用户,或从分析器跟踪中提取 | —(可选;没有则不计算 MFU) |
如果模型不在 model-config-index.json 中,请让用户提供 config.json 路径,或在运行估算前添加索引配置。
2026-10-05 索引固定了 V4 Flash/Pro/V4.1、K3、GLM-5.2/5.3/5.3-Flash、Qwen3.8-Flash-Next、Hy3/Hy4、Inkling、dots3、Step-3.7、Nemotron-3/3.5、LongCat 和 Gemma4 的公开 HF 配置版本,并修正了较早模型的维度。
Qwen/Qwen3.8-A95B 在本次审计中返回 HTTP 401,因此未编入索引。
对于原始嵌套 HF 配置,请使用 --config /path/to/config.json;本地标准化器会展开文本包装层以及专家/层别名。
推测性 MoE 的形状和计时限制
对于 DSV4.1,请从跟踪中获取实际的目标/草稿行数:即使请求 BS=1,DSPARK block size 为 5 时也可能发出六个目标验证行。不要用接受长度代替实际计算的行数。TP 分片的共享专家形状应与路由专家分配及 EP 分开核算。不要将未经验证的模型模板除以 TP/EP 后称为实测 FLOPs。 模拟器会在路由专家之外统一按 TP 除数进行拆分,并在路由专家内部统一按 EP 除数进行拆分。这只是用于假设分析的近似值:路由器、归一化层、潜在投影的复制,以及依赖后端的共享专家归属,都需要根据具体运行情况调整后,才能解读 MFU。 固定的 V4.1 条目是静态目标模型模板;DSPARK 草稿、视觉、Engram/PLE 内存流量和后端调度都需要单独的证据。
内核耗时总和包含重叠时间,也可能包含 PDL 依赖等待。计算整次遍历 MFU 的分母时,请使用墙钟时间;峰值应采用实测 GPU SKU/dtype 的数据,不要假设每个 FP8 操作都能使有效 FLOPs 翻倍。为注意力、共享专家、路由或 mHC 指定内核名称时,请遵循调度和计时原则。
工作流
第 1 步:加载模型配置
解析模型名称并加载其配置参数:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "<model name>" --list-models
脚本会根据 references/model-config-index.json 解析模型名称。该文件存储公开的 HuggingFace 配置参数(hidden_size、num_experts、MLA ranks 等)。
如果模型未编入索引,请告知用户提供 config.json 路径,或申请更新索引。
步骤 2:生成执行流程和张量维度
使用批量大小、序列长度和并行配置运行模拟器:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "Qwen3-235B-A22B" \
--batch-size 1 --seq-len 1 \
--tp 8 --dp 1 --ep 8 \
--gpu b200 --dtype bf16
模拟器会输出:
- 每层的算子序列、FLOPs 和张量形状(shape_in → shape_out)
- 每层 Attention 与 MoE/FFN 的 FLOPs 占比
- 单次前向传播的模型总 FLOPs
对于 decode:使用 --seq-len 1 --context-len TOTAL_KV_LENGTH。
对于 extend,--context-len 是前缀长度,新 --seq-len 个 token 会执行因果计算。Full/window attention 会在 QK 和 AV FLOPs 中计入 KV 上下文。
除非指定 --all-token-logits,否则 LM head 只计算最后一个 token 的 logits。
每次运行都会将批量大小/形状/并行配置/GPU/dtype 假设打印到 stderr。
稀疏选择、KDA/Mamba 标量计算、norm/Sinkhorn 和零专家 top-k 均为架构估算,并非实测指令数。LongCat 路由 FLOPs 假设所有 top-k 都非零(在测得路由数据前属于上限)。
对于 prefill:使用 --seq-len <prompt_length>。
步骤 3:使用实测延迟估算 MFU
提供实测的前向传播延迟,以计算 MFU:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "Qwen3-235B-A22B" \
--batch-size 1 --seq-len 1 \
--tp 8 --dp 1 --ep 8 \
--gpu b200 --dtype bf16 \
--measured-ms 15.0
MFU = 理论最短时间 / 实测时间 × 100%
模拟器会输出:
- 总体 MFU
- 每层 MFU(假设各层耗时一致)
- 每种算子的 FLOPs 占比(用于识别主要算子)
GPU 峰值 FLOPS 从 references/gpu-specs.json 加载。随附的硬件表包含 H100/H200/B200、B300、GB300、MI355X、RTX PRO 6000 和 DGX Spark,并为每款产品提供官方 URL。H20 保留为未经验证的历史估算值。未知的 dense 峰值为 null,因此不提供该 dtype 的 MFU;RTX Server 和 Spark 的稀疏性尚未确认。B300/GB300 的内存容量是物理最大值,并非可用分配容量。--dtype 接受 bf16、fp8/mxfp8 和 fp4/mxfp4/nvfp4;INT8 必须使用单独发布的峰值。若在这些本地设备上运行,请使用 --gpu h100、--gpu b2000 或 --gpu b200 等别名。
步骤 4:使用内核级延迟计算每种算子的 MFU
如果有每个内核的实测延迟,可将内核耗时映射到计算流程中,以计算每种算子的 MFU。
方法 A:--kernel-flow(内核级 MFU,推荐)
以 JSON 格式提供每个内核的详细信息,然后将其传递给模拟器进行 内核级 MFU 分析。此方法会保留计算流中的每一行内核数据,并添加 FLOPs/MFU 列。
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "Qwen3-235B-A22B" \
--batch-size 1 --seq-len 8192 \
--tp 8 --dp 1 --ep 8 \
--gpu b200 --dtype bf16 \
--measured-ms 100 --kernel-flow @/tmp/layer3_detail.json
--kernel-flow 参数接受 JSON 字符串或 @file 路径。它会生成
内核级 MFU 表,保留计算流中的所有内核行,并添加:
Mapped Op:此内核对应的算子FLOPs:算子的总 FLOPsTheo(us):理论最短耗时MFU%:实测 FLOPs 利用率shape_in→shape_out:算子的张量维度
提供 --kernel-flow 时,将省略静态的逐算子模板,
因为内核级 MFU 表已包含每个内核的形状和 FLOPs 信息。输出保留模型摘要、服务配置、
总 FLOPs、根据实测层耗时计算的整体 MFU,以及
内核级 MFU 表。使用 --format json 时,原始证据存储在 kernel_flow 下,
且不会附加文本表格。
映射规则:
- 直接匹配的内核(mla、moe、mhc、rmsnorm、hadamard、rope、quant、topk 等):将耗时直接分配给对应算子
- 通用 GEMM 内核(gemm_fp8、gemm_bf16):根据 FLOPs 占比,将耗时分配给尚未分配的投影 GEMM 算子
- 开销内核(allreduce、moe_align、moe_sort、other):保留行,FLOPs/MFU 标记为 N/A
FP8 内核 MFU 修正:moe(fused_moe_kernel)和 gemm_fp8
类别中的内核即使指定了 --dtype bf16,内部也会使用 fp8 运算。
对于这些内核,MFU 分母使用 GPU 的 fp8 峰值 FLOPS(bf16 峰值的 2 倍),
而非 bf16 峰值。计算出的 MFU 会添加上标 ⁸(例如 63.7%⁸),
表示使用了 fp8 分母。gemm_bf16 内核仍使用 bf16 峰值 FLOPS 作为分母。
方法 B:--kernel-detail(算子级 MFU,旧版)
输入与 --kernel-flow 相同,但输出算子级汇总表
(按算子聚合,而非按内核)。需要简洁视图时使用。
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "Qwen3-235B-A22B" \
--batch-size 1 --seq-len 8192 \
--tp 8 --dp 1 --ep 8 \
--gpu b200 --dtype bf16 \
--measured-ms 100 --kernel-detail @/tmp/layer3_detail.json
方法 C:--kernel-ms(类别级近似)
仅在无法获取每个内核的详细信息时,使用手动汇总的类别映射:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "Qwen3-235B-A22B" \
--batch-size 1 --seq-len 8192 \
--tp 8 --dp 1 --ep 8 \
--gpu b200 --dtype bf16 \
--measured-ms 100 --kernel-ms '{
"mla": 4.922, "moe": 1.644, "allreduce": 0.769,
"hadamard": 0.348, "mhc": 1.388, "gemm_fp8": 1.692,
"gemm_bf16": 0.125, "rmsnorm": 0.227, "quant": 0.311,
"rope": 0.209, "topk": 0.122, "activation": 0.071,
"other": 0.437
}'
--kernel-ms 参数接受一个 JSON 对象,将内核类别名称
映射到其毫秒级实测耗时。它会在整个类别中按 FLOPs 占比
分配耗时;与 --kernel-detail 相比,这种方式精度较低,
因为通用 GEMM 类别(gemm_fp8、gemm_bf16)涵盖多个算子类别。
--per-layer-ms、--kernel-ms、--kernel-detail 或
--kernel-flow 中只能选择一个。所有实测耗时都必须为正数。三种内核输入
还要求提供来自整轮墙钟计时的 --measured-ms;示例中的
100 ms 是占位值,需替换为实测值。流之间存在重叠时,内核耗时总和无法确定经过时间。
输出包括:
- 模型架构摘要(层数、hidden_size、attention_type、MoE 配置)
- 逐层计算流:包含张量维度、FLOPs、shape_in→shape_out 的算子序列
- 算子级 MFU 表:每个算子的 FLOPs、理论耗时、实测耗时(来自跟踪数据)和 MFU%
- 内核 → 算子映射说明(直接匹配、按 FLOPs 占比分配或开销)
- 整体及逐层 MFU
适用场景
- 需要了解已知模型或配置的计算级详细信息时
- 用户询问特定服务形状下的执行流、张量维度或 FLOPs 时
- 用户询问 MFU,且能提供实测前向传递延迟时
- 比较不同并行配置下的计算特征时
实用命令
列出已知模型 ID:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py --list-models
列出已知 GPU 类型:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py --list-gpus
为自动化输出 JSON:
python3 skills/model-compute-simulation/scripts/model_compute_simulator.py "GLM-5" --format json
报告清单
包括:
- 模型架构摘要:模型名称、配置来源、num_layers、hidden_size、attention_type、MoE 配置(num_experts、topk、shared_experts)、MHC、head_dim
- 服务配置:batch_size、seq_len、TP、DP、EP、GPU、dtype
- 每层计算流程(详细展示首个代表性层):
- 算子序列表:名称、类别、FLOPs、shape_in → shape_out
- Attention 与 MoE/FFN 的 FLOPs 占比
- 单次前向传递的模型总 FLOPs
- 内核级 MFU 表(提供
--kernel-flow时):- 保留计算流程中的所有内核行(绝不删除)
- 每个内核的列:
# | Half | Category | Simplified Name | dur(us) | % | Mapped Op | FLOPs | Theo(us) | MFU% | shape_in→shape_out - 直接匹配的内核:显示映射算子的 FLOPs/MFU
- 开销内核:FLOPs/MFU 显示 N/A,保留该行
- 算子级 MFU 表(提供
--kernel-detail或--measured-ms时):- 每个算子:名称、类别、总 FLOPs、每 GPU 的 FLOPs、理论耗时、测量耗时(来自 trace)、MFU%
- 说明内核类别 → 算子的映射关系
- 总体 MFU 和 每层 MFU
- 一句话摘要:主要计算类别、MFU 状态、关键瓶颈
基于 Trace 的验证(extract_compute_flow_from_trace.py)
使用 scripts/extract_compute_flow_from_trace.py 从 torch profiler trace 中提取真实算子序列和张量维度,然后与静态模板比较,以此进行基准真值验证。
# Extract compute flow from a trace
python3 skills/model-compute-simulation/scripts/extract_compute_flow_from_trace.py \
--input /path/to/trace.json.gz --format text
# Compare trace against static template
python3 skills/model-compute-simulation/scripts/extract_compute_flow_from_trace.py \
--input /path/to/trace.json.gz \
--compare qwen3-235b-a22b \
--batch-size 1 --seq-len 1 --tp 8 --ep 8
通过 matmul、attention、norm 和 router 等语义类别比较 trace 与模板中是否存在相应操作;不会直接将原始 aten::* 名称与模板中的语义名称进行比较。正数 --min-flops 阈值会移除 FLOPs 无法确定的操作。
计算流程确认层级
当静态模板或 trace 提取无法完整确认计算过程时(例如作用范围不明确、缺少形状信息或模型架构较新),请按以下层级逐步确认:
-
静态模板(
model_compute_simulator.py+model-config-index.json)——速度快,覆盖已知模型 -
Trace 提取(
extract_compute_flow_from_trace.py)——根据真实执行验证模板 -
推理框架源代码——当 trace 信息不足时(缺少
Input Dims、使用 CUDA Graph replay、编译后的内核没有作用范围信息),直接从服务框架源代码中读取模型的前向流程:- SGLang:
python/sglang/srt/models/<model_name>.py——包含forward()方法;python/sglang/srt/layers/layer_boundary/factories.py中包含declare_attn/declare_ffn阶段边界 - vLLM:迁移后的 2026 系列模型位于
vllm/models/<family>/{common,nvidia,amd}/;较旧模型仍位于model_executor/models - TensorRT-LLM:
tensorrt_llm/_torch/models/modeling_<family>.py+ 模型配置
查阅框架源代码时,请重点关注:
forward()方法:算子调用顺序和残差连接- QKV / O 投影:是否使用 LoRA 风格的下投影/上投影(
q_lora_rank、o_lora_rank) - MoE 路由:top-k 选择、共享专家与路由专家的划分
- TP/EP 切分:切分的维度,以及 FLOPs 如何在 GPU 之间分配
- 静态模板中未包含的模型专属算子(例如 MHC、Hadamard、indexer)
操作:如果框架源代码显示的情况与静态模板不一致,请相应更新
model-config-index.json和/或build_layer_ops()。 - SGLang:
Trace 提取的局限性
| 局限性 | 详情 | 解决方法 |
|---|---|---|
需要设置 record_shapes=True | 必须在启用形状记录的情况下采集 Trace;否则不会出现 Input Dims 字段,也无法计算 FLOPs | SGLang 实时采集和 vLLM torch_profiler_with_stack=true 已启用此设置;TensorRT-LLM 需要覆盖 py_executor.py,添加 record_shapes=True |
| CUDA Graph 模式 | 在图重放期间,cpu_op 事件可能只出现一次(在捕获时);重放迭代的形状信息不会再次记录 | 脚本会检测图捕获阶段,并为受影响的算子添加注释;如需完整覆盖,请使用 eager 模式下的 Trace |
| TP 切分维度 | Trace 显示的是 TP 切分后的维度(例如 H/TP),而非完整模型的视图 | 在 --compare 模式下使用 --tp,将 Trace FLOPs 换算回完整模型的等效值 |
| 作用域归因质量 | Python 作用域取决于 with_stack=True;某些框架或编译路径可能会产生较浅或缺失的作用域链 | 平稳降级:将作用域无法解析的算子归类为“其他” |
| 不能替代静态模板 | Trace 提取是验证和发现工具;静态模板仍是主要的快速分析路径 | 使用 Trace 提取来验证新模型的模板,然后在发现差异时更新 model-config-index.json |
参考资料
references/model-config-index.json:模型配置参数(hidden_size、专家数量、MLA 秩等)。references/gpu-specs.json:用于计算 MFU 的 GPU 峰值 FLOPS 规格。scripts/extract_compute_flow_from_trace.py:基于 Trace 的计算流提取和模板验证工具。
源代码审查:SGLang V4、
K3 潜在专家、
NVIDIA HGX 密集型/稀疏型规格、
AMD MI355X 规格。
HF 字段来源为 hf_config_revision 对应的 hf_config_source;构造
https://huggingface.co/<repo>/blob/<revision>/config.json 即可获取确切来源。
刷新配置并不意味着运行了 GPU。