code: def test_conv_bn_folded_vs_unfolded(
      self,
      batch_size,
      input_channels_per_group,
      height,
      width,
      output_channels_per_group,
      groups,
      kernel_h,
      kernel_w,
      stride_h,
      stride_w,
      pad_h,
      pad_w,
      dilation,
      padding_mode,
      eps,
      momentum,
      freeze_bn,
      bias,
  ):
      input_channels = input_channels_per_group * groups
      output_channels = output_channels_per_group * groups
      dilation_h = dilation_w = dilation
  
      qat_op = ConvBn2d(
          input_channels,
          output_channels,
          (kernel_h, kernel_w),
          (stride_h, stride_w),
          (pad_h, pad_w),
          (dilation_h, dilation_w),
          groups,
          bias,  # bias
          padding_mode,
          eps,
          momentum,
          freeze_bn=freeze_bn,
          qconfig=default_qat_qconfig,
      ).to(dtype=torch.double)
  
      qat_ref_op = _ReferenceConvBn2d(
          input_channels,
          output_channels,
          (kernel_h, kernel_w),
          (stride_h, stride_w),
          (pad_h, pad_w),
          (dilation_h, dilation_w),
          groups,
          bias,  # bias
          padding_mode,
          eps,
          momentum,
          freeze_bn=freeze_bn,
          qconfig=default_qat_qconfig,
      ).to(dtype=torch.double)
  
      qat_op.apply(torch.ao.quantization.disable_fake_quant)
      qat_ref_op.apply(torch.ao.quantization.disable_fake_quant)
  
      # align inputs and internal parameters
      qat_ref_op.weight = torch.nn.Parameter(
          qat_op.weight.detach().clone()
      )
      qat_ref_op.running_mean = qat_op.bn.running_mean.clone()
      qat_ref_op.running_var = qat_op.bn.running_var.clone()
      qat_ref_op.gamma = torch.nn.Parameter(
          qat_op.bn.weight.detach().clone()
      )
      qat_ref_op.beta = torch.nn.Parameter(
          qat_op.bn.bias.detach().clone()
      )
      if qat_op.bias is not None:
          qat_ref_op.bias = torch.nn.Parameter(
              qat_op.bias.detach().clone()
          )
  
      lr = 0.01
      qat_op_optim = torch.optim.SGD(qat_op.parameters(), lr=lr)
      qat_ref_op_optim = torch.optim.SGD(qat_ref_op.parameters(), lr=lr)
  
      for i in range(5):
          # make sure that calling model.train() does not override the
          # bn freeze setting
          qat_op.train()
          qat_ref_op.train()
  
          qat_op_optim.zero_grad()
          qat_ref_op_optim.zero_grad()
  
          input = torch.randn(
              batch_size,
              input_channels,
              height,
              width,
              dtype=torch.double,
              requires_grad=True,
          )
          input_clone = input.clone().detach().requires_grad_()
  
          if i > 2:
              qat_op.apply(torch.ao.nn.intrinsic.qat.freeze_bn_stats)
              qat_ref_op.freeze_bn_stats()
  
          if i > 3:
              qat_op.apply(torch.ao.quantization.disable_observer)
              qat_ref_op.apply(torch.ao.quantization.disable_observer)
  
          result_ref = qat_ref_op(input)
          result_actual = qat_op(input_clone)
          self.assertEqual(result_ref, result_actual)
  
          # backward
          dout = (
              torch.randn(result_ref.size(), dtype=torch.double) + 10.0
          )
  
          loss = (result_ref - dout).sum()
          loss.backward()
          input_grad_ref = input.grad.cpu()
          weight_grad_ref = qat_ref_op.weight.grad.cpu()
          gamma_grad_ref = qat_ref_op.gamma.grad.cpu()
          beta_grad_ref = qat_ref_op.beta.grad.cpu()
          running_mean_ref = qat_ref_op.running_mean
          running_var_ref = qat_ref_op.running_var
          num_batches_tracked_ref = qat_ref_op.num_batches_tracked
  
          loss = (result_actual - dout).sum()
          loss.backward()
          input_grad_actual = input_clone.grad.cpu()
          weight_grad_actual = qat_op.weight.grad.cpu()
          gamma_grad_actual = qat_op.bn.weight.grad.cpu()
          beta_grad_actual = qat_op.bn.bias.grad.cpu()
          running_mean_actual = qat_op.bn.running_mean
          running_var_actual = qat_op.bn.running_var
          num_batches_tracked_actual = qat_op.bn.num_batches_tracked
  
          precision = 1e-5
          self.assertEqual(
              input_grad_ref, input_grad_actual, atol=precision, rtol=0
          )
          self.assertEqual(
              weight_grad_ref,
              weight_grad_actual,
              atol=precision,
              rtol=0,
          )
          self.assertEqual(
              gamma_grad_ref, gamma_grad_actual, atol=precision, rtol=0
          )
          self.assertEqual(
              beta_grad_ref, beta_grad_actual, atol=precision, rtol=0
          )
          self.assertEqual(
              num_batches_tracked_ref,
              num_batches_tracked_actual,
              atol=precision,
              rtol=0,
          )
          self.assertEqual(
              running_mean_ref,
              running_mean_actual,
              atol=precision,
              rtol=0,
          )
          self.assertEqual(
              running_var_ref,
              running_var_actual,
              atol=precision,
              rtol=0,
          )
  
          qat_op_optim.step()
          qat_ref_op_optim.step()
  
imports: import copy
  import math
  import torch
  import torch.nn
  import torch.backends.mkldnn
  from torch.nn import Conv2d, BatchNorm2d, ReLU, init
  from torch.ao.nn.intrinsic.qat import ConvBn2d, ConvBnReLU2d
  from torch.nn.modules.utils import _pair
  import torch.ao.nn.quantized
  import torch.ao.nn.quantized.dynamic
  import torch.ao.nn.qat
  import torch.ao.nn.intrinsic.qat
  import torch.ao.nn.qat.dynamic
  from torch.ao.quantization import prepare, convert, prepare_qat, quantize_qat, QuantStub, DeQuantStub, default_qconfig, default_qat_qconfig, default_embedding_qat_qconfig, default_symmetric_qnnpack_qat_qconfig, get_default_qat_qconfig, FixedQParamsFakeQuantize, FusedMovingAvgObsFakeQuantize, get_embedding_qat_module_mappings, get_embedding_static_quant_module_mappings, NoopObserver
  from torch.ao.quantization.qconfig import qconfig_equals
  from torch.testing._internal.common_quantization import DeFusedEmbeddingBagLinear, QuantizationTestCase, QuantStubModel, ManualLinearQATModel, ManualDropoutQATModel, ManualLinearDynamicQATModel, ManualConvLinearQATModel, ManualConvLinearSymmQATModel, ManualEmbeddingBagLinear, TwoLayerLinearModel, test_only_eval_fn, test_only_train_fn
  from torch.testing._internal.common_quantized import override_quantized_engine, supported_qengines, override_qengines
  from torch.testing._internal.common_utils import skipIfNoXNNPACK
  from hypothesis import given
  from hypothesis import strategies
  import torch.testing._internal.hypothesis_utils
  from functools import reduce
label_desc: Use image node_id 6 for calling the TestQuantizeEagerQATNumerics obj's underlying member method code with example usage: obj.test_conv_bn_folded_vs_unfolded(batch_size, input_channels_per_group, height, width, output_channels_per_group, groups, kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dilation, padding_mode, eps, momentum, freeze_bn, bias) without return types