PyTorch 模型导出与部署实战:ONNX + onnxruntime(可直接落地)

PyTorch 模型导出与部署实战:ONNX + onnxruntime(可直接落地)

训练好的模型放在 .pth 里没人会用,导出成 ONNX 才能部署交付。这篇从导出到封装成 HTTP 服务一条龙,代码真实可跑,接单交付用得上。

前言

之前一直有个困惑:模型在 PyTorch 里跑得好好的,怎么交给别人用?给个 .pth 文件,对方没有训练环境根本跑不起来;就算能跑,每个框架一套环境,交付极其痛苦。

直到学会 ONNX 才打开新世界:训练一次,到处运行。ONNX 是微软牵头的中立模型格式,PyTorch 导出的模型能被 onnxruntime(一个几百 MB 的轻量运行时)加载,CPU 能跑、GPU 能跑、手机也能跑。这篇文章把"导出 → 验证 → 封装接口"全流程走一遍。

环境准备(先装依赖)

bat 复制代码
pip install torch torchvision onnx onnxruntime numpy fastapi uvicorn

一、为什么导出 ONNX

对比 .pth(PyTorch) .onnx
使用方需要什么 完整 PyTorch 环境 + 训练代码 只要 onnxruntime 一个包
部署形态 绑死 Python Python/Java/C#/手机都能跑
交付友好度 好(交付就是给个文件)
推理速度 基准 通常更快(图优化)

做接单/交付的人尤其在意这点:交付 .onnx + 一段推理代码,客户环境再烂也能跑

二、导出:torch.onnx.export(核心代码)

python 复制代码
import torch

# 你的模型(这里用之前训练好的图像分类模型举例)
model = SimpleCNN().to("cpu")
model.load_state_dict(torch.load("model.pth", map_location="cpu"))
model.eval()  # 必须 eval,影响 dropout/bn 行为

# 准备一个 dummy 输入,形状要和真实输入一致
dummy = torch.randn(1, 3, 32, 32)

torch.onnx.export(
    model,
    dummy,
    "model.onnx",
    input_names=["input"],
    output_names=["output"],
    dynamic_axes={"input": {0: "batch"}, "output": {0: "batch"}},  # 允许 batch 可变
    opset_version=17,
)
print("导出完成: model.onnx")

三个容易踩的细节:

  1. 模型必须先 eval(),否则导出的图里带 dropout 随机行为,推理结果对不上;
  2. dummy 输入形状必须和真实输入一致,导出时就固化了;
  3. dynamic_axes 让 batch 维度可变------不写的话,导出后只能一次推理固定数量(比如只能 1 张图一批),部署会很痛苦。

三、验证:onnxruntime 加载推理(必须做的一步)

导出不等于成功,跑一遍对比 PyTorch 的输出才放心:

bat 复制代码
pip install onnxruntime
python 复制代码
import onnxruntime as ort
import numpy as np
import torch

# 优先 GPU,没有就 CPU
sess = ort.InferenceSession(
    "model.onnx",
    providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
)

# 同一张输入,PyTorch 和 onnxruntime 各算一次
x = torch.randn(1, 3, 32, 32)
with torch.no_grad():
    torch_out = model(x).numpy()
onnx_out = sess.run(None, {"input": x.numpy()})[0]

# 数值对比:误差在 1e-4 以内算正常
diff = np.abs(torch_out - onnx_out).max()
print("最大误差:", diff)
print("ONNX 推理结果:", onnx_out.argmax(axis=1))

误差在 1e-4 量级是正常的(浮点运算顺序差异),如果差得离谱,八成是导出时忘了 eval() 或者算子不支持。

运行验证python 依次运行导出、验证、部署三段代码,期望看到:导出完成: model.onnx最大误差: 3.2e-05(1e-4 量级)、启动 uvicorn 后 curl 返回 {"class": 3, "confidence": 0.98} 这类 JSON------整条"导出→验证→接口"链路就走通了。

四、封装成 HTTP 服务(直接交付)

验证没问题后,用 FastAPI 把模型包成一个接口,客户随便什么语言都能调用:

bat 复制代码
pip install fastapi uvicorn
python 复制代码
from fastapi import FastAPI
import onnxruntime as ort
import numpy as np

app = FastAPI()
sess = ort.InferenceSession("model.onnx")

@app.post("/predict")
def predict(image: list):   # 客户端传拍平的图像数组
    arr = np.array(image, dtype=np.float32).reshape(1, 3, 32, 32)
    out = sess.run(None, {"input": arr})[0]
    cls = int(out.argmax(axis=1)[0])
    return {"class": cls, "confidence": float(out[0][cls])}

启动:

bat 复制代码
uvicorn main:app --host 0.0.0.0 --port 8000

测试调用(curl 传一个 3x32x32=3072 长度的数组即可):

bat 复制代码
curl -X POST http://127.0.0.1:8000/predict -H "Content-Type: application/json" -d "[0.1,0.2,...]"

这套交付物就三样model.onnx + main.py + requirements.txt(onnxruntime、fastapi、uvicorn)。客户 pip install -r requirements.txt && uvicorn main:app 就能跑,不依赖任何训练环境。

五、常见坑

解决
GPU 推理报错 onnxruntime-gpu;providers 里 GPU 放前面;确认 CUDA 版本匹配
导出报"不支持算子" 简化模型结构(换成 ONNX 支持的层),或调高 opset_version
推理维度对不上 客户端数据 reshape 要和导出时的 dummy 一致;注意通道顺序是 CHW
需要可变输入尺寸 dynamic_axes 里把宽高也标上({2: "height", 3: "width"}),代价是推理慢一点
导出的 onnx 比 pth 大 正常(ONNX 自带图结构);在意体积可以做模型剪枝或换小模型

六、总结

链路就四步:导出(eval + dynamic_axes)→ 验证(数值对比)→ 封装(FastAPI)→ 交付(onnx + 代码)

接单角度说一句:客户手里有训练好的模型、想部署成接口给人用,这是非常常见的外包需求。ONNX + FastAPI 这套组合,半天就能交付一个能用的推理服务,属于投入产出比很高的技能。

觉得有用点个赞收藏,有问题评论区见,看到都会回。

相关推荐
qq_454245031 小时前
本地 LLM 联调(LocalLlm / LocalLlmHttp):完全模拟调用与显式上下文传递
人工智能
ltqvibe1 小时前
Agent OS:企业智能体的控制平面
人工智能·平面·agent·智能体·企业ai
魔点科技1 小时前
一款终端, N 种场景!三端开放架构,解锁空间智能无限可能
人工智能·智能硬件·空间智能·智能终端·魔点科技
NutShell Wang1 小时前
Mojo 1.0 实战:把 Python 热路径原地加速到 C++ 级(四层渐进式迁移)
python·mojo·vibe coding
飞哥数智坊1 小时前
交付的,正在从软件变成能力
人工智能·ai编程
武子康1 小时前
DeepSeek Harness:一次 Prompt 如何变成 Turn、Step 与工具事件
人工智能·llm·agent
运维行者_1 小时前
预测性云监控怎么做?AI驱动的7大核心能力与落地路径
服务器·开发语言·网络·数据库·人工智能·python·php
赋创小助手1 小时前
机器人研发负载拆解:数据、仿真、训练与推理分别需要哪些计算资源?
服务器·人工智能·机器人·具身智能·gpu计算
小白的成长路程1 小时前
llms.txt:搜索不读,AI助手天天看
人工智能·geo