-
2021-10-10 18:08:25
在深度学习领域量化主要是存储量化(减少存储所需内存)以及计算量化(减少计算时间)。而博主主要使用pytorch,在pytorch里支持的量化主要有动态量化(推理过程中进行量化)、静态量化(训练后进行量化)、感知量化(边训练边量化,用的时间更长,但精度几乎无损)。
Tensor量化
要实现量化首先要进行Tensor量化,Tensor量化与scale、zero-point参数有关,公式为:
round(x/scale+zero-point)
Tensor一般量化有2种模式,per tensor与per channel,前者所有数值都按照相同方式进行scale与zero-point计算,后者有多种不同的scale与zero-pointc参数,而且精度损失更少。
静态量化
静态量化一般有2种形式,仅weight量化以及weight与activation同时量化。前者主要目的是使得模型参数所占内存减小,且相对简单。后者则相对较为复杂。
在pytorch内静态量化分为5个步骤。(以下步骤主要进行的是模型量化,本质上就是用量化OP替换非量化OP)
(1)fuse_model,就是将可进行融合的op进行融合,比如Conv与BN层进行融合等。融合后第一个op会替换融合后的op,其余op则替换为nn.identity。
fuse_modules(model, modules_to_fuse, inplace=False, fuser_func=fuse_known_modules, fuse_custom_config_dict=None)
(2)qconfig,该步骤目的是设置模型量化的方式,通过插入两个observer来监测activation与weight。同时由于推理平台的不同,pytorch的量化配置也不相同。
(3)prepare,将每个可支持量化的模块插入Observer,收集数据并进行量化分析。
(4)feed data,将一个合适的校验数据送入前述模型中,获得更好的activation的量化参数信息。
(5)convert,运用代码转化模型。
torch.quantization.convert(model, inplace=True)
模型量化后就是量化模型的推理,与浮点模型的区别主要是要进行量化节点的插入以及op替换。
量化节点插入:需要在网络的forward里面插入QuantStub与DeQuantSub两个节点。
op替换:需要将模型中的Add、Concat等操作替换为支持量化的FloatFunctional。
更多相关内容 -
pytorch模型量化
2020-10-14 17:27:10模型量化是为了减少模型的大小,以便在边缘设备上进行计算 首先建网络: import torch import torch.nn as nn from torchsummary import summary device = torch.device("cpu") class SimpleNet(nn.Module): def ...模型量化是为了减少模型的大小,以便在边缘设备上进行计算
首先建网络:
import torch import torch.nn as nn from torchsummary import summary device = torch.device("cpu") class SimpleNet(nn.Module): def __init__(self, num_classes=10): super(SimpleNet, self).__init__() self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=3, stride=1, padding=1) self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=3, stride=1, padding=1) self.pool = nn.MaxPool2d(kernel_size=2) self.conv3 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=3, stride=1, padding=1) self.conv4 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=3, stride=1, padding=1) self.fc = nn.Linear(in_features=16 * 16 * 24, out_features=num_classes) def forward(self, input): output = self.conv1(input) output = nn.ReLU()(output) output = self.conv2(output) output = nn.ReLU()(output) output = self.pool(output) output = self.conv3(output) output = nn.ReLU()(output) output = self.conv4(output) output = nn.ReLU()(output) output = output.view(-1, 16 * 16 * 24) output = self.fc(output) return output model = SimpleNet().to(device=device) print(model)
结果:
SimpleNet( (conv1): Conv2d(3, 12, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (conv2): Conv2d(12, 12, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv3): Conv2d(12, 24, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (conv4): Conv2d(24, 24, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc): Linear(in_features=6144, out_features=10, bias=True) )
量化操作:
这里使用的动态量化:
quantized_model = torch.quantization.quantize_dynamic( model, {nn.LSTM, nn.Linear}, dtype=torch.qint8 ) print(quantized_model)
结果:
SimpleNet( (conv1): Conv2d(3, 12, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (conv2): Conv2d(12, 12, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) (conv3): Conv2d(12, 24, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (conv4): Conv2d(24, 24, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (fc): DynamicQuantizedLinear(in_features=6144, out_features=10, dtype=torch.qint8, qscheme=torch.per_tensor_affine) )
看下到底压缩了多少:
import os def print_size_of_model(model): torch.save(model.state_dict(), "temp.p") print('Size (MB):', os.path.getsize("temp.p")/1e6) os.remove('temp.p') print_size_of_model(model) print_size_of_model(quantized_model)
结果:
Size (MB): 0.287049 Size (MB): 0.103451
压缩的效果还是比较明显的。
量化只是对模型的权重数值进行了优化,上面的是权重值的对比,看起来还是不错的
summary(model.cuda(), input_size=(3, 512, 512))
---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Conv2d-1 [-1, 12, 512, 512] 336 Conv2d-2 [-1, 12, 512, 512] 1,308 MaxPool2d-3 [-1, 12, 256, 256] 0 Conv2d-4 [-1, 24, 256, 256] 2,616 Conv2d-5 [-1, 24, 256, 256] 5,208 Linear-6 [-1, 10] 61,450 ================================================================ Total params: 70,918 Trainable params: 70,918 Non-trainable params: 0 ---------------------------------------------------------------- Input size (MB): 3.00 Forward/backward pass size (MB): 78.00 Params size (MB): 0.27 Estimated Total Size (MB): 81.27 ----------------------------------------------------------------
从上面的数据可以看到,模型权重数值(Params size (MB): 0.27)只是占一部分 ,在这个模型中占用的比例很小
由于量化后的模型没法使用summary,所以没法直接观察
-
pytorch 模型量化方法总结
2021-06-11 08:51:56静态量化需要在模型起始和结束位置定义quant和dequant接口; 2.配置好后端 3.融合的层声明;一般是conv+relu;或者是conv+bn+relu; 3.准备量化 4.配置量化的推理数据集(一般对应于你的训练任务) 5.量化模型转换;...后端:x86、arm移动嵌入式平台;
对应参数:‘fbgemm’ 、 ‘qnnpack’
命令行:torch.quantization.get_default_qconfig('fbgemm')
1.动态量化代码示例:
import torch # define a floating point model class M(torch.nn.Module): def __init__(self): super(M, self).__init__() self.fc = torch.nn.Linear(4, 4) def forward(self, x): x = self.fc(x) return x # create a model instance model_fp32 = M() # create a quantized model instance model_int8 = torch.quantization.quantize_dynamic( model_fp32, # the original model {torch.nn.Linear}, # a set of layers to dynamically quantize dtype=torch.qint8) # the target dtype for quantized weights # run the model input_fp32 = torch.randn(4, 4, 4, 4) res = model_int8(input_fp32)
适用于 Linear、LSTM、RNN等层;
权重直接量化;bias和激活函数 在推理过程中动态量化;
2.静态量化示例:
import torch # define a floating point model where some layers could be statically quantized class M(torch.nn.Module): def __init__(self): super(M, self).__init__() # QuantStub converts tensors from floating point to quantized self.quant = torch.quantization.QuantStub() self.conv = torch.nn.Conv2d(1, 1, 1) self.relu = torch.nn.ReLU() # DeQuantStub converts tensors from quantized to floating point self.dequant = torch.quantization.DeQuantStub() def forward(self, x): # manually specify where tensors will be converted from floating # point to quantized in the quantized model x = self.quant(x) x = self.conv(x) x = self.relu(x) # manually specify where tensors will be converted from quantized # to floating point in the quantized model x = self.dequant(x) return x # create a model instance model_fp32 = M() # model must be set to eval mode for static quantization logic to work model_fp32.eval() # attach a global qconfig, which contains information about what kind # of observers to attach. Use 'fbgemm' for server inference and # 'qnnpack' for mobile inference. Other quantization configurations such # as selecting symmetric or assymetric quantization and MinMax or L2Norm # calibration techniques can be specified here. model_fp32.qconfig = torch.quantization.get_default_qconfig('fbgemm') # Fuse the activations to preceding layers, where applicable. # This needs to be done manually depending on the model architecture. # Common fusions include `conv + relu` and `conv + batchnorm + relu` model_fp32_fused = torch.quantization.fuse_modules(model_fp32, [['conv', 'relu']]) # Prepare the model for static quantization. This inserts observers in # the model that will observe activation tensors during calibration. model_fp32_prepared = torch.quantization.prepare(model_fp32_fused) # calibrate the prepared model to determine quantization parameters for activations # in a real world setting, the calibration would be done with a representative dataset input_fp32 = torch.randn(4, 1, 4, 4) model_fp32_prepared(input_fp32) # Convert the observed model to a quantized model. This does several things: # quantizes the weights, computes and stores the scale and bias value to be # used with each activation tensor, and replaces key operators with quantized # implementations. model_int8 = torch.quantization.convert(model_fp32_prepared) # run the model, relevant calculations will happen in int8 res = model_int8(input_fp32)
1.静态量化需要在模型起始和结束位置定义quant和dequant接口;
2.配置好后端
3.融合的层声明;一般是conv+relu;或者是conv+bn+relu;
3.准备量化
4.配置量化的推理数据集(一般对应于你的训练任务)
5.量化模型转换;此处转换为int8精度;
6.验证量化后模型;
订阅代码可关注:https://github.com/oyjGithub
-
pytorch模型量化尝试
2020-09-24 20:45:48pytorch现在已经支持模型量化,主要支持两种量化模式(qnnpack和fbgemm):qnnpack是基于tensor的模式,这种相当于一种全局量化模式;另外fbgemm是基于通道的模式,相比qnnpack,fbgemm是以及基于通道的局部量化模式;...pytorch现在已经支持模型量化,主要支持两种量化模式(qnnpack和fbgemm):qnnpack是基于tensor的模式,这种相当于一种全局量化模式;另外fbgemm是基于通道的模式,相比qnnpack,fbgemm是以及基于通道的局部量化模式;需要说明的是这两种模式主要是针对权重而言的,激活函数的量化都是一样的。这里给出一个量化示例,pytorch目前只支持8bit的量化,通过自己实验发现对于浅层网络,分类精度损失不大,但是对于较深的网络量化就需要有针对性的优化,比如增大量化位宽,对部分权重或者activate分布不恰当的层加大这些层的位宽,或者模型训练过程中对权重或activate的大小进行约束,从而可以在量化的时候可以采用较低的位宽实现较高的精度保持。
实现过程依然是承接前一篇博客而来,只是添加了量化部分而已,代码实现如下:import os import torch import torch.optim as optim from torch.optim.lr_scheduler import StepLR from valid_simple_cnn5 import Net, QuantNet, get_dataloader, train, test, calibrate, print_size_of_model, time_model_evaluation #--------------------------------------------------- #setting input_shape = [1, 1, 28, 28] BATCH_SIZE = 1 EPOCH = 10 GAMMA = 0.7 LR = 1.0 SAVE_MODEL = True LOG_INTERVAL = 100 N_TEST_ITER = 3 QUANT_BACKEND = "fbgemm" # fbgemm for x86 / qnnpack for arm N_CALIBRATION = 10 SEED = 777 N_CPU = os.cpu_count() DATA_PATH = "./" PARAM_PATH = "mnist_qcnn05.pt" SCRIPTED_PARAM_PATH = "mnist_jit_qcnn.pt" '''USE_CUDA = True GPU_ID = [3] os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID" os.environ["CUDA_VISIBLE_DEVICES"] = ",".join([str(i) for i in GPU_ID]) device = torch.device("cuda" if torch.cuda.is_available() and USE_CUDA else "cpu") ''' #device = torch.device("cuda" if torch.cuda.is_available() else "cpu") device = torch.device("cpu") torch.manual_seed(SEED) TRAIN = False #--------------------------------------------------- #training model = Net().to(device) print('model = ',model) train_loader, test_loader = get_dataloader(DATA_PATH, BATCH_SIZE, N_CPU) if os.path.exists(PARAM_PATH) and TRAIN == False: print('start load model...') model.load_state_dict(torch.load(PARAM_PATH,map_location=torch.device('cpu'))) print('Loaded parameters from', PARAM_PATH) else: print('start training...') optimizer = optim.Adadelta(model.parameters(), lr=LR) scheduler = StepLR(optimizer, step_size=1, gamma=GAMMA) for epoch in range(1, EPOCH + 1): train(model, device, train_loader, optimizer, epoch, LOG_INTERVAL) test(model, device, test_loader) scheduler.step() if SAVE_MODEL: torch.save(model.state_dict(), PARAM_PATH) #--------------------------------------------------- #testing print('testing acc...') print('model = ',model) test(model, "cpu", test_loader) # print_size_of_model(model) # time_model_evaluation(model, test_loader, N_TEST_ITER) #-------------------------------------------------------------- #下面是基于pytorch 模型量化 #-------------------------------------------------------------- #层的合并 model = torch.quantization.fuse_modules(model,[["conv1","relu1"], ["conv2","relu2"], ["conv3","relu3"], ["conv4","relu4"], ["conv5","relu5"], ["conv6","relu6"], ["fc1","relu7"]]) #量化模式(qnnpack是基于tensor的量化,fbgemm是基于通道的量化) QUANT_BACKEND = "qnnpack" model.qconfig = torch.quantization.get_default_qconfig(QUANT_BACKEND) torch.quantization.prepare_qat(model,inplace=True) #对模型进行统计获取activate分布相关的最大最小值 calibrate(model,train_loader,N_CALIBRATION) print('calibration done') #test(model, "cpu", test_loader) print('model = ',model) torch.save(model.state_dict(),'mnist_qcnn_fuse03.pt') #转换为量化的模型 torch.quantization.convert(model,inplace=True) print('model = ',model) torch.save(model.state_dict(), 'mnist_qcnn_quant0.pt') print('quant testing...') test(model,'cpu',test_loader)
其他的代码可以通过链接下载:请戳
量化相关的东西后续会进一步更新和讲解,水平有限,不当之处请指教,希望对大家有帮助。 -
pytorch量化尝试
2020-09-24 20:38:55此代码实现的是pytorch量化的流程,里面卷积等模块也有自己实现的部分,借助pytorch的统计信息,便于后续的工程量化的落地实施 -
pytorch-quantization-demo:从头开始使用pytorch的简单网络量化演示
2021-05-15 15:41:13pytorch-quantization-demo A simple network quantization demo using pytorch from scratch. This is the code for my about network quantization written in Chinese. 感兴趣的读者欢迎关注我的知乎专栏: 以及... -
基于pytorch的yolo稀疏训练与模型剪枝
2022-03-05 14:16:28基于pytorch的yolo稀疏训练与模型剪枝 -
PyTorch训练(四):模型量化训练【①模型训练完毕后的动态量化、②模型训练完毕后的静态量化、③模型训练...
2022-05-21 22:36:02一、概述 ...一个量化后的模型,其部分或者全部的tensor操作会使用int类型来计算,而不是使用量化之前的float类型。当然,量化还需要底层硬件支持,x86 CPU(支持AVX2)、ARM CPU、Google TPU、Nvidia Volt -
一次失败的Pytorch模型量化尝试
2022-03-25 17:58:32我的原工程模型是blazeface学习笔记_zhqh100的博客-CSDN博客完整的应该是一个人脸识别项目,人脸识别,大言不惭的说,我之前其实也做过,比如用dlib来做人脸识别,就是用opencv那一套来实现,说句实在话,速度非常慢,即便是... -
实践torch.fx第一篇——基于Pytorch的模型优化量化神器
2022-05-21 21:11:23第一篇——什么是torch.fx 今天聊一下比较重要的torch.fx,也趁着这次机会把之前的torch.fx笔记整理下,笔记大概拆成三...torch.fx是Pytorch 1.8出来的一套工具或者说一个库,是做python-to-python code transformation -
PyTorch模型量化工具学习
2021-05-17 16:35:25目前很多高精度的深度学习模型所需内存、计算量和能耗巨大,并不适合部署在一些低成本的嵌入式设备中,为了解决这个矛盾,模型压缩技术应运而生,其主要是通过减少原始模型参数的数量或比特数来实现对内存和计.. -
PyTorch 量化 原理与复现
2021-12-30 10:45:33神经网络的量化是指将浮点数的权重和(或)activation用定点数表示,此外,比较完全的量化还希望整个网络的数学运算全部是基于定点数的数学运算。对于定点数来讲,小数点的选取是人为的,(例如一个3比特的定点... -
pytorch模型部署
2021-11-19 17:09:04Pytorch使用torchserve部署模型比较方便和简单,也方便管理。但是由于内网服务器系统的原因,无法使用torchserve。所以选择flask框架写webapi的方式,来调用模型。 这里首先将模型保存未onnx格式,然后使用onnx运行... -
pytorch优化之量化
2020-04-20 19:54:28思考:pytorch的eager模式,是怎样支持开发模式支持串行执行断点调试,生产模式支持生成可并发执行代码的,可以拉源码调试分析。这里会涉及到图编程模式、编译原理,执行优化等技术。 ... -
基于pytorch的模型剪枝+模型量化+BN合并+TRT部署(cifar数据)(1)
2022-03-06 15:12:02相关代码下载地址:下载地址 压缩 量化:High-Bit(>...High-Bit量化的BN融合(训练量化中,先融合再量化,融合:BN参数 —> conv的权重w和偏置b) 部署 TensorRT(fp32/fp16/int8(ptq-calibration. -
Pytorch量化之静态量化
2021-02-22 16:25:44pytorch==1.7.1 torchvision==0.8.2 python==3.6 注意: 精度变差 操作比较简单,但还是需要动模型 层合并的部分需要对结构有了解 模型大小变为原来的1/4 推理速度提高20+% step1:加载模型 就正常加载即可,... -
PyTorch量化实践(1)
2022-05-27 14:40:36PyTorch提供了几种量化模型的不同方法。在这篇博客文章中,我们将(快速)为深度学习中的量化奠定基础,然后看看每种技术在实践中是怎样的。最后,我们将以文献中关于在工作流程中使用量化的建议作为结束。 量化原理 ... -
pytorch模型转onnx-量化rknn(bisenet)
2022-01-26 10:43:031.pytorch模型转化onnx 先把pytorch的.pth模型转成onnx,例如我这个是用Bisenet转的 import argparse import os.path as osp import sys sys.path.insert(0, '.') import torch from lib.models import model_... -
基于pytorch的模型剪枝+模型量化+BN合并+TRT部署(cifar数据)(2)
2022-03-06 15:19:42量化:High-Bit(>2b): QAT, PTQ, QAFT; Low-Bit(≤2b)/Ternary and Binary: QAT 剪枝:正常、规整和分组卷积结构剪枝 针对特征(A)二值量化的BN融合(训练量化后,BN参数 —> conv的偏置b) High-Bit量化的BN融合(训练... -
pytorch量化感知训练(QAT)示例---ResNet
2022-02-19 12:30:091. 训练浮点模型,测试浮点模式在CPU和GPU上的时间; 2. BN层融合,测试融合前后精度和结果...3. 加入torch的量化感知API,训练一个QAT模型; 4. 保存定点INT8模型, 测试速度和精度; 5. 完成一致性对其,并保存int8模型。 -
pytorch的量化Quantization
2022-05-21 15:12:00pytorch 从 1.3 开始增加了量化相关的接口,目前pytorch 最新版本已经到了1.11了,猜测其量化相关工具已经完善了(易用、模型速度提升,模型质量几乎不下降),所以开始记录量化相关知识。 注意 本文开始写于 ... -
pytorch量化方法评估
2020-04-14 17:42:19对自己接触的pytorch模型量化方法做一个简单评估,欢迎补充指正。 pytorch1.4版本之后自带的量化工具 pytorch在1.4版本之后就添加了量化的功能。具体量化方案可以参见这篇官方的教程。 (EXPERIMENTAL) STATIC ... -
pytorch量化
2021-05-17 16:04:34Pytorch支持int8量化,相比于float32,模型的大小减少4倍,内存要求减少4倍。与float32计算相比,对int8计算的硬件支持通常快2到4倍。 大多数情况下,模型需要以float32精度训练,然后将模型转换为int8。如今,... -
【小白CV教程】Pytorch训练YOLOv5并量化压缩(VOC格式数据集)
2020-12-06 11:52:27【小白CV教程】Pytorch... 模型量化: 前言: 今天有时间,就写一下用yolov5训练自己数据集(自己标注的VOC格式),然后通过pytorch接口进行模型的量化压缩。 最终效果: 1. 安装Anaconda: Anaconda官网:https://ww -
基于 Pytorch 的模型量化实现
2020-09-25 22:12:21为此,剪枝算法、蒸馏算法、轻量型网络、量化算法相应提出,本文将着重介绍模型量化算法pytorch实现。 量化算法涉及到的两个概念对称量化与非对称量化,主要在zero_point 上体现,具体介绍本文将不再赘述。当前... -
使用pytorch进行参数量化
2022-04-13 21:32:44使用pytorch进行参数量化参考文章原理代码实现结果验证 参考文章 将参数量化为二进制补码定点数的形式 原作者:皮皮宽 原理 如果首位为符号位,则 4.5的补码为 0100.1 -4.5的补码为1011.1 FPGA中存储参数的格式必须... -
pytorch框架下模型的LSTM层的自定义量化
2021-05-31 11:05:40这个文件是pytorch框架下,对模型LSTM层权值的对数量化,相关表述参考这篇博客: https://blog.csdn.net/kuan__/article/details/112426594,直接运行工程中的main.py文件,可得到量化后的权值。 -
Pytorch模型权重转变为Keras对应的模型权重
2018-09-13 11:34:30pytorch的机制便于快速开发模型,但是在产品上的运用不稳定,需要将其转换为keras对应的模型权重,使用该代码进行转换的示例可见:https://blog.csdn.net/xiaoxifei/article/details/82685298 -
pytorch量化测试代码,mobilenetv2在cifar10速度测试
2022-03-31 11:32:551、pytorch动态量化、静态量化、感知训练测试代码;