docstr: Take in the data collected during graph traversal
  and transform the graph by cancelling out transpose ops that can be removed.
docstr_tok: ["Take","in","the","data","collected","during","graph","traversal","and","transform","the","graph","by","cancelling","out","transpose","ops","that","can","be","removed","."]
code: def apply_transform(self):
      """
      Take in the data collected during graph traversal
      and transform the graph by cancelling out transpose ops that can be removed.
      """
  
      logging.debug(
          "Block before optimize transpose transform:\n{}".format(
              self.block
          )
      )
      if DEBUG:
          import graphviz
  
          graphviz.Source(
              self.block.get_dot_string(
                  highlight_debug_op_names=[],
                  highlight_debug_op_types=["transpose"],
              )
          ).view(filename="/tmp/block_before_reduce_transpose")
  
      """
          First check which transposes can be cancelled.
          After this function call we get an updated dictionary "transpose_op_to_cancel_ops"
          with only the transpose ops that can really be cancelled in the graph
          Reasons to not cancel:
          - materialize_ops are greater than cancel_ops, so removing transpose will instead end up increasing the count of transposes
          - removing a transpose op can only be successful, if all of its cancel ops are removed, removing all the cancel ops
            is only successful if all of their starting transpose ops are removed and so on. This check is also done in
             "_verify_cancellable_transposes()"
          """
      self._verify_cancellable_transposes()
  
      # apply transform
      for transpose_op in self.transpose_op_to_cancel_ops:
          self._remove_transpose_ops(transpose_op)
      self.block.set_outputs(
          [sink_op.x for sink_op in self.output_sink_ops]
      )
      self.block.remove_ops(list(self.output_sink_ops))
  
      if DEBUG:
          graphviz.Source(
              self.block.get_dot_string(
                  highlight_debug_op_names=[],
                  highlight_debug_op_types=["transpose"],
              )
          ).view(filename="/tmp/block_after_reduce_transpose")
  
      logging.debug(
          "Block after optimize transpose transform:\n{}".format(
              self.block
          )
      )
  
      for op in self.block.operations:
          op.type_value_inference(overwrite_output=True)
  
imports: from __future__ import print_function
  from __future__ import division
  from __future__ import absolute_import
  from coremltools.converters.mil.mil.passes.pass_registry import register_pass
  from coremltools.converters.mil.mil import Builder
  from coremltools.converters.mil.mil.var import Var
  import logging
  import numpy
  import copy
  from collections import defaultdict
label_desc: Use image node_id 11 for calling the TransposeOptimization obj's underlying member method code with example usage: obj.apply_transform() without return types