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: Detect ``InstanceNorm`` pattern in TensorFlow-Addons.
  
  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 absent. Default values for ``gamma`` and ``beta`` would be used.
  
  .. code-block::
  
             |-------------------------------------------------|
             |                                                 |
             |                                                 V
      x --> mean   square --> mean1 --> add_eps --> rsqrt --> mul2 --> mul_sub
      |      |       ^                                |                   |
      |      V       |                                |                   |
      | --> sub -----|                                |                   |
      |                                               V                   V
      |--------------------------------------------> mul1 -------------> add --> ...
docstr_tok: ["Detect","``","InstanceNorm","``","pattern","in","TensorFlow-Addons",".","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","absent",".","Default","values","for","``","gamma","``","and","``","beta","``","would","be","used",".","..","code-block",":",":","|","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","-|","|","|","|","V","x","--",">","mean","square","--",">","mean1","--",">","add_eps","--",">","rsqrt","--",">","mul2","--",">","mul_sub","|","|","^","|","|","|","V","|","|","|","|","--",">","sub","--","--","-|","|","|","|","V","V","|","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--","--",">","mul1","--","--","--","--","--","--","-",">","add","--",">","..."]
code: def _try_match_and_transform_pattern_3(
      self, reduce_op, block
  ) -> bool:
      """
      Detect ``InstanceNorm`` pattern in TensorFlow-Addons.
  
      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 absent. Default values for ``gamma`` and ``beta`` would be used.
  
      .. code-block::
  
                 |-------------------------------------------------|
                 |                                                 |
                 |                                                 V
          x --> mean   square --> mean1 --> add_eps --> rsqrt --> mul2 --> mul_sub
          |      |       ^                                |                   |
          |      V       |                                |                   |
          | --> sub -----|                                |                   |
          |                                               V                   V
          |--------------------------------------------> mul1 -------------> add --> ...
      """
      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, ["sub", "mul", "reduce_mean"]
      ):
          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)
      reduce_mean_child_op_a = child_ops_reduce_mean[0]
      reduce_mean_child_op_b = child_ops_reduce_mean[1]
      sub_op1 = (
          reduce_mean_child_op_a
          if reduce_mean_child_op_a.op_type == "sub"
          else reduce_mean_child_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 reduce_op2 is None or 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 rsqrt
      rsqrt_op = self._try_get_child_op_type(add_eps_op, "rsqrt")
      if rsqrt_op is None:
          return False
      ops_to_remove.append(rsqrt_op)
  
      # check mul 1
      mul_op1 = self._try_get_child_op_type(rsqrt_op, "mul")
      if mul_op1 is None:
          return False
      if not (
          (mul_op1.x == root_var and mul_op1.y == rsqrt_op.outputs[0])
          or (
              mul_op1.x == rsqrt_op.outputs[0] and mul_op1.y == root_var
          )
      ):
          return False
      ops_to_remove.append(mul_op1)
  
      # check mul 2
      mul_op2 = self._try_get_child_op_type(rsqrt_op, "mul", index=1)
      if mul_op2 is None:
          return False
      if not (
          (
              mul_op2.x == reduce_op.outputs[0]
              and mul_op2.y == rsqrt_op.outputs[0]
          )
          or (
              mul_op2.x == rsqrt_op.outputs[0]
              and mul_op2.y == reduce_op.outputs[0]
          )
      ):
          return False
      ops_to_remove.append(mul_op2)
  
      # check mul (sub)
      mul_sub_op = self._try_get_child_op_type(mul_op2, "mul")
      if mul_sub_op is None:
          return False
      if mul_sub_op.y.val is None or mul_sub_op.y.val != -1:
          return False
      ops_to_remove.append(mul_sub_op)
  
      # check last add op
      add_op = self._try_get_child_op_type(mul_sub_op, "add")
      if add_op is None:
          return False
      if not (
          (
              add_op.x == mul_op1.outputs[0]
              and add_op.y == mul_sub_op.outputs[0]
          )
          or (
              add_op.x == mul_sub_op.outputs[0]
              and add_op.y == mul_op1.outputs[0]
          )
      ):
          return False
      ops_to_remove.append(add_op)
  
      gamma_var = mb.const(
          val=np.ones(shape=(1, root_var.shape[1], 1, 1)),
          name="_fuse_layernorm_or_instancenorm_gamma",
      )
      beta_var = mb.const(
          val=np.zeros(shape=(1, root_var.shape[1], 1, 1)),
          name="_fuse_layernorm_or_instancenorm_beta",
      )
  
      return self._try_apply_transform(
          reduce_op,
          block,
          gamma_var,
          beta_var,
          epsilon_var,
          add_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 8 for calling the fuse_layernorm_or_instancenorm obj's underlying member method code with example usage: obj._try_match_and_transform_pattern_3(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