YOLOv8 模型量化:动态量化&静态量化

点击下方卡片,关注“小白玩转Python”公众号

在当今世界,人工智能无处不在——从我们的智能手机到智能家居。但这些强大的AI模型如何适应如此小的设备?答案在于一种称为模型量化的技术。精致的AI设备可以放入口袋,持续工作数小时,并且不需要持续的互联网连接。这是量化正在创造的现实。在这篇博客文章中,我们将探索YOLO视觉模型的模型量化的艺术和科学。我们将了解这种技术如何使复杂的神经网络能够在资源有限的设备上高效运行,为日常生活中的AI开辟新的可能性。

什么是量化? 

想象你有一个包含100种不同蓝色阴影的大盒子。量化就像决定只使用10种阴影一样。你可能会失去一些细节,但仍然可以创建出一个可识别的图画,同时在你的盒子里节省空间。在AI的世界中,量化帮助我们缩小复杂的模型,使它们能够适应并在较小的设备上顺畅运行,如智能手机或智能家居设备。

7f1d27e66a39b435a1e760b053100c78.png

更技术性地说,模型量化是一种用于减少神经网络中数值表示精度的技术。通常,神经网络模型使用32位浮点数来表示权重和激活值。量化涉及将这些高精度数字转换为低精度格式,如8位整数或16位浮点数。

量化的类型:

静态量化

静态量化,也称为离线量化,是一种在部署前将模型的权重和激活值转换为低精度的过程。静态量化受到卷积神经网络(CNN)和目标检测模型的青睐,因为它们通常处理固定尺寸的图像,这些模型具有规律、可预测的计算模式。

优点:

  • 一致的推理时间 

  • 较低的运行时内存使用 

  • 可以利用硬件特定的优化 

缺点:

  • 可能会导致一些精度损失 

  • 对输入变化的灵活性较低 

动态量化 

动态量化,也称为运行时量化,涉及在推理过程中实时量化模型的激活值,使模型能够实时适应输入数据。这里通常只有权重是预先量化的,而激活值是动态量化的。动态量化受到自然语言处理任务的青睐,因为输入长度可能显著变化,并且输入分布可能随时间变化的场景。

优点:

  • 更能适应变化的输入分布 

  • 实现起来更容易,因为需要较少的预处理 

缺点:

  • 推理过程中稍微高一些的计算开销 

  • 可能导致变量推理时间 

  • 运行时通常比静态量化使用更多内存 

量化YOLO v8 nano模型

02d839eacf8d8e4e1f65fe014e01a84e.png

YOLOv8是YOLO(You Only Look Once)家族中的一个先进目标检测模型,主要用于实时目标检测任务。作为基于卷积神经网络(CNN)的模型,YOLOv8通常偏向于静态量化,原因有以下几个:

  1. 一致的输入:YOLOv8处理固定尺寸的图像,使其适合预定的量化参数。 

  2. 实时性能:静态量化提供了更可预测的推理时间,这对实时目标检测至关重要。 

  3. 边缘部署:YOLOv8经常部署在边缘设备上,静态量化在功耗和计算方面的效率是有益的。 

  4. 硬件加速:许多边缘设备都有针对静态量化中使用的整数操作进行优化的硬件。 

转换为ONNX

from ultralytics import YOLO


model = YOLO('yolov8n.pt')
model.export(format = 'onnx') # exports the model in '.onnx' format

模型预处理 

预处理为量化准备float32模型。更多信息可以访问:

https://github.com/microsoft/onnxruntime-inference-examples/blob/main/quantization/image_classification/cpu/ReadMe.md

动态量化

from onnxruntime.quantization import quantize_dynamic, QuantType


model_fp32 = 'preprocessed.onnx'
model_int8 = 'dynamic_quantized.onnx'


# Quantize 
quantize_dynamic(model_fp32, model_int8, weight_type=QuantType.QUInt8)

“weight_type”可以分配为QUInt8(量化的无符号8位整数——范围:0到255)或QInt8(量化的有符号8位整数——范围:-128到127)

静态量化 

校准: 校准是使用代表性数据集分析模型行为以确定量化最佳参数的过程。它涉及在样本输入上运行浮点模型,并收集关于不同层中权重和激活值分布的统计数据。这些统计数据用于计算最佳的缩放因子和零点,将浮点值转换为低精度整数,确保量化模型紧密模拟原始模型的行为。

import numpy as np
from onnxruntime.quantization import CalibrationDataReader, quantize_static, QuantType, QuantFormat
    
# Class for Callibration Data reading
class ImageCalibrationDataReader(CalibrationDataReader):
    def __init__(self, image_paths):
        self.image_paths = image_paths
        self.idx = 0
        self.input_name = "images"


    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.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 = ['test.jpg'] # you can add more of the image paths


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

量化:

05640ac906cacc4deef5096ad3221c3d.png

# Use the calibration_data_reader with quantize_static
quantize_static('preprocessed.onnx', "static_quantized.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,
                reduce_range=True,)

如Python程序和图像所示,一些最终层需要被排除才能进行预测。“nodes_to_exclude”列出了这些节点名称。查看程序,通常“weight_type”和“activation_type”是我们想要使用的精度。“quant_format”有两个值:QDQ和QOperator。

QuantFormat.QDQ(量化-反量化格式)

  • 在每个量化操作符周围添加单独的量化和反量化操作符。 

  • 更灵活且被广泛支持。

QuantFormat.QOperator

  • 直接用量化版本替换浮点操作符。 

  • 可以更高效,但支持较少。 

缺点

对于像YOLOv8这样的目标检测模型,量化有五个最显著的缺点:

  1. 精度损失:可能会减少检测精度和召回率,特别是对于小目标或在复杂光照条件下。 

  2. 有限的表示能力:减少捕捉对象特征细微差异的能力,可能影响分类精度。

  3.  对校准的敏感性:性能严重依赖于校准数据集的质量和代表性。 

  4. 微调的复杂性:在优化量化模型以在各种目标尺度和类别上保持性能方面存在挑战。 

  5. 增加开发时间:需要大量实验以找到模型大小、推理速度和检测精度之间的平衡。 

结果/成果

YOLO-v8 nano

f234c0e448f98b49ec128faf6092fe7d.jpeg

YOLO-v8 nano静态量化

55c61f8ba464697815b8b5197183f485.jpeg

YOLO-v8 nano动态量化

8c386dd41469ef9af565b8ebdef03ab5.jpeg

我们的YOLOv8静态量化取得了较好的效果:

  1. 性能:从9 FPS提高到11 FPS,推理速度提高了22%。 

  2. 精度:通过样本图像提供的视觉评估,展示了对检测质量的影响。 

  3. 权衡:在某些精度可能降低的情况下获得了速度的提升,这是量化中常见的权衡。

  4. 应用考虑:量化模型的适用性取决于具体的用例需求。 

总体而言,静态量化为YOLOv8展示了显著的速度提升。然而,在部署前需要仔细评估在各种场景下的精度,以确保效率和检测质量之间的平衡满足应用需求。

https://github.com/majipa007/Quantization-YOLOv8


·  END  ·

🌟 想要变身计算机视觉小能手?快来「小白玩转Python」公众号!

回复Python视觉实战项目,解锁31个超有趣的视觉项目大礼包!🎁

94daa913cdb9aaffaf2216a811045c58.png

本文仅供学习交流使用,如有侵权请联系作者删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值