code: def _create_obs_or_fq_from_qspec(
      quantization_spec: Optional[QuantizationSpecBase],
      obs_or_fq_map: Dict[EdgeOrNode, ObserverOrFakeQuantize],
      is_qat: bool,
  ):
      """Create observer or fake quantize objects based on quantization spec
  
      Args:
         quantization_spec: used to store parameters to create the observer or fake quantizer
         obs_or_fq_map: this is a map from edge/output to the corresponding observer/fake_quant
         instance, it may be reused for different edge/output depending on configuration
      """
      if quantization_spec is None:
          return None
      if isinstance(quantization_spec, SharedQuantizationSpec):
          edge_or_node = quantization_spec.edge_or_node
          assert edge_or_node in obs_or_fq_map, (
              "please make sure only refer to edge or node that has "
              f"observer/fake_quant inserted: '{edge_or_node}' not in\n{obs_or_fq_map.keys()}"
          )
          return obs_or_fq_map[edge_or_node]
      elif isinstance(quantization_spec, DerivedQuantizationSpec):
          # can't use asdict, so not calling get_observer_kwargs here
          kwargs = {
              "dtype": quantization_spec.dtype,
              "derive_qparams_fn": quantization_spec.derive_qparams_fn,
              "quant_min": quantization_spec.quant_min,
              "quant_max": quantization_spec.quant_max,
              "qscheme": quantization_spec.qscheme,
              "ch_axis": quantization_spec.ch_axis,
          }
          edge_or_nodes = quantization_spec.derived_from
          obs_or_fqs = [obs_or_fq_map[k] for k in edge_or_nodes]
          kwargs["obs_or_fqs"] = obs_or_fqs
          return _DerivedObserverOrFakeQuantize.with_args(**kwargs)()
      elif isinstance(quantization_spec, FixedQParamsQuantizationSpec):
          kwargs = _get_observer_kwargs(quantization_spec)
          observer_ctr = FixedQParamsObserver.with_args(**kwargs)
          if is_qat:
              return FixedQParamsFakeQuantize.with_args(
                  observer=observer_ctr
              )
          else:
              return observer_ctr()
  
      assert isinstance(quantization_spec, QuantizationSpec)
      observer_or_fake_quant_ctr = (
          quantization_spec.observer_or_fake_quant_ctr
      )
      kwargs = _get_observer_kwargs(quantization_spec)
      kwargs.pop("observer_or_fake_quant_ctr")
      # we will remove is_dynamic from QuantizationSpec because
      # it seems that dynamic range quantization
      obs_or_fq_class = observer_or_fake_quant_ctr
      if isinstance(observer_or_fake_quant_ctr, _PartialWrapper):
          obs_or_fq_class = observer_or_fake_quant_ctr.p.func  # type: ignore[union-attr, assignment]
      if "PerChannel" not in obs_or_fq_class.__name__:  # type: ignore[operator, union-attr]
          kwargs.pop("ch_axis")
      return observer_or_fake_quant_ctr.with_args(**kwargs)()
  
imports: import copy
  import torch
  import warnings
  from torch.fx import GraphModule
  from torch.fx.graph import Graph, Node
  from torch.fx.node import Argument
  from ..quantize import propagate_qconfig_
  from ..observer import _is_activation_post_process, _PartialWrapper
  from ..qconfig import _is_reuse_input_qconfig, QConfigAny
  from ..qconfig_mapping import QConfigMapping
  from .qconfig_mapping_utils import _generate_node_name_to_qconfig, _update_qconfig_for_fusion, _get_flattened_qconfig_dict, _update_qconfig_for_qat
  from .quantize_handler import _default_root_node_getter, _get_pattern_to_quantize_handlers, QuantizeHandler
  from torch.ao.quantization import ObserverBase, FixedQParamsObserver, FixedQParamsFakeQuantize, _DerivedObserverOrFakeQuantize
  from torch.ao.quantization.utils import Pattern, NodePattern
  from ._equalize import is_equalization_observer, node_supports_equalization
  from .pattern_utils import _sorted_patterns_dict
  from .match_utils import _MatchResultWithQConfig, _find_matches
  from .utils import _insert_dequant_stubs_for_custom_module_lstm_output, _is_custom_module_lstm, _maybe_get_custom_module_lstm_from_node_arg, _qconfig_satisfies_dtype_config_constraints, get_custom_module_class_keys, all_node_args_have_no_tensors, assert_and_get_unique_device, get_non_observable_arg_indexes_and_types, get_new_attr_name_with_prefix, node_arg_is_weight, node_arg_is_bias, NON_QUANTIZABLE_WEIGHT_OPS, ObservedGraphModuleAttrs
  from torch.ao.quantization import PlaceholderObserver
  from torch.ao.quantization.quantize import convert
  from ..utils import _parent_name, get_qconfig_dtypes, get_swapped_custom_module_class
  from ..backend_config.utils import get_pattern_to_dtype_configs, get_module_to_qat_module, get_fusion_pattern_to_root_node_getter
  from ..backend_config import BackendConfig, DTypeConfig, get_native_backend_config
  from .custom_config import PrepareCustomConfig, StandaloneModuleConfigEntry
  from torch.ao.quantization.quantizer import EdgeOrNode, QuantizationSpec, QuantizationSpecBase, FixedQParamsQuantizationSpec, SharedQuantizationSpec, DerivedQuantizationSpec
  from torch.ao.quantization import ObserverOrFakeQuantize
  from torch._subclasses import FakeTensor
  from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union
  from dataclasses import asdict
label_desc: Use image node_id 3 for calling a global function with example usage: _create_obs_or_fq_from_qspec(quantization_spec, obs_or_fq_map, is_qat) and returns: observer_or_fake_quant_ctr, None, obs_or_fq_map, _DerivedObserverOrFakeQuantize, FixedQParamsFakeQuantize, observer_ctr