开发者实战 | 使用 OpenVINO™ 实现 RT-DETR 模型 INT8 量化推理加速

2023/11/29 17:00
阅读数 88

点击蓝字

关注我们,让开发变得更有趣

作者: 颜国进 英特尔边缘计算创新大使





RT-DETR 是在 DETR 模型基础上进行改进的,一种基于 DETR 架构的实时端到端检测器,它通过使用一系列新的技术和算法,实现了更高效的训练和推理,在前文我们发表了《基于 OpenVINO™ Python API 部署 RT-DETR 模型 | 开发者实战》、《基于 OpenVINO™ C++ API 部署 RT-DETR 模型 | 开发者实战》以及《基于 OpenVINO™ C# API 部署 RT-DETR 模型 | 开发者实战》,实现了基于 OpenVINO™ Python 、 C++ API 和 C# API 向大家展示了的 RT-DETR 模型的部署流程,并分别展示了是否包含后处理的模型部署流程,为大家使用 RT-DETR 模型提供了很好的范例。


但是经过时间检测,使用 OpenVINO™ 在 CPU 平台上运行 RT-DETR 模型,其推理速度最快可以达到 3 ~ 4 帧左右,但这对于视频数据预测是远远不够的。由于 OpenVINO™ 最新发行版 2023.1.0 在 GPU 平台对 RT-DETR 模型算子还不支持,所以在前面文章中我们没有在 iGPU 平台上进行测试。为了提高推理速度,在本文章中,我们将使用 OpenVINO™ 实现 RT-DETR 模型 INT8 量化,通过模型优化技术实现模型推理加速;并且在 OpenVINO™ 工程师指导下,通过修改 OpenVINO™ 源码,重现编译了官方库,实现了 GPU 对 RT-DETR 模型的支持。


项目所使用的全部代码已经在 GitHub 上开源,并且收藏在 OpenVINO™ -CSharp-API 项目里,项目所在目录链接为:

https://github.com/guojin-yan/OpenVINO-CSharp-API/tree/csharp3.0/tutorial_examples


也可以直接访问该项目,项目链接为:

https://github.com/guojin-yan/RT-DETR-OpenVINO.git


第1章

使用 OpenVINO™ 

实现 RT-DETR 模型 INT8 量化


训练后模型优化是使用无需重新训练或微调的特殊方法,即可将模型转换为对硬件更友好的表示形式。目前最流行和使用最广泛使用的方法是 INT8 量化,具有以下优点:


  • 它易于使用。

  • 它不会对准确性造成太大影响。

  • 它提供了显著的性能改进。

  • 它适合许多库存硬件,因为它们中的大多数都原生支持 8 位计算。


INT 8 量化将模型权重和激活函数的精度降低到 8 位,从而将模型占用空间减少近 4 倍,降低推理所需的吞吐量,并显著提高推理速度,量化过程在实际推理之前离线完成。通过 OpenVINO™ 实现模型的量化过程不需要源深度学习框架中的训练数据集或训练代码。


为了让大家更好的复现 RT-DETR 模型 INT8 量化流程,我们提供了完整的 Notebook 文件,使用者可以根据文件操作流程进行一步步操作。使用 OpenVINO™ 实现 RT-DETR 模型 INT8 量化的完整代码已经上传到 GitHub 中,文章链接为:

https://github.com/guojin-yan/RT-DETR-OpenVINO/blob/master/optimize/openvino-convert-and-optimize-rt-detr.ipynb


为了方便大家复现该项目,此处录制了演示视频,已经发布到 B 站,视频链接为

https://www.bilibili.com/video/BV11N411T7m5/


1.1

神经网络压缩框架(NNCF)


神经网络压缩框架(NNCF)提供了 Python 中提供的训练后量化 API,旨在重用代码进行模型训练或验证,这些代码通常可用于源框架中的模型,例如 PyTorch 或 TensroFlow。NNCF API 是跨框架的,目前支持以下框架中的模型:OpenVINO™ 、PyTorch、TensorFlow 2.x 和 ONNX。目前,OpenVINO™ 中间表示中模型的训练后量化在支持的方法和模型覆盖率方面是最成熟的。


NNCF API 有两个方式来实现训练后 INT 8 量化:


1. 基本量化

基本量化流程是将 INT 8 量化应用于模型的最简单方法,它适用于 OpenVINO™、PyTorch、TensorFlow 2.x 和 ONNX 框架中的模型。在这种情况下,只需要具有代表性的校准数据集进行。

2. 具有精度控制的量化

这是高级量化流程,允许将 INT 8 量化应用于模型,并通过验证函数控制精度指标。目前只支持 OpenVINO™ 框架中的模型。除了校准数据集之外,还需要验证数据集来计算准确性指标。


1.2

准备校准数据集


在本实验中,我们只实现基本量化,因此只需要准备校验数据集即可。RT-DETR 模型预训练模型是在 COCO 数据集下训练的,因此我们只需要准备 COCO 验证数据集即可。为了更容易构建验证数据集,我们此处使用 ultralytics 框架下的 API 方法实现。


1.2.1 下载 COCO 验证数据集


COCO 验证数据集可以通过官网直接下载,也可以通过下面的代码下载:

DATA_URL = "http://images.cocodataset.org/zips/val2017.zip"LABELS_URL = "https://github.com/ultralytics/yolov5/releases/download/v1.0/coco2017labels-segments.zip"CFG_URL = "https://raw.githubusercontent.com/ultralytics/ultralytics/8ebe94d1e928687feaa1fee6d5668987df5e43be/ultralytics/datasets/coco.yaml"CACHE_URL = "https://github.com/guojin-yan/RT-DETR-OpenVINO/releases/download/Model2.0/val2017.cache"OUT_DIR = Path('./datasets')DATA_PATH = OUT_DIR / "val2017.zip"LABELS_PATH = OUT_DIR / "coco2017labels-segments.zip"CFG_PATH = OUT_DIR / "coco.yaml"CACHE_PATH = OUT_DIR / "coco/labels/val2017.cache"download_file(DATA_URL, DATA_PATH.name, DATA_PATH.parent)download_file(LABELS_URL, LABELS_PATH.name, LABELS_PATH.parent)download_file(CFG_URL, CFG_PATH.name, CFG_PATH.parent)if not (OUT_DIR / "coco/labels").exists():    with ZipFile(LABELS_PATH , "r") as zip_ref:        zip_ref.extractall(OUT_DIR)    with ZipFile(DATA_PATH , "r") as zip_ref:        zip_ref.extractall(OUT_DIR / 'coco/images')download_file(CACHE_URL, CACHE_PATH.name, CACHE_PATH.parent)

左滑查看更多


1.2.2 Validator 包装器


Yolov8 模型存储库使用 Validator 包装器,它表示准确性验证管道。它创建数据加载器和评估度量,并更新数据加载器生成的每个数据批次的度量。除此之外,它还负责数据的预处理和结果的后处理。RT-DETR 模型训练集也使用了 COCO 数据集。为了方便起见,我们使用 Yolov8 环境来配置此处的数据。


对于类初始化,应该提供配置。我们将使用默认设置,但可以用一些参数替代它来测试自定义数据。Yolov8 模型模型已经连接了 ValidatorClass 方法,因此我们通过该模型进行创建验证器类实例。

args = get_cfg(cfg=DEFAULT_CFG)args.data = str(CFG_PATH)YOLO_MODEL = "yolov8n"models_dir = Path('./models')yolo_model = YOLO(models_dir / f'{YOLO_MODEL}.pt')det_validator = yolo_model.ValidatorClass(args=args)det_validator.data = check_det_dataset(args.data)det_data_loader = det_validator.get_dataloader("./datasets/coco", 1)det_validator.is_coco = Truedet_validator.class_map = ops.coco80_to_coco91_class()det_validator.names = yolo_model.model.namesdet_validator.metrics.names = det_validator.namesdet_validator.nc = yolo_model.model.model[-1].nc

左滑查看更多


1.2.3 转换用于量化的数据集


上一步中我们使用 Validator 包装器创建了验证数据集,但如果能在量化中使用,还需要进行转换,此处 OpenVINO™ 提供了 API 接口 nncf.Dataset(),通过该接口读取 Validator 包装器中的验证数据。

def transform_fn(data_item:Dict):    input_tensor = det_validator.preprocess(data_item)['img'].numpy()    return input_tensorquantization_dataset = nncf.Dataset(det_data_loader, transform_fn)

左滑查看更多


1.3

定义模型精度校验方法


为了观测模型量化前后模型预测精度变化,此处自定义了模型精度测试方法:

def sigmoid(z):    return 1/(1+np.exp(-z))def rtdetr_result(preds_box,preds_score):    results=[]    n=0    for i in range(300):        scores=preds_score[0,i,:]        score=sigmoid(np.max(np.array(scores)))        if(score<0.0001):            continue        result=[]        cx=preds_box[0,i,0]*640.0        cy=preds_box[0,i,1]*640.0        w=preds_box[0,i,2]*640.0        h=preds_box[0,i,3]*640.0        result.append(cx-0.5*w)        result.append(cy-0.5*h)        result.append(cx+0.5*w)        result.append(cy+0.5*h)        result.append(score)        result.append(np.argmax(scores))        results.append(result)        n+=1    return [torch.tensor(results)]def test(model:ov.Model, core:ov.Core, data_loader:torch.utils.data.DataLoader, validator, num_samples:int = None):    validator.seen = 0    validator.jdict = []    validator.stats = []    validator.batch_i = 1    validator.confusion_matrix = ConfusionMatrix(nc=validator.nc)    compiled_model = core.compile_model(model)    for batch_i, batch in enumerate(tqdm(data_loader, total=num_samples)):        if num_samples is not None and batch_i == num_samples:            break        batch = validator.preprocess(batch)        results = compiled_model(batch["img"])        preds_box = torch.from_numpy(results[compiled_model.output(0)])        preds_score = torch.from_numpy(results[compiled_model.output(1)])              preds=rtdetr_result(preds_box,preds_score)        validator.update_metrics(preds, batch)    stats = validator.get_stats()    return stats

左滑查看更多


1.4

模型量化


1.4.1 模型量化实现


首先我们定义量化接口,nncf.quantize 函数为模型量化提供了一个接口,主要输入参数为:OpenVINO™ 模型和量化数据集,实现如下所示:

quantized_det_model = nncf.quantize(    det_ov_model,    quantization_dataset,    preset=nncf.QuantizationPreset.MIXED)

左滑查看更多


通过上述方法,便可以实现 RT-DETR 模型的量化。


1.4.2 量化前后精度测试


在前文中我们定义了模型精度测试方法,因此我们在此处进行量化前后的精度检测,通过该方法,在 1000 张测试集上进行检测,最后打印模型预测精度:

fp_det_stats = test(det_ov_model, core, det_data_loader, det_validator, num_samples=NUM_TEST_SAMPLES)int8_det_stats = test(quantized_det_model, core, det_data_loader, det_validator, num_samples=NUM_TEST_SAMPLES)print("FP32 model accuracy")print_stats(fp_det_stats, det_validator.seen, det_validator.nt_per_class.sum())print("INT8 model accuracy")print_stats(int8_det_stats, det_validator.seen, det_validator.nt_per_class.sum())

左滑查看更多



上图中是打印的模型量化前后的预测精度情况,为了更好的查看量化前后精度变化,此处绘制了柱状图,如下图所示,通过该柱状图可以看出,模型在量化前后,模型预测精度存在较小的下降,但也满足我们的模型量化需求。



1.4.3 量化前后速度对比


OpenVINO™ 提供了性能测试工具 Benchmark App,方便开发者快速测试 OpenVINO™ 模型在不同的硬件平台上的性能,此处由于 OpenVINO™ GPU 算子对 RT-DETR 模型还不支持,因此此处我们只进行在 CPU 平台上测试。


首先测试量化前的模型,只需要输入以下指令即可:

!benchmark_app -m {det_model_path} -d {device.value} -api async -shape "[1,3,640,640]"

左滑查看更多



上图中展示了量化前的模型在 CPU 平台下的推理速度,可以看到,量化前模型推理速度仅能达到 2.67 FPS。接下来测试量化后的模型,只需要输入以下指令即可:

!benchmark_app -m {int8_model_det_path} -d {device.value} -api async -shape "[1,3,640,640]" -t 15

左滑查看更多



上图中展示了量化后的模型在 CPU 平台下的推理速度,可以看到,量化前模型推理速度仅能达到 8.82 FPS,推理速度提升了 3.3 倍。


注:上述量化过程只是根据量化过程的几个重点步骤进行了讲解,完整的量化步骤以及实现顺序请参考上文中所指出的 Notebook 文章。



第2章

英特尔 iGPU 推理

加速 RT-DETR 模型和速度比较


2.1

英特尔 iGPU 推理

加速 RT-DETR 模型实现


由于当前 OpenVINO™ 发行版 GPU 算子不支持 RT-DETR 模型实现,所以我们无法直接进行 iGPU 加速推理,但为了提升模型推理速度,通过 OpenVINO™ GitHub 提交 Issues,对源码进行修改,然后重新编译源码,更新动态链接库引用,便可以实现 iGPU 加速推理。Issues 链接为:

[Bug]:There was an error compiling the RT-DETR model on the GPU platform using OpenVINO. · Issue #20871 · openvinotoolkit/openvino (github.com)


大家在使用时,可以参考官方提供的解决方案,对源码进行修改,然后根据 OpenVINO™ 源码编译流程,对源码进行编译,获取修改后的动态链接库。


此处为了方便大家使用,我们在项目中提供了编译好的 Windows 的动态链接库,通过下述方式进行下载:

wget https://github.com/guojin-yan/RT-DETR-OpenVINO/releases/download/Model2.0/openvino_new_build.rar


通过该方式下载编译好的动态链接库文件后,然后参考上一篇文章《基于 OpenVINO™ C++ API 部署 RT-DETR 模型 | 开发者实战》进行开发,将动态链接库引用替换成此处下载的动态链接库文件,并将设备设置为 GPU,然后便可以实现 GPU 推理。


2.2

CPU 与 iGPU 推理速度对比


在上一步中我们实现了基于 OpenVINO™ 在 iGPU 设备上进行 RT-DETR 模型的推理加速,并在上一节中我们实现了模型 INT8 量化,最后我们在此处进行一个对比试验,分别在 CPU 和 iGPU 推理设备下,推理 FP32 和 INT8 模型,检验模型的推理速度,为了避免偶然性,此处通过推理 100 次求平均获取最后的推理速度,如下表所示:



测试硬件:CPU 处理器为第 11 代英特尔® 酷睿™ i7-1165G7,iGPU 为 Intel Iris Xe Graphics 集成显卡。通过绘制在不同平台、不同精度模型推理时间以及 FPS 柱状图,可以很明显看出,不管模型是经过量化或者是 iGPU 加速,在不同推理设备上,模型推理速度会有 1 ~ 3 倍不同程度的提升。通过测试可以看出最快速度可以实现 23 帧左右的推理。





第3章

总结


在本文中,我们基于 OpenVINO™ 下的模型优化工具 NNCF,实现了 RT-DETR 模型的 INT8 量化,并且在损失极少的精度代价下,实现了模型推理速度提升 3 ~ 4 倍左右,模型大小将为原来的 1/4,即提升了模型的推理速度,又降低了模型推理占用内存,这对在边缘设备部署具有十分重要的意义。


另外,我们通过 OpenVINO™ Github 指导,解决了 RT-DETR 模型无法在英特尔 iGPU 上推理的困扰,实现了使用 OpenVINO™ 在 iGPU 设备上的推理加速,使得模型推理速度有了 1 ~ 3 倍的提升。

OpenVINO™

--END--


               
               
               
你也许想了解(点击蓝字查看)⬇️
➡️  OpenVINO™ 2023.2 发布:让生成式 AI 在实际场景中更易用
➡️ 开发者实战 | 介绍OpenVINO™ 2023.1:在边缘端赋能生成式AI
➡️ 基于 ChatGLM2 和 OpenVINO™ 打造中文聊天助手
➡️ 基于 Llama2 和 OpenVINO™ 打造聊天机器人
➡️ OpenVINO™ DevCon 2023重磅回归!英特尔以创新产品激发开发者无限潜能
➡️ 5周年更新 | OpenVINO™  2023.0,让AI部署和加速更容易
➡️ OpenVINO™5周年重头戏!2023.0版本持续升级AI部署和加速性能
➡️ OpenVINO™2023.0实战 | 在 LabVIEW 中部署 YOLOv8 目标检测模型
➡️ 开发者实战系列资源包来啦!
➡️  以AI作画,祝她节日快乐;简单三步,OpenVINO™ 助你轻松体验AIGC
➡️  还不知道如何用OpenVINO™作画?点击了解教程。


              
              
              

扫描下方二维码立即体验 

OpenVINO™ 工具套件 2023.2


点击 阅读原文 立即体验OpenVINO 2023.2
文章这么精彩,你有没有“在看”?

本文分享自微信公众号 - OpenVINO 中文社区(openvinodev)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部