赞
踩
点击下方卡片,关注“小白玩转Python”公众号
在当今世界,人工智能无处不在——从我们的智能手机到智能家居。但这些强大的AI模型如何适应如此小的设备?答案在于一种称为模型量化的技术。精致的AI设备可以放入口袋,持续工作数小时,并且不需要持续的互联网连接。这是量化正在创造的现实。在这篇博客文章中,我们将探索YOLO视觉模型的模型量化的艺术和科学。我们将了解这种技术如何使复杂的神经网络能够在资源有限的设备上高效运行,为日常生活中的AI开辟新的可能性。
什么是量化?
想象你有一个包含100种不同蓝色阴影的大盒子。量化就像决定只使用10种阴影一样。你可能会失去一些细节,但仍然可以创建出一个可识别的图画,同时在你的盒子里节省空间。在AI的世界中,量化帮助我们缩小复杂的模型,使它们能够适应并在较小的设备上顺畅运行,如智能手机或智能家居设备。
更技术性地说,模型量化是一种用于减少神经网络中数值表示精度的技术。通常,神经网络模型使用32位浮点数来表示权重和激活值。量化涉及将这些高精度数字转换为低精度格式,如8位整数或16位浮点数。
量化的类型:
静态量化
静态量化,也称为离线量化,是一种在部署前将模型的权重和激活值转换为低精度的过程。静态量化受到卷积神经网络(CNN)和目标检测模型的青睐,因为它们通常处理固定尺寸的图像,这些模型具有规律、可预测的计算模式。
优点:
一致的推理时间
较低的运行时内存使用
可以利用硬件特定的优化
缺点:
可能会导致一些精度损失
对输入变化的灵活性较低
动态量化
动态量化,也称为运行时量化,涉及在推理过程中实时量化模型的激活值,使模型能够实时适应输入数据。这里通常只有权重是预先量化的,而激活值是动态量化的。动态量化受到自然语言处理任务的青睐,因为输入长度可能显著变化,并且输入分布可能随时间变化的场景。
优点:
更能适应变化的输入分布
实现起来更容易,因为需要较少的预处理
缺点:
推理过程中稍微高一些的计算开销
可能导致变量推理时间
运行时通常比静态量化使用更多内存
量化YOLO v8 nano模型
YOLOv8是YOLO(You Only Look Once)家族中的一个先进目标检测模型,主要用于实时目标检测任务。作为基于卷积神经网络(CNN)的模型,YOLOv8通常偏向于静态量化,原因有以下几个:
一致的输入:YOLOv8处理固定尺寸的图像,使其适合预定的量化参数。
实时性能:静态量化提供了更可预测的推理时间,这对实时目标检测至关重要。
边缘部署:YOLOv8经常部署在边缘设备上,静态量化在功耗和计算方面的效率是有益的。
硬件加速:许多边缘设备都有针对静态量化中使用的整数操作进行优化的硬件。
转换为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)
量化:
- # 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这样的目标检测模型,量化有五个最显著的缺点:
精度损失:可能会减少检测精度和召回率,特别是对于小目标或在复杂光照条件下。
有限的表示能力:减少捕捉对象特征细微差异的能力,可能影响分类精度。
对校准的敏感性:性能严重依赖于校准数据集的质量和代表性。
微调的复杂性:在优化量化模型以在各种目标尺度和类别上保持性能方面存在挑战。
增加开发时间:需要大量实验以找到模型大小、推理速度和检测精度之间的平衡。
结果/成果
YOLO-v8 nano
YOLO-v8 nano静态量化
YOLO-v8 nano动态量化
我们的YOLOv8静态量化取得了较好的效果:
性能:从9 FPS提高到11 FPS,推理速度提高了22%。
精度:通过样本图像提供的视觉评估,展示了对检测质量的影响。
权衡:在某些精度可能降低的情况下获得了速度的提升,这是量化中常见的权衡。
应用考虑:量化模型的适用性取决于具体的用例需求。
总体而言,静态量化为YOLOv8展示了显著的速度提升。然而,在部署前需要仔细评估在各种场景下的精度,以确保效率和检测质量之间的平衡满足应用需求。
https://github.com/majipa007/Quantization-YOLOv8
· END ·
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。