doc
: Quantization Recipe — PyTorch Tutorials 1.11.0+cu102 documentation
2022年5月24日
tag : 翻译学习
topic : Pytorch 量化
该Recipe演示了如何量化PyTorch模型,以便以较小的尺寸和更快的推理速度运行,并且精度与原始模型大致相同。量化可以应用于服务器和移动模型部署,在移动设备上可能特别重要甚至至关重要,因为非量化模型的大小可能会超过iOS或Android应用程序允许的限制,导致部署或OTA更新花费太多时间,并使推理太慢而无法获得良好的用户体验。
量化是一种将模型参数中的 32 位浮点数转换为 8 位整数的技术。通过量化,模型大小和内存占用可以减少到其原始大小的1/4,并且推理可以快2-4倍,同时精度保持不变。
量化模型的方法或工作流总共有三种:训练后动态量化、训练后静态量化和量化感知训练。
但是,如要使用的模型已经具有量化版本,则可以直接使用它,而无需执行上述三个工作流中的任何一个。例如,Torchvision库已经包括MobileNet v2,ResNet 18,ResNet 50,Inception v3,GoogleNet等型号的量化版本。因此,将使最后一种方法作为工作流展示,尽管是一个简单的工作流。
Notice :
The quantization support is available for a limited set of operators. See this for more information.
PyTorch 1.6.0 或 1.7.0
torchvision 0.6.0 或 0.7.0
使用以下四个工作流之一来量化模型。
要获取 MobileNet v2 量化模型,只需执行以下操作:
import torchvision
model_quantized = torchvision.models.quantization.mobilenet_v2(pretrained=True, quantize=True)
要将非量化 MobileNet v2 模型的大小差异与其量化版本进行比较,执行以下操作:
model = torchvision.models.mobilenet_v2(pretrained=True)
import os
import torch
def print_model_size(mdl):
torch.save(mdl.state_dict(), "tmp.pt")
print("%.2f MB" %(os.path.getsize("tmp.pt")/1e6))
os.remove('tmp.pt')
print_model_size(model)
print_model_size(model_quantized)
输出将是:
14.27 MB
3.63 MB
要应用动态量化,它将模型中的所有权重从 32 位浮点数转换为 8 位整数,但直到对激活执行计算之前才将激活转换为 int8(which converts all the weights in a model from 32-bit floating numbers to 8-bit integers but doesn’t convert the activations to int8 till just before performing the computation on the activations),
只需调用 torch.quantization.quantize_dynamic:
model_dynamic_quantized = torch.quantization.quantize_dynamic(
model, qconfig_spec={torch.nn.Linear}, dtype=torch.qint8
)
其中,qconfig_spec指定模型中要应用量化的子模块名称列表。
WARNING
An important limitation of Dynamic Quantization, while it is the easiest workflow if you do not have a pre-trained quantized model ready for use, is that it currently only supports nn.Linear and nn.LSTM in qconfig_spec, meaning that you will have to use Static Quantization or Quantization Aware Training, to be discussed later, to quantize other modules such as nn.Conv2d.
动态量化的一个重要限制是,如果没有准备好使用预先训练的量化模型,它是最简单的工作流程,但qconfig_spec目前仅支持nn.Linear和nn.LSTM ,这意味着您将不得不使用静态量化或量化感知训练,稍后将讨论,以量化其他模块,如nn.Conv2d.
quantize_dynamic API 调用的完整文档 : here.
使用训练后动态量化的其他三个示例
此方法事先将权重和激活都转换为 8 位整数,因此在推理过程中不会像动态量化那样对激活进行动态转换,从而显著提高性能。
若要对模型应用静态量化,请运行以下代码:
backend = "qnnpack"
model.qconfig = torch.quantization.get_default_qconfig(backend)
torch.backends.quantized.engine = backend
model_static_quantized = torch.quantization.prepare(model, inplace=False)
model_static_quantized = torch.quantization.convert(model_static_quantized, inplace=False)
此后运行print_model_size(model_static_quantized)
显示静态量化模型为3.98MB。
完整的模型定义和静态量化示例 : here
专用的静态量化教程 : here
NOTE
To make the model run on mobile devices which normally have arm architecture, you need to use qnnpack for backend; to run the model on computer with x86 architecture, use fbgemm.
要使模型在通常具有arm架构的移动设备上运行,您需要使用qnnpack作为后端;
若要在具有 x86 体系结构的计算机上运行模型,请使用 fbgemm。
量化感知训练在模型训练过程中将fake量化插入到所有权重和激活中,并导致比PTQ训练后量化方法更高的推理准确性。它通常用于 CNN 模型。
要启用量化感知训练的模型,在模型定义的__init__方法中定义一个 QuantStub 和一个 DeQuantStub,用于将张量从浮点转换为量化类型,反之亦然:
self.quant = torch.quantization.QuantStub()
self.dequant = torch.quantization.DeQuantStub()
然后在模型定义的forward方法def forward(self, x)
的开头和结尾,调用 x = self.quant(x) 和 x = self.dequant(x)。
若要执行量化感知训练,使用以下代码段:
model.qconfig = torch.quantization.get_default_qat_qconfig(backend)
model_qat = torch.quantization.prepare_qat(model, inplace=False)
# quantization aware training goes here
model_qat = torch.quantization.convert(model_qat.eval(), inplace=False)
有关量化感知训练的更多详细示例,请参阅此处和此处。
预训练的量化模型也可用于量化的感知迁移学习,使用上面显示的相同量化和去量化调用。有关完整示例,请参阅此处。
使用上述步骤之一生成量化模型后,在模型可用于在移动设备上运行之前,需要将其进一步转换为 TorchScript 格式,然后针对移动应用进行优化。有关详细信息,请参阅针对移动设备的脚本和优化配方。
有关量化的不同工作流程的详细信息,请参阅此处和此处。