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 = gamma * (x - mean) / sqrt(variance + epsilon) + beta``
  
  ``y = x * [gamma * rsqrt(variance + eps)] + (beta - mean * [gamma * rsqrt(variance + eps)])``
  
  .. code-block::
  
      x --> reduce_mean --> sub --> square --> reduce_mean --> add(epsilon) --> rsqrt
      |             |        ^                                                    |
      |             |        |                                                    V
      |-----------------------                                              mul (gamma)
      |             |                                                           |
      |             |                                                   --------|---------
      |             |                                                   |                |
      |             |                                                   |                V
      |             |---------------------------------------------------------------->  mul
      |                                                                 |                |
      |                                                                 V                |
      |--------------------------------------------------------------> mul               |
                                                                        |                V
                                                                        |              sub (beta) --> add --> [...]
                                                                        |                              ^
                                                                        |-------------------------------
  
  This pattern corresponds to either ``layer_norm`` or ``instance_norm``.
  
  It is ``instance_norm`` if all of the following are true:
      - ``input`` is rank 4.
      - ``axes`` of ``reduce_mean`` is ``[-2, -1]`` or ``[-3, -2]``
        (when ``[-3, -2]``, a channel first to channel last transpose would be inserted).
      - ``gamma`` and ``beta`` are rank 1, after ``squeeze``.
  
  It is ``layer_norm`` if all of the following are true:
      - ``axes`` is either ``[-1]``, ``[-1, -2]``, or ``[-1, -2, -3]``, and so on.
      - ``rank`` of ``gamma`` and ``beta`` is equal to the length of the ``axes``.
  
   
docstr_tok: ["Identify","the","pattern",":","``","y","=","gamma","*","(","x","-","mean",")","\/","sqrt","(","variance","+","epsilon",")","+","beta","``","``","y","=","x","*","[","gamma","*","rsqrt","(","variance","+","eps",")","]","+","(","beta","-","mean","*","[","gamma","*","rsqrt","(","variance","+","eps",")","]",")","``","..","code-block",":",":","x","--",">","reduce_mean","--",">","sub","--",">","square","--",">","reduce_mean","--",">","add","(","epsilon",")","--",">","rsqrt","|","|","^","|","|","|","|","V","|","--","--","--","--","--","--","--","--","--","--","--","-","mul","(","gamma",")","|","|","|","|","|","--","--","--","--","|","--","--","--","--","-","|","|","|","|","|","|","|","V","|","|","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--",">","mul","|","|","|","|","V","|","|","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--",">","mul","|","|","V","|","sub","(","beta",")","--",">","add","--",">","[","...","]","|","^","|","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","-","This","pattern","corresponds","to","either","``","layer_norm","``","or","``","instance_norm","``",".","It","is","``","instance_norm","``","if","all","of","the","following","are","true",":","-","``","input","``","is","rank","4",".","-","``","axes","``","of","``","reduce_mean","``","is","``","[","-2",",","-1","]","``","or","``","[","-3",",","-2","]","``","(","when","``","[","-3",",","-2","]","``",",","a","channel","first","to","channel","last","transpose","would","be","inserted",")",".","-","``","gamma","``","and","``","beta","``","are","rank","1",",","after","``","squeeze","``",".","It","is","``","layer_norm","``","if","all","of","the","following","are","true",":","-","``","axes","``","is","either","``","[","-1","]","``",",","``","[","-1",",","-2","]","``",",","or","``","[","-1",",","-2",",","-3","]","``",",","and","so","on",".","-","``","rank","``","of","``","gamma","``","and","``","beta","``","is","equal","to","the","length","of","the","``","axes","``","."]
code: def _try_match_and_transform_pattern_1(
      self, reduce_op, block
  ) -> bool:
      """
      Identify the pattern:
  
      ``y = gamma * (x - mean) / sqrt(variance + epsilon) + beta``
  
      ``y = x * [gamma * rsqrt(variance + eps)] + (beta - mean * [gamma * rsqrt(variance + eps)])``
  
      .. code-block::
  
          x --> reduce_mean --> sub --> square --> reduce_mean --> add(epsilon) --> rsqrt
          |             |        ^                                                    |
          |             |        |                                                    V
          |-----------------------                                              mul (gamma)
          |             |                                                           |
          |             |                                                   --------|---------
          |             |                                                   |                |
          |             |                                                   |                V
          |             |---------------------------------------------------------------->  mul
          |                                                                 |                |
          |                                                                 V                |
          |--------------------------------------------------------------> mul               |
                                                                            |                V
                                                                            |              sub (beta) --> add --> [...]
                                                                            |                              ^
                                                                            |-------------------------------
  
      This pattern corresponds to either ``layer_norm`` or ``instance_norm``.
  
      It is ``instance_norm`` if all of the following are true:
          - ``input`` is rank 4.
          - ``axes`` of ``reduce_mean`` is ``[-2, -1]`` or ``[-3, -2]``
            (when ``[-3, -2]``, a channel first to channel last transpose would be inserted).
          - ``gamma`` and ``beta`` are rank 1, after ``squeeze``.
  
      It is ``layer_norm`` if all of the following are true:
          - ``axes`` is either ``[-1]``, ``[-1, -2]``, or ``[-1, -2, -3]``, and so on.
          - ``rank`` of ``gamma`` and ``beta`` is equal to the length of the ``axes``.
  
      """
      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(list(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", "mul"]
      ):
          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", "mul"], check_order=False
      ):
          return False
      child_ops_reduce_mean = list(reduce_op.outputs[0].child_ops)
      op_a = child_ops_reduce_mean[0]
      op_b = child_ops_reduce_mean[1]
      sub_op1 = op_a if op_a.op_type == "sub" else op_b
      if not (
          sub_op1.x == root_var and sub_op1.y == reduce_op.outputs[0]
      ):
          return False
      ops_to_remove.append(sub_op1)
  
      # check square op
      square_op = self._try_get_child_op_type(sub_op1, "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_op1 = self._try_get_child_op_type(reduce_op2, "add")
      if add_op1 is None:
          return False
      epsilon_var = (
          add_op1.y if add_op1.x == reduce_op2.outputs[0] else add_op1.x
      )
      if epsilon_var.val is None or len(epsilon_var.val.shape) != 0:
          return False  # must be scalar
      ops_to_remove.append(add_op1)
  
      # check rsqrt
      rsqrt_op = self._try_get_child_op_type(add_op1, "rsqrt")
      if rsqrt_op is None:
          return False
      ops_to_remove.append(rsqrt_op)
  
      # check mul (gamma)
      mul_op1 = self._try_get_child_op_type(rsqrt_op, "mul")
      if mul_op1 is None:
          return False
      gamma_var = (
          mul_op1.y if mul_op1.x == rsqrt_op.outputs[0] else mul_op1.x
      )
      if gamma_var.val is None:
          return False
      ops_to_remove.append(mul_op1)
  
      # check 2 muls after the gamma mul
      if not self._check_child_op_types(mul_op1, ["mul", "mul"]):
          return False
      child_ops = list(mul_op1.outputs[0].child_ops)
      mul_op2 = child_ops[0]
      mul_op3 = child_ops[1]
      mul_op2_other_var = (
          mul_op2.x if mul_op2.y == mul_op1.outputs[0] else mul_op2.y
      )
      mul_op3_other_var = (
          mul_op3.x if mul_op3.y == mul_op1.outputs[0] else mul_op3.y
      )
      if not (
          (
              mul_op2_other_var == root_var
              and mul_op3_other_var == reduce_op.outputs[0]
          )
          or (
              mul_op2_other_var == reduce_op.outputs[0]
              and mul_op3_other_var == root_var
          )
      ):
          return False
      if mul_op2_other_var == root_var:
          mul_root_op = mul_op2
          mul_mean_op = mul_op3
      else:
          mul_root_op = mul_op3
          mul_mean_op = mul_op2
      ops_to_remove.append(mul_mean_op)
      ops_to_remove.append(mul_root_op)
  
      # check sub with beta
      sub_op2 = self._try_get_child_op_type(mul_mean_op, "sub")
      if sub_op2 is None:
          return False
      if sub_op2.y != mul_mean_op.outputs[0]:
          return False
      beta_var = sub_op2.x
      if beta_var.val is None:
          return False
      ops_to_remove.append(sub_op2)
  
      # check last add op
      add_op2 = self._try_get_child_op_type(sub_op2, "add")
      if add_op2 is None:
          return False
      if not (
          add_op2.x == mul_root_op.outputs[0]
          or add_op2.y == mul_root_op.outputs[0]
      ):
          return False
      ops_to_remove.append(add_op2)
  
      return self._try_apply_transform(
          reduce_op,
          block,
          gamma_var,
          beta_var,
          epsilon_var,
          add_op2,
          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 6 for calling the fuse_layernorm_or_instancenorm obj's underlying member method code with example usage: obj._try_match_and_transform_pattern_1(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, False