这是PPQ的接口库定义,该文件中定义的内容允许你在任何Python程序中嵌入PPQ的执行逻辑。
1.PPQ.lib.common.Qauntizer
截至PPQ 0.6.6,软件中共有20种不同的量化器,对应不同的部署平台。在PPQ中,量化器负责为算子初始化量化信息,其量化策略对于不同的硬件平台是不同的,所以量化器也有不同的实现逻辑。量化器必须实现init_quant_config函数,根据算子的类别为算子初始化量化配置信息。量化器还必须告知所有可量化的算子类型,以协助调度器确定调度方案。
{
TargetPlatform.PPL_DSP_INT8: PPL_DSP_Quantizer,
TargetPlatform.PPL_DSP_TI_INT8: PPL_DSP_TI_Quantizer,
TargetPlatform.SNPE_INT8: PPL_DSP_Quantizer,
TargetPlatform.QNN_DSP_INT8: PPL_DSP_Quantizer,
TargetPlatform.TRT_INT8: TensorRTQuantizer,
TargetPlatform.MNN_INT8: MNNQuantizer,
TargetPlatform.ASC_INT8: ASCendQuantizer,
TargetPlatform.NCNN_INT8: NCNNQuantizer,
TargetPlatform.NXP_INT8: NXP_Quantizer,
TargetPlatform.RKNN_INT8: RKNN_PerTensorQuantizer,
TargetPlatform.METAX_INT8_C: MetaxChannelwiseQuantizer,
TargetPlatform.METAX_INT8_T: MetaxChannelwiseQuantizer,
TargetPlatform.PPL_CUDA_INT8: PPLCUDAQuantizer,
TargetPlatform.EXTENSION: ExtQuantizer,
TargetPlatform.FPGA_INT8: FPGAQuantizer,
TargetPlatform.OPENVIVO_INT8: OpenvinoQuantizer,
TargetPlatform.TENGINE_INT8: TengineQuantizer,
TargetPlatform.GRAPHCORE_FP8: GraphCoreQuantizer,
TargetPlatform.TRT_FP8: TensorRTQuantizer,
TargetPlatform.ONNXRUNTIME: OnnxruntimeQuantizer,
}
注册新的量化器
用户可以使用接口函数ppq.lib.register_network_quantizer来注册一个自定义的量化器,要知道注册的量化器必须继承ppq.quantization.quantizer.BaseQuantizer基类并实现相应的接口:
# 示例代码
from ppq.IR import Operation
from ppq.core import OperationQuantizationConfig
from ppq.quantization.quantizer import BaseQuantizer
from ppq.core import TargetPlatform
class MyQuantizer(BaseQuantizer):
def init_quantize_config(self,operation:Operation) -> OperationQuantizationConfig:
return super().init_quantize_config(operation)
def quant_operation_types(self) -> set:
return {'Conv','Gemm'}
register_network_quantizer(quantizer=MyQuantizer,platform=TargetPlatform.PPL_CUDA_INT8)
用户可以通过接口函数ppq.lib.quant.quantizer获得与平台对应的量化器,或者从ppq.quantization.quantizer ...导入所需的量化器。
2.PPQ.lib.common.Export
在PPQ中,我们用量化控制信息来描述网络的量化,而网络中与量化相关的参数都存储在算子的量化控制信息中。因此,网络的导出也是将绑定在算子上的量化控制信息导出到一个文件中,你应该根据推理框架的需要导出相应的模型格式。截止到PPQ 0.6.6,目前共支持19种导出格式:
{
TargetPlatform.PPL_DSP_INT8: PPLDSPCaffeExporter,
TargetPlatform.PPL_DSP_TI_INT8: PPLDSPTICaffeExporter,
TargetPlatform.QNN_DSP_INT8: QNNDSPExporter,
TargetPlatform.PPL_CUDA_INT8: PPLBackendExporter,
TargetPlatform.SNPE_INT8: SNPECaffeExporter,
TargetPlatform.NXP_INT8: NxpExporter,
TargetPlatform.ONNX: OnnxExporter,
TargetPlatform.ONNXRUNTIME: ONNXRUNTIMExporter,
TargetPlatform.OPENVINO_INT8: OpenvinoExporter,
TargetPlatform.CAFFE: CaffeExporter,
TargetPlatform.NATIVE: NativeExporter,
TargetPlatform.EXTENSION: ExtensionExporter,
TargetPlatform.RKNN_INT8: OnnxExporter,
TargetPlatform.METAX_INT8_C: ONNXRUNTIMExporter,
TargetPlatform.METAX_INT8_T: ONNXRUNTIMExporter,
TargetPlatform.TRT_INT8: TensorRTExporter_JSON,
TargetPlatform.ASC_INT8: AscendExporter,
TargetPlatform.TRT_FP8: ONNXRUNTIMExporter,
TargetPlatform.NCNN_INT8: NCNNExporter,
TargetPlatform.TENGINE_INT8: TengineExporter,
TargetPlatform.MNN_INT8: MNNExporter,
}
用户可以使用接口函数ppq.lib.register_network_quantizer来注册自定义导出逻辑,要知道注册的量化器必须继承ppq.parser.GraphExporter基类并实现相应接口:
# 示例代码
from ppq.IR import BaseGraph
from ppq.core import TargetPlatform
class MyExporter(GraphExporter):
def export(self,file_path:str,graph:BaseGraph,config_path:str=None,**kwargs):
return super().export(file_path,graph,config_path,**kwargs)
register_network_exporter(exporter=MyExporter,platform=TargetPlatform.PPL_CUDA_INT8)
获取一个量化器的例子
用户可以通过接口函数ppq.lib.quant.Exporter获得与平台相对应的导出器,或者从ppq.parser ... 导入所需的导出器。
3.PPQ.lib.quant 库
1.Quantizer(platform:TargetPlatform,graph:BaseGraph) -> BaseGraph:
根据目标平台获取一个系统预定义的量化器。在PPQ中,量化器是一个用于为算子初始化量化信息Tensor Quantization Config的对象。量化器决定了你的算子是如何被量化的,你也可以设计新的量化器来适配不同的后端推理框架,在PPQ中,为不同的后端推理框架设计好了一些预定义的量化器,可以通过ppq.lib.Quantizer来访问它们。
2.Pipeline(optims: List[QuantizationOptimizationPass]) -> QuantizationOptimizationPipeline:
使用给定的量化过程集合创建量化管线。
3.Observer(quant_config: TensorQuantizationConfig,variable: Variable=None) -> BaseTensorObserver:
根据TQC中observer_algorithm属性获取对应的Observer。
4.LinearQuantizationConfig(symmetrical: bool=True,dynamic: bool=False,power_of_2:bool=False,channel_axis:int=None,quant_min:int=-128,quant_max:int=127,num_of_bits=8,calibration:str='minmax',rounding:RoundingPolicy=RoundingPolicy.ROUND_HALF_EVEN) -> TensorQuantizationConfig:
创建线性量化信息。
5.LinearQuantizationConfig(symmetrical:bool=True,power_of_2:bool=True,channel_axis:int=None,quant_min:float=-448.0,quant_max:float=448.0,exponent:int=4,mantissa:int=3,calibration:str='constant',rounding:RoundingPolicy=RoundingPolicy.ROUND_HALF_EVEN) -> TensorQuantizationConfig:
创建浮点量化信息。
6.Dispatcher(graph:BaseGraph,method:str='conservative') -> GraphDispatch:
获取一个指定的调度器。
7.OperationForwardFunction(optype:str,platform:TargetPlatform=TargetPlatform.FP32) -> Callable:
获取一个算子前向传播执行函数。在PPQ中,相同的算子可以在不同的平台上注册成不同的执行逻辑,使用platform=TargetPlatform.FP32来获取默认执行逻辑。
8.Exporter(platform:TargetPlatform) -> GraphExporter:
获取一个网络导出器。
9.Parser(framework:NetworkFramework) -> GraphExeporter:
获取一个网络解析器。
4.PPQ.lib.extension函数库
1.register_network_quantizer(quantizer:type,platform:TargetPlatform):
将一个量化器注册注册到PPQ量化器集合。这个函数将覆盖默认的量化器集合:register_network_quantizer(MyQuantizer,TargetPlatform.TRT_INT8)将取代默认的TRT_INT8量化器。量化器应该是一个BaseQuantizer的子类,不要在这里启动一个实例,PPQ将在后面启动它。你的量化器不需要初始化参数。
Args:
*.quantizer(类型):要插入的量化器。
*.platform(TargetPlatform):你的量化器对应的平台。
2.register_network_parser(parser:type,framework:NetworkFramework):
向PPQ解析器集合注册一个解析器。这个函数将覆盖默认的解析器集合:register_network_parser(MyParser,NetworkFramework.ONNX)将取代默认的ONNX解析器。
解析器应该是GraphBuilder的一个子类,不要在这里提供一个实例,因为PPQ将在后面启动它。你的量化器不需要初始化参数。
Args:
*.parser(type):要插入的解析器。
*.framework(NetworkFramework):你的解析器对应的NetworkFramework。
3.register_network_exporter(exporter:type,platform:TargetPlatform):
向PPQ的导出器集合注册一个导出器。这个函数将覆盖默认的导出器集合:register_network_quantizer(MyExporter,TargetPlatform.TRT_INT8)将替换默认的TRT_INT8导出器。Exporter应该是GraphExporter的一个子类,不要在这里提供一个实例,因为PPQ将在后面初始化它。你的Exporter不需要初始化参数。
Args:
*.exporter(type):要插入的导出器。
*.platform(TargetPlatform):你的导出器对应的平台。
4.register_calibration_observer(algorithm:str,observer:type):
向OBSERVER_TABLE注册一个校准观测器。这个函数将覆盖现有的OBSERVER_TABLE,不会有任何警告,注册的观测器必须是OperationObserver的子类。
Args:
*.exporter(type):要插入的导出器。
*.platform(TargetPlatform):你的导出器对应的平台。
5.register_operation_handler(handler:Callable,operation_type:str,platform:TargetPlatform):
注册一个定制函数作为操作处理程序。函数应该接受至少3个输入参数,返回一个或多个Tensor作为结果:func(op:Operation,values:List[torch.Tensor],ctx:TorchBackendContext=None,**kwargs) -> torch.Tensor:
如果已经有另一个操作处理程序来处理给定的操作类型,新的处理程序将取代旧的处理程序,不需等待。
Args:
*.handler(Callable):可调用函数,其接口遵循上述限制。
*.operation_type(str):操作类型。
*.platform(TargetPlatform):注册平台。