5. PTQ量化

后摩大道® M50 HMQuantool量化工具 支持PTQ(Post-Training Quantization,训练后量化),并支持混合精度等方法对模型调优。

PTQ量化是一种无需重新训练,即可对预训练模型进行量化的方法。HMQuantool量化工具的PTQ量化功能,用于将模型中权重(weight)和激活值(activation)从浮点数转换为具有低尾数位宽的低精度数据类型,并导出HMONNX格式的量化模型文件。生成的量化模型能够在后摩M50设备上实现高效推理,也可在CPU和GPU上进行精度仿真验证。

5.1. 量化策略

随着深度学习模型规模的不断增长,部署模型所需的计算资源和存储空间也急剧上升,因此降低推理过程中的计算开销与存储成本至关重要。HMQuantool量化工具通过灵活的量化策略,将原始FP16 浮点模型中的权重转换为低精度INT4、INT8、bFP16或bFP24格式,并将激活值转换为低精度bFP16或bFP24格式,从而显著提升模型在推理场景下的性能和部署效率。

量化策略主要分为两个部分:

  • 尾数位量化 :通过精确控制浮点数尾数的位宽来权衡数值精度与存储开销,直接影响量化后数值的细节保留程度。

  • 量化格式 :基于缩放因子(scale)机制,提供两种数值表示方式,来进一步优化存储和计算效率:

    • SSFP(Shared Scale Floating Point,共享缩放因子浮点格式)

    • SEFP(Shared Exponent Floating Point,共享指数浮点格式)

HMQuantool量化工具量化后的数据类型全面适配后摩M50设备的计算格式,确保在后摩M50设备上实现高效推理。

量化策略可通过 QuantScheme类quant_type 参数设置。

5.1.1. 尾数位量化

一个浮点数通常由以下结构定义:

  • 符号位: 标识数值的正负。

  • 指数位: 定义数值的量级或范围。

  • 尾数位: 确定数值的精确程度,即小数点后的有效数字位数。

在浮点数表示中,尾数位是决定数值精度的核心组成部分。尾数位比特数量与数值精度呈正相关。尾数位比特数越多,数值可表示的粒度越细,舍入误差越小。反之,尾数比特数越少,精度越低,但存储和计算效率更高。

尾数位量化策略中,将模型权重量化为具有8-bit或4-bit尾数位的低精度格式,将激活值量化为具有8-bit至16-bit范围内的尾数位低精度格式。该策略完全满足后摩M50芯片在推理过程中对数据格式的需求,能够有效降低模型的计算和存储开销,在保持模型精度的同时显著提升推理性能和部署效率,特别适用于大规模模型压缩和部署场景。

下表详细阐述各选项对模型精度、内存占用和推理性能的影响。

表 5.1 量化权重和激活值尾数位说明

量化项

尾数位

量化后内存占用

量化后计算性能

量化后精度

权重

8-bit

权重

4-bit

最高

激活值

8 ~ 16 bit

中到高

高到中

5.1.2. 量化格式

除针对尾数位的量化策略,HMQuantool量化工具还通过缩放因子机制进一步优化存储和计算效率。该机制支持两种共享比例数据格式,能够在降低内存占用的同时尽可能保持数值精度:

5.1.2.1. SSFP

SSFP为共享缩放因子浮点格式。该格式将模型权重按组划分,每组内所有值共享一个FP16 浮点类型的缩放因子。量化时,用该缩放因子对原始权重进行缩放,从而实现内存压缩。

5.1.2.2. SEFP

SEFP为共享指数浮点格式,将模型的权重或激活值按组划分,每组内所有数值共享一个指数部分。组内各值只需要单独存储其尾数部分。

该格式是根据“Microscaling Data Formats for Deep Learning” 论文实现,了解详情可参看 https://arxiv.org/pdf/2310.10537

5.2. 量化基本流程

以下步骤以ResNet50模型量化为例,展示了HMQuantool工具在CV模型上的典型量化流程。示例中所用的原始模型为 FP16 类型的 ONNX 浮点模型。由于HMQuantool 仅支持 FP16 类型的 ONNX 模型作为输入,若原始模型为其他数据类型,需用户在使用前自行转换为 FP16 格式。此外,为获得更优性能,推荐使用 ONNX 格式作为输入模型。

  1. 导入依赖库。

    import argparse
    from pathlib import Path
    import onnx
    import torch
    from xhquant.api import (
        DeviceType,
        HMONNXGoldenInference,
        QuantScheme,
        convert_onnx_to_hmonnx,
        create_quant_config,
        xhquant_init,
    )
    
  2. 准备输入参数与模型数据。

    • 设置原始ONNX模型路径。示例如下:

      onnx_file = "data/models/resnet/resnet50_224x224.onnx"
      
    • 设置模型输入。示例如下:

      # Load the ONNX model from file
      onnx_model = onnx.load(onnx_file)
      # Extract the input shape from the first input of the ONNX model
      input_shape = [int(dim.dim_value) for dim in onnx_model.graph.input[0].type.tensor_type.shape.dim]
      # Set the batch size for the input shape
       batch_size = 1
      input_shape[0] = batch_size
      # Generate a random input tensor with the specified shape and float32 data type
      input = torch.randn(input_shape, dtype=torch.float32)
      
    • 设置量化后输出路径。示例如下:

      # Build working directory path based on model name and input shape
      onnx_name = Path(onnx_file).stem
      str_shape = "x".join([str(dim) for dim in input_shape])
      onnx_name = f"{onnx_name}_{str_shape}"
      work_dirs = Path("work_dirs") / onnx_name
      work_dirs.mkdir(exist_ok=True, parents=True)
      
      # Set output path for quantized HMONNX model
      target_device = DeviceType.XH2a
      out_hmonnx_file = work_dirs / "hmonnx" / f"{onnx_name}_{target_device}.onnx"
      out_hmonnx_file.parent.mkdir(exist_ok=True, parents=True)
      out_hmonnx_file: str = str(out_hmonnx_file)
      
  3. 调用 xhquant_init 接口,初始化量化环境。示例如下:

    xhquant_init(None, debug=args.debug)
    
  4. 通过 Class QuantScheme 设置量化方案。示例如下:

    quant_scheme = QuantScheme(target_device=DeviceType.XH2a, quant_type=w8a8h1_sefp)
    

    示例中,设置推理目标设备类型为后摩M50芯片(DeviceType.XH2a),并设置权重与激活均保留 8-bit尾数位,使用SEFP格式的量化方案(w8a8h1_sefp)。

  5. 调用 create_quant_config 接口,构建量化配置。示例如下:

    quant_config = create_quant_config(quant_scheme)
    
  6. 调用 convert_onnx_to_hmonnx 接口,量化模型并导出量化后HMONNX模型。示例如下:

    convert_onnx_to_hmonnx(
        onnx_file,
        [input],
        DeviceType.XH2a,
        out_hmonnx_file,
        quant_config=quant_config,
        input_names=["images"],
        output_names=["cls_score"],
    )
    
  7. (可选)调用 HMONNXGoldenInference 接口,生成Goden数据,用于验证量化精度是否达标。示例如下:

    device = "cuda" if torch.cuda.is_available() else "cpu"
    session = HMONNXGoldenInference(out_hmonnx_file)
    session.to(device) # Set the device for inference
    session.save_golden = True  # Enable saving of golden outputs
    # Set the directory where golden outputs will be saved
    session.golden_dir = work_dirs / "hmonnx/golden"
    session.step = 0
    session(input.half().to(device)) # Model inference
    

完整示例参看 ResNet50模型量化示例