class_docstr: Prepares the model for QAT by inserting weight and activation quantizers as
  specified in qconfig_mapping.
  
  Implements additional graph passes on a prepared module returned by prepare_qat_fx.
class_docstr_tok: ["Prepares","the","model","for","QAT","by","inserting","weight","and","activation","quantizers","as","specified","in","qconfig_mapping",".","Implements","additional","graph","passes","on","a","prepared","module","returned","by","prepare_qat_fx","."]
docstr: This method follows the same reasoning as described in ``_mark_always_affine_layers_for_replacement``,
  but instead of replacing activation quantizers for stand-alone ops, it replaces them for
  ops which consume more than 1 tensor as input.
  
  For add or cat, if the qscheme of all tensors being combined together is
  affine, it also uses affine qscheme, otherwise, it uses symmetric qscheme.
docstr_tok: ["This","method","follows","the","same","reasoning","as","described","in","``","_mark_always_affine_layers_for_replacement","``",",","but","instead","of","replacing","activation","quantizers","for","stand-alone","ops",",","it","replaces","them","for","ops","which","consume","more","than","1","tensor","as","input",".","For","add","or","cat",",","if","the","qscheme","of","all","tensors","being","combined","together","is","affine",",","it","also","uses","affine","qscheme",",","otherwise",",","it","uses","symmetric","qscheme","."]
code: def _mark_always_affine_combination_ops_for_replacement(
      self, model: _fx.GraphModule
  ):
      """
      This method follows the same reasoning as described in ``_mark_always_affine_layers_for_replacement``,
      but instead of replacing activation quantizers for stand-alone ops, it replaces them for
      ops which consume more than 1 tensor as input.
  
      For add or cat, if the qscheme of all tensors being combined together is
      affine, it also uses affine qscheme, otherwise, it uses symmetric qscheme.
      """
      for node in model.graph.nodes:
          if node.op == "call_function":
              combine_op_type = _combine_op_type(node)
              if (
                  combine_op_type is not None
                  and combine_op_type != _CombinationOpType.AddReLU
              ):
                  args = node.args
                  if combine_op_type == _CombinationOpType.Concat:
                      args = node.args[0]
                  arg_act_qschemes = []
                  for arg in args:
                      arg_mod = _find_module(model, arg)
                      if arg_mod is not None:
                          if (
                              type(arg_mod) in _always_affine_layers
                              or arg in self._modules_to_replace
                          ):
                              arg_act_qschemes.append(
                                  _QuantizationScheme.affine
                              )
                          elif hasattr(arg_mod, "qscheme"):
                              if (
                                  arg_mod.qscheme
                                  == _torch.per_tensor_affine
                              ):
                                  arg_act_qschemes.append(
                                      _QuantizationScheme.affine
                                  )
                              else:
                                  arg_act_qschemes.append(
                                      _QuantizationScheme.symmetric
                                  )
                          else:
                              arg_act_qschemes.append(
                                  _QuantizationScheme.symmetric
                              )
                      else:
                          arg_act_qschemes.append(
                              _QuantizationScheme.symmetric
                          )
                  if all(
                      x == _QuantizationScheme.affine
                      for x in arg_act_qschemes
                  ):
                      # We have already marked cat op for replacement, when one of the
                      # tensors it combines was marked for replacement. So we don't need to
                      # add it here again.
                      if combine_op_type != _CombinationOpType.Concat:
                          self._mark_act_post_process_for_replacement(
                              node, model
                          )
                  else:
                      # If any of the tensor being cat-ed together need to use
                      # [-128, 127] range, we can't use affine quantization in
                      # symmetric mode for them, so we remove them from modules marked for replacement.
                      if combine_op_type == _CombinationOpType.Concat:
                          for arg in args:
                              if arg in self._modules_to_replace:
                                  self._modules_to_replace.pop(arg)
                              if arg in self._new_act_post_process:
                                  self._new_act_post_process.pop(arg)
  
imports: from collections import defaultdict
  from typing import Any
  from typing import Optional
  import torch
  import torch.ao.quantization
  import torch.fx
  import torch.nn
  import torch.nn.intrinsic
  import torch.nn.intrinsic.qat
  from torch.ao.quantization.backend_config import BackendConfig
  from torch.ao.quantization.fx.custom_config import PrepareCustomConfig
  from torch.quantization.quantize_fx import prepare_qat_fx
  import coremltools.optimize.torch.quantization.modules.qat_modules
  from coremltools.optimize.torch._utils.torch_utils import get_parent_child_name
  from coremltools.optimize.torch.quantization._backend_config import _fixed_qparams_modules
  from coremltools.optimize.torch.quantization._utils import CombinationOpType
  from coremltools.optimize.torch.quantization._utils import combine_op_type
  from coremltools.optimize.torch.quantization._utils import find_module
  from coremltools.optimize.torch.quantization._utils import find_target
  from coremltools.optimize.torch.quantization._utils import get_share_qparams_ops
  from coremltools.optimize.torch.quantization._utils import group_activation_quantization_modules_by_id
  from coremltools.optimize.torch.quantization._utils import is_activation_post_process
  from coremltools.optimize.torch.quantization._utils import is_quantized
  from coremltools.optimize.torch.quantization.quantization_config import QuantizationScheme
label_desc: Use image node_id 7 for calling the QATConfigurationHandler obj's underlying member method code with example usage: obj._mark_always_affine_combination_ops_for_replacement(model) without return types