class_docstr: Base test class for StableHLO quant tests.
code: def _create_conv2d_model(
      self,
      input_shape: Sequence[int],
      filter_shape: Sequence[int],
      saved_model_path: str,
      has_bias: bool = False,
      has_batch_norm: bool = False,
      activation_fn: Optional[ops.Operation] = None,
      strides: Sequence[int] = (1, 1, 1, 1),
      dilations: Sequence[int] = (1, 1, 1, 1),
      padding: str = "SAME",
  ) -> module.Module:
      class ConvModel(module.Module):
          """A simple model with a single conv2d, bias and relu."""
  
          def __init__(self):
              self.out_channel_size = filter_shape[-1]
  
              # This ensures filters will have different value range per out channel
              self.filters = np.stack(
                  [
                      np.random.uniform(
                          low=-(i + 1),
                          high=(i + 1),
                          size=filter_shape[:-1],
                      ).astype("f4")
                      for i in range(self.out_channel_size)
                  ],
                  axis=-1,
              )
  
              self.bias = np.random.uniform(
                  low=0, high=10, size=(self.out_channel_size)
              ).astype("f4")
  
          @def_function.function
          def conv2d(
              self, input_tensor: core.Tensor
          ) -> Mapping[str, core.Tensor]:
              """Performs a 2D convolution operation.
  
              Args:
                input_tensor: Input tensor to perform convolution on.
  
              Returns:
                A map of: output key -> output result.
              """
              scale = [1.0] * self.out_channel_size
              offset = [0.5] * self.out_channel_size
              mean, variance = scale, offset
              out = nn_ops.conv2d(
                  input_tensor,
                  self.filters,
                  strides=strides,
                  dilations=dilations,
                  padding=padding,
                  data_format="NHWC",
                  name="sample/conv",
              )
              if has_batch_norm:
                  # Fusing is supported for non-training case.
                  out, _, _, _, _, _ = nn_ops.fused_batch_norm_v3(
                      out,
                      scale,
                      offset,
                      mean,
                      variance,
                      is_training=False,
                  )
              return {"output": out}
  
      model = ConvModel()
      saved_model_save.save(
          model,
          saved_model_path,
          signatures=model.conv2d.get_concrete_function(
              tensor_spec.TensorSpec(
                  shape=input_shape,
                  dtype=dtypes.float32,
                  name="input_tensor",
              )
          ),
      )
      return model
  
imports: from typing import Mapping, Sequence, Optional
  from absl.testing import parameterized
  import numpy
  import tensorflow
  from tensorflow.python.eager import def_function
  from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import tensor_spec
  from tensorflow.python.module import module
  from tensorflow.python.ops import array_ops
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops import nn_ops
  from tensorflow.python.platform import test
  from tensorflow.python.saved_model import save
  from tensorflow.python.types import core
label_desc: Use image node_id 4 for calling the QuantizedModelTest obj's underlying member method code with example usage: obj._create_conv2d_model(input_shape, filter_shape, saved_model_path, has_bias, has_batch_norm, activation_fn, strides, dilations, padding) and returns: model, dict