4. 图像数据预处理

后摩硬件设备内置Resizer组件专用于在模型推理前对图像预处理,以达到模型推理所需要的数据格式要求。Resizer内部按以下固定顺序完成图像预处理操作:

  1. Crop:以(top, left)为起点裁剪出一个(crop_height \times crop_width)区域的图像。

  2. Resize:调整图像大小。

  3. Pad:填充图像。

后摩大道® M50 HMQuantool量化工具 提供硬件Resizer的配置和模拟功能。此外,除了Crop、Resize、Pad图像预处理操作,HMQuantool量化工具还支持归一化等一系列图像预处理辅助功能。

对于图像数据输入,HMQuantool量化工具会根据预处理参数设置,在量化生成的模型文件中添加ImageResize或DynamicImageResize算子。在调用后摩TCIM接口推理时,输入图像数据将通过硬件 Resizer 模块完成预处理操作,确保图像数据满足模型输入要求。

4.1. 功能说明

4.1.1. 功能限制

  • 图像缩放:

    • 缩小: 图像宽度(W)和高度(H)方向最大可缩小至原始尺寸的 1/32。

    • 放大: 图像宽度(W)和高度(H)方向最大可放大 16 倍。

  • 图像填充: 支持单方向填充,可选择上下或左右方向填充,但不能同时在两个方向进行。

4.1.2. 输入图像规格

  • 支持格式: YUV420SP、YUV422SP、YUV444SP、R8、RGB888-Planar和RGBA8888-Planar。

  • 最大输入尺寸(width x height):

    • YUV420SP、YUV422SP、R8、RGB8888-Planar、RGBA8888‑Planar:1024 x 4096 pixels;

    • YUV444SP:512 x 4096 pixels;

  • 像素精度: 8 位无符号整数(uint8),像素值范围为 0 ~ 255。

4.1.3. 输出图像规格

  • 最大输出尺寸(width x height): 1024 x 4096 pixels。

  • 像素精度:

    • uint8,无符号数,取值范围为 0 ~ 255;

    • int8,有符号数,取值范围为 -128 ~ 127;

4.2. 图像预处理操作

4.2.1. 图像尺寸固定的场景

下面示例展示在图像尺寸固定的场景下,模型量化过程中配置并启用图像预处理的主要步骤。

示例中通过 ResizerScheme 配置了图像裁剪的区域,并设置 dynamic_cropFalse。预处理阶段将输入的 RGB 图像 resize 到固定的 512 x 512,不启用裁剪和填充操作。图像数据按通道进行归一化处理,将像素值缩放到 [0, 1] 范围。预处理输入与输出的图像格式均为 RGB,因此不会发生格式转换。该配置适用于输入尺寸固定的常规图像模型量化与推理场景。

示例展示关键步骤代码,仅供参考,不可以直接拷贝运行。

  1. 导入依赖库。

    import cv2
    import torch
    import numpy as np
    from xhquant.api import ResizerScheme
    from xhquant.api import (
        DeviceType,
        HMONNXGoldenInference,
        HMONNXInference,
        QuantScheme,
        convert_onnx_to_hmonnx,
        create_quant_config,
        convert_fx_model_to_quanted_model,
        convert_quanted_model_to_hmonnx,
        ConfigDict
    )
    
  2. 加载模型。示例如下:

    onnx_model = onnx.load(onnx_path)
    
  3. 读取输入图像并构造模型输入 Tensor。示例如下:

    img = cv2.imread("image.jpg")
    img_tensor = torch.from_numpy(img).permute(2, 0, 1).unsqueeze(0)
    
  4. 调用 xhquant_init 接口,初始化量化环境。示例如下:

    xhquant_init(None, debug=args.debug)
    
  5. 通过 Class ResizerScheme 设置图像预处理参数,设置 dynamic_cropFalse。示例如下:

    resizer_config = ResizerScheme(
        size=(512,512),
        align_corners=False,
        fmt="rgb",
        int_trans=True,
        crop_size=(0, 0),
        crop_offset=(0, 0),
        pad_size=(0, 0, 0, 0),
        pad_value=0,
        mean=[0.0,0.0,0.0],
        std=[1.0/255,1.0/255,1.0/255],
        dynamic_crop=False,
        model_inp_fmt="rgb",
    ).to_dict()
    
  6. 通过 Class QuantScheme 设置量化方案。示例如下:

    quant_scheme = QuantScheme(
        target_device=DeviceType.XH2a,
        quant_type=w8a8h1_sefp,
        input_ppc_config=[
            resizer_config
        ]
    )
    

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

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

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

    convert_onnx_to_hmonnx(
        onnx_model,
        [img_tensor],
        DeviceType.XH2a,
        quant_config=quant_config,
    )
    

4.2.2. 图像尺寸可变的场景

下面示例展示在图像尺寸可变的场景下,模型量化过程中配置并启用图像预处理的主要步骤。

示例中通过 ResizerScheme 配置了图像预处理参数,并设置 dynamic_cropTrue。预处理阶段将输入的 YUV420 图像 resize 到目标尺寸 224 x 224,未启用裁剪和填充操作。图像数据按通道进行归一化处理,减去均值 [0.485, 0.456, 0.406] 并除以标准差 [1/255, 1/255, 1/255]。输入图像格式为 YUV420,预处理输出的图像格式为 RGB,因此在处理过程中会进行图像格式转换。该配置适用于图像尺寸可变场景的模型量化与推理。示例展示关键步骤代码,仅供参考,不可以直接拷贝运行。

  1. 导入依赖库。

    import torch
    import cv2
    import onnx
    import numpy as np
    import onnxruntime as ort
    from xhquant.api import ResizerScheme
    from xhquant.api import (
        DeviceType,
        HMONNXGoldenInference,
        HMONNXInference,
        QuantScheme,
        convert_onnx_to_hmonnx,
        create_quant_config,
        convert_fx_model_to_quanted_model,
        convert_quanted_model_to_hmonnx,
        ConfigDict
    )
    
  2. 加载模型。示例如下:

    onnx_model = onnx.load(onnx_path)
    
  3. 构造量化校准输入数据。在动态裁剪或图像尺寸可变场景下,量化阶段需要为模型提供校准数据集(calibration dataset),用于生成量化参数。示例如下:

    dims = onnx_model.graph.input[0].type.tensor_type.shape.dim
    input_shape = [dim.dim_value for dim in dims]
    seed = 100
    torch.manual_seed(seed)
    dst_h = op_conf['compile_config']['dst_h']
    dst_w = op_conf['compile_config']['dst_w']
    params = [[0, 0, dst_h, dst_w, dst_h, dst_w, 0, 0, 0, 0]]
    crop_input = torch.tensor(params)
    calib_dataset = [
        torch.randint(low=0, high=255, size=input_shape, dtype=torch.unit8),
        crop_input,
    ]
    

    上面 calib_dataset 是对图像进行裁剪、缩放及填充的设置。 params 参数表示动态裁剪输入,依次表示:

    • cropY :裁剪区域左上角的垂直坐标,单位为像素。

    • cropX:裁剪区域左上角的水平坐标,单位为像素。

    • crop_height:裁剪区域的高度,单位为像素。

    • crop_width:裁剪区域的宽度,单位为像素。

    • resize_height:缩放后图像的目标高度,单位为像素。

    • resize_width:缩放后图像的目标宽度,单位为像素。

    • pad_top:顶部填充的像素数。

    • pad_left:左侧填充的像素数。

    • pad_bottom:底部填充的像素数。

    • pad_right:右侧填充的像素数。

  4. 设置模型输入和输出。示例如下:

    注意

    用户需在模型输入名称列表 input_names 末尾使用 append() 添加一个自定义名称,该名称用于标识预处理输入tensor,以便在后续推理前方便定位这些 tensor,并对其进行动态图像处理。

    input_names = [_input.name for _input in onnx_model.graph.input]
    output_names = [_output.name for _output in onnx_model.graph.output]
    input_names.append("dyn_info")
    
  5. 调用 xhquant_init 接口,初始化量化环境。示例如下:

    xhquant_init(None, debug=args.debug)
    
  6. 通过 Class ResizerScheme 设置图像预处理参数,设置 dynamic_cropTrue。示例如下:

    resizer_config = ResizerScheme(
        size=(224, 224),
        mode="bilinear",
        align_corners=False,
        fmt="yuv420",
        int_trans=True,
        crop_size=(0, 0),
        crop_offset=(0, 0),
        pad_size=(0, 0, 0, 0),
        pad_value=0,
        mean=[0.485, 0.456, 0.406],
        std=[1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0],
        dynamic_crop=True,
        model_inp_fmt="rgb",
    ).to_dict()
    
  7. 通过 Class QuantScheme 设置量化方案。示例如下:

    quant_scheme = QuantScheme(
        target_device=DeviceType.XH2a,
        quant_type=w8a8h1_sefp,
        input_ppc_config=[
            resizer_config
        ]
    )
    

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

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

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

    convert_onnx_to_hmonnx(
        onnx_path,
        calib_dataset,
        device_type=DeviceType.XH2a,
        out_hmonnx_file="hm.onnx",
        quant_config=quant_config,
        input_names=input_names,
        output_names=output_names,
    )