TensorRT的两种INT8量化方式: QTA, PTQ

news2024/9/28 13:17:18

TensorRT的两种INT8量化方式: QTA, PTQ

深度学习 (DL) 模型的训练阶段包括学习大量密集的浮点权重矩阵,这导致推理过程中需要进行大量的浮点计算。 研究表明,可以通过强制某些权重为零来跳过其中许多计算,而对最终精度的影响很小。

与此同时,之前的帖子表明较低的精度(例如 INT8)通常足以在推理过程中获得与 FP32 相似的精度。 稀疏性和量化是流行的优化技术,用于解决这些问题,缩短推理时间并减少内存占用。

NVIDIA TensorRT 已经提供量化支持一段时间(从 2.1 版本开始),并且最近在 NVIDIA Ampere 架构 Tensor Cores 中内置了对稀疏性的支持,并在 TensorRT 8.0 中引入。

这篇文章是关于如何使用稀疏性和量化技术使用 TensorRT 加速 DL 模型的分步指南。 尽管已经单独讨论了这些优化中的每一个,但仍然需要展示从训练到使用 TensorRT 部署的端到端工作流,同时考虑这两种优化。

在这篇文章中,我们旨在弥合这一差距并帮助您了解稀疏量化训练工作流程是什么样的,就 TensorRT 加速方面的稀疏性最佳实践提出建议,并展示 ResNet-34 的端到端案例研究.

结构稀疏

NVIDIA 稀疏张量核心使用 2:4 模式,这意味着四个值的每个连续块中的两个必须为零。 换句话说,我们遵循 50% 的细粒度结构化稀疏度配方,由于直接在 Tensor Core 上提供可用支持,因此不会对零值进行任何计算。 这导致在相同的时间内计算更多的工作量。 在这篇文章中,我们将此过程称为修剪。

有关详细信息,请参阅使用 NVIDIA Ampere 架构和 NVIDIA TensorRT 通过稀疏性加速推理。

量化

量化是指将连续的无限值映射到一组有限的离散值(例如,FP32 到 INT8)的过程。 这篇文章中讨论了两种主要的量化技术:

  • 训练后量化 (PTQ):使用隐式量化工作流程。 在隐式量化网络中,每个量化张量都有一个关联的标度,用于通过校准对值进行隐式量化和反量化。 然后 TensorRT 检查该层运行速度更快的精度并相应地执行它。
  • 量化感知训练 (QAT):使用显式量化工作流程。 显式量化网络利用量化和反量化 (Q/DQ) 节点来明确指示必须量化哪些层。 这意味着您可以更好地控制在 INT8 中运行哪些层。 有关详细信息,请参阅 Q/DQ 层布局建议。

有关量化基础知识、PTQ 和 QAT 量化技术之间的比较、何时选择哪种量化的见解以及 TensorRT 中的量化的更多信息,请参阅使用 NVIDIA TensorRT 的量化感知训练实现 INT8 推理的 FP32 精度。

在 TensorRT 中部署稀疏量化模型的工作流程

在 TensorRT 中部署稀疏量化模型的工作流程,以 PyTorch 作为 DL 框架,有以下步骤:

  • 在 PyTorch 中对预训练的密集模型进行稀疏化和微调。
  • 通过 PTQ 或 QAT 工作流程量化稀疏化模型。
  • 在 TensorRT 中部署获得的稀疏 INT8 引擎。
    下图显示了所有三个步骤。 步骤 2 中的一个区别是 Q/DQ 节点存在于通过 QAT 生成的 ONNX 图中,但在通过 PTQ 生成的 ONNX 图中不存在。 有关详细信息,请参阅使用 INT8。

鉴于此,这是 QAT 的完整工作流程:

  • 在 PyTorch 中对预训练的密集模型进行稀疏化和微调。
  • 在 PyTorch 中量化、校准和微调稀疏模型。
  • 将 PyTorch 模型导出到 ONNX。
  • 通过 ONNX 生成 TensorRT 引擎。
  • 在 TensorRT 中部署获得的 Sparse INT8 引擎。

另一方面,这是 PTQ 的完整工作流程:

  • 在 PyTorch 中对预训练的密集模型进行稀疏化和微调。
  • 将 PyTorch 模型导出到 ONNX。
  • 通过 TensorRT 构建器对稀疏化的 ONNX 模型进行校准和量化,生成 TensorRT 引擎。
  • 在 TensorRT 中部署获得的稀疏 INT8 引擎。

案例研究:ResNet-34

本节演示了使用 ResNet-34 的稀疏量化工作流程的案例研究。 有关详细信息,请参阅 /SparsityINT8 GitHub 存储库中的完整代码示例。

要求

以下是完成此案例研究所需的基本配置:

  • Python 3.8
  • PyTorch 1.11 (also tested with 2.0.0)
  • PyTorch vision
  • apex sparsity toolkit
  • pytorch-quantization toolkit
  • TensorRT 8.6
  • Polygraphy
  • ONNX opset>=13
  • NVIDIA Ampere architecture GPU for Tensor Core support

本案例研究需要使用 ImageNet 2012 数据集进行图像分类。 有关下载数据集并将其转换为所需格式的更多信息,请参阅 GitHub 存储库上的自述文件。

稀疏训练、稀疏 QAT 模型微调和稀疏 PTQ 模型校准需要此数据集。 它还用于评估模型。

第 1 步:从密集模型中进行稀疏化和微调

加载预训练的密集模型并增强模型和优化器以进行稀疏训练。 有关详细信息,请参阅 NVIDIA/apex/tree/master/apex/contrib/sparsity 文件夹。

import copy
from torchvision import models
from apex.contrib.sparsity import ASP
 
# Load dense model
model_dense = models.__dict__["resnet34"](pretrained=True)
 
# Initialize sparsity mode before starting sparse training
model_sparse = copy.deepcopy(model_dense)
ASP.prune_trained_model(model_sparse, optimizer)
 
# Re-train model
for e in range(0, epoch):
    for i, (image, target) in enumerate(data_loader):
        image, target = image.to(device), target.to(device)
        output = model_sparse(image)
        loss = criterion(output, target)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
 
# Save model
torch.save(model_sparse.state_dict(), "sparse_finetuned.pth")

第 2 步:量化 PyTorch 模型

您可以为此步骤选择两种量化方法:PTQ 或 QAT。

PTQ 通过 TensorRT 校准

此选项将 PyTorch 模型导出到 ONNX 并通过 TensorRT Python API 对其进行校准。 这会生成校准缓存和准备部署的 TensorRT 引擎。

将稀疏 PyTorch 模型导出到 ONNX:

dummy_input = torch.randn(batch_size, 3, 224, 224, device="cuda")
torch.onnx.export(model_sparse, dummy_input, "sparse_finetuned.onnx", opset_version=13, do_constant_folding=True)

使用校准数据集校准在上一步中导出的 ONNX 模型。 以下代码示例假定 ONNX 模型具有静态输入形状和批量大小。

from infer_engine import infer
from polygraphy.backend.trt import Calibrator, CreateConfig, EngineFromNetwork, NetworkFromOnnxPath, TrtRunner, SaveEngine
from polygraphy.logger import G_LOGGER
 
 
# Data loader argument to `Calibrator` 
def calib_data(val_batches, input_name):
    for iteration, (images, labels) in enumerate(val_batches):
        yield {input_name: images.numpy()}
 
# Set path to ONNX model
onnx_path = "sparse_finetuned.onnx"
 
# Set calibrator
calibration_cache_path = onnx_path.replace(".onnx", "_calibration.cache")
calibrator = Calibrator(
    data_loader=calib_data(data_loader_calib, args.onnx_input_name), 
    cache=calibration_cache_path
)
 
# Build engine from ONNX model by enabling INT8 and sparsity weights, and providing the calibrator
build_engine = EngineFromNetwork(
    NetworkFromOnnxPath(onnx_path),
    config=CreateConfig(
        int8=True,
        calibrator=calibrator,
        sparse_weights=True
    )
)
 
# Trigger engine saving
engine_path = onnx_path.replace(".onnx", ".engine")
build_engine = SaveEngine(build_engine, path=engine_path)
 
# Calibrate engine (activated by the runner)
with G_LOGGER.verbosity(G_LOGGER.VERBOSE), TrtRunner(build_engine) as runner:
    print("Calibrated engine!")
 
    # Infer PTQ engine and evaluate its accuracy
    log_file = engine_path.split("/")[-1].replace(".engine", "_accuracy.txt")
    infer(
        engine_path,
        data_loader_test,
        batch_size=args.batch_size,
        log_file=log_file
    )

QAT 通过 pytorch-quantization 工具包

此选项使用 pytorch-quantization 工具包在稀疏 PyTorch 模型中添加 Q/DQ 节点,对其进行校准,并对其进行微调几个 epoch。 然后将微调后的模型导出到 ONNX 并转换为 TensorRT 引擎进行部署。

为确保已计算的稀疏浮点权重不会被覆盖,确保 QAT 权重也将结构化为稀疏,您必须再次准备模型进行剪枝。

在加载微调的稀疏权重之前初始化 QAT 模型和优化器以进行修剪。 稀疏掩码重新计算也必须禁用,因为它们已经在步骤 1 中计算过。这需要一个自定义函数,该函数是对 APEX 工具包的 prune_trained_model 函数的轻微修改。 修改在代码示例中突出显示:

from apex.contrib.sparsity import ASP
 
def prune_trained_model_custom(model, optimizer, compute_sparse_masks=False):
    asp = ASP()
    asp.init_model_for_pruning(model, mask_calculator="m4n2_1d", verbosity=2, whitelist=[torch.nn.Linear, torch.nn.Conv2d], allow_recompute_mask=False)
    asp.init_optimizer_for_pruning(optimizer)
    if compute_sparse_masks:
        asp.compute_sparse_masks()

为了优化 Q/DQ 节点放置,您必须修改模型的定义以量化残差分支,如 pytorch-quantization 工具包示例所示。 例如,对于ResNet,需要在残差分支中添加Q/DQ节点的修改突出显示如下:


from pytorch_quantization import nn as quant_nn
 
class BasicBlock(nn.Module):
 
   def __init__(self, ..., quantize: bool = False) -> None:
       super().__init__()
       ...
       if self._quantize:
            self.residual_quantizer = quant_nn.TensorQuantizer(quant_nn.QuantConv2d.default_quant_desc_input)
 
   def forward(self, x: Tensor) -> Tensor:
       identity = x
       ...
       if self._quantize:
           out += self.residual_quantizer(identity)
       else:
           out += identity
       out = self.relu(out)
       return out

必须对 Bottleneck 类重复相同的修改,并且必须通过 ResNet、_resnet 和 resnet34 函数传播量化 bool 参数。 完成这些修改后,使用 quantize=True 实例化模型。 有关详细信息,请参阅 resnet.py 中的第 734 行。

通过 QAT 量化稀疏模型的第一步是在模型中启用量化和剪枝。 第二步是加载微调的稀疏检查点,对其进行校准,然后最后对该模型进行一些 epoch 的微调。 有关 collect_stats 和 compute_amax 函数的更多信息,请参阅 calibrate_quant_resnet50.ipynb。

# Add Q/DQ nodes to the dense model
from pytorch_quantization import quant_modules
quant_modules.initialize()
model_qat = models.__dict__["resnet34"](pretrained=True, quantize=True)
 
# Initialize sparsity mode before starting Sparse-QAT fine-tuning
prune_trained_model_custom(model_qat, optimizer, compute_sparse_masks=False)
 
# Load Sparse weights
load_dict = torch.load("sparse_finetuned.pth")
model_qat.load_state_dict(load_dict["model_state_dict"])
 
# Calibrate model
collect_stats(model_qat, data_loader_calib, num_batches=len(data_loader_calib))
compute_amax(model_qat, method="entropy”)
 
# Fine-tune model
for e in range(0, epoch):
    for i, (image, target) in enumerate(data_loader):
        image, target = image.to(device), target.to(device)
        output = model_qat(image)
        ...
 
# Save model
torch.save(model_qat.state_dict(), "quant_finetuned.pth")

要准备部署 TensorRT 引擎,您必须将稀疏量化 PyTorch 模型导出到 ONNX。 TensorRT 期望 QAT ONNX 模型指示哪些层应该通过一组 QuantizeLinear 和 DequantizeLinear ONNX 操作进行量化。 在将量化的 PyTorch 模型导出到 ONNX 时,通过启用伪量化来满足此要求。

from pytorch_quantization import nn as quant_nn
quant_nn.TensorQuantizer.use_fb_fake_quant = True
dummy_input = torch.randn(batch_size, 3, 224, 224, device="cuda")
torch.onnx.export(model_qat, dummy_input, "quant_finetuned.onnx", opset_version=13, do_constant_folding=True)

最后,构建 TensorRT 引擎:

$ trtexec --onnx=quant_finetuned.onnx --int8 --sparsity=enable --saveEngine=quant_finetuned.engine --skipInference

第三步:部署TensorRT引擎

$ trtexec --loadEngine=quant_finetuned.engine -v

结果

以下是在配备 TensorRT 8.6-GA (8.6.1.6) 的 NVIDIA A40 GPU 上针对 ResNet-34 密集量化和稀疏量化模型在分类精度和运行时方面的性能测量。 要重现这些结果,请遵循上一节中描述的工作流程。

下图显示了 TensorRT 中 ResNet-34 在三种设置下的密集精度与稀疏精度的比较:

  • FP32 中的密集与稀疏
  • INT8 中的密集 PTQ 与稀疏 PTQ
  • INT8 中的密集 QAT 与稀疏 QAT

如您所见,与所有设置的密集变体相比,稀疏变体在很大程度上可以保持准确性。

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

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

相关文章

【学习】企业申请DCMM原来有这么多的好处

DCMM,即数据管理能力成熟度评估模型(Data management Capability Maturity Model),是我国在数据管理领域首个正式发布的国家标准。DCMM的核心目的是帮助企业利用先进的数据管理理念和方法,建立和评价自身的数据管理能力…

JAVA------基础篇

java基础 1.JDK JDK :java development kit JRE:java runtime environment JDK包含JRE java跨平台:因为java程序运行依赖虚拟机,虚拟机需要有对应操作系统的版本,而jre中有虚拟机。 当你想要在Linux系统下运行,则需要…

U盘未格式化?数据恢复大揭秘!

在日常办公和生活中,U盘已成为我们不可或缺的数据存储工具。然而,有时我们会遇到这样一个令人头疼的问题:原本正常使用的U盘,突然提示“未格式化”,里面的文件似乎都消失不见了。面对这种情况,很多人会感到…

[2021]Zookeeper getAcl命令未授权访问漏洞概述与解决

今天在漏洞扫描的时候蹦出来一个zookeeper的漏洞问题,即使是非zookeeper的节点,或者是非集群内部节点,也可以通过nc扫描2181端口,获取极多的zk信息。关于漏洞的详细描述参考apache zookeeper官方概述:CVE-2018-8012: A…

FPGA时钟资源详解(2)——Clock-Capable Inputs

FPGA时钟系列文章总览:FPGA原理与结构(14)——时钟资源https://ztzhang.blog.csdn.net/article/details/132307564 目录 一、概述 1.1 为什么使用CC 1.2 如何使用CC 二、Clock-Capable Inputs 2.1 SRCC 2.2 MRCC 2.3 其他用途 2.3.1…

Day23 代码随想录(1刷) 二叉树

669. 修剪二叉搜索树 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代…

安踏,步入“高端化”的甜蜜陷阱

文丨黄小艺 2023年3月14日,徐阳重回安踏担任CEO的第二天,就颇为急切地拉了一场高层会议。 面对在场的安踏老人们,徐阳提了两个很终极的问题,“是什么让过去30年的安踏获得了成功?”“未来30年,如果安踏想…

mysql80-DBA数据库学习1-数据库安装

掌握能力 核心技能 核心技能 mysql部署 官网地址www.mysql.com 或者www.oracle.com https://dev.mysql.com/downloads/repo/yum/ Install the RPM you downloaded for your system, for example: yum install mysql80-community-release-{platform}-{version-number}.noarch…

智慧公厕的技术融合策略

智慧公厕是迎合现代城市发展需要的一项重要基础设施,其设计的技术融合策略在实现公共厕所泛在感知、互通互联、协同构筑智慧城市等方面起到了关键作用。本文将以智慧公厕源头实力厂家广州中期科技有限公司,大量精品案例现场实景实图实例,从物…

NetCore3.1 Controller中直接返回JObject对象抛出异常解决方案

问题描述 在NetCore 3.1的Web项目中,Controller有一个方法直接返回JObject对象时,抛出了异常 S y s t e m . N o t S u p p o r t e d E x c e p t i o n : T h e c o l l e c t i o n t y p e ′ N e w t o n s o f t . J s o n . L i n q . J O b j …

FID离子流采集硬件方案设计

一、原理简介 氢离子火焰检测器(Flame Ionization Detector, FID)是气相色谱仪中常用的一种检测器,主要用于检测有机化合物。它的工作原理基于在高温氢气/空气火焰中,有机化合物会发生离子化放出电子的过程。 1、FID的基本结构 燃烧器: 内部有一个小型燃烧池,燃烧池顶端有一个…

GA遗传算法和ALNS算法的区别(我的APS项目七)

博主用最简单的方式告诉你遗传算法是什么,估计这是网上最简单的遗传算法入门教程了。首先我们先带入一个问题,我们要去9大城市旅游,想知道每个城市走一遍,总路程最短的出行顺序是什么? OK,题目我们已经明确…

由浅到深认识Java语言(38):I/O流

该文章Github地址:https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.c…

【前端学习——js篇】5.事件循环

详细:https://github.com/febobo/web-interview 5.事件循环 js是一种单线程语言,同一时间内只能做一件事情,为了避免单线程阻塞的方法就是事件循环。 在javascript当中,所有的任务都可以分为: 同步任务:按…

Java Swing游戏开发学习19

内容来自RyiSnow视频讲解 这一节讲的是**Entity ArrayList(Render Order Revised)**实体数组列表(渲染顺序修改)。 前言 由于NPC和player的实体碰撞区域比他们本身的大小要小,所以会造成一个bug,当前的绘制顺序是,NP…

进程的基础知识

1).进程:一个正在运行中的程序; 2).PCB:进程控制块,进程描述符(PID:进程唯一的标识符) 进程控制块是用一个结构体struct task_struct来实现; 3).进程的状态: 就绪,阻塞,运行; 时间片轮转调度; 时间片轮转调度是一种最古老,最简单,最公平且使用最广的…

一文即可帮助你认识进程和线程~

本文的重点:什么是:进程、进程调度、线程和他们之间的联系。主讲概念知识,不讲代码实现 目录 一、认识进程 1.什么是进程 2.进程的信息 3.进程调度(***) 4.进程调度的基本过程 二、线程 1.线程的引入 2.什么是线程 3.进程于线程的联…

鸿蒙开发之ArkUI组件常用组件图片和文本

ArkUI即方舟开发框架是HarmonyOS应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。 开发文档地址 &…

【功能实现】新年贺卡(蓝桥)

题目分析: 想要实现一个随机抽取功能 功能拆解:题目给了数组,我们采用生成随机数的方式,随机数作为数组的索引值访问数组的值。 并返回获取到的值,将获取到的值插入到页面中。 document.addEventListener(DOMConten…

Diffusion添加噪声noise的方式有哪些?怎么向图像中添加噪声?

添加噪声的方式大致分为两种,一种是每张图像在任意timestep都加入一样的均匀噪声,另一种是按照timestep添加不同程度的噪声 一、在任意timestep都加入一样的noise batch_size 32x_start torch.rand(batch_size,3,256,256) noise torch.randn_like(x_…