QLinearConv#

  • Domain: ai.onnx

  • Since version: 10

The convolution operator consumes a quantized input tensor, its scale and zero point, a quantized filter, its scale and zero point, and output’s scale and zero point, and computes the quantized output. Each scale and zero-point pair must have same shape. It means they must be either scalars (per tensor) or 1-D tensors (per output channel). Each input or output and its related zero point must have same type. When bias is present it must be quantized using scale = input scale * weight scale and zero point as 0.

Inputs

  • x (T1): Input data tensor from previous layer; has size (N x C x H x W), where N is the batch size, C is the number of channels, and H and W are the height and width. Note that this is for the 2D image. Otherwise the size is (N x C x D1 x D2 … x Dn). Optionally, if dimension denotation is in effect, the operation expects input data tensor to arrive with the dimension denotation of [DATA_BATCH, DATA_CHANNEL, DATA_FEATURE, DATA_FEATURE …].

  • x_scale (tensor(float)): Scale tensor for input ‘x’. It’s a scalar, which means a per-tensor/layer quantization.

  • x_zero_point (T1): Zero point tensor for input ‘x’. It’s a scalar, which means a per-tensor/layer quantization.

  • w (T2): The weight tensor that will be used in the convolutions; has size (M x C/group x kH x kW), where C is the number of channels, and kH and kW are the height and width of the kernel, and M is the number of feature maps. For more than 2 dimensions, the kernel shape will be (M x C/group x k1 x k2 x … x kn), where (k1 x k2 x … kn) is the dimension of the kernel. Optionally, if dimension denotation is in effect, the operation expects the weight tensor to arrive with the dimension denotation of [FILTER_OUT_CHANNEL, FILTER_IN_CHANNEL, FILTER_SPATIAL, FILTER_SPATIAL …]. X.shape[1] == (W.shape[1] * group) == C (assuming zero based indices for the shape array). Or in other words FILTER_IN_CHANNEL should be equal to DATA_CHANNEL.

  • w_scale (tensor(float)): Scale tensor for input ‘w’. It could be a scalar or a 1-D tensor, which means a per-tensor/layer or per output channel quantization. If it’s a 1-D tensor, its number of elements should be equal to the number of output channels (M).

  • w_zero_point (T2): Zero point tensor for input ‘w’. It could be a scalar or a 1-D tensor, which means a per-tensor/layer or per output channel quantization. If it’s a 1-D tensor, its number of elements should be equal to the number of output channels (M).

  • y_scale (tensor(float)): Scale tensor for output ‘y’. It’s a scalar, which means a per-tensor/layer quantization.

  • y_zero_point (T3): Zero point tensor for output ‘y’. It’s a scalar, which means a per-tensor/layer quantization.

  • B (T4): Optional 1D bias to be added to the convolution, has size of M. Bias must be quantized using scale = x_scale * w_scale and zero_point = 0

Outputs

  • y (T3): Output data tensor that contains the result of the convolution. The output dimensions are functions of the kernel size, stride size, and pad lengths.

Type Constraints

  • T1: Constrain input type to 8-bit integer tensor. Allowed types: tensor(int8), tensor(uint8).

  • T2: Constrain filter type to 8-bit integer tensor. Allowed types: tensor(int8), tensor(uint8).

  • T3: Constrain output type to 8-bit integer tensor. Allowed types: tensor(int8), tensor(uint8).

  • T4: Constrain bias type to 32-bit integer tensor. Allowed types: tensor(int32).

Examples#

test_cc_qlinearconv

Node:
  QLinearConv(x, x_scale, x_zero_point, w, w_scale, w_zero_point, y_scale, y_zero_point) -> (y)
Inputs:
  x: shape=(1, 1, 7, 7), dtype=uint8
    [[[[  0,   4,   8,  12,  16,  20,  24],
       [ 28,  32,  36,  40,  44,  48,  52],
       [ 56,  60,  64,  68,  72,  76,  80],
       [ 84,  88,  92,  96, 100, 104, 108],
       [112, 116, 120, 124, 128, 132, 136],
       [140, 144, 148, 152, 156, 160, 164],
       [168, 172, 176, 180, 184, 188, 192]]]]
  x_scale: shape=(), dtype=float32
    0.00369205
  x_zero_point: shape=(), dtype=uint8
    132
  w: shape=(1, 1, 1, 1), dtype=uint8
    [[[[0]]]]
  w_scale: shape=(1,), dtype=float32
    [0.00172795]
  w_zero_point: shape=(1,), dtype=uint8
    [255]
  y_scale: shape=(), dtype=float32
    0.00162681
  y_zero_point: shape=(), dtype=uint8
    123

Outputs:
  y: shape=(1, 1, 7, 7), dtype=uint8
    [[[[255, 251, 247, 243, 239, 235, 231],
       [227, 223, 219, 215, 211, 207, 203],
       [199, 195, 191, 187, 183, 179, 175],
       [171, 167, 163, 159, 155, 151, 147],
       [143, 139, 135, 131, 127, 123, 119],
       [115, 111, 107, 103,  99,  95,  91],
       [ 87,  83,  79,  75,  71,  67,  63]]]]

test_cc_qlinearconv_int8

Node:
  QLinearConv(x, x_scale, x_zero_point, w, w_scale, w_zero_point, y_scale, y_zero_point) -> (y)
Inputs:
  x: shape=(1, 1, 2, 2), dtype=int8
    [[[[10, 20],
       [30, 40]]]]
  x_scale: shape=(), dtype=float32
    0.1
  x_zero_point: shape=(), dtype=int8
    5
  w: shape=(1, 1, 2, 2), dtype=int8
    [[[[1, 1],
       [1, 1]]]]
  w_scale: shape=(1,), dtype=float32
    [1.]
  w_zero_point: shape=(1,), dtype=int8
    [0]
  y_scale: shape=(), dtype=float32
    1.
  y_zero_point: shape=(), dtype=int8
    -10

Outputs:
  y: shape=(1, 1, 1, 1), dtype=int8
    [[[[-2]]]]