class_docstr: In Core ML quantization, the performance is better when ``zero point = 0``,
  so we try to make ``zero point = 0`` if possible:
  
  * ``zero point = -128``
      * this must be an int8 quantization
      * equivalent to uint8 quantization with 0 zero point
  * ``zero point = 128``
      * this must be an uint8 quantization
      * equivalent to int8 quantization with 0 zero point
  
  Since ``zero point = 0`` is equivalent to ``zero point = None`` in Core ML semantics,
  we further canonicalize to ``zero point = None`` to:
  
  * make further graph passes easier
  * avoid serializing trivial 0
  
  The ``zero point = 0`` case can be canonicalized trivially
  
  .. code-block::
  
      Input op:
  
          quantize/dequantize(zero_point=0)
  
      Output op:
  
          quantize/dequantize(zero_point=None)
  
  To guarantee the conservation of output regardless the zero-point shift
  in ``zero point = ±128`` cases, we would only transform:
  
  * const dequantize, where we fuse the zero-point shift into the const
  
  .. code-block::
  
      Input op:
  
          dequantize(input=const, zero_point=±128)
  
      Output op:
  
          dequantize(input=const∓128, zero_point=None)
  
  * ``quantize -> dequantize``, where we nullify both simultaneously
  
  .. code-block::
  
      Input graph:
  
          input -> quantize(zero_point=±128) -> dequantize(zero_point=±128) -> output
  
      Output graph:
  
          input -> quantize(zero_point=None) -> dequantize(zero_point=None) -> output
class_docstr_tok: ["In","Core","ML","quantization",",","the","performance","is","better","when","``","zero","point","=","0","``",",","so","we","try","to","make","``","zero","point","=","0","``","if","possible",":","*","``","zero","point","=","-128","``","*","this","must","be","an","int8","quantization","*","equivalent","to","uint8","quantization","with","0","zero","point","*","``","zero","point","=","128","``","*","this","must","be","an","uint8","quantization","*","equivalent","to","int8","quantization","with","0","zero","point","Since","``","zero","point","=","0","``","is","equivalent","to","``","zero","point","=","None","``","in","Core","ML","semantics",",","we","further","canonicalize","to","``","zero","point","=","None","``","to",":","*","make","further","graph","passes","easier","*","avoid","serializing","trivial","0","The","``","zero","point","=","0","``","case","can","be","canonicalized","trivially","..","code-block",":",":","Input","op",":","quantize\/dequantize","(","zero_point=0",")","Output","op",":","quantize\/dequantize","(","zero_point=None",")","To","guarantee","the","conservation","of","output","regardless","the","zero-point","shift","in","``","zero","point","=","\u00b1128","``","cases",",","we","would","only","transform",":","*","const","dequantize",",","where","we","fuse","the","zero-point","shift","into","the","const","..","code-block",":",":","Input","op",":","dequantize","(","input=const",",","zero_point=\u00b1128",")","Output","op",":","dequantize","(","input=const\u2213128",",","zero_point=None",")","*","``","quantize","-",">","dequantize","``",",","where","we","nullify","both","simultaneously","..","code-block",":",":","Input","graph",":","input","-",">","quantize","(","zero_point=\u00b1128",")","-",">","dequantize","(","zero_point=\u00b1128",")","-",">","output","Output","graph",":","input","-",">","quantize","(","zero_point=None",")","-",">","dequantize","(","zero_point=None",")","-",">","output"]
code: def try_transform_zp0(op: Operation) -> bool:
      if op.op_type not in ("quantize", "dequantize"):
          return False
  
      zero_point = op.zero_point
      # if already no zero point, no need for further nullification
      if zero_point is None:
          return False
      zero_point = zero_point.val
  
      if not np.all(zero_point == 0):
          return False
  
      new_var: Var
      if op.op_type == "quantize":
          new_var = mb.quantize(
              input=op.input,
              scale=op.scale,
              axis=op.axis,
              output_dtype=op.output_dtype,
              before_op=op,
          )
      else:
          new_var = mb.dequantize(
              input=op.input,
              scale=op.scale,
              axis=op.axis,
              before_op=op,
          )
  
      block: Block = op.enclosing_block
      if not block.try_replace_uses_of_var_after_op(
          anchor_op=op, old_var=op.outputs[0], new_var=new_var
      ):
          return False
      block.remove_ops([op])
  
      return True
  
imports: from typing import Tuple
  import numpy
  import coremltools.converters.mil.mil.types
  from coremltools.converters.mil._deployment_compatibility import AvailableTarget
  from coremltools.converters.mil.mil import Block
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil import Operation, Var
  from coremltools.converters.mil.mil.passes.graph_pass import AbstractGraphPass
  from coremltools.converters.mil.mil.passes.helper import _check_child_op_type, _check_no_output_connection, block_context_manager
  from coremltools.converters.mil.mil.passes.pass_registry import register_pass
label_desc: Use image node_id 3 for calling the nullify_redundant_quantization_zero_point obj's underlying member method code with example usage: obj.try_transform_zp0(op) and returns: True, False, False, False, False