class_docstr: A graph optimization pass on PyMIL to detect and fuse several variants of ``layer_norm`` or
  ``instance_norm``. Pattern 1 corresponds to either ``layer_norm`` or ``instance_norm``. Patterns 2-4
  are ``instance_norm``. Pattern 5 is ``layer_norm``. You can find these patterns in the methods for
  this class in the source code. To quickly view the source code, click the **[source]** button at
  the end of the class definition.
docstr: Identify the pattern:
  
  ``y = (x - mean) / pow(variance + epsilon) * gamma + beta``
  
  This pattern corresponds to, and should be fused as, ``instance_norm``.
  
  All of the following conditions must be satisfied:
  
  1. ``input`` is rank 4 tensor.
  2. ``reduce`` operates on spatial dimensions ``axes=[-2, -1]``, or ``axes=[-3, -2]`` (a
     channel first to channel last transpose would be inserted in such cases).
  3. ``gamma`` and ``beta`` are both shape ``(C,)`` after ``squeeze``, where ``C`` is number of channels.
  
  .. code-block::
  
      |----> sub -----|                            const (0.5)
      |       ^       |                                |
      |       |       V                                V
      x ---> mean  square --> mean1 --> add_eps ---> pow       const_gamma   const_beta
      |       |                                        |             |            |
      |       V                                        V             V            V
      |----> sub1 --------------------------------> real_div --> mul_gamma --> add_beta --> ...
docstr_tok: ["Identify","the","pattern",":","``","y","=","(","x","-","mean",")","\/","pow","(","variance","+","epsilon",")","*","gamma","+","beta","``","This","pattern","corresponds","to",",","and","should","be","fused","as",",","``","instance_norm","``",".","All","of","the","following","conditions","must","be","satisfied",":","1",".","``","input","``","is","rank","4","tensor",".","2",".","``","reduce","``","operates","on","spatial","dimensions","``","axes=","[","-2",",","-1","]","``",",","or","``","axes=","[","-3",",","-2","]","``","(","a","channel","first","to","channel","last","transpose","would","be","inserted","in","such","cases",")",".","3",".","``","gamma","``","and","``","beta","``","are","both","shape","``","(","C",",",")","``","after","``","squeeze","``",",","where","``","C","``","is","number","of","channels",".","..","code-block",":",":","|","--","--",">","sub","--","--","-|","const","(","0.5",")","|","^","|","|","|","|","V","V","x","--","-",">","mean","square","--",">","mean1","--",">","add_eps","--","-",">","pow","const_gamma","const_beta","|","|","|","|","|","|","V","V","V","V","|","--","--",">","sub1","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--",">","real_div","--",">","mul_gamma","--",">","add_beta","--",">","..."]
code: def _try_match_and_transform_pattern_2(
      self, reduce_op, block
  ) -> bool:
      """
      Identify the pattern:
  
      ``y = (x - mean) / pow(variance + epsilon) * gamma + beta``
  
      This pattern corresponds to, and should be fused as, ``instance_norm``.
  
      All of the following conditions must be satisfied:
  
      1. ``input`` is rank 4 tensor.
      2. ``reduce`` operates on spatial dimensions ``axes=[-2, -1]``, or ``axes=[-3, -2]`` (a
         channel first to channel last transpose would be inserted in such cases).
      3. ``gamma`` and ``beta`` are both shape ``(C,)`` after ``squeeze``, where ``C`` is number of channels.
  
      .. code-block::
  
          |----> sub -----|                            const (0.5)
          |       ^       |                                |
          |       |       V                                V
          x ---> mean  square --> mean1 --> add_eps ---> pow       const_gamma   const_beta
          |       |                                        |             |            |
          |       V                                        V             V            V
          |----> sub1 --------------------------------> real_div --> mul_gamma --> add_beta --> ...
      """
      ops_to_remove = []
      root_var = reduce_op.x
  
      if root_var.shape is None:
          return False
  
      # check that root_var feeds into exactly 3 ops
      if len(root_var.child_ops) != 3:
          return False
      if root_var.op is not None and not self._check_child_op_types(
          root_var.op, child_op_types=["reduce_mean", "sub", "sub"]
      ):
          return False
  
      # check 1st reduce_mean op
      if not self._check_reduce_op(reduce_op):
          return False
      ops_to_remove.append(reduce_op)
  
      # check 1st sub op
      if not self._check_child_op_types(reduce_op, ["sub", "sub"]):
          return False
      child_ops_reduce_mean = list(reduce_op.outputs[0].child_ops)
      reduce_mean_child_op_a = child_ops_reduce_mean[0]
      reduce_mean_child_op_b = child_ops_reduce_mean[1]
      # One of sub op directly goes square, the other one goes real_div
      if (
          list(reduce_mean_child_op_a.outputs[0].child_ops)[0].op_type
          == "square"
      ):
          sub_op0 = reduce_mean_child_op_a
          sub_op1 = reduce_mean_child_op_b
      else:
          sub_op0 = reduce_mean_child_op_b
          sub_op1 = reduce_mean_child_op_a
      if not (
          sub_op0.x == root_var and sub_op0.y == reduce_op.outputs[0]
      ):
          return False
      if not (
          sub_op1.x == root_var and sub_op1.y == reduce_op.outputs[0]
      ):
          return False
      ops_to_remove.append(sub_op0)
      ops_to_remove.append(sub_op1)
  
      # check square op
      square_op = self._try_get_child_op_type(sub_op0, "square")
      if square_op is None:
          return False
      ops_to_remove.append(square_op)
  
      # check second reduce mean
      reduce_op2 = self._try_get_child_op_type(square_op, "reduce_mean")
      if not self._check_reduce_op(reduce_op2):
          return False
      ops_to_remove.append(reduce_op2)
  
      # check add op (with epsilon)
      add_eps_op = self._try_get_child_op_type(reduce_op2, "add")
      if add_eps_op is None:
          return False
      epsilon_var = (
          add_eps_op.y
          if add_eps_op.x == reduce_op2.outputs[0]
          else add_eps_op.x
      )
      if epsilon_var.val is None or len(epsilon_var.val.shape) != 0:
          return False  # must be scalar
      ops_to_remove.append(add_eps_op)
  
      # check pow
      pow_op = self._try_get_child_op_type(add_eps_op, "pow")
      if pow_op is None:
          return False
      if pow_op.y.val is None or not np.isclose(pow_op.y.val, 0.5):
          return False
      ops_to_remove.append(pow_op)
  
      # check real_div
      real_div_op = self._try_get_child_op_type(pow_op, "real_div")
      if real_div_op is None:
          return False
      if not (
          real_div_op.x == sub_op1.outputs[0]
          and real_div_op.y == pow_op.outputs[0]
      ):
          return False
      ops_to_remove.append(real_div_op)
  
      # check mul with gamma
      mul_gamma_op = self._try_get_child_op_type(real_div_op, "mul")
      if mul_gamma_op is None:
          return False
      gamma_var = (
          mul_gamma_op.y
          if mul_gamma_op.x == real_div_op.outputs[0]
          else mul_gamma_op.x
      )
      if gamma_var.val is None:
          return False
      ops_to_remove.append(mul_gamma_op)
  
      # check add with beta
      add_beta_op = self._try_get_child_op_type(mul_gamma_op, "add")
      if add_beta_op is None:
          return False
      beta_var = (
          add_beta_op.y
          if add_beta_op.x == mul_gamma_op.outputs[0]
          else add_beta_op.x
      )
      if beta_var.val is None:
          return False
      ops_to_remove.append(add_beta_op)
  
      return self._try_apply_transform(
          reduce_op,
          block,
          gamma_var,
          beta_var,
          epsilon_var,
          add_beta_op,
          ops_to_remove,
      )
  
imports: from typing import List, Optional
  import numpy
  from coremltools import _logger
  from coremltools.converters.mil.mil import Block
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil import Operation, Program, Var
  from coremltools.converters.mil.mil.passes.graph_pass import AbstractGraphPass
  from coremltools.converters.mil.mil.passes.helper import _check_no_output_connection, block_context_manager
  from coremltools.converters.mil.mil.passes.pass_registry import register_pass
label_desc: Use image node_id 7 for calling the fuse_layernorm_or_instancenorm obj's underlying member method code with example usage: obj._try_match_and_transform_pattern_2(reduce_op, block) and returns: self, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False