大模型太慢?别急着上 GPU 堆钱:Python + ONNX Runtime 优化推理性能实战指南
大家好,我是 Echo_Wish。
这两年,大模型真的卷疯了。
模型参数从几亿到几百亿,大家都在追“更大、更强”。
但现实世界里有个残酷的问题:
模型越大,推理越慢,钱烧得越快。
很多团队第一反应是:
“上更好的 GPU!上 A100!上多卡!”
但作为一个长期做工程优化的人,我想说一句:
性能问题,很多时候不是靠堆资源解决的,而是靠结构优化。
今天我们就聊聊一个特别实用的方案:
✅ Python + ONNX Runtime 优化大模型推理性能
不换模型,不改算法,直接提速。
而且我们会一步步实战,讲清楚原理,讲清楚思路。
一、ONNX Runtime 是什么?一句话讲清
ONNX 是一个模型交换标准(Open Neural Network Exchange)。
简单说就是:
把 PyTorch / TensorFlow 模型转换成统一格式,让推理更高效。
ONNX Runtime(简称 ORT)是微软主导的高性能推理引擎。
它的优势:
- 更激进的图优化
- 更底层的算子融合
- 支持 CPU / GPU / TensorRT
- 内存管理更高效
很多人不知道的是:
同样的模型,换成 ONNX Runtime,CPU 上可能直接快 30%~200%。
二、为什么 ONNX Runtime 会更快?
我们用一个图理解它的优化思路。
假设你在 PyTorch 里写:
x = x.matmul(w)
x = x + b
x = torch.relu(x)
在原始框架中,这三步是三个算子:
- MatMul
- Add
- ReLU
但 ONNX Runtime 会做算子融合:
👉 把它优化成一个 Fused Kernel
这样做的好处:
- 减少内存读写
- 减少 kernel 启动开销
- 更好利用 CPU cache
这就是图优化的威力。
三、实战:从 PyTorch 到 ONNX
我们先来个简单模型做演示。
import torch
import torch.nn as nn
class SimpleMLP(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(768, 1024)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(1024, 10)
def forward(self, x):
return self.fc2(self.relu(self.fc1(x)))
model = SimpleMLP()
model.eval()
1️⃣ 导出 ONNX
dummy_input = torch.randn(1, 768)
torch.onnx.export(
model,
dummy_input,
"model.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={
"input": {
0: "batch_size"}},
opset_version=17
)
这一步只是“转换格式”。
真正的优化,在推理阶段。
四、使用 ONNX Runtime 推理
我们先安装:
pip install onnxruntime
然后写推理代码:
import onnxruntime as ort
import numpy as np
session = ort.InferenceSession("model.onnx")
input_data = np.random.randn(1, 768).astype(np.float32)
outputs = session.run(
None,
{
"input": input_data}
)
print(outputs[0])
到这里,你已经完成了最基础的迁移。
但这还没开始优化。
五、开启优化模式
ONNX Runtime 有图优化等级:
- ORT_DISABLE_ALL
- ORT_ENABLE_BASIC
- ORT_ENABLE_EXTENDED
- ORT_ENABLE_ALL
我们直接拉满。
so = ort.SessionOptions()
so.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
session = ort.InferenceSession(
"model.onnx",
sess_options=so
)
仅仅这一行,在很多场景就能带来 10%+ 提升。
六、真正的杀手锏:量化(Quantization)




很多人优化推理只想到 GPU。
但其实:
CPU + INT8 量化,才是性价比之王。
我们用 ONNX Runtime 自带工具做动态量化:
from onnxruntime.quantization import quantize_dynamic, QuantType
quantize_dynamic(
"model.onnx",
"model_int8.onnx",
weight_type=QuantType.QInt8
)
然后加载量化模型:
session = ort.InferenceSession("model_int8.onnx")
在 CPU 场景下,你会看到:
- 推理延迟下降
- 内存占用下降
- 吞吐上升
代价通常只是极小精度损失。
七、GPU 加速(Execution Provider)
如果你用 GPU:
pip install onnxruntime-gpu
然后:
session = ort.InferenceSession(
"model.onnx",
providers=["CUDAExecutionProvider"]
)
如果是 NVIDIA 生产环境,我强烈建议配合 TensorRT:
providers=["TensorrtExecutionProvider", "CUDAExecutionProvider"]
这样可以获得:
- kernel 自动融合
- FP16 加速
- 动态 shape 优化
八、我真实的优化经验
说点真心话。
我曾经帮一个团队优化一个 NLP 模型推理服务。
情况是:
- 8 核 CPU
- QPS 低
- 延迟 120ms+
他们第一反应是“上 GPU”。
我做了三件事:
- 导出 ONNX
- 打开全部图优化
- 做 INT8 量化
结果:
- 延迟降到 45ms
- QPS 翻倍
- 成本不变
那一刻我真的感慨:
工程优化比买硬件更性感。
九、别忽略的隐藏优化点
1️⃣ 批量推理
input_data = np.random.randn(32, 768).astype(np.float32)
Batch 处理通常吞吐提升明显。
2️⃣ 线程优化
so = ort.SessionOptions()
so.intra_op_num_threads = 8
CPU 场景下非常关键。
3️⃣ I/O 绑定优化
ONNX Runtime 支持避免内存复制:
io_binding = session.io_binding()
这个在大模型场景里效果更明显。
十、最后一点思考
很多人觉得大模型推理慢,是模型太大。
但我越来越觉得:
性能瓶颈往往不是模型,而是工程实现。
优化顺序应该是:
1️⃣ 算子融合
2️⃣ 图优化
3️⃣ 量化
4️⃣ Batch 调整
5️⃣ 硬件升级
而不是一上来就买更贵的卡。
总结一句话
ONNX Runtime 是大模型工程优化的瑞士军刀。
它不改变模型能力,
却能改变你的成本结构。