class_docstr: FuncGraph for the gradient function of the body of a While op.
  
  Contains the logic for capturing the tensors from the body of the forward
  While op which is as follows:
  1. If the tensor is of resource type (these are not accumulated):
     a. Ensure that the tensor is a loop invariant, i.e., it exists in both loop
        inputs and outputs at the same index.
     b. Lookup the corresponding resource tensor in the forward outer graph and
        try to capture that.
  2. If the tensor is not of resource type:
     a. Create an accumulator for that tensor and output it from the forward
        pass. Note this also requires adding it as an input to the forward pass.
     b. Capture the accumulator from the forward pass in this FuncGraph. This
        will later be resolved to the correct output of the forward While op.
     c. Pop a value from the captured placeholder and use it as the captured
        value for the forward pass tensor.
  
  This only allows capturing tensors in the forward graph. A ValueError is
  raised if an attempt is made to capture a tensor not in the forward graph.
  To manually capture a tensor that is not in the forward graph, call `capture`
  with `allowlisted=True`.
  
  Note: The `captures` dict does not contain the forward tensor since it is not
  directly captured. It contains the accumulator corresponding to this forward
  tensor.
  
  Attributes:
    while_op_needs_rewrite: True if any non-resource intermediates were
      captured, meaning the forward While op needs to be rewritten to output the
      corresponding accumulators.
    extra_inputs: list of EmptyTensorList tensors to be used as initial input to
    the new accumulators in the forward graph. It may also contain external
    captures of the custom gradient function.
    internal_capture_to_output: dict from a tensor_id(captured placeholder) to
      the corresponding tensor that needs to be added to the list of outputs.
      For instance, when capturing an accumulator TensorList this contains the
      TensorList obtained after popping a tensor from the list. Other entries
      in this dict are expected, though not enforced, to be identities.
      This dict is needed because these output tensors need to be added to
      FuncGraph.outputs "after" the tensors returned from the gradient function.
class_docstr_tok: ["FuncGraph","for","the","gradient","function","of","the","body","of","a","While","op",".","Contains","the","logic","for","capturing","the","tensors","from","the","body","of","the","forward","While","op","which","is","as","follows",":","1",".","If","the","tensor","is","of","resource","type","(","these","are","not","accumulated",")",":","a",".","Ensure","that","the","tensor","is","a","loop","invariant",",","i.e.",",","it","exists","in","both","loop","inputs","and","outputs","at","the","same","index",".","b.","Lookup","the","corresponding","resource","tensor","in","the","forward","outer","graph","and","try","to","capture","that",".","2",".","If","the","tensor","is","not","of","resource","type",":","a",".","Create","an","accumulator","for","that","tensor","and","output","it","from","the","forward","pass",".","Note","this","also","requires","adding","it","as","an","input","to","the","forward","pass",".","b",".","Capture","the","accumulator","from","the","forward","pass","in","this","FuncGraph",".","This","will","later","be","resolved","to","the","correct","output","of","the","forward","While","op",".","c.","Pop","a","value","from","the","captured","placeholder","and","use","it","as","the","captured","value","for","the","forward","pass","tensor",".","This","only","allows","capturing","tensors","in","the","forward","graph",".","A","ValueError","is","raised","if","an","attempt","is","made","to","capture","a","tensor","not","in","the","forward","graph",".","To","manually","capture","a","tensor","that","is","not","in","the","forward","graph",",","call","`","capture","`","with","`","allowlisted=True","`",".","Note",":","The","`","captures","`","dict","does","not","contain","the","forward","tensor","since","it","is","not","directly","captured",".","It","contains","the","accumulator","corresponding","to","this","forward","tensor",".","Attributes",":","while_op_needs_rewrite",":","True","if","any","non-resource","intermediates","were","captured",",","meaning","the","forward","While","op","needs","to","be","rewritten","to","output","the","corresponding","accumulators",".","extra_inputs",":","list","of","EmptyTensorList","tensors","to","be","used","as","initial","input","to","the","new","accumulators","in","the","forward","graph",".","It","may","also","contain","external","captures","of","the","custom","gradient","function",".","internal_capture_to_output",":","dict","from","a","tensor_id","(","captured","placeholder",")","to","the","corresponding","tensor","that","needs","to","be","added","to","the","list","of","outputs",".","For","instance",",","when","capturing","an","accumulator","TensorList","this","contains","the","TensorList","obtained","after","popping","a","tensor","from","the","list",".","Other","entries","in","this","dict","are","expected",",","though","not","enforced",",","to","be","identities",".","This","dict","is","needed","because","these","output","tensors","need","to","be","added","to","FuncGraph.outputs","``","after","''","the","tensors","returned","from","the","gradient","function","."]
code: def _get_optimized_reduction_ops_cache_key(
      self,
      op_type,
      inputs,
      dtypes=None,  # pylint: disable=redefined-outer-name
      input_types=None,
      name=None,
      attrs=None,
      op_def=None,
      compute_device=True,
  ):
      # We need all elements of CacheKey to be hashable.
      inputs = tuple(map(lambda t: t.ref(), inputs))
  
      if dtypes is not None:
          dtypes = tuple(dtypes)
  
      if input_types is not None:
          input_types = tuple(input_types)
  
      if attrs is not None:
          hashable_attrs = []
          for attr_name, attr_value in sorted(attrs.items()):
              hashable_attrs.append(
                  (attr_name, attr_value.SerializeToString())
              )
          attrs = tuple(hashable_attrs)
  
      if op_def is not None:
          op_def = op_def.SerializeToString()
  
      return OptimizedReductionOpsCacheKey(
          op_type,
          inputs,
          dtypes,
          input_types,
          name,
          attrs,
          op_def,
          compute_device,
      )
  
imports: import collections
  from tensorflow.core.framework import attr_value_pb2
  from tensorflow.python.client import pywrap_tf_session
  from tensorflow.python.eager import backprop_util
  from tensorflow.python.framework import auto_control_deps_utils
  from tensorflow.python.framework import constant_op
  from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import func_graph
  from tensorflow.python.framework import indexed_slices
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import tensor
  from tensorflow.python.framework import tensor_shape
  from tensorflow.python.framework import tensor_spec
  from tensorflow.python.framework import tensor_util
  from tensorflow.python.ops import array_ops
  from tensorflow.python.ops import control_flow_ops
  from tensorflow.python.ops import control_flow_util
  from tensorflow.python.ops import control_flow_util_v2
  from tensorflow.python.ops import default_gradient
  from tensorflow.python.ops import gen_functional_ops
  from tensorflow.python.ops import gen_resource_variable_ops
  from tensorflow.python.ops import gradients_util
  from tensorflow.python.ops import handle_data_util
  from tensorflow.python.ops import list_ops
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops import tensor_array_ops
  from tensorflow.python.ops import while_v2_indexed_slices_rewriter
  from tensorflow.python.util import compat
  from tensorflow.python.util import nest
  from tensorflow.python.util import object_identity
  from tensorflow.python.util import variable_utils
label_desc: Use image node_id 5 for calling the _WhileBodyGradFuncGraph obj's underlying member method code with example usage: obj._get_optimized_reduction_ops_cache_key(op_type, inputs, dtypes, input_types, name, attrs, op_def, compute_device) and returns: OptimizedReductionOpsCacheKey