
简介面向计算机视觉与深度学习开发者的算法部署实战项目聚焦使用TensorRT优化RTMPose人体姿态估计算法解决直播流、视频监控等场景下的实时推理性能瓶颈。资源共16个文件包含5个C源码文件、4个头文件、2个TensorRT推理引擎文件、Python辅助脚本、Visual Studio解决方案与项目文件整体约63.6MB目录结构清晰可直接参考工程组织方式。项目从理论到实践完整覆盖部署流程先介绍RTMPose的模型结构与关键特性再剖析TensorRT的层融合、精度校准等优化机制随后演示模型导出、转换、校准与序列化步骤并通过优化前后的推理速度、准确率、资源消耗对比验证效果。实战环节提供环境搭建、模型加载与实时推理测试案例帮助读者掌握从源码到可运行推理服务的完整链路。已有246人学习下载适合希望提升模型部署性能的工程师与研究人员参考。1. RTMPose部署实战这份项目包解决的是你上线时最头疼的帧率问题一个训练好的RTMPose模型在PyTorch里跑推理T4卡上单实例延迟轻松超过二十毫秒一旦业务要求1080p25帧每秒实时处理帧率立刻不够用。这个标题里的项目包做的就是典型算法部署动作把RTMPose人体姿态估计模型从PyTorch权重转成TensorRT引擎再落到可复用的推理代码上。它解决的是算法工程师和部署工程师最常撞上的那堵墙——模型效果够了但速度上不去。TensorRT做的是层融合、算子替换、半精度和INT8量化专吃NVIDIA GPU的红利。RTMPose这类基于SimCC坐标分类的模型输出没有热图后处理的负担结构规整是非常适合走TensorRT的一条链路。这个方向值不值得投入取决于你的场景是否有实时性要求和GPU成本压力下面从原理、环境、导出、转换、推理到避坑完整拆开讲。2. 先立住理论RTMPose的算法结构与TensorRT部署选型2.1 为什么RTMPose适合走TensorRT这条部署链路RTMPose是MMPose仓库里的一套人体姿态估计模型它的核心创新在SimCCSimplified Coordinate Classification这个解码方式。传统姿态估计模型输出的是一个K通道的热图每个通道对应一个关键点空间尺寸和特征图一致RTMPose把问题简化成了坐标分类——每个关键点在x方向输出一个长度为W的概率分布在y方向输出一个长度为H的概率分布分布里峰值的位置就是关键点的坐标。这个改动对部署极其友好。热图方案的后处理要做argmax、高斯拟合甚至多尺度融合而SimCC只需要对分布向量做Softmax再算期望后处理代码减少到几行。同时输出张量从K×H×W变成了K×W加K×H显存占用和访存开销都降了一个量级。RTMPose的主干网络用的是CSPNeXt这类CNN结构没有Transformer里的动态序列操作和复杂maskONNX导出时几乎不会遇到算子断层。我在实际项目里对比过RTMPose和HRNet的部署体验HRNet的并行分支结构导出ONNX没问题但TensorRT转换时经常出现层融合不充分、延迟压不下去的情况RTMPose的结构相对规整TensorRT的图优化能把它拆得很狠。如果你要部署的姿态估计模型还没定优先考虑RTMPose这个系列的模型是合理的。另外要注意RTMPose走的是Top-Down流程前面要接一个行人检测器把人框出来再裁剪送进姿态模型。这个项目包如果只覆盖姿态模型部分检测器需要你自行配套后面所有性能分析都离不开这条完整链路。2.2 TensorRT相比ONNX Runtime和OpenVINO的取舍同是一份ONNX模型在NVIDIA GPU服务器上做推理备选方案里有ONNX Runtime、OpenVINO和TensorRT三个主流选项。ONNX Runtime通用性最好CPU、GPU都能跑装个Python包就能用适合快速验证结果对不对。OpenVINO在Intel平台上有优势放到NVIDIA卡上性能表现一般。TensorRT是NVIDIA自己出的推理引擎专门针对自家GPU的架构做kernel级优化支持FP16和INT8量化性能压得最狠。TensorRT换来的是更高的复杂度。engine文件和GPU架构、TensorRT版本、CUDA版本强绑定换一张卡、升一个版本engine就得重新生成。trtexec转换时还可能遇到个别算子没有实现、量化校准后精度掉点等问题。所以选型逻辑应该是GPU是NVIDIA、服务端并发压力大、延迟敏感值得上TensorRT只是内部验证、跨平台交付先用ONNX Runtime。我见过不少团队把ONNX Runtime当成最终方案部署结果单实例延迟下不来GPU数量翻倍最后还是回头上TensorRT。性能上TensorRT能带来多少收益取决于模型本身。纯CNN结构的RTMPoseFP16通常能做到比PyTorch快两到三倍INT8能再快一倍左右。但INT8的精度损失要看校准集质量这个后面展开。选型时要留好“先FP16保精度再INT8追性能”的节奏不要一上来就上INT8。2.3 RTMPose版本选择与部署成本的对应关系RTMPose按模型规模分成t、s、m、l几档分别对应不同算力平台和精度需求。RTMPose-t和RTMPose-s适合边缘GPU和低延迟场景模型小、显存占用低推理速度快但精度在复杂姿态上会弱一些。RTMPose-m是服务器端最常用的中间档精度和速度平衡得好。RTMPose-l追求极致精度但延迟和显存开销都上去了适合离线批处理或者对精度极其敏感的业务。部署成本不能只看模型本身还要看输入分辨率和单帧人数。同样是RTMPose-m输入从192×256提到384×288TensorRT延迟可能翻倍。同一张画面里如果有十个人Top-Down流程就要对每个检测框各跑一次姿态模型成本按人数线性增长这时候算力瓶颈往往不在模型单次延迟而在检测框数量。实际项目里单人或少量人物场景用RTMPose-s或m192×256输入T4上FP16能跑出非常理想的延迟大流量多人的视频分析场景要优先优化检测器的帧率和batch策略而不是盲目升级RTMPose版本。模型版本适合场景部署侧关注点RTMPose-t边缘设备、低延迟算子精简INT8量化收益大RTMPose-s单路实时、轻量服务192×256输入FP16性价比高RTMPose-m服务器端主力平衡点适合batch推理RTMPose-l离线分析、高精度显存占用大优先保精度3. Ubuntu环境搭建与PyTorch到ONNX导出3.1 环境版本搭配最重要的原则TensorRT部署第一步不是写代码是把环境趟平。版本矩阵错了后面每一步都在绕路。这套项目实战包最常见的技术栈是Ubuntu 20.04或22.04、NVIDIA驱动、CUDA、cuDNN、TensorRT、PyTorch每个都有版本兼容性问题。我给出的推荐组合是基于大量项目验证过的稳定搭配组件推荐版本范围注意事项Ubuntu20.04 / 22.04不要追最新版驱动兼容性风险大NVIDIA驱动470 / 525以你的GPU型号为准新卡用新驱动CUDA11.8 / 12.1与TensorRT官方构建对齐cuDNN8.9版本跟着TensorRT依赖走TensorRT8.6 / 10.x存量项目用8.6新项目用10.xPython3.8 - 3.10TensorRT wheel覆盖有限TensorRT 8.6是存量项目的主力文档多、坑都被踩平了。TensorRT 10.x改了一些API名称比如workspace参数变成memPoolSize老代码要跟着调整。新项目我倾向于直接用10.x因为它对新GPU架构支持更好只要ONNX导出的opset版本不低于17基本不会卡在算子兼容上。3.2 Ubuntu安装TensorRT的常见做法tar包还是deb包Ubuntu上安装TensorRT常见做法有三种官方apt源安装deb包、官方tar包解压、pip安装Python wheel。deb包会把TensorRT、依赖库装进系统目录卸载和升级容易出连锁问题tar包解压到指定目录干净可控卸载直接删目录。我习惯用tar包方式把TensorRT放到/opt下然后在shell配置里导出环境变量export TRT_ROOT/opt/TensorRT-10.x.x.x export LD_LIBRARY_PATH$TRT_ROOT/lib:$LD_LIBRARY_PATH export PATH$TRT_ROOT/bin:$PATH部分项目也会用pip安装tensorrt包这个能快速拿到Python侧的API但trtexec命令行工具和C开发库还是需要tar包或deb包补全。这里有个常见的坑只用pip装完以为trtexec也能用执行时提示命令找不到就是漏了bin目录的环境变量。安装完成后做一次简单验证确认环境真的就绪。在Python里执行tensorrt.version在命令行执行trtexec --version两个都正常再继续。3.3 PyTorch模型导出ONNX从权重文件到干净的计算图RTMPose模型按照MMPose仓库的结构训练和保存导出时使用仓库自带的tools/deploy.py是最稳妥的方式。它会自动处理模型结构里的自定义算子生成适合推理框架的ONNX图。基本命令格式如下python tools/deploy.py \ configs/body_2d_keypoint/rtmpose/rtmpose.py \ /path/to/rtmpose.pth \ --device cuda \ --output rtmpose.onnx \ --dynamic-export如果不使用MMPose的导出脚本也可以用torch.onnx.export手动导出但需要额外处理动态轴和输出名称。手动导出时最关键的是把batch维度标成动态否则TensorRT推理时batch只能固定没法做多路并发。参考代码import torch model.load_state_dict(torch.load(rtmpose.pth)) model.eval() dummy_input torch.randn(1, 3, 192, 256).cuda() torch.onnx.export( model, dummy_input, rtmpose.onnx, input_names[input], output_names[x_out, y_out], dynamic_axes{input: {0: batch}, x_out: {0: batch}, y_out: {0: batch}}, opset_version17, )RTMPose的SimCC输出是x和y两个方向的分布向量导出时给它们起清晰的名字很重要。我踩过的一个坑是导出后不看ONNX的输入输出节点名就去转TensorRT结果engine里的输出索引和代码里写的不一致后处理数据全是乱的。导出后先用ONNX Runtime跑一遍对比PyTorch和ONNX的输出误差控制在1e-4级别再往下一个环节走。这一步做了后面TensorRT的调试成本会低很多。3.4 检查ONNX计算图的完整工具链导出ONNX之后还有一步检查工作就是确认计算图里有没有可疑的算子。用Python加载ONNX文件遍历节点是比较直接的做法import onnx model onnx.load(rtmpose.onnx) onnx.checker.check_model(model) for node in model.graph.node: if node.op_type not in [Conv, Relu, Resize, Softmax, Gemm]: print(node.op_type, node.name)遇到DeformableConv2D这类算子时TensorRT 8.6及以上版本部分支持但转换策略和普通卷积不同要留意trtexec的报错信息。还有一种做法是使用onnxsim对计算图做简化把常量折叠、冗余节点清理掉TensorRT转换时间会缩短生成的engine也更干净。onnxsim在RTMPose这类模型上的效果比较明显推荐加上。4. 从ONNX到TensorRT引擎trtexec、FP16/INT8与推理代码4.1 用trtexec快速生成FP16引擎拿到干净的ONNX文件接下来是TensorRT部署的核心动作——转换engine。trtexec是TensorRT自带的命令行工具加载ONNX、做图优化、kernel选择、生成engine一条龙。FP16是性价比最高的一档转换简单速度快一倍左右精度损失很小。基本命令/opt/TensorRT/bin/trtexec \ --onnxrtmpose.onnx \ --saveEnginertmpose_fp16.engine \ --fp16 \ --minShapesinput:1x3x192x256 \ --optShapesinput:1x3x192x256 \ --maxShapesinput:4x3x192x256参数含义逐一说清楚。--onnx指定输入模型文件--saveEngine指定输出engine路径--fp16开启半精度推理--minShapes、--optShapes、--maxShapes分别对应动态batch的最小、最优、最大三个档位。TensorRT在转换时会对这三个档位分别做kernel选择运行时传入的batch必须落在min和max之间同时越接近optShapes性能越好。TensorRT 10.x用户需要注意旧版本的--workspace参数已经改名为--memPoolSize命令报参数错误时用新参数名。转换完成后trtexec会打印一段性能统计包含平均延迟、显存占用。这段输出建议留存它记录的是整个engine在当前GPU上的基准性能后面做压测和调优时是重要的对照基线。engine文件和GPU强绑定同一份ONNX在A100上转出的engine不能放到T4上跑这是TensorRT最需要记住的特性。4.2 INT8量化校准数据决定成败FP16满足不了延迟要求时再上INT8。INT8能把模型体积和计算量再压缩一半但代价是需要校准。TensorRT通过校准过程统计每一层激活值的分布计算量化参数。这里有一个实际项目里反复出现的教训校准数据必须来自真实业务场景覆盖不同光照、姿态、角度数量越多越好。用公开数据集校准、线上跑自己的视频流关键点坐标会出现肉眼可见的漂移。trtexec支持直接指定校准数据文件/opt/TensorRT/bin/trtexec \ --onnxrtmpose.onnx \ --saveEnginertmpose_int8.engine \ --int8 \ --calib/path/to/calibration.bin如果采用Python API做校准需要实现TensorRT的IInt8Calibrator接口核心是提供校准图像batch。常见做法是先把校准图片预处理成模型输入格式存成二进制文件再在Calibrator里按batch读取。校准集规模建议至少500张代表性图片每张图要包含完整的单人姿态不要只截上半身否则躯干和腿部关键点的量化误差会放大。INT8转换完成后必须做精度对比验证。对比指标通常用关键点坐标的欧氏距离或OKSObject Keypoint Similarity。平均坐标误差在2到3个像素以内是合理范围超过这个值就需要检查校准集质量或考虑混合精度让敏感层保持FP16。RTMPose是SimCC结构量化误差容易出现在分布向量的尾部如果校准集覆盖不充分解码出的坐标会在相邻帧之间来回跳。4.3 Python推理代码从engine文件到关键点坐标engine文件准备好后推理代码的核心是创建ExecutionContext、分配显存buffer、执行一次前向。一个最小可跑的Python推理骨架如下import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np logger trt.Logger(trt.Logger.WARNING) runtime trt.Runtime(logger) with open(rtmpose_fp16.engine, rb) as f: engine runtime.deserialize_cuda_engine(f.read()) context engine.create_execution_context() # 分配host和device内存 h_input np.zeros((1, 3, 192, 256), dtypenp.float32) h_x_out np.zeros((1, 17, 192), dtypenp.float32) h_y_out np.zeros((1, 17, 256), dtypenp.float32) d_input cuda.mem_alloc(h_input.nbytes) d_x_out cuda.mem_alloc(h_x_out.nbytes) d_y_out cuda.mem_alloc(h_y_out.nbytes) bindings [int(d_input), int(d_x_out), int(d_y_out)] stream cuda.Stream() # 输入拷贝到显存并执行 cuda.memcpy_htod_async(d_input, h_input, stream) context.execute_async_v2(bindings, stream.handle) cuda.memcpy_dtoh_async(h_x_out, d_x_out, stream) cuda.memcpy_dtoh_async(h_y_out, d_y_out, stream) stream.synchronize()这段代码的逻辑说明先反序列化engine文件得到engine对象再创建执行上下文。输入和输出张量分别分配host端和device端内存bindings列表里放的是device内存指针。execute_async_v2在指定的CUDA stream上异步执行最后同步等待结果。核心注意点有三个bindings的index顺序必须和engine里的输入输出顺序一致执行前如果使用动态batch需要调用context.set_binding_shape设置当前实际shape整个推理过程一定在PyTorch的torch.no_grad模式下做避免额外构建计算图占用显存。4.4 SimCC后处理从分布向量解码出17个关键点RTMPose的输出和常规热图不同x_out和y_out分别代表关键点在x和y方向上的坐标分布。解码逻辑分为三步对分布做Softmax归一化、用位置索引做加权求和、乘缩放系数映射回原图坐标。def decode_simcc(x_out, y_out, scale_x, scale_y): B, K, W x_out.shape x_coords np.zeros((B, K), dtypenp.float32) y_coords np.zeros((B, K), dtypenp.float32) for i in range(K): px np.exp(x_out[0, i, :] - np.max(x_out[0, i, :])) px / px.sum() x_coords[0, i] (px * np.arange(W)).sum() py np.exp(y_out[0, i, :] - np.max(y_out[0, i, :])) py / py.sum() y_coords[0, i] (py * np.arange(H)).sum() x_coords * scale_x y_coords * scale_y return x_coords, y_coords参数scale_x和scale_y的算法是原图宽度除以输入宽度、原图高度除以输入高度。如果你在预处理时做的是等比例缩放加padding那么还需要减去padding偏移量。这里有一个高频翻车点导出ONNX时如果不做任何特殊处理模型输出的分布是未经过Softmax的logits直接拿去做argmax或加权坐标整体会偏移甚至出现NaN。正确做法一定是先做Softmax。区分方法很简单拿PyTorch模型的原始输出和TensorRT输出对比两者的数值范围一致再进解码。4.5 性能压测单实例延迟和多线程吞吐压测分两个层次第一层是单实例网络执行延迟第二层是真实服务端的多线程吞吐。单实例延迟用CUDA event计时最准确不要用Python的time.time()它计的是CPU墙钟中间有PCIe拷贝和context切换的干扰。多线程吞吐的结论很明确TensorRT的ExecutionContext不是线程安全的每个线程必须创建自己的context显存buffer可以共享但context不能。常见错误是在多线程脚本里只创建一个context然后用锁去串行化执行这样延迟虽然稳定但吞吐永远上不去。正确的多线程做法是每个线程加载一次engine或共享engine对象各自创建context然后把预处理好的图像输入拼成batch一次execute处理多张图。batch推理对TensorRT的吞吐提升非常明显尤其是RTMPose这类计算密集型CNN模型batch从1提到4总吞吐通常能提升两倍以上。但这个结论受显存限制batch越大显存占用越高需要根据GPU显存实测。5. 部署避坑清单七个高频问题与排查办法5.1 trtexec转换时报错提示算子不支持现象trtexec运行到一半中止报错信息包含Unsupported Operator或Plugin之类的关键词例如DeformableConv2D。 原因RTMPose某些变体的backbone里使用了可变形卷积PyTorch导出ONNX时把这个自定义算子原样保留TensorRT内置算子库没有对它的标准实现。 解决优先使用MMDeploy或MMPose自带的部署工具导出它们会自动处理这类自定义算子的替换。如果手动导出导致转换失败可以把DCN层退化替换为标准卷积重新训练或微调精度损失通常可控。备选做法是自己写TensorRT plugin但工作量较大不建议在初版部署时走这一步。我在项目里遇到过几次全部是换导出工具链解决的。5.2 FP16推理精度明显下降关键点偏移量超过5个像素现象FP16 engine跑出来的坐标和PyTorch的FP32结果差异很大尤其是手指、脚踝这类远端关键点。 原因FP16把激活值的动态范围压缩到约5位有效数字某些层对精度极其敏感误差在深层网络里被放大。RTMPose的SimCC解码对分布尾部的数值敏感单点误差会被放大到坐标偏移。 解决先定位敏感层逐个层测试FP16和FP32的精度差异。TensorRT支持按层设置精度可以把最后几个输出层锁定为FP32。具体做法是在ONNX导出时给敏感层设置名称转换时通过精度控制策略指定这些层强制FP32计算。如果问题集中在输出分布层优先保住最后三个算子的精度。5.3 engine文件在一台机器上生成到另一台机器反序列化失败现象engine文件拷贝到另一台相同型号GPU的机器上运行时抛错Cuda Error或Engine File Not Compatible。 原因engine文件和TensorRT版本、CUDA版本、GPU计算能力强绑定。哪怕GPU型号一样TensorRT版本不同文件格式也不兼容。 解决把ONNX当作持久化的事实来源engine永远作为缓存现场生成。部署时先看目标机器的TensorRT版本用对应版本的trtexec重新转换。这一步没有捷径市面上不存在跨版本通用engine的说法。我习惯把转换命令写成一个shell脚本每次部署新环境只需要改TRT_ROOT路径一分钟以内重建engine。5.4 INT8校准后精度测试通过了但线上新数据表现不稳定现象校准集上精度验证正常线上真实视频流里关键点出现间歇性抖动尤其是暗光和运动模糊场景。 原因校准集和线上数据分布不同。TensorRT的INT8量化参数是根据校准数据统计出来的如果校准集里没有暗光、低对比度、运动模糊的样本量化后这些场景的激活值落在低精度区间。 解决校准数据尽可能贴近线上真实数据。从线上采集不同时段、不同摄像机位、不同光线条件下的图像最少500张剔除完全一样的重复帧。校准数据的预处理管线必须和推理时的预处理完全一致包括通道顺序、归一化系数、缩放尺寸。5.5 Python推理时显存占用持续增长最后OOM现象服务运行几个小时显存占用缓慢爬升最终报CUDA Out of Memory。 原因PyCUDA的mem_alloc申请显存后如果变量被重新赋值旧显存块没有立即释放。Python的垃圾回收机制不会马上触发加上TensorRT的context本身也持有显存。 解决把所有显存buffer在初始化阶段统一分配整个服务生命周期内复用不要每次推理都重新申请。如果需要频繁调整输入shape使用context.set_binding_shape动态变更避免反复分配device内存。另一个隐蔽坑是每个线程都load一次engine显存重复占用合理做法是共享同一个engine反序列化后的对象只新建context。5.6 多路视频流场景GPU利用率低但延迟超高现象开了8路视频流GPU利用率只有30%但每路延迟都超过100毫秒。 原因CPU预处理和GPU推理串行了。视频解码、缩放、归一化都在Python主线程里做GPU推理等着CPU的数据两个环节没有重叠。 解决用生产者消费者模型拆分CPU和GPU负载。视频解码和图像预处理放到独立线程池或进程池预处理结果放入队列GPU推理线程只消费队列里的数据。另一个有效做法是把多路视频帧拼成batch做推理TensorRT对batch的优化比单帧串行高很多。压测时重点观察CPU核数和GPU利用率两条曲线如果CPU先到瓶颈增加预处理并行度如果GPU打满再考虑检测器是否在等姿态模型。5.7 同一个模型转出来的engine在不同batch下延迟波动非常大现象trtexec测试batch1时延迟优秀但服务端实际跑batch4时延迟翻了两倍以上不升反降。 原因TensorRT生成engine时用的是optShapes对应的kernel。如果你转换时把optShapes设成了batch1engine里优化的是batch1的kernel实际跑到batch4时kernel选择可能退化为保守策略。 解决转换时把optShapes设为实际业务中最常见的batch大小。如果服务峰值batch波动大用多个engine分别对应不同batch区间运行时按请求量路由。这个细节在官方文档里写得不显眼但直接影响吞吐我在这上面吃过亏后来在转换脚本里把optShapes改成业务均值batch再重新转延迟曲线立刻正常了。6. 双轨压测方法、T4级多路支撑与部署前后验证6.1 用trtexec和自写压测脚本双轨验证性能压测要跑两条线一条是trtexec的标准输出记录纯engine的网络延迟另一条是自写脚本记录包含预处理、后处理在内的端到端延迟。trtexec的统计是理想化的它不经过视频解码和数据拷贝自写脚本才代表真实服务体验。压测时记录P50、P95、P99三个分位的延迟姿态估计服务最怕的是长尾延迟P99如果超过50毫秒用户体验会明显卡顿。/opt/TensorRT/bin/trtexec \ --loadEnginertmpose_fp16.engine \ --shapesinput:1x3x192x256 \ --duration30 \ --percentile99上述命令读取已有engine固定输入shape跑30秒输出99分位延迟。这个数字作为理论下限自写压测脚本实测出来的端到端延迟正常会在它的1.5倍到2倍之间超过3倍就要检查预处理和后处理是否有瓶颈。6.2 T4上跑1080p25帧每秒能支撑多少路视频流算路数前先明确一个概念单路1080p25帧的每帧时间预算是40毫秒。Top-Down流程下单帧处理时间等于检测单帧时间加检测框数量乘单人姿态推理时间。RTMPose在T4上FP16的毫秒级延迟是真实可期的但加上检测器和解码后单帧总耗时往往在10毫秒以上。场景单帧估算耗时25帧每秒下理论路数单人或双人场景检测姿态串行10-16ms2-4路检测器和姿态模型配合batch推理6-10ms4-6路再加上INT8量化4-7ms6-8路要紧的是理解这个表是粗算。T4的FP16算力约为65 TFLOPS你的实际路数取决于模型版本、输入分辨率、平均人数、检测框数量。一个低调结论CPU端预处理往往先到瓶颈视频流的路数受解码能力限制比受GPU限制更早。如果业务目标是8路以上优先上独立解码卡或GPU硬解而不是只压模型延迟。6.3 部署前后如何验证关键点精度没丢上线前必须做一次部署一致性验证。准备200张有标注的评测图片先跑PyTorch模型得到参考坐标再跑TensorRT engine得到部署坐标统计每个关键点的平均坐标误差和OKS指标。经验红线是两个像素以内的平均误差OKS下降不超过1%。如果超了先排查预处理差异再排查FP16/INT8量化影响。def evaluate(onnx_scores, trt_scores, oks_sigma0.1): delta np.abs(onnx_scores - trt_scores) mean_delta delta.mean(axis1) oks np.exp(-delta ** 2 / (2 * oks_sigma ** 2)).mean(axis1) return mean_delta, oks这个脚本的阈值可以根据业务调整但思路固定坐标误差和OKS双指标并行单看坐标误差可能忽略分布偏移。我在项目中养成的习惯是把验证脚本固定存放在部署项目里每次更换TensorRT版本或GPU型号后重新生成engine并跑一遍验证脚本确保精度指标没有回归。这套RTMPose部署方案的完整闭环价值不在于engine本身而在于你掌握了一条从PyTorch权重到可上线服务的可靠流水线以及一套保得住精度和延迟的验证方法。转换工具、校准脚本、压测方式、验证指标这些沉淀下来下次再部署类似模型时就能直接复用同一套方法论。希望这份笔记能帮你在实际部署RTMPose时少走几趟弯路。本文还有配套的精品资源点击获取