yolov8.onnx的int8量化代码(去掉检测头)

部署运行你感兴趣的模型镜像
import os

import numpy as np
from onnxruntime.quantization import CalibrationDataReader, quantize_static, QuantType, QuantFormat, CalibrationMethod
import cv2

# Class for Callibration Data reading
class ImageCalibrationDataReader(CalibrationDataReader):
    def __init__(self, image_paths):
        # self.image_paths = image_paths # 单张图片
        self.image_paths = self._get_all_images(image_paths, (".jpg", ".png"))#文件夹
        self.idx = 0
        self.input_name = 'input'

    def _get_all_images(self, image_dir, valid_extensions):
        """获取文件夹中所有符合条件的图像文件路径"""
        image_paths = []
        # 遍历文件夹中的所有文件
        for filename in os.listdir(image_dir):
            # 检查文件扩展名是否符合要求
            if filename.lower().endswith(valid_extensions):
                # 构建完整文件路径
                full_path = os.path.join(image_dir, filename)
                image_paths.append(full_path)
        return image_paths
    def preprocess(self, frame):
        # Same preprocessing that you do before feeding it to the model
        frame = cv2.imread(frame)
        X = cv2.resize(frame, (640, 640))
        # image_data = np.array(X).astype(np.float32) / 255.0  # Normalize to [0, 1] range

        image_data = np.array(X).astype(np.float32)
        image_data = np.transpose(image_data, (2, 0, 1))  # (H, W, C) -> (C, H, W)
        image_data = np.expand_dims(image_data, axis=0)  # Add batch dimension
        return image_data


    def get_next(self):
        # method to iterate through the data set
        if self.idx >= len(self.image_paths):
            return None

        image_path = self.image_paths[self.idx]
        input_data = self.preprocess(image_path)
        self.idx += 1
        return {self.input_name: input_data}


# Assuming you have a list of image paths for calibration
calibration_image_paths = [r"F:\man_data\mpii_human_pose_v1\images512\000004812.jpg"]  # you can add more of the image paths

# # Create an instance of the ImageCalibrationDataReader
calibration_data_reader = ImageCalibrationDataReader(calibration_image_paths)


# Use the calibration_data_reader with quantize_static
quantize_static(
    # r"yolov8n.onnx", "yolov8n_int8(3).onnx",
r"E:\Nexwise_Internship\mmdeploy\export\rtmo-s_8xb32-600e_body7-640x640.onnx",r"E:\Nexwise_Internship\mmdeploy\export\rtmo-s_8xb32-600e_body7-640x640_nonmsint8.onnx",
                weight_type=QuantType.QInt8,
                activation_type=QuantType.QUInt8,
                calibration_data_reader=calibration_data_reader,
                quant_format=QuantFormat.QDQ,
                nodes_to_exclude=['/model.22/Concat_3', '/model.22/Split', '/model.22/Sigmoid'
                                 '/model.22/dfl/Reshape', '/model.22/dfl/Transpose', '/model.22/dfl/Softmax',
                                 '/model.22/dfl/conv/Conv', '/model.22/dfl/Reshape_1', '/model.22/Slice_1',
                                 '/model.22/Slice', '/model.22/Add_1', '/model.22/Sub', '/model.22/Div_1',
                                  '/model.22/Concat_4', '/model.22/Mul_2', '/model.22/Concat_5'],
                
                per_channel=False,
                calibrate_method=CalibrationMethod.Entropy,
                reduce_range=True,)

您可能感兴趣的与本文相关的镜像

Yolo-v5

Yolo-v5

Yolo

YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的Joseph Redmon 和Ali Farhadi 开发。 YOLO 于2015 年推出,因其高速和高精度而广受欢迎

<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. **动态维度问题**:YOLOv8ONNX模型可能包含动态维度(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转换后,输出格式可能变化(例如,转换工具可能将多个输出合并为一个输出)。需要检查转换后的输出结构,并调整后处理代码。 例如,原始YOLOv8ONNX模型可能有三个输出(对应三个检测头),而转换后TensorRT引擎可能只有一个输出(将所有检测结果合并)。因此,需要根据转换后的输出维度调整后处理代码。 ### 步骤6:使用最新的转换工具 确保使用的TensorRT版本是最新的,并且支持YOLOv8的所有算子。可以尝试使用Ultralytics官方提供的转换工具(如果有)。 总结:YOLOv8 onnx转trt后输出异常,主要排查方向是转换过程是否正确、精度设置、输入输出处理和后处理代码调整。按照上述步骤逐一排查。 §§相关问题§§ 1. 如何使用TensorRT Python API加载引擎并推理? 2. YOLOv8的后处理(非极大值抑制)如何实现? 3. ONNX模型如何简化以提高转换成功率? </think> ### YOLOv8 ONNX转TensorRT后推理结果异常的解决方案 当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. **输入数据一致性验证** TensorRT与ONNX的输入预处理需完全一致: ```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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值