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

news2024/9/23 3:30:40

目录

    • 前言
    • 0. 简述
    • 1. 案例运行
    • 2. 补充说明
    • 3. 量化分析
    • 4. 探讨
    • 总结
    • 下载链接
    • 参考

前言

自动驾驶之心推出的 《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部署分析的学习,敬请期待😄

下载链接

  • tensorrt_starter源码
  • 7.4-quantization-analysis案例文件

参考

  • Ubuntu20.04软件安装大全
  • https://github.com/kalfazed/tensorrt_starter
  • 四. TensorRT模型部署优化-quantization(calibration)
  • 六. 部署分类器-trt-engine-explorer
  • 七. 部署YOLOv8检测器-deploy-yolov8-basic

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无限边界:现代整合安全如何保护云

尽管云计算和远程工作得到广泛采用,零信任网络也稳步推广,但边界远未消失。相反,它已被重新定义。就像数学分形的边界一样,现代网络边界现在无限延伸到任何地方。 不幸的是,传统工具在现代无限边界中效果不佳。现代边…

优化算法(三)—模拟退火算法(附MATLAB程序)

模拟退火算法(Simulated Annealing, SA)是一种基于概率的优化算法,旨在寻找全局最优解。该算法模拟金属退火过程中的物质冷却过程,逐渐降低系统的“温度”以达到全局优化的效果。它特别适用于解决复杂的组合优化问题。 一、模拟退…

深度学习笔记(6)文本分类

深度学习笔记(6)文本分类 文章目录 深度学习笔记(6)文本分类一、文本分析与关键词提取1.关键概念1.停用词2 Tf-idf:关键词提取 3.相似度 二、文本分析案例1.数据处理2.分词:实用结巴分词器3.清洗4.TF-IDF5.…

FastText 和 Faiss 的初探了解

概览 大模型目前已经是如火如荼的程度,各个大厂都有推出面向大众的基础大模型,同时诸多行业也有在训练专有大模型,而大模型的发展由来却是经过多年从文本检索生成、深度学习、自然语言处理,在Transformer架构出来后,才…

win11下面graphviz的用法

安装 安装graphviz 2.38版本 控制面板在变量path中增加E:\software\Graphviz\bin example.dot代码 digraph SignalPathway {node [fontname"SimHei"];edge [fontname"SimHei"];// 定义节点形状node [shapecircle];// 定义节点CellA [label"细胞 A&…

第 13 章 兵马未动,粮草先行——InnoDB 统计数据是如何收集的

表的统计数据:SHOW TABLE STATUS LIKE table_name; 索引的统计数据:SHOW INDEX FROM table_name; 13.1 两种不同的统计数据存储方式 InnoDB 提供了两种存储统计数据的方式: 永久性的统计数据。存储在磁盘上,服务器重启之后还在…

nvm安装并配置全局缓存文件

nvm下载,最新版为 1.1.12:Releases coreybutler/nvm-windows GitHub 下载exe,选择指定位置安装即可,安装及配置参考链接:window下安装并使用nvm(含卸载node、卸载nvm、全局安装npm)-CSDN博客 …

SpringBoot教程(安装篇) | RabbitMQ的安装

SpringBoot教程(安装篇) | RabbitMQ的安装 一、下载RabbitMQ(windows版本)1. 先下载 RabbitMQ2. 再下载Erlang3. 开始安装 Erlang4. 为Erlang配置环境变量5、验证安装6. 开始安装 RabbitMQ7. 启用RabbitMQ的管理插件(图…

学习整理vue前端框架项目目录结构的含义

学习整理vue前端框架项目目录结构的含义 1、目录结构2、结构含义 1、目录结构 2、结构含义

C++STL~~deque

文章目录 deque的概念deque的使用deque的练习总结 deque的概念 deque(双端队列):是一种序列容器、是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)&#xff…

F12抓包12:Performance(性能)前端性能分析

课程大纲 使用场景: ① 前端界面加载性能测试。 ② 导出性能报告给前端开发。 复习:后端(接口)性能分析 ① 所有请求耗时时间轴:“网络”(Network) - 概览。 ② 单个请求耗时:“网络”(Network&#xf…

FIB对芯片反向技术的贡献

目前由于国内在模拟集成电路设计领域的研究较为薄弱,芯片逆向分析便成为大多数模拟集成电路工程师基础实际模拟电路积累经验的有效途径,IC反向设计也成为推动国内集成电路设计进步的有效手段。在IC逆向分析与设计服务中,主要用FBI对IC线路进行…

计算机二级office操作技巧——Excel篇

文章目录 函数公式总结写在前面五大基本函数sum求和函数average求平均函数max求最大值函数min求最小值函数count求个数函数 rank排名函数if逻辑判断函数条件求个数函数countif单条件求个数函数countifs多条件求个数函数 条件求和函数sumifs多条件求和函数sumproduct乘积求和函数…

【学习笔记】线段树合并

前言 一般来说,线段树会有 O ( n ) O(n) O(n) 个节点。但是有的时候,整棵线段树就只进行了一次插入操作,这样只会有 O ( l o g n ) O(logn) O(logn) 个节点。 处理树上问题时,我们有时需要把儿子的信息合并到父亲节点。这个时候…

松理解数据库并发调度与可串行性

‍ 前言 在数据库系统中,多个事务的并发执行是不可避免的。然而,并发执行可能导致数据不一致的情况。为了解决这个问题,数据库管理系统(DBMS)使用调度策略来控制事务的执行顺序。本文将简洁地介绍可串行化调度这一概…

基于springboot旅游管理系统设计与实现

基于springboot旅游管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本旅游管理系统就是在这样的大环境下诞生,其可以帮助使用…

[数据集][目标检测]智慧交通铁轨裂缝检测数据集VOC+YOLO格式4类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2709 标注数量(xml文件个数):2709 标注数量(txt文件个数):2709 标注…

通过对比理解C++智能指针

理论 概述 智能指针:把管理资源的责任交给了对象,这样我们在使用结束时不需要显式地释放资源,而是由析构函数自动完成这一工作 它是一个类模板,可以创建任意类型的指针对象 智能指针使用时,资源对象不能被重复释放&a…

【CSS|第1期】网页设计的演变:从表格布局到Grid布局

日期:2024年9月9日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉在这里插入代码片得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对…

调用系统的录音设备提示:line with format PCM_SIGNED 16000.0 Hz

javax.sound.sampled.LineUnavailableException: line with format PCM_SIGNED 16000.0 Hz, 8 bit, mono, 1 bytes/frame, not supported. 打开 设置->隐私->麦克风->允许应用访问你的麦克风 与 16000Hz没关系 与 16000Hz没关系 与 16000Hz没关系