七. 部署YOLOv8检测器-quantization-analysis

前言

自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考

本次课程我们来学习课程第七章—部署YOLOv8检测器,一起来学习分析 YOLOv8 量化掉点严重的问题

课程大纲可以看下面的思维导图

在这里插入图片描述

0. 简述

本小节目标:学习分析 YOLOv8 量化掉点严重的原因

这节我们主要解决上节课中提到的 YOLOv8 量化后掉点严重的的问题

下面我们开始本次课程的学习🤗

1. 案例运行

在正式开始课程之前,博主先带大家跑通 7.4-quantization-analysis 这个小节的案例

源代码获取地址:https://github.com/kalfazed/tensorrt_starter

首先大家需要把 tensorrt_starter 这个项目给 clone 下来,指令如下:

git clone https://github.com/kalfazed/tensorrt_starter.git

也可手动点击下载,点击右上角的 Code 按键,将代码下载下来。至此整个项目就已经准备好了。也可以点击 here 下载博主准备好的源代码(注意代码下载于 2024/7/14 日,若有改动请参考最新

由于 INT8 量化需要 calibration dataset 校准数据集,所以我们还需要下载 COCO 数据集,大家可以点击 here 下载,另外一般来说校准图片选个 1000 张左右就足够了,博主这里从 coco2017 训练集中随机选取了 1000 张,大家如果只是单纯的测试效果可以直接点击 here 下载博主准备好的 1000 张校准图片数据

和 6.3 小节案例一样,校准数据集准备好后我们还要准备一个 .txt 文档,该文档里面保存着每张校准图片的完整路径,因为本小节案例代码中是通过解析 calibration/calibration_list_coco.txt 去读取每张校准图片进行量化的,因此我们需要把我们自己校准数据集的路径覆盖写入到 calibration_list_coco.txt

在 7.4-quantization-analysis 主目录下新建一个 python 脚本文件,内容如下:(from ChatGPT)

import os
import re

# 设置图像文件夹的路径
image_folder = '/home/jarvis/Learn/tensorrt_starter/chapter7-deploy-yolo-detection/7.4-quantization-analysis/images'
# 设置输出文件的路径
output_file = 'calibration/calibration_list_coco.txt'

# 辅助函数,用于从文件名中提取数字
def extract_number(filename):
    # 从文件名中提取数字,确保正则表达式匹配 "任何数字" 部分
    match = re.search(r'\d+', filename)
    # 如果找到数字,转换为整数;否则返回一个很大的数字,以便将这些文件放在列表末尾
    return int(match.group()) if match else float('inf')

# 初始化一个列表用来存储图像路径
image_paths = []

# 遍历指定文件夹
for filename in os.listdir(image_folder):
    # 检查文件是否为 JPEG 图像
    if filename.endswith('.JPEG') or filename.endswith('.jpg'):
        # 构建完整的文件路径
        file_path = os.path.join(image_folder, filename)
        # 添加到列表
        image_paths.append(file_path)

# 对图像路径列表按文件名中的数字排序
image_paths.sort(key=lambda path: extract_number(os.path.basename(path)))

# 打开文件准备写入
with open(output_file, 'w') as f:
    for path in image_paths:
        # 将路径写入文件
        f.write(path + '\n')

print(f'Image paths have been saved to {output_file}, number = {len(image_paths)}')

注意将 image_folder 的路径修改为你自己的校准数据集路径,执行上述脚本输出如下:

在这里插入图片描述

我们在 calibration/calibration_list_coco.txt 中可以看到路径的修改,如下图所示:

在这里插入图片描述

至此,我们完成了校准图片的准备工作,下面我们就来执行这个小节的案例

整个项目后续需要使用的软件主要有 CUDA、cuDNN、TensorRT、OpenCV,大家可以参考 Ubuntu20.04软件安装大全 进行相应软件的安装,博主这里不再赘述

假设你的项目、环境准备完成,下面我们一起来运行下 7.4-quantization-analysis 小节案例代码

开始之前我们需要创建几个文件夹,在 tensorrt_starter/chapter7-deploy-yolo-detection/7.4-quantization-analysis 小节中创建一个 models 文件夹,接着在 models 文件夹下创建一个 onnx 和 engine 文件夹,总共三个文件夹需要创建

创建完后 7.4 小节整个目录结构如下:

在这里插入图片描述

接着我们要导出 YOLOv8 的 ONNX 模型,具体流程可以参考:七. 部署YOLOv8检测器-deploy-yolov8-basic,博主这里就不再赘述了,大家也可以点击 here 下载博主准备好的 ONNX

大家需要把刚导出好的 ONNX 模型放在 tensorrt_starter/chapter7-deploy-yolo-detection/7.4-quantization-analysis/models/onnx 文件夹下

ONNX 模型准备好后,我们把韩君老师生成的推理结果给删除,方便后续查看我们自己推理的结果,指令如下:

cd 7.4-quantization-analysis
rm -rf *

然后我们需要利用 ONNX 生成对应的 engine 完成推理,在此之前我们需要修改下整体的 Makefile.config,指定一些库的路径:

# tensorrt_starter/config/Makefile.config
# CUDA_VER                    :=  11
CUDA_VER                    :=  11.6
    
# opencv和TensorRT的安装目录
OPENCV_INSTALL_DIR          :=  /usr/local/include/opencv4
# TENSORRT_INSTALL_DIR        :=  /mnt/packages/TensorRT-8.4.1.5
TENSORRT_INSTALL_DIR        :=  /home/jarvis/lean/TensorRT-8.6.1.6

Note:大家查看自己的 CUDA 是多少版本,修改为对应版本即可,另外 OpenCV 和 TensorRT 修改为你自己安装的路径即可

接着我们就可以来执行编译,指令如下:

make -j64

输出如下:

在这里插入图片描述

接着执行:

./bin/trt-infer

输出如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们这里可以看到每张图片的一个推理结果,并且推理后的图片保存在 data/result 文件夹下,大家可以查看,如下图所示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果大家能够看到上述输出结果,那就说明本小节案例已经跑通,下面我们就来看看具体的代码实现

2. 补充说明

在分析代码之前我们先来看下韩君老师在这小节中写的 README 文档

这个小节主要解决 7.3-deploy-yolo-basic 中出现的 int8 量化掉点严重的问题,当我们发现 int8 量化掉点严重的时候,我们可以有以下几个参考的点:

  • 是否在 input/output 附近做了 int8 量化
  • 如果是 multi-task 的话,是否所有的 task 都掉点严重
  • calibration 的数据集是不是选的不是很好
  • calibration batch size 是不是选择的不是很好
  • calibrator 是不是没有选择好
  • 某些计算是否不应该做量化
  • 使用 polygraphy 分析

其实,恢复精度有很大程度上需要依靠经验,但是比较好的出发点是从量化的基本原理去寻找答案,结合 yolov8 的模型架构,我们就能顺理成章的猜到 yolov8 掉点严重的原因是因为 IInt8EntropyCalibrator2。这个小节带着大家引导一下思路,以及今后遇到类似的问题的时候应该如何去考虑。

3. 量化分析

我们首先利用 trt-engine-explore 来查看 tensorRT 优化后的 engine 结构,来看下每一个 layer 的精度是否符合我们的预期

关于 trt-engine-explore 的使用大家可以参考:六. 部署分类器-trt-engine-explorer,博主这里就不再赘述了

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

上面是 yolov8n-int8.engine 的部分结构图,从中我们可以发现几个现象:

  • Reformat 节点大量存在,可能会影响模型推理速度
  • 靠近输入部分是 INT8 精度,可能会影响模型精度
  • 靠近输出部分是 FP32 精度

那掉点严重是不是因为输入部分 INT8 导致的呢?那其实我们上节课有提到目标框的回归比较好,而分类比较差,如果是输入部分 INT8 量化导致的问题,那应该二者都有损失,所以我们猜测应该不是输入 INT8 量化导致的

那是不是数据集的原因呢?是不是 calibration dataset 没有选好呢?是不是选多了或者选少了呢?那博主这里没有测试,大家感兴趣的可以自行测试下,不过一般来说应该不是 calibration dataset 导致的,因为首先 calibration dataset 来自于 coco2017 的训练数据,来源没问题,其次它是博主随机挑选的,分布没问题,最后数量是 1000 张也没有啥问题,因此 calibration 的数据集应该不是导致掉点的主因

那是不是 calibration batch size 的原因呢?我们在 四. TensorRT模型部署优化-quantization(calibration) 有提到 calibration 时的 batch size 会影响模型量化后的精度,更准确来说会影响 histogram 的分布,这个其实跟 TensorRT 在构建浮点数的 histogram 的算法有关。那是不是 batch size 选择的原因呢?那其实博主认为 calibration 的 batch size 大小其实对最终量化后的精度没有啥影响,当然这是博主个人的一些想法,大家感兴趣的可以自行测试下看看 batch size 的大小能否影响精度

那下一个可能的原因是不是 calibrator 没有选择好呢?在 trt_calibrator.hpp 文件中我们本来默认使用的是 IInt8EntropyCalibrator2 但是在 yolov8 的 int8 量化中韩君老师修改成了 IInt8MinMaxCalibrator,如下所示:

// class Int8EntropyCalibrator: public nvinfer1::IInt8EntropyCalibrator2 {
class Int8EntropyCalibrator: public nvinfer1::IInt8MinMaxCalibrator {
// class Int8EntropyCalibrator: public nvinfer1::IInt8LegacyCalibrator {
// class Int8EntropyCalibrator: public nvinfer1::IInt8MinMaxCalibrator {
// class Int8EntropyCalibrator: public nvinfer1::IInt8Calibrator {

public:
    Int8EntropyCalibrator(
        const int& batchSize,
        const std::string& calibrationSetPath,
        const std::string& calibrationTablePath,
        const int& inputSize,
        const int& inputH,
        const int& inputW);
	...
}

那我们来对比看下两个不同的 calibrator 的推理效果图,如下所示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

似乎也没有太大的区别,不过 MinMax calibrator 量化出来的模型检测率比较高,其回归和分类效果较 Entropy calibrator 要好点🤔

韩君老师在代码中有记录测试结果,在 TensorRT-8.6 下:

  • IInt8EntropyCalibrator2:int8 精度下降严重,classness 掉点严重
  • IInt8MinMaxCalibrator:int8 推理精度可以恢复, classness 的 max 会凸显出来

那为什么会这样呢?韩君老师给出的解释是因为 MinMax 会把 FP32 中的最大最小值也会留下来,而 yolov8 的 fp32 的最大最小值非常重要,因为 C2F 架构中会 DWConv,depthwise 的存在会潜在性的让 output tensor 的 FP32 在每一个 layer 都会有很大不同的分布,如果用 entropy 的话,很有可能会让某些关键信息流失掉

4. 探讨

那首先上节案例中 yolov8 量化后掉点严重的原因博主认为依旧是因为预处理方式的实现将图片缩放到 224x224 导致的,而并不是 calibrator 导致的,而这节案例代码中韩君老师将输入修改回 640x640,所以从推理结果来看两个 calibrator 其实并没有太大的区别,掉点也是正常 PTQ 量化的掉点

那至于哪个 calibrator 比较好,需要大家具体拿数据集测试下 mAP 等评价指标,单纯看一两张推理结果图看不出什么东西来,不过像 YOLO 系列检测器而言就博主的经验一般来说用 Entropy calibrator 就行,但是也要看具体的数据集和模型,大家如果在自己的数据集发现掉点比较严重(一般而言 1~2 个掉点较正常)可以考虑换一个 calibrator,如果还是一样那就需要做敏感层分析或者上 QAT 了

其次关于 YOLOv8 的结构博主印象中 C2F 结构中是没有 DWConv 的,都是正常的 Conv,博主之前简单绘制过 YOLOv8 网络结构图如下:

在这里插入图片描述

我们可以使用 onnx 库来查找 onnx 模型中是否存在 DWConv,代码如下所示:(from ChatGPT)

import onnx
import numpy as np

def is_dwconv(weight_tensor):
    # 获取卷积权重的维度
    weight_shape = weight_tensor.dims
    
    # 深度卷积的特点是输出通道数等于输入通道数
    if len(weight_shape) == 4 and weight_shape[1] == 1 and weight_shape[0] == weight_shape[1] * weight_shape[0]:
        return True
    return False

def check_dwconv_by_weights(model_path):
    # 加载ONNX模型
    model = onnx.load(model_path)
    graph = model.graph

    # 遍历模型的所有节点
    for node in graph.node:
        if node.op_type == 'Conv':  # 只检查Conv节点
            # 获取该节点的输入权重
            for input_name in node.input:
                # 查找权重的初始值
                for initializer in graph.initializer:
                    if initializer.name == input_name:
                        weight_tensor = initializer
                        # 检查是否是深度卷积
                        if is_dwconv(weight_tensor):
                            print(f"Found DWConv node: {node.name}")
                            return True

    print("No DWConv node found in the ONNX model.")
    return False

# 使用模型路径进行检查
model_path = 'yolov8n.onnx'  # 替换为你的ONNX模型路径
check_dwconv_by_weights(model_path)

因此,总的来说韩君老师在代码中提到的 DWConv 影响 yolov8 calibrator 的选择博主认为并没有这个说法,不过单纯推理的图片来看 MinMax calibrator 量化出来的效果确实要较 Entropy calibrator 要好,另外上节案例代码量化掉点的主因是预处理函数输入分辨率的问题,而 yolov8 的 calibrator 选择可以根据具体的数据集、模型以及 mAP 评价测试指标来综合考虑

总结

本次课程我们学习分析了 YOLOv8 量化掉点严重的问题,虽然没有定位到真正的问题所在但是我们还是掌握了当模型量化掉点严重时该怎么做。首先利用 trt-engine-explore 工具查看 INT8 模型的结构,观察是否在 inpput/output 附近做了 INT8 量化,如果是的可以考虑做敏感层分析输入输出量化对精度影响,让它们保持在 FP16 精度。另外可以考虑 calibration 数据集是不是没有选好,换一些校准图片测试下,还有 calibrator 的选择也很重要,如果这些都没有办法解决掉点问题,那么需要使用 polygraphy 工具进行分析

OK,以上就是 7.4 小节案例的全部内容了,下节我们进入第八章节—CUDA-BEVFusion部署分析的学习,敬请期待😄

下载链接

参考

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
file "e:\projects\snn\snnver0.1\quantization\yolov8-qat-master\utils\dataset" 是一个文件路径,指向一个名为 "dataset" 的模块或者文件夹。该路径位于 "yolov8-qat-master" 文件夹下的 "quantization" 文件夹中的 "utils" 文件夹里。这个文件或者文件夹可能与数据集的处理或者管理有关。 根据路径的结构,可以看出该文件或者文件夹与使用 YOLOv8 进行量化训练(Quantization-Aware Training)的项目相关。YOLOv8 是一种目标检测算法,通过将神经网络量化为较低精度的表示,从而减少存储和计算需求,提高在资源受限环境下的实时性能。在这个项目中,"dataset" 可能是用于加载和处理训练数据的工具集。 在这个文件或者文件夹中,可能包含以下功能: 1. 数据集加载:用于从特定的数据集中加载图像、标签或其他相关信息的模块或函数。 2. 数据预处理:对加载的数据进行预处理,例如调整图像的大小、裁剪图像、增强数据等。 3. 数据增强:在训练阶段对数据进行增强,以增加数据的多样性和泛化能力。 4. 数据集划分:将数据集划分为训练集、验证集和测试集的工具函数。 5. 数据集统计:对数据集进行统计分析,例如计算类别分布、图像数量等。 6. 其他与数据集相关的功能或工具。 总之,"file "e:\projects\snn\snnver0.1\quantization\yolov8-qat-master\utils\dataset"" 指向的文件或者文件夹与 YOLOv8 的量化训练项目中数据集的处理和管理有关。具体包含了哪些功能,需要深入查看该路径下的文件和代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱听歌的周童鞋

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

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

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

打赏作者

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

抵扣说明:

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

余额充值