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

目录

    • 前言
    • 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 npdef 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 Truereturn Falsedef 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 Trueprint("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.rhkb.cn/news/424579.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言:链表

链表是一种常见的基础数据结构,它由一系列节点(Node)组成。每个节点包含两部分:数据域(存储数据)和指针域(存储下一个节点的地址)。链表的特点是元素在内存中不一定连续存储&#xf…

BUUCTF 之Basic 1(BUU LFI COURSE 1)

1、启动靶场,会生成一个URL地址,打开给的URL地址,会看到一个如下界面 可以看到是一个PHP文件,非常的简单,就几行代码,判断一下是否有一个GET的参数,并且是file名字,如果是并且加载&a…

GEE:连续变化检测与分类(Continuous Change Detection and Classification, CCDC)教程

连续变化检测与分类(Continuous Change Detection and Classification, CCDC)是一种土地变化监测算法,旨在对卫星数据的时间序列进行操作,特别是Landsat数据。CCDC包括两个部分,其一是变化检测算法(Change …

python小脚本,实时监测服务器是否宕机状态,并发送到指定群组

一,前言 众所周知,市面上监控软件很多,有Zabbix,Prometheus等,但对于相对简单的功能,需要第一时间发现问题,如服务器宕机,zabbix和Prometheus都需要等几分钟才会报警。 想到最原始…

故障排查:VMware虚拟机网络冲突,导致VPN网络无法正常访问

故障现象 某台windows10系统电脑,远程拨号SSL VPN后,无法正常公司内网。通过排查,发现重启开机,操作系统的默认路由多了一条公司内网的默认路由,但网关不正确。手动删除,重启系统又恢复原样。 排查过程 c…

adb的安装和使用 以及安装Frida 16.0.10+雷电模拟器

.NET兼职社区 .NET兼职社区 .NET兼职社区 1.下载adb Windows版本:https://dl.google.com/android/repository/platform-tools-latest-windows.zip 2.配置adb环境变量 按键windowsr打开运行,输入sysdm.cpl,回车。 高级》环境变量》系统变量》…

OpenCV结构分析与形状描述符(20)计算一个包围给定点集的最小外接圆函数minEnclosingCircle()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 找到一个包围二维点集的最小面积的圆。 该函数使用迭代算法来寻找一个二维点集的最小外接圆。这意味着函数将会通过反复逼近的过程来计算出能够…

多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测

多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测 目录 多维时序 | Matlab基于BO-LSSVM贝叶斯优化最小二乘支持向量机数据多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于BO-LSSVM贝叶斯优化最小二乘支…

莎朗斯通的比基尼视频曝光了她的日常锻炼!自爆曾在重症监护室呆了9天

如果您错过了,莎朗斯通 (Sharon Stone) 的华丽比基尼视频向您展示了她的日常锻炼! 9 月 12 日,斯通分享了一段她在泳池里锻炼的视频。她分享了这段视频,并配文:“我刚刚和教练 kristinemarie_18 完成了最后一次锻炼&a…

【Python刷题】Atcoder Beginner Contest 371

目录 A - Jiro题目描述算法思路代码实现 B - Taro题目描述算法思路代码实现 D - 1D Country题目描述算法思路代码实现 E - I Hate Sigma Problem题目描述算法思路代码实现 A - Jiro 题目描述 有三个人,知道他们之中每两个人的年龄关系,输出年龄第二大的…

Unity实现自己的协程系统

为什么自己实现一套协程系统 协程(Coroutine)是一个强大且灵活的工具,它可以帮助开发者处理异步任务,例如等待某些事件、处理逐帧更新等。在Unity中,协程通常通过IEnumerator来实现,这种机制允许代码在执行…

效率神器来了:AI工具手把手教你快速提升工作效能

随着科技的进步,AI工具已经成为提升工作效率的关键手段。本文将介绍一些实用的AI工具和方法,帮助你自动化繁琐的重复性任务、优化数据管理、促进团队协作与沟通,并提升决策质量。 背景:OOP AI-免费问答学习交流-GPT 自动化重复性任…

IP纯净度对跨境电商有哪些影响

在全球化贸易的浪潮中,跨境电商凭借其打破地理界限的能力,成为推动国际贸易的重要力量。然而,跨境电商的运营并非没有挑战,其中IP纯净度是影响其成功的关键因素之一。本文将探讨IP纯净度对跨境电商运营的多方面影响,并…

从单体到微服务:FastAPI ‘挂载’子应用程序的转变

在现代 Web 应用开发中,模块化架构是一种常见的设计模式,它有助于将大型应用程序分解为更小、更易于管理的部分。FastAPI,作为一个高性能的 Python Web 框架,提供了强大的支持来实现这种模块化设计。通过“挂载”子应用程序&#…

WebGL系列教程八(GLSL着色器基础语法)

目录 1 前言2 基本原则3 基本数据类型4 顶点着色器和片元着色器4.1 声明4.2 初始化项目4.3 赋值 5 结构体5.1 声明5.2 赋值 6 函数6.1 基本结构6.2 自定义函数6.3 常用内置函数 7 精度8 其他9 总结 1 前言 通过前七讲,我们已经见过了WebGL中的部分基础语法&#xff…

webpack5-手撸RemoveConsolePlugin插件

写在前面 其实呢,这个东西也就那样,主要是我们得清楚webpack构建过程中的生命周期钩子, 就拿这个插件来说,我们想要把输出的js文件里面的内容中的console语句去掉,那么我们就需要找到webpack处理完文件时的钩子&#…

海外VS国内:网安上市公司人均创收对比

二级市场分析章节中分析了中国网络网络安全上市公司人均创收63.2万、人均毛利37.6万,人均创利-1.6万。 有网友问了:海外网络安全公司的人均情况如何?那么让我们一起看看吧。 我们统计了在海外上市的28家主要网络安全公司的2023年的人均情况&…

2020ICPC上海 D - Walker M - Gitignore

D: 首先显然要二分,判断当前二分的mid时间下是否能满足走满0~n 枚举所有情况,这里按照左,右起点p1,p2分别讨论 p1向左 p2向左(以下向左和向右都代表向左或者向右到墙,而不代表初速度方向),只需要计算p1或者p2反弹之后还能走距离n就是合法 p1向左 p2向右&#xff…

PHP智慧家政同城服务家政系统小程序源码

智慧家政,同城服务新篇章 —— 探索家政系统的无限可能 开篇:走进智慧家政时代 在这个快节奏的生活中,每一分每一秒都显得尤为珍贵。当忙碌成为常态,如何让家成为真正的避风港?答案或许就藏在“智慧家政同城服务家政…

155K Star,Python 入门到进阶最佳学习资源

Hi,骚年,我是大 G,公众号「GitHub 指北」会推荐 GitHub 上有趣有用的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注。 导语 如果你正在寻找一个全面、系统、深入的 Python 学习项目&#…