code: def test_quantized_conv():
      def check_quantized_conv(
          data_shape,
          kernel,
          num_filter,
          pad,
          stride,
          dilate,
          use_bias,
          qdtype,
      ):
          if is_test_for_native_cpu():
              print(
                  "skipped testing quantized_conv for native cpu since it is not supported yet"
              )
              return
          elif is_test_for_dnnl():
              # (TODO)Xinyu: https://github.com/apache/mxnet/issues/16830
              print(
                  "skipped testing quantized_conv for oneDNN cpu since it is a flaky case"
              )
              return
          elif qdtype == "uint8" and is_test_for_gpu():
              print(
                  "skipped testing quantized_conv for gpu uint8 since it is not supported yet"
              )
              return
          elif is_test_for_gpu() and len(data_shape) != 4:
              print(
                  "skipped testing quantized_conv for gpu 5d layout since it is not supported yet"
              )
              return
  
          # run fp32 conv
          if len(data_shape) == 4:
              convfp32 = mx.gluon.nn.Conv2D(
                  channels=num_filter,
                  kernel_size=kernel,
                  strides=stride,
                  padding=pad,
                  dilation=dilate,
                  use_bias=use_bias,
              )
          elif len(data_shape) == 5:
              convfp32 = mx.gluon.nn.Conv3D(
                  channels=num_filter,
                  kernel_size=kernel,
                  strides=stride,
                  padding=pad,
                  dilation=dilate,
                  use_bias=use_bias,
              )
          else:
              print("unsupported shape")
              assert False
  
          if qdtype == "uint8":
              data_low = 0.0
              data_high = 127.0
          else:
              data_low = -127.0
              data_high = 127.0
  
          convfp32.initialize()
          input_data = (
              mx.np.random.uniform(
                  low=data_low, high=data_high, size=data_shape
              )
              .astype("int32")
              .astype("float32")
          )
          convfp32(input_data)  # initialize params
          npx.waitall()
          fp32_params = convfp32.collect_params()
          weight_shape = fp32_params["weight"].shape
          new_args = dict()
          new_args["weight"] = (
              mx.np.random.uniform(
                  low=-127.0, high=127.0, size=weight_shape
              )
              .astype("int32")
              .astype("float32")
          )
          if use_bias:
              new_args["bias"] = (
                  mx.np.random.uniform(
                      low=-127.0,
                      high=127.0,
                      size=fp32_params["bias"].shape,
                  )
                  .astype("int32")
                  .astype("float32")
              )
          convfp32.load_dict(
              new_args, cast_dtype=True, dtype_source="saved"
          )
  
          output = convfp32(input_data)
  
          # run quantized conv
          class QuantConv(mx.gluon.nn.HybridBlock):
              def __init__(
                  self,
                  channels,
                  kernel_size,
                  strides=(1, 1),
                  padding=(0, 0),
                  dilation=(1, 1),
                  use_bias=True,
                  **kwargs,
              ):
                  super(QuantConv, self).__init__(**kwargs)
                  self.use_bias = use_bias
                  self._kwargs = {
                      "kernel": kernel_size,
                      "stride": strides,
                      "dilate": dilation,
                      "pad": padding,
                      "num_filter": channels,
                      "no_bias": not use_bias,
                      "num_group": 1,
                      "layout": "NCHW",
                  }
  
                  self.min_data = mx.gluon.Parameter(
                      "min_data",
                      dtype="float32",
                      shape=(1),
                      allow_deferred_init=True,
                  )
                  self.max_data = mx.gluon.Parameter(
                      "max_data",
                      dtype="float32",
                      shape=(1),
                      allow_deferred_init=True,
                  )
  
                  self.weight = mx.gluon.Parameter(
                      "weight",
                      dtype="int8",
                      shape=weight_shape,
                      allow_deferred_init=True,
                  )
                  self.min_weight = mx.gluon.Parameter(
                      "min_weight",
                      dtype="float32",
                      shape=(1),
                      allow_deferred_init=True,
                  )
                  self.max_weight = mx.gluon.Parameter(
                      "max_weight",
                      dtype="float32",
                      shape=(1),
                      allow_deferred_init=True,
                  )
  
                  if use_bias:
                      self.bias = mx.gluon.Parameter(
                          "bias",
                          dtype="int8",
                          shape=(num_filter,),
                          allow_deferred_init=True,
                      )
                      self.min_bias = mx.gluon.Parameter(
                          "min_bias",
                          dtype="float32",
                          shape=(1),
                          allow_deferred_init=True,
                      )
                      self.max_bias = mx.gluon.Parameter(
                          "max_bias",
                          dtype="float32",
                          shape=(1),
                          allow_deferred_init=True,
                      )
  
              def forward(self, x):
                  device = x.device
                  weight = self.weight.data().to_device(device)
                  bias = (
                      self.bias.data().to_device(device)
                      if self.use_bias
                      else None
                  )
                  min_data = self.min_data.data().to_device(device)
                  max_data = self.max_data.data().to_device(device)
                  min_weight = self.min_weight.data().to_device(device)
                  max_weight = self.max_weight.data().to_device(device)
                  min_bias = (
                      self.min_bias.data().to_device(device)
                      if self.use_bias
                      else None
                  )
                  max_bias = (
                      self.max_bias.data().to_device(device)
                      if self.use_bias
                      else None
                  )
                  out = npx.quantized_conv(
                      data=x,
                      weight=weight,
                      bias=bias,
                      min_data=min_data,
                      max_data=max_data,
                      min_weight=min_weight,
                      max_weight=max_weight,
                      min_bias=min_bias,
                      max_bias=max_bias,
                      **self._kwargs,
                  )
                  return out
  
          convint8 = QuantConv(
              channels=num_filter,
              kernel_size=kernel,
              strides=stride,
              padding=pad,
              dilation=dilate,
              use_bias=use_bias,
          )
  
          quantized_range = 127.0
          qargs = {
              "weight": new_args["weight"].astype("int8"),
              "min_data": mx.np.array([-quantized_range]),
              "max_data": mx.np.array([quantized_range]),
              "min_weight": mx.np.array([-quantized_range]),
              "max_weight": mx.np.array([quantized_range]),
          }
          if use_bias:
              qargs.update(
                  {
                      "bias": new_args["bias"].astype("int8"),
                      "min_bias": mx.np.array([-quantized_range]),
                      "max_bias": mx.np.array([quantized_range]),
                  }
              )
  
          convint8.load_dict(
              qargs, cast_dtype=True, dtype_source="saved"
          )
  
          qoutput, min_range, max_range = convint8(
              input_data.astype(qdtype)
          )
  
          if use_bias:
              # with adding bias, accuracy loss should not be greater than one
              diff = mx.np.abs(output - qoutput.astype(output.dtype))
              cond = mx.np.less(2, diff).sum().item()
              assert cond == 0
          else:
              assert_almost_equal(
                  output.asnumpy(), qoutput.asnumpy(), atol=1
              )
  
      for qdtype in ["int8", "uint8"]:
          check_quantized_conv(
              (3, 4, 28, 28),
              (3, 3),
              128,
              (1, 1),
              (1, 1),
              (1, 1),
              True,
              qdtype,
          )
          check_quantized_conv(
              (3, 4, 28, 28),
              (3, 3),
              128,
              (1, 1),
              (1, 1),
              (1, 1),
              False,
              qdtype,
          )
          check_quantized_conv(
              (1, 3, 4, 28, 28),
              (1, 3, 3),
              128,
              (1, 1, 1),
              (1, 1, 1),
              (1, 1, 1),
              False,
              qdtype,
          )
          check_quantized_conv(
              (1, 3, 4, 28, 28),
              (1, 3, 3),
              128,
              (1, 1, 1),
              (1, 1, 1),
              (1, 1, 1),
              True,
              qdtype,
          )
          check_quantized_conv(
              (1, 3, 4, 28, 28),
              (1, 3, 3),
              128,
              (1, 1, 1),
              (1, 1, 1),
              (2, 2, 2),
              False,
              qdtype,
          )
          check_quantized_conv(
              (1, 3, 4, 28, 28),
              (1, 3, 3),
              128,
              (1, 1, 1),
              (1, 1, 1),
              (2, 2, 2),
              True,
              qdtype,
          )
  
imports: import os
  import mxnet
  import numpy
  from mxnet import npx
  from mxnet.util import use_np
  from mxnet.gluon.model_zoo import vision
  from mxnet.test_utils import assert_almost_equal, assert_exception, rand_ndarray, rand_shape_nd, same, DummyIter
  from common import xfail_when_nonstandard_decimal_separator
  from mxnet.io import NDArrayIter
  import unittest
  import operator
label_desc: Use image node_id 10 for calling a global function with example usage: test_quantized_conv() and returns: out