使用 Intel® Neural Compressor 为 PyTorch 进行易用量化¶
概述¶
大多数深度学习应用程序都使用 32 位浮点精度进行推理。但是,由于性能显著提升,低精度数据类型,尤其是 int8,正越来越受到关注。采用低精度的主要问题之一是如何轻松缓解潜在的精度损失并达到预定义的精度要求。
Intel® Neural Compressor 旨在通过扩展 PyTorch 来解决上述问题,它提供以精度为导向的自动调整策略,帮助用户快速找出 Intel 硬件上的最佳量化模型,包括 Intel 深度学习加速 (Intel DL Boost) 和 Intel 高级矩阵扩展 (Intel AMX).
Intel® Neural Compressor 已作为开源项目发布在 Github 上。
特性¶
易用的 Python API:Intel® Neural Compressor 为用户提供简单的 Python 前端 API 和实用程序,只需几行代码更改即可完成神经网络压缩。通常只需要添加 5 到 6 个子句即可。
量化: 英特尔® 神经压缩支持在 PyTorch fx 图模式和急切模型上对训练后静态量化、训练后动态量化和量化感知训练进行精度驱动的自动调整过程。
本教程主要关注量化部分。有关如何使用英特尔® 神经压缩进行修剪和蒸馏,请参阅英特尔® 神经压缩 github 存储库中的相应文档。
入门¶
安装¶
# install stable version from pip
pip install neural-compressor
# install nightly version from pip
pip install -i https://test.pypi.org/simple/ neural-compressor
# install stable version from from conda
conda install neural-compressor -c conda-forge -c intel
支持的 python 版本为 3.6 或 3.7 或 3.8 或 3.9
用法¶
用户需要进行少量代码更改才能开始使用英特尔® 神经压缩量化 API。支持 PyTorch fx 图模式和急切模式。
英特尔® 神经压缩以 FP32 模型和 yaml 配置文件作为输入。为了构建量化过程,用户可以通过 yaml 配置文件或 python API 指定以下设置:
校准数据加载器(静态量化需要)
评估数据加载器
评估指标
英特尔® 神经压缩支持一些流行的数据加载器和评估指标。有关如何在 yaml 配置文件中配置它们,用户可以参考 内置数据集.
如果用户想使用自行开发的数据加载器或评估指标,英特尔® 神经压缩支持通过使用 python 代码注册自定义数据加载器/指标来实现。
有关 yaml 配置文件格式,请参考 yaml 模板.
对英特尔® 神经压缩所需的代码更改在上面一行中用注释突出显示。
模型¶
在本教程中,使用 LeNet 模型来演示如何处理英特尔® 神经压缩。
# main.py
import torch
import torch.nn as nn
import torch.nn.functional as F
# LeNet Model definition
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc1_drop = nn.Dropout()
self.fc2 = nn.Linear(50, 10)
def forward(self, x):
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = x.reshape(-1, 320)
x = F.relu(self.fc1(x))
x = self.fc1_drop(x)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
model = Net()
model.load_state_dict(torch.load('./lenet_mnist_model.pth', weights_only=True))
预训练模型权重 lenet_mnist_model.pth 来自 这里.
精度驱动量化¶
英特尔® 神经压缩支持精度驱动的自动调整,以生成满足预定义精度目标的最佳 int8 模型。
以下是如何通过自动调整在 PyTorch FX 图模式 上对简单网络进行量化的示例。
# conf.yaml
model:
name: LeNet
framework: pytorch_fx
evaluation:
accuracy:
metric:
topk: 1
tuning:
accuracy_criterion:
relative: 0.01
# main.py
model.eval()
from torchvision import datasets, transforms
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=False, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
])),
batch_size=1)
# launch code for Intel® Neural Compressor
from neural_compressor.experimental import Quantization
quantizer = Quantization("./conf.yaml")
quantizer.model = model
quantizer.calib_dataloader = test_loader
quantizer.eval_dataloader = test_loader
q_model = quantizer()
q_model.save('./output')
在 conf.yaml 文件中,将英特尔® 神经压缩的内置指标 top1 指定为评估方法,并将 1% 相对精度损失设置为自动调整的精度目标。英特尔® 神经压缩将遍历每个操作级别的所有可能的量化配置组合,以找出达到预定义精度目标的最佳 int8 模型。
除了这些内置指标之外,英特尔® 神经压缩还支持通过 python 代码进行自定义指标。
# conf.yaml
model:
name: LeNet
framework: pytorch_fx
tuning:
accuracy_criterion:
relative: 0.01
# main.py
model.eval()
from torchvision import datasets, transforms
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=False, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
])),
batch_size=1)
# define a customized metric
class Top1Metric(object):
def __init__(self):
self.correct = 0
def update(self, output, label):
pred = output.argmax(dim=1, keepdim=True)
self.correct += pred.eq(label.view_as(pred)).sum().item()
def reset(self):
self.correct = 0
def result(self):
return 100. * self.correct / len(test_loader.dataset)
# launch code for Intel® Neural Compressor
from neural_compressor.experimental import Quantization
quantizer = Quantization("./conf.yaml")
quantizer.model = model
quantizer.calib_dataloader = test_loader
quantizer.eval_dataloader = test_loader
quantizer.metric = Top1Metric()
q_model = quantizer()
q_model.save('./output')
在上面的示例中,实现了一个包含 update() 和 result() 函数的 class,用于记录每个小批量结果并在最后计算最终精度。
量化感知训练¶
除了训练后静态量化和训练后动态量化之外,英特尔® 神经压缩还支持使用精度驱动的自动调整机制进行量化感知训练。
以下是如何在 PyTorch FX 图模式 上对简单网络进行量化感知训练的示例。
# conf.yaml
model:
name: LeNet
framework: pytorch_fx
quantization:
approach: quant_aware_training
evaluation:
accuracy:
metric:
topk: 1
tuning:
accuracy_criterion:
relative: 0.01
# main.py
model.eval()
from torchvision import datasets, transforms
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('./data', train=False, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=1)
import torch.optim as optim
optimizer = optim.SGD(model.parameters(), lr=0.0001, momentum=0.1)
def training_func(model):
model.train()
for epoch in range(1, 3):
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
# launch code for Intel® Neural Compressor
from neural_compressor.experimental import Quantization
quantizer = Quantization("./conf.yaml")
quantizer.model = model
quantizer.q_func = training_func
quantizer.eval_dataloader = test_loader
q_model = quantizer()
q_model.save('./output')
仅性能量化¶
英特尔® 神经压缩支持使用虚拟数据集直接生成 int8 模型,以用于性能基准测试目的。
以下是如何在 PyTorch FX 图模式 上使用虚拟数据集对简单网络进行量化的示例。
# conf.yaml
model:
name: lenet
framework: pytorch_fx
# main.py
model.eval()
# launch code for Intel® Neural Compressor
from neural_compressor.experimental import Quantization, common
from neural_compressor.experimental.data.datasets.dummy_dataset import DummyDataset
quantizer = Quantization("./conf.yaml")
quantizer.model = model
quantizer.calib_dataloader = common.DataLoader(DummyDataset([(1, 1, 28, 28)]))
q_model = quantizer()
q_model.save('./output')
量化输出¶
用户可以从英特尔® 神经压缩打印的日志中了解有多少个操作被量化,如下所示:
2021-12-08 14:58:35 [INFO] |********Mixed Precision Statistics*******|
2021-12-08 14:58:35 [INFO] +------------------------+--------+-------+
2021-12-08 14:58:35 [INFO] | Op Type | Total | INT8 |
2021-12-08 14:58:35 [INFO] +------------------------+--------+-------+
2021-12-08 14:58:35 [INFO] | quantize_per_tensor | 2 | 2 |
2021-12-08 14:58:35 [INFO] | Conv2d | 2 | 2 |
2021-12-08 14:58:35 [INFO] | max_pool2d | 1 | 1 |
2021-12-08 14:58:35 [INFO] | relu | 1 | 1 |
2021-12-08 14:58:35 [INFO] | dequantize | 2 | 2 |
2021-12-08 14:58:35 [INFO] | LinearReLU | 1 | 1 |
2021-12-08 14:58:35 [INFO] | Linear | 1 | 1 |
2021-12-08 14:58:35 [INFO] +------------------------+--------+-------+
量化后的模型将生成在 ./output 目录下,其中包含两个文件:1. best_configure.yaml 2. best_model_weights.pt
第一个文件包含每个操作的量化配置,第二个文件包含 int8 权重以及激活的零点和比例信息。
部署¶
用户可以使用以下代码加载量化后的模型,然后进行推理或性能基准测试。
from neural_compressor.utils.pytorch import load
int8_model = load('./output', model)
教程¶
请访问 英特尔® 神经压缩 Github 存储库 获取更多教程。