惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
腾讯CDC
博客园 - 司徒正美
A
About on SuperTechFans
H
Help Net Security
J
Java Code Geeks
C
Check Point Blog
B
Blog RSS Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MongoDB | Blog
MongoDB | Blog
U
Unit 42
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
MyScale Blog
MyScale Blog
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
I
InfoQ
H
Hackread – Cybersecurity News, Data Breaches, AI and More
F
Fortinet All Blogs
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
GbyAI
GbyAI
博客园 - 【当耐特】
雷峰网
雷峰网

又见苍岚

COLMAP PatchMatch Stereo 算法详解 事件驱动的状态机框架:从理论到工程实践 Git 在国内网络环境下无法 Push 的排查与修复 —— 配置 Clash 代理 分段五次多项式插值原理详解 路径插值方法深度对比研究 Claude Code 使用指南 OpenClaw 记忆管理与技能创建指南 CBS(Conflict-Based Search)算法详解 A* 算法及其变种详解 OpenClaw 配置多 Agents Windows Powershell 无法加载文件,因为在此系统上禁止运行脚本问题的解决方案 MaxClaw 安装流程 大模型 AI 名词介绍 AList 网盘聚合工具简介 Protobuf 简介与测试 Claude Code 简介以及 GLM 4.7 模型接入 Github 歌词下载工具 163MusicLyrics Python __getattr__ 懒加载 Python TypedDict 机器人仿真平台 Gazebo 安装记录 机器人仿真平台 Gazebo 简介 多机器人路径规划问题(Multi-Agent Path Finding, MAPF)简介 Python exifread 读取修改过的 jpeg 信息错误问题修复 3D 坐标系变换的理解 3D 旋转矩阵基本概念 MongoDB Compass 介绍 Python 环境管理工具 uv Flutter 开发指南 Snipaste 安装下载与黑屏问题解决方案 全局路径规划算法记录
onnxruntime-gpu 预热速度优化
Yiwei Zhang · 2024-04-18 · via 又见苍岚

onnxruntime-gpu 在程序启动后第一次推断会消耗较大的系统资源,并且耗时更久,本文记录优化方法。

问题描述

在 Python 下 onnxruntime-gpu 加载 onnx 模型后,创建 seddion 进行数据推断,在第一次执行时会比之后执行耗时更久,需要资源更多。

1
2
3
4
5
session = onnxruntime.InferenceSession(str(model_path),  providers=[
"CUDAExecutionProvider",
"CPUExecutionProvider"
])
session.run(None, inputs)

解决方案

onnxruntime 的官方文档中有一些关于 Provider 的配置项说明:NVIDIA - CUDA | onnxruntime

其中 https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html#cudnn_conv_algo_search

The type of search done for cuDNN convolution algorithms.

Value Description
EXHAUSTIVE (0) expensive exhaustive benchmarking using cudnnFindConvolutionForwardAlgorithmEx
HEURISTIC (1) lightweight heuristic based search using cudnnGetConvolutionForwardAlgorithm_v7
DEFAULT (2) default algorithm using CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM

描述了Onnx 优化卷积操作的一个初始化搜索操作,在卷积多,而且 Onnx 需要接受多种可变尺寸输入时耗时严重,该选项 默认为 EXHAUSTIVE, 就是最耗时的那种。

因此如果遇到上述问题可以考虑尝试将该选项改为 DEFAULT

1
2
3
4
session = onnxruntime.InferenceSession(str(model_path), opts, providers=[
("CUDAExecutionProvider", {"cudnn_conv_algo_search": "DEFAULT"}),
"CPUExecutionProvider"
])

该选项优化在 Linux 下收益不太大,在 Windows 下可以将初始化预热时间从 500s 缩短到 70s。

其他性能调优

max_workspace

ORT 会使用 CuDNN 库来进行卷积计算,第一步是根据输入的 input shape, filter shape … 来决定使用哪一个卷积算法更好

需要预先分配 workspace,如果 workspace 不够大,有可能还执行不了最优的卷积算法

因此会想让 workspace 尽可能大,从而选择性能较好的卷积算法

1.14 以前的版本 cudnn_conv_use_max_workspace 这个 flag 默认是 0,意味着只会分配 32MB 出来,1.14 之后的版本默认是设置为 1,保证选择到最优的卷积算法,但有可能造成 peak memory usage 提高

官方说法是,fp16 模型,cudnn_conv_use_max_workspace 设置为 1 很重要,floatanddouble 就不一定

需要改的话:

1
providers = [("CUDAExecutionProvider", {"cudnn_conv_use_max_workspace": '1'})]

io_binding

可以减少一些数据拷贝(有时是设备间)的耗时。

如果要用这个,需要把 InferenceSession.run() 替换成 InferenceSession.run_with_iobinding()

推理时:

1
session.run_with_iobinding(binding)

在此之前需要创建 binding:

1
binding = session.io_binding()

把你需要的输入输出绑到 binding 上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 输入 X 来自 numpy array
io_binding.bind_cpu_input('X', X)

# 输入 X 来自 torch tensor
X_tensor = X.contiguous()
binding.bind_input(
name='X',
device_type='cuda',
device_id=0,
element_type=np.float32,
shape=tuple(x_tensor.shape),
buffer_ptr=x_tensor.data_ptr(),
)

# 让输出直接输出在一个 torch tensor 上
np_type = np.float32
DEVICE_NAME = 'cuda' if torch.cuda.is_available() else 'cpu'
DEVICE_INDEX = 0 # Replace this with the index of the device you want to run on
z_tensor = torch.empty(x_tensor.shape, dtype=torch_type, device=DEVICE).contiguous()
binding.bind_output(
name='z',
device_type=DEVICE_NAME,
device_id=DEVICE_INDEX,
element_type=np_type,
shape=tuple(z_tensor.shape),
buffer_ptr=z_tensor.data_ptr(),
)

# 让输出直接输出在 numpy array 上
binding.bind_output(

)

Convolution Input Padding

卷积被转换成大矩阵乘法时,可以选择 [N, C, D, 1] or [N, C, 1, D] 两种 pad 方式,结果相同,但由于会选择不同的卷积算法,导致性能可能不太一样。

特别是像 A100 这种显卡。

设置方式:

1
providers = [("CUDAExecutionProvider", {"cudnn_conv1d_pad_to_nc1d": '1'})]

可以设置 0 和设置 1 都尝试一下,看看哪个更快。

参考资料

文章链接:
https://www.zywvvd.com/notes/study/deep-learning/deploy/onnxruntime-cuda-speedup/onnxruntime-cuda-speedup/