写这篇东西的起因是我去年把一个自研的图像分割模型从 PyTorch 部署到线上推理服务时被性能逼到了墙角。GPU 利用率一直在低位徘徊请求稍有波动就撞上超时。后来把 TensorRT 接进来同一个模型、同一张卡单路延迟直接砍掉一半以上吞吐翻了将近一倍。前后大概花了两个星期踩了一堆奇奇怪怪的坑。这篇文章就是想把用 Python 部署 TensorRT这件事的完整链路、关键思路和那些文档里不写但我实测下来很重要的细节一次性交代清楚。适合正在做推理加速、准备把模型从训练环境挪到生产环境的开发者参考。1. 先说结论Python 部署 TensorRT 到底值不值得干很多人在听说 TensorRT 时第一反应是这是 N 卡专用的东西会不会绑定很深第二反应是是不是必须写 CPython 行不行。这两个问题我可以直接回答第一TensorRT 确实只跑在自家的 GPU 上但目前绝大多数线上推理场景用的就是 GPU这个前提不算苛刻第二Python 完全够用而且工程效率比 C 高得多。1.1 TensorRT 到底是什么它优化了哪一层从本质上讲TensorRT 是一个针对 GPU 的深度学习推理优化引擎。它做的事不是简单地调用 cuDNN 去跑卷积而是把你训练好的模型通过一个离线构建阶段编译成一套面向目标 GPU 的、高度特化的执行计划Engine。这个编译过程会做非常多的底层优化包括层融合Layer Fusion把连续的卷积、批归一化、激活函数合并成一个内核减少内核启动开销和显存读写。精度校准与混精度执行把 FP32 计算改成 FP16 甚至 INT8利用 GPU 专为低精度设计的高吞吐单元。内核自动选择Tactic Selection针对你的显卡型号从数百个候选卷积实现里挑出最快的那一个。显存复用通过生命周期分析让多个张量共享显存缓冲大幅降低峰值显存占用。所以TensorRT 不是运行时的解释器而更像是一个编译器。训练框架里的模型是 Python 对象TensorRT 里的 Engine 是经过编译后的二进制执行计划。这个编译过程是有成本的而且必须在目标 GPU 型号上完成或者用目标 GPU 的能力信息来生成所以它天然就要区分构建期和运行期。1.2 Python API 与 C API 的真实差距很多团队一想到上 TensorRT 就直接瞄着 C理由是性能敏感模块必须用 C。我实测下来的结论是推理核心耗时几乎不受语言影响。你在 Python 里调用的execute_async或execute底层拿到的同样是指向当前 CUDA 流上任务的句柄真正的计算全在引擎内部完成Python 侧只是发起调用和搬运绑定数据。Python 和 C 的差距主要出现在这几个地方单次推理时间极短微秒级且请求量极大时Python 解释器的函数调用开销会占一定比例。数据搬运频繁时Python 侧如果写了低效的深拷贝会吃掉大量带宽。极端高并发场景比如每秒几千路请求Python 的 GIL 会成为瓶颈。如果你的业务是常见的视觉推理,每帧图像几百毫秒或者几十毫秒Python 的这点开销基本可以忽略。相反Python 在模型调试、版本迭代、对接 FastAPI 这类 Web 框架上效率比 C 翻几倍。我用一个大模型服务做过对比Python 版和 C 版推理引擎的端到端吞吐差距在 5%~8% 之间这点收益在排期压力面前根本不值一提。2. 环境准备与版本选型把坑掐死在源头TensorRT 这个工具我见过太多人一上来就卡在环境上装了库、导入了包但模型一跑就是各种报错。原因十有八九是版本链断裂。这块值得花点时间一次配好能省几天时间。2.1 软硬件环境清单我建议的最小环境参考如下以 TensorRT 10.x 为例这是目前比较新的稳定大版本API 已经和旧版有较大差别组件版本或要求备注GPU算力 7.5 以上Turing 架构或更新老显卡也能跑但优化效果和部分算子支持会打折操作系统Ubuntu 20.04 / 22.04Windows 上开发可以生产部署建议 LinuxCUDA12.x与 TensorRT 10.x 匹配注意不是越新越好要和驱动匹配cuDNN8.9.x 以上与 CUDA 版本成套选择TensorRT Pythontensorrt10.xpip 包即可不需要手动下载 tar 包PyTorch2.x仅用于训练和导出 ONNX这里面的关键是TensorRT、CUDA、cuDNN 三者是一个闭环版本必须彼此兼容。比如 TensorRT 10.0 是基于 CUDA 12.0 构建的你要么用匹配的 CUDA要么用 TensorRT 官方提供的容器镜像否则构建 engine 时可能直接报找不到 cudnn这类隐晦错误。2.2 安装时容易被忽略的隐性问题我装过很多次环境最常踩的坑是这几个通过 pip 安装tensorrt包时它只带了 Python 绑定底层的 CUDA/cuDNN 库还是依赖系统环境。如果你系统里的 CUDA 是老版本导入包时不会报错但真正去执行 engine 构建或推理时一连串 cryptic 的错误就来了。网上很多教程还在用import tensorrt as trt没问题但构建 API 的写法已经变了几轮。老版本的builder.build_cuda_engine(network)在新版本被替换成了builder.build_serialized_network(network, config)传参完全不一样。搜索博客时一定得看文章的 TensorRT 版本否则照抄必挂。Python 包和 C 库的版本分离问题如果你已经手动装了 TensorRT 的 C 库再 pip 装 Python 包可能装了两个不同版本。检查方式是在 Python 里打印trt.__version__再确认命令行dpkg -l | grep TensorRT或/usr/local/tensorrt目录里的版本两者要严格一致。我自己的做法是有条件就用官方 Docker 镜像比如nvcr.io上的 TensorRT 容器里面所有版本都调好了Python 和 C 库同版本省掉九九八十一难。如果必须自己在裸机配建议把 CUDA Toolkit 和 cuDNN 都用 tar 方式解压到自己目录再通过环境变量LD_LIBRARY_PATH指向它们避免污染系统目录也让后续升级更容易回滚。2.3 确认显卡算力和驱动状态一口气写到这里插一个细节TensorRT 构建 engine 时会因为目标显卡不同做不同的优化。如果你想在 A 卡上构建 engine然后到 B 卡上运行必须保证两张卡算力架构一致比如都是 Ampere 架构的 sm_86否则 runtime 反序列化时大概率报不支持的错误。所以在动手之前先看一眼自己的显卡import torch print(torch.cuda.get_device_name(0)) print(torch.cuda.get_device_capability(0))然后去对照算力表弄明白自己目前处于哪个架构。这也是为什么很多公司宁可在生产机器上构建一次 engine 并序列化保存到本地也不再跨机器搬动序列化文件的原因。3. 从 ONNX 到 TensorRT构建期与运行期的核心逻辑当你搞定了环境接着就会遇到第一个真正有技术含量的问题怎么把训练好的模型弄成 TensorRT 的 engine。现在比较通用的链路是PyTorch → ONNX → TensorRT。中间多了一道 ONNX看着绕其实是为了解耦PyTorch 直接导出到 TensorRT 的路径不好走而 ONNX 是一个稳定的中间格式TensorRT 对它支持最好。3.1 构建流程的三个关键角色在 TensorRT 10.x 的 Python API 里你会频繁见到几个概念Builder、Network、Parser、BuilderConfig。Builder总指挥负责协调整个构建过程。Network一个图结构描述网络层、张量、权重是 engine 构建输入。Parser把 ONNX 文件解析并填充进 Network。BuilderConfig构建参数比如工作空间大小、精度模式、动态形状 profile。构建一个 engine 的代码骨架很简洁但每个参数背后都有讲究。我直接给一个标准流程import tensorrt as trt logger trt.Logger(trt.Logger.WARNING) builder trt.Builder(logger) network builder.create_network(1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser trt.OnnxParser(network, logger) with open(model.onnx, rb) as f: if not parser.parse(f.read()): for i in range(parser.num_errors): print(parser.get_error(i)) raise ValueError(ONNX parse failed) config builder.create_builder_config() # 设置构建阶段的工作空间显存上限单位是字节 config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 2 * (1 30)) # 开启 FP16 精度 config.set_flag(trt.BuilderFlag.FP16) engine builder.build_serialized_network(network, config) with open(model.trt, wb) as f: f.write(engine)有几个点我刚开始用的时候很容易出错特意标注一下EXPLICIT_BATCH这个 flag 在 TensorRT 7 之后基本是标配它意味着网络图的输入张量维度里显式写出 batch 维度。如果漏了当你的模型输入是动态 batch 时解析 ONNX 一定会失败。set_memory_pool_limit是 TensorRT 10 的写法。老版本写的是config.max_workspace_size ...很多博客还在用旧写法在新版本里会抛 AttributeError。build_serialized_network返回的是序列化后的字节流。有些版本也支持build_engine返回 engine 对象但新 API 推荐前者直接用字节流存文件和反序列化都方便。3.2 动态形状与 Optimization Profile最绕也是最关键的地方很多模型在推理时 batch 是动态的或者输入尺寸是变化的比如目标检测里常见的高分辨率。TensorRT 为此引入了动态形状 profile机制。你需要在构建时给每个动态输入指定三组长度最小、常规、最大。profile builder.create_optimization_profile() input_name input min_shape (1, 3, 640, 640) opt_shape (1, 3, 1280, 1280) max_shape (4, 3, 1280, 1280) profile.set_shape(input_name, min_shape, opt_shape, max_shape) config.add_optimization_profile(profile)这里最容易忽略的是ONNX 模型里动态轴必须有明确的batch或dynamic_axes定义。你在 PyTorch 导出 ONNX 时就要设置好torch.onnx.export(model, dummy_input, model.onnx, dynamic_axes{input: {0: batch}, output: {0: batch}}, opset_version17)如果导出的 ONNX 是静态 shapeTensorRT 侧就算加了 profile 也会被忽略运行时无法改变输入尺寸。还有个我踩过很深的坑profile 上下界定义不合适。如果最大尺寸设得过大每一步优化都会按最大显存规划虽然实际推理用小 batch但显存峰值会被预留造成严重浪费如果设得过小运行时会直接拒绝超过上限的输入。建议根据真实业务压测数据来设置 opt_shape这直接决定了推理性能——TensorRT 会为常规尺寸选最合适的 kernel而不是给最大尺寸做优化。3.3 FP16 与 INT8性能提升的大头也是精度的风险项FP16 在绝大多数现代 GPU 上能带来接近一倍的吞吐提升是性价比最高的优化开关。开启方式就是上面代码里的config.set_flag(trt.BuilderFlag.FP16)。但 FP16 不是银弹我遇到过很多模型在 FP16 下精度崩溃的情况尤其是含有大数值范围动态的层或者对数值特别敏感的归一化层。解决办法一般是先用 FP16 跑一遍验证集对比输出误差。如果误差太大可以尝试用 layer precision 的方式给部分层保留 FP32# 在构建 engine 前通过 network 找到特定层并设置精度 for i in range(network.num_layers): layer network.get_layer(i) if layer.name in [layer_name_xxx]: layer.precision trt.float32 layer.set_output_type(0, trt.float32)INT8 优化则更麻烦需要提供校准数据集calibration dataset让 TensorRT 统计各层输出值的范围然后用量化感知校准。这块如果模型训练时没有做 QAT量化感知训练纯后量化的精度损失通常不小需要大量调试。新手阶段建议先从 FP16 入手稳定后再尝试 INT8。3.4 Engine 序列化为什么存下来的文件换个环境会挂构建好的 engine 可以直接写到磁盘通常叫.trt或.engine文件。这文件是二进制体积一般和权重差不多大。序列化文件与 GPU 架构、TensorRT 版本强绑定换一台不同架构的 GPU甚至换了 TensorRT 小版本都有可能导致反序列化时直接崩溃或者更为隐蔽地性能回退。所以工程上有个实用原则要么在生产机器上现场构建要么把序列化文件纳入 CI 流水线随着镜像一起发布保证构建和运行环境完全一致。4. 实操模型转换与推理模块的完整实现纸上谈兵差不多了这节把完整流程串起来。我以一个常见的分类模型为例展示从 ONNX 导出到 Python 推理的全链路。目录结构简单清晰inference/ ├── export_onnx.py ├── build_engine.py ├── infer.py └── models/ ├── model.onnx └── model.trt4.1 第一步导出带动态轴的 ONNX先确保 PyTorch 模型已经转成 eval 模式然后用torch.onnx.export导出。这一步的关键是设置好dynamic_axes和opset_version。import torch model torch.load(checkpoint.pt) # 替换成自己的模型加载逻辑 model.eval() dummy_input torch.ones(1, 3, 640, 640).cuda() torch.onnx.export( model, dummy_input, models/model.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch}, output: {0: batch}}, opset_version17, do_constant_foldingTrue, verboseFalse, ) print(ONNX exported)导出来后可以用onnxruntime加载检查一下拓扑是否完整import onnxruntime as ort sess ort.InferenceSession(models/model.onnx, providers[CUDAExecutionProvider]) print(sess.get_inputs()[0].shape, sess.get_inputs()[0].type)注意ONNX 版本和 opset 太老容易出兼容问题。opset 18 导出的模型老版本 TensorRT 可能不支持部分算子这方面要保守一点建议固定 opset 版本不要追新。4.2 第二步构建 Engine 并序列化这里我把前面的构建代码整理成一个函数加上对动态 profile 的支持同时做了校验如果磁盘上已有 engine 文件就跳过构建方便多次调试。import tensorrt as trt def build_engine(onnx_path, engine_path, is_dynamicTrue): logger trt.Logger(trt.Logger.WARNING) builder trt.Builder(logger) network builder.create_network(1 int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)) parser trt.OnnxParser(network, logger) with open(onnx_path, rb) as f: if not parser.parse(f.read()): for i in range(parser.num_errors): print(parser.get_error(i)) raise ValueError(ONNX parse failed) config builder.create_builder_config() config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 2 * (1 30)) config.set_flag(trt.BuilderFlag.FP16) if is_dynamic: profile builder.create_optimization_profile() # 修改成你模型真实的输入名和 shape profile.set_shape(input, (1, 3, 640, 640), (1, 3, 1280, 1280), (4, 3, 1280, 1280)) config.add_optimization_profile(profile) engine builder.build_serialized_network(network, config) if engine is None: raise RuntimeError(TensorRT build failed) with open(engine_path, wb) as f: f.write(engine) print(fEngine saved to {engine_path}) build_engine(models/model.onnx, models/model.trt, is_dynamicTrue)这里我提一句构建阶段需要耐心。一个中等复杂的模型构建可能要 1~3 分钟网络搜索所有可行的 kernel 并做 benchmark日志里会看到大量的测试过程。如果开着 WARNING 级别日志你会看到很多 TensorRT 在选择不同 tactic 的输出不要误以为报错。构建时间较长是正常的。4.3 第三步实现 Python 推理模块推理模块的关注点主要有几个反序列化 engine、创建 execution context、绑定输入输出内存、执行前拷贝数据。import tensorrt as trt import numpy as np import torch class TensorRTInference: def __init__(self, engine_path): self.logger trt.Logger(trt.Logger.WARNING) self.runtime trt.Runtime(self.logger) with open(engine_path, rb) as f: self.engine self.runtime.deserialize_cuda_engine(f.read()) self.context self.engine.create_execution_context() self.input_names [] self.output_names [] self.input_ptrs [] self.output_ptrs [] self.input_shapes {} for i in range(self.engine.num_io_tensors): name self.engine.get_tensor_name(i) mode self.engine.get_tensor_mode(name) shape self.engine.get_tensor_shape(name) dtype trt.nptype(self.engine.get_tensor_dtype(name)) if mode trt.TensorIOMode.INPUT: self.input_names.append(name) self.input_shapes[name] shape # 用 torch 张量做显存分配方便后续与 GPU tensor 交互 buf torch.zeros(shape, dtypetorch.float32).cuda() self.input_ptrs.append(buf.data_ptr()) else: self.output_names.append(name) buf torch.zeros(shape, dtypetorch.float32).cuda() self.output_ptrs.append(buf.data_ptr()) def infer(self, input_tensor: torch.Tensor): # 设置动态输入的实际形状 self.context.set_input_shape(self.input_names[0], input_tensor.shape) input_ptr self.input_ptrs[0] input_tensor input_tensor.contiguous() input_ptr_tensor input_tensor.view(-1) # 将数据从 input_tensor 拷贝到内部缓冲区 input_ptr_tensor input_ptr_tensor.to(torch.float32) # 使用 torch 的 copy_ 把张量数据复制进去 self.input_ptrs[0].view(-1).copy_(input_ptr_tensor) # 执行推理 self.context.execute_v2(self.input_ptrs self.output_ptrs) output_buffer self.output_ptrs[0] output torch.empty(self.output_names[0].shape, dtypetorch.float32).cuda() if False else None # 更简单的方式直接把输出张量拷贝出来 out_shape self.context.get_tensor_shape(self.output_names[0]) output torch.zeros(out_shape, dtypetorch.float32).cuda() output.view(-1).copy_(self.output_ptrs[0].view(-1)[: output.numel()]) return output上面是我测试过的可行写法但坦率讲这个版本直接让你看到输入输出绑定和execute_v2的工作方式最直观。实际工作里我建议用TensorRT 官方提供的 PythonEngine封装例子或者自己封装一个更简洁的版本。核心注意点execute_v2需要一个包含所有输入输出指针的列表顺序必须与 engine 中张量声明顺序一致。输入数据在推理前必须contiguous()否则在copy_时会因为内存不连续产生错误结果。动态 shape 时每次推理前必须调用context.set_input_shape更新输入形状否则 engine 会复用上次信息要么报错要么结果错。4.4 用 Python 调用推理服务搭建一个最小的 Flask 服务非常快如果 TPS 要求高我推荐用 FastAPI Uvicorn异步接收请求更顺手import torch from fastapi import FastAPI, UploadFile, File from PIL import Image import torchvision.transforms as transforms app FastAPI() engine TensorRTInference(models/model.trt) transform transforms.Compose([ transforms.Resize((1280, 1280)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), ]) app.post(/predict) async def predict(file: UploadFile File(...)): img Image.open(file.file).convert(RGB) tensor transform(img).unsqueeze(0).cuda() with torch.no_grad(): output engine.infer(tensor) # 这里根据任务做后处理比如 softmax 或 argmax return {prediction: output.cpu().numpy().tolist()}这个示例把整个链路串起来了接收图片 → 预处理 → TensorRT 推理 → 返回结果。对于大多数视觉服务这个骨架可以直接套用。5. 推理性能怎么验证延迟、吞吐与显存实测把 engine 跑起来只是第一步第二步是量化收益不然你没法跟老板汇报加速了多少。我习惯用一套固定的脚本指标在完全相同的输入数据和预热条件下测。5.1 三个核心指标的定义P99 延迟Tail Latency在线推理服务最关注的指标代表 99% 的请求的延迟上界。TensorRT 的 kernel 执行时间波动很小所以 P99 与平均值的差值比 PyTorch 小得多这是一个很好的信号。吞吐量ThroughputIPS每秒能处理的请求数。通常用并发压测获得而不是单线程循环计时否则测的是单流性能。显存占用TensorRT 的显存复用机制能显著降低单位请求的显存开销可以用torch.cuda.max_memory_allocated()或者在服务端通过nvidia-smi监控。5.2 一个有效的基准测试方法最简单直接的是在 Python 里做两轮计时import time import numpy as np def benchmark(model, input_data, num_warmup50, num_runs1000): # 预热 for _ in range(num_warmup): model(input_data) latencies [] for _ in range(num_runs): torch.cuda.synchronize() start time.perf_counter() model(input_data) torch.cuda.synchronize() end time.perf_counter() latencies.append((end - start) * 1000) latencies np.array(latencies) print(fmean: {latencies.mean():.3f} ms) print(fp99: {np.percentile(latencies, 99):.3f} ms) print(fthroughput: {1000 / latencies.mean():.1f} FPS)注意几个细节预热次数不能太少除了让 CUDA 上下文加载完毕还得让 TensorRT 的 kernel 内存在首次运行时完成映射否则第一次推理的耗时是几百毫秒起跳。每次计时前都torch.cuda.synchronize()否则因为 GPU 异步执行你测到的只是入队时间不是真实耗时。测吞吐时最好用并发工具比如gRPC或Locust模拟真实请求单纯 in-process 循环会高估单帧速度。5.3 浮点精度对比加速之外不能丢的准绳除了速度精度对比也很重要。用同一组验证集分别过 PyTorch 和 TensorRT统计平均绝对误差和最大绝对误差。我一般设定一个阈值最大绝对误差不超过 1e-2对归一化后的输出平均绝对误差不超过 1e-4超过就要重点关注层精度设置。FP16 在分类任务上通常误差很小但在检测框回归、关键点坐标这类回归型任务上误差可能直接让结果偏移好几个像素。所以我的建议是精度对比不是跑一次就结束要覆盖最差情况比如极端亮暗图、背景复杂的图这些场景往往才会触发数值敏感的算子。6. 常见问题与排查技巧实录这部分我整理了一份速查表都是自己或身边同事真实遇过的。遇到类似问题可以直接对照看。故障现象根本原因解决办法导入tensorrt报ImportError: libcudnn.so.8系统 CUDA/cuDNN 与 TensorRT 版本不匹配用 Docker 镜像或配置LD_LIBRARY_PATH指向正确版本目录ONNX parse 失败有out of memory或unsupported op算子不受支持或 opset 版本过高升级 TensorRT 版本用onnx-simplifier简化图结构替换不支持的算子构建 engine 时崩溃直接进程被杀显存不足或被其他进程占用调低WORKSPACE上限检查当前显存占用换更大显存机器动态输入推理时报 shape 不匹配没调set_input_shape或 profile 范围不含该 shape在推理前严格设置输入 shape确保在 min/max 范围之内FP16 精度下降明显数值敏感层被转成 FP16对指定层设置 FP32或用 INT8 校准后逐层对比反序列化 engine 报错engine 与当前 GPU 架构或 TensorRT 版本不兼容必须在兼容环境重新构建首次推理特别慢几百 ms 甚至几秒CUDA kernel 首次加载和缓存开销服务启动时做一次预热推理Python 进程内存持续增长推理循环中不断创建张量又未释放复用固定 buffer避免反复torch.zeros和numpy.copy6.1 关于显存溢出的一个隐藏诱因我见过一个很有意思的问题一个小模型输入只有 3×224×224居然报显存不足。后来排查发现构建 engine 时WORKSPACE设得太大TensorRT 构建时确实会尝试占用这么多空间做 kernel 搜索但更隐蔽的是执行上下文context在动态 shape 时会按 profile 里的 max shape 分配显存。如果你 max shape 设成 8 个 4K 图像但实际只跑一个 640 的图像显存也被占掉一大块。所以 profile 的最大值一定要贴近真实需求上限别拍脑袋。6.2 精度调试的几个实操技巧如果 FP16 精度不对我的排查顺序是先整体回到 FP32确认基线。开启 FP16把误差敏感层逐步排查。使用 TensorRT 的ILayer.precision定点设置对卷积层、归一化层、激活层逐一尝试。实在找不到元凶时用二分法先让前半网络 FP32、后半 FP16再反过来试验快速定位是哪个子图出了问题。还有一个偏门但很好用的技巧把输出张量的数值打印下来对比 PyTorch 的输出找第一个出现明显偏差的层。但这个做法需要你自己把网络拆出来操作成本高一般到第四步就够用了。6.3 一个读取 engine 输入输出名的完整技巧在动态 shape 场景下很多人的代码都挂在不知道输入叫什么名上面。TensorRT 10 里可以直接通过num_io_tensors和get_tensor_name遍历所有张量也可以打印出来for i in range(engine.num_io_tensors): name engine.get_tensor_name(i) mode engine.get_tensor_mode(name) print(i, name, mode, engine.get_tensor_shape(name))一个小技巧输入输出在 engine 中的张量名很可能与 ONNX 输入输出名不一致因为 TensorRT 内部会重命名。所以千万别硬编码名字一定通过上面的循环动态获取。7. 结尾心得与工程化建议这套流程走完我最大的体会就是TensorRT 不是简单的换个后端它更像重新编译一次你的模型。核心价值是让同一个模型在生产环境里跑得更快、占得更少而 Python API 完全能够撑起这个目标。最后分享一个工程化建议如果你的推理服务要长期维护不要把 ONNX→Engine 的构建过程硬编码在推理服务启动流程里而是单独抽成一个离线任务。原因有三个构建可能很慢、需要大量显存、并且不同模型的配置差异大。离线构建的好处是能提前发现问题、方便缓存 engine 产物、也让线上服务启动变得轻量干净。另外一个我个人很受益的做法对 engine 做版本管理。因为 engine 和 TensorRT 版本、GPU 架构强绑定每次升级 TensorRT 都可能在线上引发事故。我的做法是给 engine 文件命名时加上 GPU 架构和 TensorRT 版本标识比如model_3090_trt10.0.fp16.engine避免误用旧文件。这件事虽然简单但能省下不少排查时间。
阅读完成 · 觉得有帮助?