跳到主要内容

附录

Eager 模式

和 PyTorch 官方一样,我们推荐用户优先使用的 fx 量化模式。horizon_plugin_pytorch 目前支持采用 eager 模式进行量化。 Eager 模式的整体流程同样参考了 PyTorch 官方的量化接口和思路,因此,建议您先阅读 PyTorch 官方文档中 Eager 模式相关部分。

与 fx 模式的区别

在 horizon_plugin_pytorch 中使用 eager 模式,和 fx 模式的主要区别在于:

  • eager 模式仅支持 module 形式的算子。您需要手动将浮点模型中的函数形式的算子替换为 PyTorch 中 Module 类型的算子或者是 horizon_plugin_pytorch 中定义的专有算子,包括但不限于:
原始的浮点算子需要替换的算子
torch.nn.functional.relutorch.nn.ReLU()
a + b
torch.add
horizon.nn.quantized.FloatFunctional().add
Tensor.exphorizon.nn.Exp()
torch.nn.functional.interpolatehorizon.nn.Interpolate()
  • 您必须手动定义需要融合的算子,并显示调用融合函数,调用时也需指定使用 horizon_plugin_pytorch 中提供的 fuser_func。如下所示:
import torch
from torch import nn
import horizon_plugin_pytorch as horizon


class ConvBNReLU(nn.Sequential):
def __init__(self, in_channels, out_channels, kernel_size):
super(ConvBNReLU, self).__init__(
nn.Conv2d(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size
),
nn.BatchNorm2d(num_features=out_channels),
nn.ReLU()
)

# 指定可以 fuse 的算子
def fuse_model(self):
torch.quantization.fuse_modules(
self,
['0', '1', '2'],
inplace=True,
# 指定 horizon_plugin_pytorch 中提供的 fuse 函数
fuser_func=horizon.quantization.fuse_known_modules,
)

float_model = ConvBNReLU(1, 1, 1)
# 需要显示调用 fuse 函数
float_model.fuse_model()

print(float_model)
# ConvBNReLU(
# (0): ConvReLU2d(
# (0): Conv2d(1, 1, kernel_size=(1, 1), stride=(1, 1))
# (1): ReLU()
# )
# (1): Identity()
# (2): Identity()
# )

使用流程

Eager 模型下量化训练的整体流程如下图所示:

qat

构建浮点模型

Eager 模式下,您在构建浮点模型时,需要注意以下几点:

  1. 在网络中插入量化和反量化节点。一般在浮点模型的开始需要插入一个量化节点,在结束部分需要插入一个反量化节点。当浮点模型在被转为待量化训练的 QAT 模型之后,插入的量化节点将会对输入进行量化操作;

  2. 一些浮点的函数形式算子需要替换为 Pytorch 中继承自 Module 的算子或是 Plugin 提供的一些专有算子;

  3. 定义浮点算子的融合函数,对可以融合的算子进行融合。

import torch
import torch.optim as optim
import horizon_plugin_pytorch as horizon
import os
from torch import nn
from torchvision import datasets, transforms
from torch.quantization import DeQuantStub
from horizon_plugin_pytorch.quantization import QuantStub

class ConvBNReLU(nn.Sequential):
def __init__(self, in_channels, out_channels, kernel_size):
super(ConvBNReLU, self).__init__(
nn.Conv2d(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=kernel_size
),
nn.BatchNorm2d(num_features=out_channels),
nn.ReLU()
)

# 指定可以融合的浮点算子
def fuse_model(self):
torch.quantization.fuse_modules(
self,
['0', '1', '2'],
inplace=True,
fuser_func=horizon.quantization.fuse_known_modules,
)

class ClassiFier(nn.Module):
def __init__(self, in_channels, out_channels):
super(ClassiFier, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, 1)

def forward(self, data):
return self.conv(data)

# 构建浮点模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv0 = ConvBNReLU(1, 10, 5)
self.max_pool = nn.MaxPool2d(kernel_size=2)
self.conv1 = ConvBNReLU(10, 20, 5)
self.avg_pool = nn.AvgPool2d(kernel_size=8)
self.classifier = ClassiFier(20, 10)
# 为了适配 bpu,当从摄像头获取输入时 QuantStub 的 scale 必须显示地设置成 1/128
self.quant = QuantStub(scale=1/128)
self.dequant = DeQuantStub()

def forward(self, x):
# 插入量化节点对输入进行量化
x = self.quant(x)
x = self.conv0(x)
x = self.max_pool(x)
x = self.conv1(x)
x = self.avg_pool(x)
x = self.classifier(x)
# 插入反量化节点对输出进行反量化
x = self.dequant(x)
return x

# 定义融合函数
def fuse_model(self):
from horizon_plugin_pytorch import quantization

for m in self.modules():
if type(m) == ConvBNReLU:
m.fuse_model()

浮点模型预训练

train_batch_size = 16
test_batch_size = 16
epoch_num = 1
neval_batches = 1
model_file = 'model.pt'

class AverageMeter(object):
"""Computes and stores the average and current value"""

def __init__(self, name, fmt=":f"):
self.name = name
self.fmt = fmt
self.reset()

def reset(self):
self.val = 0
self.avg = 0
self.sum = 0
self.count = 0

def update(self, val, n=1):
self.val = val
self.sum += val * n
self.count += n
self.avg = self.sum / self.count

def __str__(self):
fmtstr = "{name} {val" + self.fmt + "} ({avg" + self.fmt + "})"
return fmtstr.format(**self.__dict__)

criterion = nn.CrossEntropyLoss()

def accuracy(output, target, topk=(1,)):
"""Computes the accuracy over the k top predictions for the specified
values of k
"""
with torch.no_grad():
maxk = max(topk)
batch_size = target.size(0)

_, pred = output.topk(maxk, 1, True, True)
pred = pred.t()
correct = pred.eq(target.view(1, -1).expand_as(pred))

res = []
for k in topk:
correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True)
res.append(correct_k.mul_(100.0 / batch_size))
return res


def get_train_data_loader():
train_loader = torch.utils.data.DataLoader(
datasets.MNIST(
'mnist_data',
train=True,
download=True,
transform=transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))]
)
),
batch_size=train_batch_size,
shuffle=True,
)
return train_loader

def get_test_data_loader():
train_loader = torch.utils.data.DataLoader(
datasets.MNIST(
'mnist_data',
train=False,
download=True,
transform=transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))]
)
),
batch_size=test_batch_size,
shuffle=True,
)
return train_loader

data_loader = get_train_data_loader()
test_loader = get_test_data_loader()

def train(model, device, optimizer, epoch):
global min_loss
model.train()
for batch_idx, (data, target) in enumerate(data_loader):
data = data.to(device)
target = target.to(device)
output = model(data)
output = output.view(-1, 10)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print ('Train Epoch: {} batch {} \t Loss: {:.6f}'.
format(epoch, batch_idx, loss.item()))

def evaluate(model, device, neval_batches):
model.eval()
top1 = AverageMeter("Acc@1", ":6.2f")
top5 = AverageMeter("Acc@5", ":6.2f")
tested_batches = 0
with torch.no_grad():
for batch_idx, (data, target) in enumerate(test_loader):
tested_batches += 1
data = data.to(device)
target = target.to(device)
output = model(data)
output = output.view(-1, 10)
loss = criterion(output, target)
acc1, acc5 = accuracy(output, target, topk=(1, 5))
top1.update(acc1[0], data.size(0))
top5.update(acc5[0], data.size(0))
if tested_batches >= neval_batches:
return top1, top5

return top1, top5


def train_float_model(device):
model = Net().to(device)
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.1)
for nepoch in range(epoch_num):
train(model, device, optimizer, nepoch)
top1, top5 = evaluate(model, device, neval_batches)
print(
"float training Epoch %d :float evaluation accuracy on %d images, \
%2.2f" % (nepoch, neval_batches * test_batch_size, top1.avg)
)
torch.save(model.state_dict(), model_file)

train_float_model(torch.device('cuda'))

如果您希望在已有的浮点模型基础上进行量化训练,可以先加载浮点模型再进行后续融合算子及量化训练的步骤。如果是浮点训练完成后紧接着量化训练,则无需刻意加载,直接进行后续步骤即可。

def load_model():
model = Net()
state_dict = torch.load(model_file)
model.load_state_dict(state_dict)
model.to('cpu')
return model

qat_model = load_model()

设置 BPU 架构

# 设置 march **RDK X3** 设置BERNOULLI2, **RDK Ultra** 设置为BAYES, **RDK X5** 设置为BAYES_E。
horizon.march.set_march(horizon.march.March.BAYES)

算子融合

qat_model.fuse_model()

浮点模型转为量化模型

def load_and_prepare_qat_model(device):
# 加载预训练浮点模型
global qat_model
qat_model = qat_model.to(device)
top1, top5 = evaluate(qat_model, device, neval_batches)
print(
"float evaluation accuracy on %d images, \
%2.2f" % (neval_batches * test_batch_size, top1.avg)
)
# 设置量化训练的量化参数用于指定如何对算子的权值 (weight) 和输出进行量化
qat_model.qconfig = horizon.quantization.get_default_qat_qconfig()
# 取消输出层的量化功能提高输出的准确性
qat_model.classifier.qconfig = \
horizon.quantization.get_default_qat_out_qconfig()
# 将浮点模型转化为量化模型
horizon.quantization.prepare_qat(qat_model, inplace=True)
print(
"After preparation for QAT, note fake-quantization modules \n",
qat_model.conv0,
)
qat_model = qat_model.to(device)

load_and_prepare_qat_model(torch.device('cuda'))

量化训练

def quantization_training(device):
# 对量化模型进行量化训练
optimizer = optim.SGD(qat_model.parameters(), lr=0.0001)
for nepoch in range(1):
train(qat_model, device, optimizer, nepoch)
# 训练一个轮次的量化模型进行评测
top1, top5 = evaluate(qat_model, device, neval_batches)
print(
"QAT Epoch %d :float evaluation accuracy on %d images, %2.2f"
% (nepoch, neval_batches * test_batch_size, top1.avg)
)

quantization_training(torch.device('cuda'))

量化模型转为定点模型

quantized_model = horizon.quantization.convert(
qat_model.eval(), inplace=False
)

对定点预测模型进行检查和编译

def compile_quantized_model(device):
example_input = torch.ones(size=(neval_batches, 1, 28, 28), device=device)
traced_model = torch.jit.trace(quantized_model, example_input)
top1, top5 = evaluate(traced_model, device, neval_batches)
print(
"Traced : int evaluation accuracy on %d images, %2.2f"
% (neval_batches * test_batch_size, top1.avg)
)

# 检查模型是否能够被 hbdk 编译。hbdk 是一个对定点模型进行编译的工具。
horizon.quantization.check_model(quantized_model, example_input, advice=1)
hbdk_dir = "hbdk_model"
if not os.path.exists(hbdk_dir):
os.mkdir(hbdk_dir)

# 编译模型,hbdk_model 目录下的 model.hbm 就是编译得到的上板模型
horizon.quantization.compile_model(
traced_model, [example_input], opt=2, hbm=hbdk_dir + "/model.hbm"
)
# 对模型进行静态性能分析
horizon.quantization.perf_model(
traced_model,
[example_input],
opt=2,
input_source=["pyramid"],
layer_details=True,
out_dir=hbdk_dir,
)
horizon.quantization.visualize_model(
traced_model,
[example_input],
save_path=hbdk_dir + "/model.svg",
show=False,
)

compile_quantized_model(torch.device('cuda'))

支持的公版算子

综合说明

  1. 除特别说明,Bernoulli2 架构限制算子的输入输出均为 4 维。
  2. 在 eager 模式中,部分算子需要手动替换,fx 模式无需手动替换算子。
  3. 以下支持的算子默认为不进行算子融合,对于可进行融合的算子(如 (conv,bn),relu)),参考算子融合章节。
  4. 在预测阶段,透传的算子(例如 Identity,Dropout),在部署时会被优化掉。

torch function 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torch.abs不支持qint8, qint16同输入
torch.acoshorizon.nn.Acos不支持qint8, qint16qint8, qint16底层查表实现,有精度风险
torch.acoshhorizon.nn.Acosh不支持参考 torch.acos
torch.addtorch.nn.quantized.FloatFunctional 或 horizon.nn.quantized.FloatFunctionalqint8, qint16qint8, qint16in_channel<=2048,不支持操作数为常数qint8, qint16qint8, qint16支持除 N 维以外的广播,只能有一个 input 广播,如果其中一个操作数为 scalar,需要调用 add_scalar
torch.argmax参考 torch.max参考 torch.max
torch.argmin参考 torch.max参考 torch.max
torch.asinhorizon.nn.Asin不支持参考 torch.acos
torch.asinhhorizon.nn.Asinh不支持参考 torch.acos
torch.atanhorizon.nn.Atan不支持参考 torch.acos
torch.atanhhorizon.nn.Atanh不支持参考 torch.acos
torch.cattorch.nn.quantized.FloatFunctional 或 horizon.nn.quantized.FloatFunctionalqint8, qint16qint8, qint16qint8, qint16qint8, qint16input shape: [N, C, H, W], N<=4096, HWC<=65536, 2<=input number<=1024
torch.ceilhorizon.nn.Ceil不支持qint8, qint16同输入int8下输入数量级不要超过1e6, int16 下输入数量级不要超过 1e8。
torch.clamp不支持qint8, qint16同输入支持min和max的输入为Tensor/常量Tensor/标量/None。 为常量Tensor时,min 和 max 的输入数据范围最好和 input 一致,否则有精度风险
torch.clip不支持参考 torch.clamp
torch.coshorizon.nn.Cos不支持参考 torch.acos
torch.coshhorizon.nn.Cosh不支持参考 torch.acos
torch.divhorizon.nn.Div不支持qint16qint16
torch.eq不支持qint8, qint16qbool
torch.erfhorizon.nn.Erf不支持参考 torch.acos
torch.exphorizon.nn.Expqint8qint8使用查表拼凑,有精度风险参考 torch.acos
torch.floorhorizon.nn.Floor不支持qint8, qint16同输入int8下输入数量级不要超过1e6, int16 下输入数量级不要超过 1e8。
torch.gather不支持qint8, qint16, qint32同输入
torch.ge不支持参考 torch.eq
torch.greater不支持参考 torch.eq
torch.greater_equal不支持参考 torch.eq
torch.gt不支持参考 torch.eq
torch.le不支持参考 torch.eq
torch.less不支持参考 torch.eq
torch.less_equal不支持参考 torch.eq
torch.loghorizon.nn.HardLog不支持参考 torch.acos
torch.lt不支持参考 torch.eq
torch.matmulhorizon.nn.quantized.FloatFunctionalqint8qint8, qint32qint8, qint16, qint32input shape: [N, C, H, W], input_size<1 G bytes, N<=4096, C, H, W<=8192.
torch.maxqint8同输入只能作为模型输出。 输出格式和 torch 不同: 编译器支持的输出是一个 Tensor,其中一个 channel 中的值是 max_value, 另一个 channel 中的值是 max_value_indexqint8, qint16out: qint8, qint16 index: int32index 只能作为模型输出。 input_shape: [N, C, H, W], 1<=N<=4096, 1<=H, W, C<=65535 支持min和max的输入为Tensor/常量Tensor/标量/None。为常量Tensor时,min 和 max 的输入数据范围最好和 input 一致,否则有精度风险
torch.maximumhorizon.nn.quantized.FloatFunctional不支持input: qint8, qint16
other: qint8, qint16
qint8, qint16
torch.meanhorizon.nn.quantized.FloatFunctionalqint8, qint16qint8, qint16只支持在 channel 方向的 mean。QAT 有训练参数,不要单独在预测中使用。qint8, qint16qint8, qint16支持在 CHW 上求 mean.QAT 有量化参数
torch.min不支持参考 torch.max
torch.minimumhorizon.nn.quantized.FloatFunctional不支持参考 torch.maximum
torch.multorch.nn.quantized.FloatFunctional 或 horizon.nn.quantized.FloatFunctional参考 torch.add参考 torch.add
torch.powhorizon.nn.Pow不支持参考 torch.acos
torch.reciprocalhorizon.nn.Reciprocal不支持参考 torch.acos
torch.seluhorizon.nn.Selu不支持参考 torch.acos
torch.sinhorizon.nn.Sin不支持参考 torch.acos
torch.sinhhorizon.nn.Sinh不支持参考 torch.acos
torch.splitqint8, qint16同输入qint8, qint16同输入
torch.sqrthorizon.nn.Sqrt不支持参考 torch.acos
torch.subhorizon.nn.quantized.FloatFunctionalqint8, qint16qint8, qint16in_channel<=2048qint8, qint16qint8, qint16支持除 N 维以外的广播,只能有一个 input 广播。
torch.sumhorizon.nn.quantized.FloatFunctionalqint8qint8, qint32只支持 batch 和 channel 方向的 sum。qint8, qint16qint8, qint16仅支持 HWC 三个维度的 sum
torch.tanhorizon.nn.Tan不支持参考 torch.acos
torch.topk不支持qint8, qint16, qint32同输入

torch.nn.functional function 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torch.nn.functional.grid_sample不支持不支持不支持input:`qint8
grid: qint8, qint16
qint8输入 shape: [N, C, H, W], 1<=H, W<=1024 且 H*W<=720*1024; grid 支持 qint8 和 qint16,只支持 bilinear 和 nearest 插值 padding 模式只支持 zeros 和 border;
torch.nn.functional.interpolateqint8qint8支持 nearest 和 billinear 插值模式。1/256<缩放比例<=256qint8qint8只支持 nearest 和 billinear 插值模式。input_shape: [N, C, H, W], 1<=C, H, W<=8192,align_corners 支持 False 和 None,scale=[] 时要求 recompute_scale_factors 为 True
torch.nn.functional.pad不支持不支持不支持qint8, qint16同输入不支持 reflect 模式
torch.nn.functional.relutorch.nn.ReLUqint8qint8qint8同输入Conv2d+BN+ReLU 这种模式会自动 fuse
torch.nn.functional.relu6(fused)torch.nn.ReLU6qint8同输入

torch.nn Module 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torch.nn.AdaptiveAvgPool2d不支持不支持不支持qint8同输入使用 AvgPool2d 非等价拼凑,有精度问题
torch.nn.AvgPool2dqint8同输入1<=kernel<=7,1<=stride<=1851<=kernel, stride, padding<=256;
torch.nn.BatchNorm2dBatchNorm2d 在 QAT 阶段被吸收,不体现在预测模型中。由于编译器限制,独立使用的 BatchNorm2d 底层调用 BpuConvolution 实现qint8qint8BatchNorm2d 在 QAT 阶段被吸收,因此,不体现在模型中。独立使用限制参考 Conv2d
torch.nn.BatchNorm3dBatchNorm3d 在 QAT 阶段被吸收,不体现在预测模型中。由于编译器限制,独立使用的 BatchNorm3d 底层调用 BpuConvolution 实现qint8qint8BatchNorm3d 在 QAT 阶段被吸收,因此,不体现在模型中。独立使用限制参考 Conv2d
torch.nn.ChannelShuffleqint8同输入qint8, qint16同输入shuffle_index 中的数值不能重复
torch.nn.ConstantPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d
torch.nn.Conv2dqint8qint8,qint32input: qint8, qint16; weight: qint8; bias: qint32qint8, qint16,qint32out_channel<=8192,作为模型输出时,out_channel <= 16384. 输入 channel<=8192, kernel<32, dilation<=16, 当 dilation!=1 时,stride 只能 为 1. 支持 sumin, 带 sumin 的 conv 只支持 stride 为 (1, 1) 或 (2, 2). weight_shape: [N, C, H, W], N, C<=8192, H, W<=31, 作为模型输出 C<=16384, weight_size < 65535. padding<=256 qint16 输入时累加和不能超过 int32 范围
torch.nn.Conv3d不支持不支持不支持input: qint8, weight: qint8, bias: qint32qint8input: [N, C, D, H, W] int8, N<=128; H, W, D, C<=65536; weight: [C_o, C_i, D, H, W] int8, N, C<=65536, D, H<=9, W<=8191; bias: int32; output: [N, C, D, H, W] int8, int16, int32; stride: [D, H, W], D, H, W 等于 1 或 2, 并且 D, H, W 相同; padding: [D, H, W], D<=kernel_d/2, H<=kernel_h/2, W<=kernel_w/2(kernel_w 指 weight W 维大小) group, dilation: 暂不支持
torch.nn.ConvTranspose2dqint8qint82<=kernel<= 14.channel<=2048. padding H*W=[0, (kernel_h-1)/2] * [0, (kernel_w-1)/2] 2<=stride<=4, dilation=(1, 1)qint8qint8输入 shape: [N, C, H, W], 1<=N<=128, 1<=channel<=2048; weight_shape: [N, C, H, W], 1<=N, C<=2048, 2<=H, W<=14, weight_size<=65535; kernel>=stride, 1<=stride<=14, 1<=out_channel<=2048, in_channel<=2048 pad<=kernel/stride, 0<=out_pad<=1; bias 类型为 int32; 支持 sumin, sumin 输入类型为 int8; 0<=output_padding<=1; 支持 group, 要求 weight_n 和 输入 channel 均能被 group 整除; dilation=1
torch.nn.Dropoutqint8, qint16,qint32同输入qint8, qint16,qint32同输入
torch.nn.Dropout2dqint8, qint16,qint32同输入qint8, qint16,qint32同输入
torch.nn.ELU不支持不支持不支持参考 torch.acos参考 torch.acos
torch.nn.GELU参考 torch.exp参考 torch.exp参考 torch.exp参考 torch.acos参考 torch.acos
torch.nn.GLU不支持不支持参考 torch.acos参考 torch.acos
torch.nn.HardSigmoid不支持不支持不支持参考 torch.acos参考 torch.acos
torch.nn.Identityqint8, qint16,qint32同输入qint8, qint16,qint32同输入
torch.nn.Layernorm不支持不支持不支持qint8qint8, qint16底层使用多次查表拼凑,精度风险较高。可通过 rsqrt_kwargs 属性来控制内部 rsqrt 查表的参数,若遇到 convert 精度降低的问题可以尝试 layernorm_op.rsqrt_kwargs = {“auto_divide_strategy”: “curvature”}. H * W <= 16384, normalized_shape H * W < 16384
torch.nn.LeakyReLU不支持不支持不支持参考 torch.acos参考 torch.acos
torch.nn.Linear不支持不支持不支持input: qint8; weight:qint8; bias: qint32qint8in_features <= 8192, out_features <= 8192.
torch.nn.LSTMCell不支持不支持不支持qint8, qint16qint8, qint16输入是 2 维
torch.nn.MaxPool2dqint8同输入1<=kernel<=64, 1<=stride<=256, padding>=0qint8同输入input_shape: [N, C, H, W], 1<=H, W, C<=8192;1<=kernel, stride<=256; 0<=padding<=255;
torch.nn.MultiheadAttention不支持不支持不支持qint8,qint16qint8,qint16不支持 add_bias_kv、add_zero_attn 和 q k v embed_dim 不一致的情况,支持输入输出 int8/int16,底层查表算子与 mask 量化可能带来精度风险
torch.nn.PixelShuffleqint8, qint16同输入qint8,qint16同输入
torch.nn.PixelUnshuffleqint8, qint16同输入qint8,qint16同输入
torch.nn.PReLU不支持不支持不支持参考 torch.acos参考 torch.acos
torch.nn.ReLUqint8同输入qint8,qint16同输入
torch.nn.ReLU6qint8同输入qint8,qint16同输入
torch.nn.ReplicationPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d参考 torch.nn.ZeroPad2d
torch.nn.Sigmoid参考 torch.exp参考 torch.exp参考 torch.exp参考 torch.acos参考 torch.acos
torch.nn.SiLU参考 torch.exp参考 torch.exp参考 torch.exp参考 torch.acos参考 torch.acos
torch.nn.Softmax不支持不支持不支持qint8qint8, qint16使用多次查表、求和等算子拼凑,精度风险较高
torch.nn.Softplus不支持不支持不支持参考 torch.acos参考 torch.acos
torch.nn.SyncBatchNormqint8qint8使用 torch.nn.Conv2d 拼凑qint8qint8使用 torch.nn.Conv2d 拼凑
torch.nn.Tanh参考 torch.exp参考 torch.exp参考 torch.exp参考 torch.acos参考 torch.acos参考 torch.acos
torch.nn.Upsample参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate
torch.nn.UpsamplingBilinear2d参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate
torch.nn.UpsamplingNearest2d参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate参考 torch.nn.functional.interpolate
torch.nn.ZeroPad2dqint8同输入qint8, qint16同输入

torch.quantization Module 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torch.quantization.DeQuantStubqint8,qint16,qint32float32典型使用场景:网络模型分段的场景,需要把数据 从 BPU 传输到 CPU,在 CPU 上进行反量化,方便 CPU 上处理qint8,qint16,qint32float32典型使用场景:网络模型分段的场景,需要把数据 从 BPU 传输到 CPU,在 CPU 上进行反量化,方便 CPU 上处理
torch.quantization.QuantStubhorizon.quantization.QuantStubfloat32qint8,qint16典型使用场景:整个网络模型的输入。模型分段的场景:数据从 CPU 送入到 BPU 之前需要把数据进行量化。scale 参数设置方法:scale 的设置和具体的输入有关。设置目标是使得输入的 float 类型的数据尽量 高精度地量化到 int8 类型 这就有两个方面的要求:可以覆盖所有的(至少是绝大部分)输入数据,量化精度高。例如:输入 float 的范围是 (-1, 1), 那么,我们可以设置 scale = 1 / 128。Float 预训练模型:在预训练模型中,由于模型已经训练好,不一定遵循上述 scale 参数设置方法,这时,可以通过插入一个特殊的 conv 的方法来解决。要求输入 QuantStub 的数据的分布是均匀的float32qint8,qint16典型使用场景:整个网络模型的输入。模型分段的场景,数据从 CPU 送入到 BPU 之前需要把数据进行量化。scale 参数设置方法:scale 的设置和具体的输入有关。设置目标是使得输入的 float 类型的数据尽量 高精度地量化到 int8 类型,这就有两个方面的要求:可以覆盖所有的(至少是绝大部分)输入数据,量化精度高。例如:输入 float 的范围是 (-1, 1), 那么,我们可以设置 scale = 1 / 128。Float 预训练模型:在预训练模型中,由于模型已经训练好,不一定遵循上述 scale 参数设置方法,这时,可以通过插入一个特殊的 conv 的方法来解决。要求输入 QuantStub 的数据的分布是均匀的

torch.Tensor method 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torch.Tensor.getitemqint8, qint16, qint32同输入
torch.Tensor.transpose不支持不支持不支持qint8, qint16, qint32Tensor.dtype不支持对 N 维的 transpose
torch.Tensor.argmax参考 torch.max参考 torch.max参考 torch.max参考 torch.max参考 torch.max参考 torch.max
torch.Tensor.argmin参考 torch.max参考 torch.max参考 torch.max参考 torch.max参考 torch.max参考 torch.max
torch.Tensor.clamp不支持不支持不支持qint8, qint16Tensor.dtypedim <= 10, 1 <= each_dim_size < 65536
torch.Tensor.clip不支持不支持不支持参考 torch.Tensor.clip参考 torch.Tensor.clip参考 torch.Tensor.clip
torch.Tensor.eq不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.expand不支持不支持不支持qint8, qint16Tensor.dtype
torch.Tensor.ge不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.greater不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.greater_equal不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.gt不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.le不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.less不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.less_equal不支持不支持不支持参考 torch.eq参考 torch.eq参考 torch.eq
torch.Tensor.max不支持不支持不支持参考 torch.max参考 torch.max参考 torch.max
torch.Tensor.min不支持不支持不支持参考 torch.max
torch.Tensor.repeat不支持不支持不支持qint8, qint16Tensor.dtype
torch.Tensor.reshape不支持不支持不支持Tensor.dtype
torch.Tensor.tile不支持不支持不支持qint8, qint16Tensor.dtype
torch.Tensor.abs不支持不支持不支持qint8, qint16Tensor.dtype

torchvision 类

算子eager 模式替换算子Bernoulli2Bayes
输入输出其它限制输入输出其它限制
torchvision.models.detection.rpn.AnchorGeneratorhorizon.nn.AnchorGeneratorqint8,qint16,qint32,float32float32仅支持 Tensor.shape 可以离线确定的情况qint8,qint16,qint32,float32float32支持输入 int8/int16/int32/float32, 输出 float32
torchvision.ops.MultiScaleRoIAlignhorizon.nn.MultiScaleRoIAlign参考 torchvision.ops.RoIAlign参考 torchvision.ops.RoIAlign参考 torchvision.ops.RoIAlign参考 torchvision.ops.RoIAlign参考 torchvision.ops.RoIAlign参考 torchvision.ops.RoIAlign
torchvision.ops.RoIAlignqint8qint8qint8qint81<=feature number<=5;bbox 仅支持 List[Tensor] 格式 shape:[1, box_num, 4], bbox 最后一维 4 个数分别为:[left, top, right, bottom]