如何解析trtexec输出的模型推理结果数据

该博客介绍了如何使用trtexec工具解析ONNX模型高效Det-D0的输出,并将结果保存到JSON文件中。内容涉及了对输出数据的后处理,包括非极大值抑制(NMS),以在图像上绘制识别结果的边界框。同时,提供了使用PyTorch和ONNXRuntime的代码示例,展示如何将模型输出转换为与trtexec相同格式的JSON文件。

还是以onnx为例,执行下面的命令解析onnx生成engine并推理输出结果到一个json文件:

./trtexec --onnx=efficientdet-d0-s.onnx --loadInputs='data':o4_clip-1_raw_data.bin --saveEngine=efficientdet-d0-s.engine  --exportOutput=trtexec-result.json

这个--exportOutput指定的json文件里保存的是network的输出节点的数据,对于我修改过的efficientdet网络的输出节点有三个:regression、anchors和classification,那么这个json文件的内容类似如下:

[
  { "name" : "regression"
  , "dimensions" : "1x49104x4"
  , "values" : [ 5.78506, 6.88422, -1.56519, -17.5148, -0.113892, 0.545003, -1.52597, -0.767865, 1.00629, 0.163376, 0.0242282, -1.89316, 0.187985, 0.499627, -0.414611, -2.14051, 0.371698, 0.478594, -0.0126426, 2.01423, 0.997112, 0.517545, 1.88847, -0.707338, 0.157562, 0.0627687, 0.10975, -0.430063, 0.537361, 0.670655, 0.428142, ...]},
  { "name" : "anchors"
  , "dimensions" : "1x49104x4"
  , "values" : [ -12, -12, 20, 20, -7.2, -18.4, 15.2, 26.4, -18.4, -7.2, 26.4, 15.2, -16.1587, -16.1587, 24.1587, 24.1587, -10.1111, -24.2222, 18.1111, 32.2222, -24.2222, -10.1111, 32.2222, 18.1111, -21.3984, -21.3984, 29.3984, 29.3984, -13.7789, -31.5578, 21.7789, 39.5578, -31.5578, -13.7789, 39.5578, 21.7789, -12, ...]},
  { "name" : "classification"
  , "dimensions" : "1x49104x1"
  , "values" : [ 0.000323705, 3.062e-07, 0.00457684, 0.000632869, 0.0004986, 0.000207652, 0.000125256, 6.19738e-07, 0.0203817, 8.39792e-06, 8.40121e-09, 9.50497e-05, 9.16859e-06, 2.48826e-05, 1.39859e-06, 3.46441e-06, 2.93581e-08, 0.000207522, 6.74278e-06, 1.8361e-08, 3.44744e-05, 3.35026e-06, 2.89377e-05, 3.85066e-07, 1.02452e-05,...]}
]

怎么把它这个结果解析出来并过滤处理成最终的结果并且在图上画出识别结果的bbox来呢?这个和一般的模型的post process是类似的,需要结合网络本身设计对输出数据做后处理得出合理的bbox和对应的class以及score,针对我这个修改过的efficientdet导出的onnx调用trtexec推理得到的json结果数据进行解析的相关代码如下:

#encoding: utf-8
import numpy as np
import os
import cv2
import json

classes = ['baggage']

def nms(bboxes, classifictaion, thresh):
    
    x1 = bboxes[:, 0]
    y1 = bboxes[:, 1]
    x2 = bboxes[:, 2]
    y2 = bboxes[:, 3]
    scores = classifictaion[:, 1]

    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.min
<think> 我们正在处理的问题:用户询问YOLOv8模型ONNX转换为TensorRT格式后推理结果输出异常的解决方案。 根据用户提供的引用(虽然用户说这些引用仅供参考,但我们可以从中提取相关信息): 引用[1]提到将yolov3_tiny.onnx转成trt后,获得了显著的加速效果(FPS 400+,推理时间2-3ms),但用户现在遇到的是转换后推理结果异常的问题。 引用[2]展示了一个yolov8 onnx转trt的命令行示例:`python3 build.py --weights yolov8s.onnx --iou-thres 0.65 --conf-thres 0.25 --topk 100 --fp16 --device cuda:0`,这可能是转换过程中使用的参数。 用户的问题:转换后的模型推理结果输出异常。 我们需要分析可能的原因并提供解决方案。以下是常见的原因和对应的解决方案: 1. **转换过程中出现错误**:在转换过程中,可能由于某些操作(如层融合、量化)导致模型结构改变,从而输出错误。 - 解决方案:确保转换过程没有报错,检查转换日志。尝试使用TensorRT的`trtexec`工具进行转换并查看详细日志。 2. **输入/输出节点不匹配**:ONNX模型和转换后的TensorRT引擎的输入输出节点可能不一致,导致数据传递错误。 - 解决方案:确认转换前ONNX模型的输入输出节点名称和TensorRT引擎的输入输出节点名称一致。在转换时,确保正确指定了输入输出的名称和维度。 3. **精度问题**:在转换时使用了FP16或INT8量化,可能导致精度损失,从而引起输出异常(尤其是小目标检测)。 - 解决方案:尝试使用FP32模式转换(去掉`--fp16`选项),看是否恢复正常。如果问题消失,则说明量化导致精度损失,需要检查量化过程(如校准数据集是否具有代表性)。 4. **后处理错误**:YOLOv8的输出后处理(如非极大值抑制NMS)可能在转换过程中被修改,或者在推理代码中未正确处理TensorRT引擎的输出- 解决方案:检查转换后的模型输出维度是否与ONNX模型一致。在转换时,有时会改变输出格式(例如,合并检测框和类别分数)。确保推理代码中的后处理部分针对TensorRT输出格式进行了调整。 5. **版本兼容性问题**:使用的TensorRT版本与导出的ONNX模型版本可能存在兼容性问题。 - 解决方案:确保使用的TensorRT版本支持ONNX模型中的算子。可以尝试更新TensorRT到最新版本,或者使用ONNX Simplifier对ONNX模型进行简化。 6. **预处理不一致**:在推理时,输入图像的预处理(如归一化、归一化参数、缩放)必须与训练时一致。 - 解决方案:检查推理代码中的预处理步骤是否与训练时相同。 7. **动态维度问题**:YOLOv8的ONNX模型可能包含动态维度(batch size,图像尺寸),转换时未正确处理。 - 解决方案:在转换时显式指定输入尺寸(固定维度),例如使用`trtexec`时指定`--minShapes`、`--optShapes`、`--maxShapes`。 8. **自定义算子问题**:YOLOv8中可能包含一些特殊操作(如SiLU激活函数),这些操作可能不被TensorRT直接支持。 - 解决方案:确保TensorRT版本支持这些算子(如TensorRT 8.0+支持SiLU)。如果不支持,可能需要使用插件(plugin)或者修改模型结构。 基于以上分析,我们逐步提供解决方案: ### 步骤1:验证ONNX模型 在转换之前,确保ONNX模型ONNX Runtime上推理结果正确。可以使用以下代码验证: ```python import onnxruntime as ort import numpy as np # 加载ONNX模型 session = ort.InferenceSession("yolov8s.onnx") input_name = session.get_inputs()[0].name output_name = [output.name for output in session.get_outputs()] # 准备输入数据(假数据,需与训练预处理一致) dummy_input = np.random.randn(1, 3, 640, 640).astype(np.float32) # 假设输入尺寸为640x640 # 推理 outputs = session.run(output_name, {input_name: dummy_input}) # 检查输出是否合理 ``` ### 步骤2:转换时使用详细日志 在转换过程中,打开详细日志,查看是否有错误或警告。例如,使用`trtexec`转换: ```bash trtexec --onnx=yolov8s.onnx --saveEngine=yolov8s.engine --fp16 --verbose ``` 注意观察日志中是否有不支持的层或错误。 ### 步骤3:检查转换后的引擎 使用TensorRT的API加载引擎并运行推理,同时与ONNX推理结果对比(使用相同的输入数据): ```python import tensorrt as trt import pycuda.driver as cuda import pycuda.autoinit import numpy as np # 加载引擎 logger = trt.Logger(trt.Logger.WARNING) with open("yolov8s.engine", "rb") as f, trt.Runtime(logger) as runtime: engine = runtime.deserialize_cuda_engine(f.read()) # 创建执行上下文 context = engine.create_execution_context() # 分配输入输出内存(根据引擎绑定的输入输出) # 注意:需要根据引擎信息获取输入输出名称和尺寸 # 这里假设只有一个输入和一个输出 input_binding = engine[0] # 第一个绑定为输入 output_binding = engine[1] # 第二个绑定为输出 # 创建输入输出缓冲区(GPU内存) input_buffer = cuda.mem_alloc(dummy_input.nbytes) # dummy_input为步骤1中的输入 output_buffer = cuda.mem_alloc(output_size) # 输出尺寸需要根据模型确定 # 执行推理 stream = cuda.Stream() cuda.memcpy_htod_async(input_buffer, dummy_input, stream) context.execute_async_v2(bindings=[int(input_buffer), int(output_buffer)], stream_handle=stream.handle) cuda.memcpy_dtoh_async(output_data, output_buffer, stream) # output_data为numpy数组 stream.synchronize() # 对比ONNX输出TensorRT输出 # 如果输出差异很大,说明转换有问题 ``` ### 步骤4:调整转换参数 如果使用FP16出现问题,尝试使用FP32(去掉`--fp16`选项)。同样,如果使用了INT8,确保校准数据集合适。 ### 步骤5:检查后处理 在YOLOv8中,输出通常是多个检测头(不同尺度)的拼接。在TensorRT转换后,输出格式可能变化(例如,转换工具可能将多个输出合并为一个输出)。需要检查转换后的输出结构,并调整后处理代码。 例如,原始YOLOv8的ONNX模型可能有三个输出(对应三个检测头),而转换后TensorRT引擎可能只有一个输出(将所有检测结果合并)。因此,需要根据转换后的输出维度调整后处理代码。 ### 步骤6:使用最新的转换工具 确保使用的TensorRT版本是最新的,并且支持YOLOv8的所有算子。可以尝试使用Ultralytics官方提供的转换工具(如果有)。 总结:YOLOv8 onnx转trt后输出异常,主要排查方向是转换过程是否正确、精度设置、输入输出处理和后处理代码调整。按照上述步骤逐一排查。 §§相关问题§§ 1. 如何使用TensorRT Python API加载引擎并推理? 2. YOLOv8的后处理(非极大值抑制)如何实现? 3. ONNX模型如何简化以提高转换成功率? </think> ### YOLOv8 ONNXTensorRT推理结果异常的解决方案 当YOLOv8模型ONNX转换为TensorRT格式后出现推理结果异常(如检测框错位、置信度异常或漏检),主要原因包括转换误差、精度损失和后处理兼容性问题。以下是系统性的排查解决方案: --- #### 一、检查转换过程(核心环节) 1. **验证ONNX模型正确性** 转换前先用ONNX Runtime验证原始ONNX模型推理结果: ```python import onnxruntime as ort import numpy as np sess = ort.InferenceSession("yolov8s.onnx") inputs = {"images": np.random.rand(1, 3, 640, 640).astype(np.float32)} outputs = sess.run(None, inputs) # 检查输出格式是否符合预期 ``` **异常处理**:若此处输出异常,需重新导出ONNX(使用`export(format='onnx')`时确保`dynamic=False`)[^2]。 2. **TensorRT转换参数优化** 参考引用[2]命令调整关键参数: ```bash # 强制使用FP32避免精度损失 python3 build.py --weights yolov8s.onnx --fp32 ``` - 若原命令含`--fp16`,移除后重试(FP16可能导致小目标检测失效) - 添加`--verbose`查看详细层融合日志,排查unsupported layers 3. **动态维度处理** YOLOv8默认输出动态维度,在转换时需显式固定: ```bash # 指定输入/输出维度 trtexec --onnx=yolov8s.onnx --saveEngine=yolov8s.engine \ --minShapes=images:1x3x640x640 \ --optShapes=images:1x3x640x640 \ --maxShapes=images:1x3x640x640 ``` --- #### 二、推理阶段调试 1. **输入数据一致性验证** TensorRTONNX的输入预处理需完全一致: ```python # 检查预处理顺序:RGB转换 -> 归一化 -> 缩放 input_tensor = cv2.dnn.blobFromImage(image, scalefactor=1/255.0, size=(640,640), swapRB=True) ``` 2. **输出解析修正** TensorRT可能合并输出层,需调整后处理逻辑: ```python # 原ONNX输出格式 (1,84,8400) -> TRT可能变为 (1,8400,84) detections = output.reshape(8400, 84) # 调整维度顺序 ``` 3. **精度对比测试** 用相同输入对比ONNX与TRT输出差异: ```python onnx_output = onnx_session.run(...) trt_output = trt_inferencer.infer(...) np.testing.assert_allclose(onnx_output, trt_output, rtol=1e-3) # 容差>1%说明异常 ``` --- #### 三、常见问题专项解决 | 故障现象 | 解决方案 | |---------------------------|--------------------------------------------------------------------------| | 检测框位置漂移 | 检查输入尺寸是否与训练一致,缩放是否采用`letterbox`方式 | | 置信度全部为0/1 | 移除`--fp16`改用FP32,或添加校准数据集启用INT8量化 | | 特定类别漏检 | 检查转换日志是否出现`Unsupported layer: TopK`,需自定义插件实现NMS | | 内存溢出 | 添加`--workspace=4096`增大显存分配 | --- #### 四、高级调试工具 1. **网络可视化** 使用Netron对比ONNX与TRT引擎结构: ```bash netron yolov8s.onnx # 原始模型 polygraphy inspect model yolov8s.engine # TRT引擎结构 ``` **重点检查**:输出层名称、维度、激活函数(SiLU需TRT 8.4+支持) 2. **精度分析工具** 使用Polygraphy进行逐层误差分析: ```bash polygraphy run yolov8s.engine --onnx yolov8s.onnx \ --precision-consistency --validate ``` > **关键参考**:当YOLOv3-tiny转换后FPS达400+时验证了TensorRT的加速潜力,但必须确保转换过程无精度损失[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arnold-FY-Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值