PPQ官网用法介绍

1.用于加速的cuda内核

PPQ 已经实现了一些 cuda 内核,用于张量的量化-反量化执行过程, 这些内核可以加速量化模式下的图执行过程,当您在以下所有内容之前打开 CUDA 内核选项时,任何基于算法在繁重的图执行都可能会获得加速。

from ppq.core.config import PPQ_CONFIG
PPQ_CONFIG.USING_CUDA_KERNEL = True

注:如果您的环境无法编译共享库,则不必打开上述选项, 它只是为了加速,PPQ 在没有打开的情况下会做得很好。

2.准备模型和数据

首先,您需要准备模型和校准数据文件夹,请注意,PPQ 目前支持的模型只有onnx和caffe,您可能需要提前预处理校准数据并存储为npy 或二进制文件的校准数据文件夹中。

2.1准备模型

2.1.1模型是 onnx 格式

model_path = '/path/to/your/model.onnx'
data_path = '/path/to/your/dataFolder'

2.1.2模型是caffe格式

prototxt_path = '/path/to/your/model.prototxt'
weight_path = '/path/to/your/model.caffemodel'
data_path = '/path/to/your/dataFolder'

2.2自定义Dataloader

你可以自定义你自己的dataloader,你的dataloader可以是任何可迭代的东西,如:列表。

2.2.1npy文件

import os
import numpy as np
import torch
dataloader = [torch.from_numpy(np.load(os.path.join(data_path,file_name))) for file_name in os.listdir(data_path)]

2.2.2bin文件(以numpy数组形式加载)

INPUT_SHAPE = [1,3,224,224]
npy_array = [np.fromfile(os.path.join(data_path,file_name],dtype=np.float32).reshape(*INPUT_SHAPE) for file_name in os.listdir(data_path)
dataloader = [torch.from_numpy(np.load(npy_tensor)) for npy_tensor in npy_array]

2.2.3随机数据(为了测试)

创建一个随机长度为32的校准dataloader,batch为16。

dataloader = [torch.randn(16,3,224,224] for _ in range (32)]

如果你正在使用cuda并且有足够的内存,你可以提前将输入数据放在gpu以确保加速。

dataloader = [torch.randn(16,3,224,224).to('cuda') for _ in range (32)]

如果模型有多个输入,可以用一个字典指定图的每个输入。

dataloader = [{'input_1':torch.randn(16,3,224,224),'input_2':torch.rand(16,3,224,224)} for _ in range(32)]

3.加载模型(只支持onnx/caffe模型)

在做任何事之前,PPQ需要加载你的模型变成PPQ中间计算图形式。

from ppq.api import load_onnx_graph,load_caffe_graph
ppq_graph_ir = load_onnx_graph(model_path)
ppq_graph_ir = load_caffe_graph(prototxt_path,weight_path)

4.确保目标Platform

在量化之前你必须选择你的目标platform(你想部署你的量化模型的后端)。比如:如果你想将你的模型部署在TensorRT,你只需这样指定:

from ppq.core import TargetPlatform
target_platform = TargetPlatform.TRT_INT8

ppq支持的platform:                        

MNN_INT8 = 100TRT_INT8 = 101TRT_FP8 = 105
 NCNN_INT8 =102 TENGINE_INT8 = 104 ASC_INT8 = 106
PPL_CUDA_INT8 = 201PPL_CUDA_INT4 = 202   PPL_CUDA_FP16 = 203
PPL_CUDA_MIX = 204PPL_DSP_INT8 = 301SNPE_INT8 = 302
PPL_DSP_TI_INT8 = 303QNN_DSP_INT8 = 304HOST_INT8 = 401
NXP_INT8 = 501FPGA_INT8 = 502RKNN_INT8 = 601
METAX_INT8_C = 701METAX_INT8_T = 702HEXAGON_INT8 = 801
GRAPHCORE_FP8 = 901**********************************************************

PPQ将为指定的目标platform分配一个量化器和一个导出器,不同的目标platform可能产生完全不同的量化方案和导出文件格式。

5.准备你的设置

在进行量化时量化设置扮演着引导者,PPQ已经为一些后端platforms提供了默认设置。

from ppq import QuantizationSettingFactory
setting = QuantizationSettingFactory.pplcuda_setting() # for OpenPPL CUDA
setting = QuantizationSettingFactory.dsp_setting() # for DSP/SNPE

如果你想自定义你的设置,你可以从一个默认设置开始。

setting = QuantizationSettingFactory.default_setting()

如果你想应用SSD均衡算法,而不是默认的均衡方法,你只需要在设置中打开相应的pass即可。

setting = QuantizationSettingFactory.default_setting()
setting.ssd_equalization = True

 如果你想应用基于训练的lsp优化,并控制更多的特定pass的细节。

setting.lsq_optimization = True # turn on pass
setting.lsq_optimization_setting.lr = 1e-4 # adjust learning rate
setting.lsq_optimization_setting.epochs = 30 # adjust number of training epochs for every block

参见下面这个网址查看更多关于支持的的pass和它们的应用:

 https://kgithub.com/openppl-public/ppq/blob/master/ppq/api/setting.py

 6.安排你的图

在用量化器处理中间图之前,PPQ需要调度中间图上的算子到不同的platforms。例如,关于形状的算子将会被调度到TargetPlatform.SHAPE_OR_INDEX;不可量化的算子将会被调度到TargetPlatform.FP32,这意味着它们将始终以fp32模式运行,并且永远不会被量化。

from ppq.api.interface import dispatch_graph
ppq_graph_ir = dispatch_graph(ppq_graph_ir,target_platform,setting)

7.初始化执行器

所有的操作都是由PPQ中的TorchExecutor执行。

from ppq.executor import TorchExecutor
executor = TorchExecutor(ppq_graph_ir,device='cuda') # for cuda execution
executor = TorchExecutor(ppq_graph_ir,device='cpu') # for cpu execution

8.量化

PPQ将为您的目标平台指定一个量化器,该量化器将遵循以下惯例来实际运行量化:

  1. 准备校验需要的调度中间图
  2. 细化某些操作的量化行为
  3. 运行参数和激活的校准过程
  4. 提供量化参数
  5. 运行量化设置中指定的激活优化算法
from ppq.api.interface import QUANTIZER_COLLECTION
quantizer = QUANTIZER_COLLECTION[target_platform](graph=ppq_graph_ir)
quantizer.quantize(
        inputs=dummy_input, # some random input tensor,should be list or dict for multiple inputs
        calib_dataloader=dataloader, # calibration dataloader
        executor=executor, # executor in charge of everywhere graph execution is needed
        setting=setting, # quantization setting
        calib_steps=calib_steps, # number of batched data needed in calibration,8~512
        collate_fn=lambda x: x.to(EXECUTING_DEVICE) # final processing of batched data tensor
)

9.推理模拟 

量化之后,量化的ppq中间图处于量化模式,如果你直接用TorchExecutor运行量化的ppq中间图:

for data in dataloader:
    if collate_fn is not None: # process batched data tensor
        data = collate_fn(data)
    outputs = executor.forward(data)

你将获得在量化模式下的每个可量化算子的最终输出,然而,如果你想禁用量化获得fp32输出,你只需禁用每个可量化操作的量化。

for op in ppq_ir_graph.operations.values():
    if isinstance(op,QuantableOperation):
        op.dequantize() # disable quantization
outputs = executor.forward(data) # execution in fp32 mode

10.分析

PPQ提供了强大的分析工具来分析量化图不同层的精度下降,graphwise_error_analyse考虑了执行过程中的量化误差积累,而layerwise_error_analyse则考虑了每一层的量化误差,如果你想通过分析fp32输出和不同层的量化输出的信号噪声比来了解量化图的整体性能:

from ppq.quantization.analyse import layerwise_error_analyse,graphwise_error_analyse
graphwise_error_analyse(
    graph=quantized, # ppq ir graph
    running_device=EXECUTING_DEVICE, # cpu or cuda
    method='snr', # the metric is signal noise ratio by default,adjust it to 'cosine' if that's desired
    step=32, # how many batches of data will be used for error analysis
    dataloader=dataloader,
    collate_fn=lambda x: x.to(EXECUTING_DEVICE)
)

或者分析每一层的量化误差:

layerwise_error_analyse(
    graph=quantized,
    running_device=EXECUTING_DEVICE,
    method='snr' # the metric is signal noise ratio by default, adjust it to 'cosine' if that's desired
    steps=32,
    dataloader-dataloader
    collate_fn=lambda x: x.to(EXECUTING_DEVICE)
)

11.导出

为了在目标后端部署你的模型,应该从量化的PPQ中间图中导出适当格式的量化模型和相应的量化参数。PPQ将为不同的目标平台指定不同的导出器。例如,如果OpenPPL CUDA(PPL_CUDA_INT8)是所需的后端,PPLBackendExporter将导出一个onnx模型和一个指定量化参数的json文件,关于更多的目标平台和导出器,请查看interface.py。

通常情况下,目标平台决定了量化后的中间图的确切导出格式,但有时你可能想以不同的格式导出,比如你想在PPL_CUDA_INT8上部署你的模型:

from ppq.api.interface import export_ppq_graph
export_platform = TargetPlatform.PPL_CUDA_INT8 # could be other platforms in TargetPlatform class
export_ppq_graph(graph=ppq_ir_graph,platform=platform,graph_save_to='quantized',config_save_to='quantized.json')

或者你想部署你的模型在NCNN_INT8上,那么需要一个量化表文件:

export_ppq_graph(graph=ppq_ir_graph,platform=TargetPlatform.NCNN_INT8,graph_save_to='quantized',config_save_to='quantized.table')

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值