ONNX Runtime 怎样生成算子级延迟 profiling JSON
我第一次排查 ONNX Runtime 推理变慢时,最容易犯的错是只看一次总耗时,然后猜测“是不是模型太大”。更稳妥的做法是先让运行时把每个算子和相关线程事件写进 profiling JSON,再根据事件类别缩小范围。
在创建InferenceSession前把SessionOptions.enable_profiling设为True,完成与真实负载接近的推理后调用session.end_profiling()。返回值就是生成的 JSON 文件路径,里面可以按cat、name和dur读取算子级延迟。
官方地址:https://onnxruntime.ai/docs/performance/tune-performance/profiling-tools.html
先分清会话级 profiling 和一次总耗时
ONNX Runtime 的 profiling 是会话选项。它不是给某一次普通计时额外打印一行数字,而是让会话积累线程、算子延迟等详细性能事件。因此开关必须在创建会话前设置;会话已经创建后再修改一个独立的 options 对象,不会回头补录之前的事件。
图中的分组只表达静态关系:会话选项决定记录范围,推理调用产生事件,结束 profiling 再把事件写成文件。它是结构说明图,不是运行截图,也不代表某个模型已经得到固定耗时。

用代表性输入生成一份可分析的 JSON
下面的示例把模型输入准备部分故意写得简单:input_ids 和形状只是示意,实际项目应按 session.get_inputs() 返回的名称、类型和形状准备 feed。重点在于 profiling 开关、推理调用和结束时机。
import json
from pathlib import Path
import numpy as np
import onnxruntime as ort
# 先创建并配置会话选项,profiling 必须在建会话前打开。
options = ort.SessionOptions()
options.enable_profiling = True
# 这里的 provider 与模型环境有关;没有 CUDA 时可以改成 CPUExecutionProvider。
session = ort.InferenceSession(
"model.onnx",
sess_options=options,
providers=["CPUExecutionProvider"],
)
# 输入名和形状仅作示意,实际使用时要按模型元数据调整。
feed = {"input_ids": np.zeros((1, 8), dtype=np.int64)}
# 用接近真实请求的输入运行,必要时可重复几次减少一次性初始化的干扰。
session.run(None, feed)
# 结束会话级 profiling,并取得生成文件的路径。
profile_path = Path(session.end_profiling())
print(f"profile 文件:{profile_path}")
# 只读取事件结构做后续分析,不把示意输出当成固定运行结果。
events = json.loads(profile_path.read_text(encoding="utf-8"))
print(f"事件数量:{len(events.get('traceEvents', []))}")
如果只想分析特定负载,可以让 profiling 会话只覆盖那一段请求,然后立即结束。不要把模型加载、预热、业务序列化和正式请求混在一起后再凭一个数字下结论;profiling 的价值在于保留“这个数字由哪些事件组成”的线索。
读取 Node、Kernel 和 dur,避免重复计算
生成的文件属于标准性能 tracing 文件。常见事件会带有 cat、name 和 dur 等字段。Node 更接近主机侧算子事件;启用对应 GPU profiling 后,还可能看到 Kernel 事件。两者是有关联的记录,不应简单相加后当成端到端延迟。
import json
from collections import Counter
# profile_path 指向上一段代码返回的 JSON 文件。
with open(profile_path, "r", encoding="utf-8") as stream:
trace = json.load(stream)
events = trace.get("traceEvents", [])
counts = Counter()
for event in events:
# 跳过没有类别或名称的元数据事件,避免把它们当成算子耗时。
category = event.get("cat")
name = event.get("name")
duration = event.get("dur")
if category and name and duration is not None:
counts[category] += 1
# dur 的单位以当前 trace 的时间约定为准,先保留原值再比较。
if category in {"Node", "Kernel"}:
print(category, name, duration)
print("事件分类:", counts)
排查时可以先按 Node 找到耗时异常的算子,再结合是否存在对应 Kernel 记录判断设备侧关联。这个过程适合定位下一步要查的算子、执行提供者或数据搬运,不等于单凭一份 trace 就能证明某个优化一定有效。

我会优先检查的三个边界
第一,输入是否代表真实请求。全零输入、过短序列或只有一次冷启动,得到的 trace 只能说明那种输入下的事件结构,不能直接代表线上延迟。
第二,结束时机是否明确。end_profiling() 用来结束记录并返回文件路径。拿到路径后再读取文件,避免在写出前就开始解析。
第三,主机与设备事件是否混看。如果要分析 CUDA kernel,需要满足官方文档列出的 GPU profiling 条件。即使文件里同时出现 Node 和 Kernel,也应把它们作为关联线索分别解读,而不是把每条事件无条件求和。
这三个边界能把“模型慢”拆成更具体的问题:是输入负载不同、初始化混入了样本,还是某个算子与执行提供者之间存在额外开销。定位到具体事件后,再决定是否需要调整图优化、线程、I/O Binding 或 provider 配置。
相关问题
为什么设置了 enable_profiling 却没有文件?
先确认开关是在创建 InferenceSession 前设置,并且确实调用了 end_profiling()。只创建 options 或只执行推理而不结束 profiling,都不能代替完整的导出动作。
profiling JSON 能直接说明哪个算子最慢吗?
它能提供算子级事件和持续时间线索,但仍要结合输入形状、预热状态、执行提供者以及 Node/Kernel 的关系判断。不要把一次样本的最大 dur 当成所有请求的固定结论。
应该用会话 profiling 还是 RunOptions profiling?
本文讨论会话级 profiling,适合覆盖一段代表性推理。若只想观察单次运行,应根据所用语言绑定的 RunOptions API 选择单次 profiling,并保持同样的“明确范围、结束导出、按事件类别解读”原则。
总结一下:先在建会话前打开 profiling,用代表性输入产生事件,调用 end_profiling() 拿到 JSON,再按 Node、Kernel 和 dur 分层阅读。这样得到的是一份可以继续排查的证据线索,而不是脱离负载的单个总耗时。
LlamaIndex 怎样把元数据加入向量检索过滤
- 上一篇
- LlamaIndex 怎样把元数据加入向量检索过滤
- 下一篇
- MLflow 怎样记录模型版本和评估指标
-
- 科技周边 · 人工智能 | 58分钟前 | API · 人工智能 · vLLM max_tokens 推理服务
- vLLM 怎样为在线服务设置请求最大 Token 数
- 326浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | 人工智能 · 评估指标 MLFlow 模型版本 Model Registry 机器学习实验
- MLflow 怎样记录模型版本和评估指标
- 313浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- LlamaIndex 怎样把元数据加入向量检索过滤
- 334浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- LangChain 怎样为工具调用保留中间消息
- 450浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | 自定义词表 tokenizer Hugging Face Tokenizers tokenizer.json
- Hugging Face Tokenizers 怎样保存自定义词表
- 311浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | Transformers bitsandbytes BitsAndBytesConfig 4bit量化
- BitsAndBytesConfig 怎样查看 4bit 量化参数
- 205浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 | 缓存 · snapshot_download Hugging Face Hub hf_hub_download revision
- Hugging Face Hub 怎样下载指定提交版本的模型文件
- 415浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- Hugging Face Hub 怎样为私有模型配置访问令牌
- 127浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- OpenAI API 流式响应怎样按事件类型更新界面
- 228浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- scikit-learn ColumnTransformer 怎样让数值与类别特征分别预处理
- 459浏览 收藏
-
- 科技周边 · 人工智能 | 1小时前 |
- scikit-learn DummyClassifier 怎样建立分类基线
- 189浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 764次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 760次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 842次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 813次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 641次使用
-
- Go Flight Recorder 实战:线上偶发卡顿,别再只靠日志碰运气
- 2026-06-01 323浏览
-
- Go runtime/trace 任务区域如何标记异步链路:Log、Region 与查看顺序
- 2026-08-27 244浏览
-
- Go 1.25 runtime/pprof Label 控制采样范围:Do、ForLabels 与 goroutine 归因
- 2026-08-27 447浏览
-
- Go runtime/metrics.Float64Histogram 怎么计算 P99:Buckets 与 Counts 的边界
- 2026-08-28 314浏览
-
- Go runtime/trace 如何定位 goroutine 阻塞:trace.NewTask、Logf 与时间线筛选
- 2026-08-28 474浏览

