code: def convert_symbol(
      sym,
      input_dtypes,
      param_dtypes,
      target_dtype,
      target_dtype_ops=None,
      fp32_ops=None,
      conditional_fp32_ops=None,
      excluded_sym_names=[],
      cast_params_offline=False,
  ):
      """Given a symbol object representing a neural network of data type FP32 and target_dtype,
      add cast layers according to the op lists (target_dtype_ops, fp32_ops,
      conditional_fp32_ops) if provided, otherwise use the default
      lists provided by the framework.
  
      Parameters
      ----------
      sym : Symbol
          FP32 neural network symbol
      input_dtypes: dict
          Dictionary mapping names of model inputs to their dtypes
      param_dtypes: dict
          Dictionary mapping names of model parameters to their dtypes
      target_dtype : str or numpy, optional defaults to float16
          currently only supports float16 and bfloat16. The target dtype indicates to add cast layers
          when possible so that lower precision computation can be leveraged.
      target_dtype_ops : list of strs, optional
          Override the list of operator names casted to the target_dtype.
          If None, uses the framework's default list to be casted to target_dtype.
      fp32_ops : list of strs, optional
          Override the list of operator names casted to FP32.
          If None, uses the framework's default list to be casted to FP32.
      conditional_fp32_ops : list of (string, string, list of string), optional
          Override the list of functions to be casted to FP32.
          The format of the list is
          (name of the function, name of the parameter,
           list of values of the parameter that make the operator to be casted to FP32)
      excluded_sym_names : list of strs, optional
          A list of strings that represent the names of symbols that users want to exclude
          from being casted to LP16 or FP32.
      data_names : list of strs, optional
          A list of strings that represent input data tensor names to the model
      cast_params_offline : bool, default False
          Whether to cast arg_params and aux_params now, instead of doing it every time at runtime.
      """
      import json
  
      assert isinstance(
          sym, Symbol
      ), "First argument to convert_symbol should be a Symbol"
      assert target_dtype_ops is None or isinstance(
          target_dtype_ops, list
      ), "target_dtype_ops should be a list of strings"
      assert fp32_ops is None or isinstance(
          fp32_ops, list
      ), "fp32_ops should be a list of strings"
      assert conditional_fp32_ops is None or isinstance(
          conditional_fp32_ops, list
      ), "conditional_fp32_ops should be a list of strings"
  
      target_dtype = get_dtype_name(target_dtype)
      assert target_dtype in [
          "float16",
          *bfloat16.names,
      ], "Only float16 and bfloat16 types are currently supported as target_dtype"
  
      if target_dtype_ops is None:
          target_dtype_ops = list_lp16_ops(target_dtype)
      if fp32_ops is None:
          fp32_ops = list_fp32_ops(target_dtype)
  
      # conditional ops
      if conditional_fp32_ops is None:
          conditional_fp32_ops = list_conditional_fp32_ops(target_dtype)
      cond_ops = {cond_op[0]: {} for cond_op in conditional_fp32_ops}
      for cond_op in conditional_fp32_ops:
          op_name, attr_name, attr_vals = cond_op
          assert (
              isinstance(op_name, str)
              and isinstance(attr_name, str)
              and isinstance(attr_vals, list)
          ), "conditional_fp32_ops should be a list of (str, str, list of str)"
          cond_ops[op_name].setdefault(attr_name, []).extend(attr_vals)
  
      nodes_attrs = sym.attr_dict()
      nodes_op = {
          n["name"]: n["op"] for n in json.loads(sym.tojson())["nodes"]
      }
      for node_name, node_op in nodes_op.items():
          if node_op not in cond_ops:
              continue
          node_attrs = nodes_attrs[node_name]
          for attr_name, attr_vals in cond_ops[node_op].items():
              assert attr_name in node_attrs
              if node_attrs[attr_name] in attr_vals:
                  excluded_sym_names.append(node_name)
                  break
  
      excluded_sym_names = set(excluded_sym_names)
      for node in sym.get_internals():
          if node.name in excluded_sym_names:
              excluded_sym_names.remove(node.name)
              opt_constraints = node.attr("__opt_constraint__")
              opt_constraints = (
                  0 if opt_constraints is None else int(opt_constraints)
              )
              opt_constraints |= (
                  HybridBlock.OptConstraint.Flag.DisableAMP.value
              )
              node._set_attr(__opt_constraint__=str(opt_constraints))
  
      if len(excluded_sym_names) > 0:
          logging.warning(
              "excluded_sym_names are not present in the network. Missing nodes: {}".format(
                  excluded_sym_names
              )
          )
  
      # Op lists should not intersect
      common_ops = set(target_dtype_ops) & set(fp32_ops)
      assert (
          len(common_ops) == 0
      ), "Common ops in target_dtype_ops and fp32_ops: {}".format(
          common_ops
      )
      common_ops = set(target_dtype_ops) & set(cond_ops)
      assert (
          len(common_ops) == 0
      ), "Common ops in target_dtype_ops and conditional_fp32_ops: {}".format(
          common_ops
      )
      common_ops = set(cond_ops) & set(fp32_ops)
      assert (
          len(common_ops) == 0
      ), "Common ops in fp32_ops and conditional_fp32_ops: {}".format(
          common_ops
      )
  
      combined_ops = set(
          target_dtype_ops + fp32_ops + list(cond_ops.keys())
      )
      original_cond_ops = [
          cond_op[0]
          for cond_op in list_conditional_fp32_ops(target_dtype)
      ]
      all_lp16_fp32_ops = set(
          list_lp16_ops(target_dtype)
          + list_fp32_ops(target_dtype)
          + list_lp16_fp32_ops(target_dtype)
          + original_cond_ops
      )
  
      illegal_ops = combined_ops - all_lp16_fp32_ops
      assert (
          len(illegal_ops) == 0
      ), f"""Can only choose ops from one of the four lists
                              for lp16_ops and fp32_ops
                              1. amp.list_lp16_ops(target_dtype)
                              2. amp.list_fp32_ops(target_dtype)
                              3. amp.list_lp16_fp32_ops(target_dtype)
                              4. amp.list_conditional_fp32_ops(target_dtype)
                              Op {illegal_ops} not in any of them"""
  
      widest_dtype_ops = list_widest_type_cast(target_dtype)
  
      input_names = list(input_dtypes.keys())
      all_arg_names, all_arg_types = [], []
  
      for name, dtype in {**input_dtypes, **param_dtypes}.items():
          all_arg_names.append(name)
          all_arg_types.append(dtype_np_to_mx(dtype))
      out = SymbolHandle()
      check_call(
          _LIB.MXReducePrecisionSymbol(
              sym.handle,
              ctypes.byref(out),
              ctypes.c_int(dtype_np_to_mx(target_dtype)),
              ctypes.c_int(cast_params_offline),
              c_str(OFFLINE_CAST_DTYPE_ATTR),
              ctypes.c_uint(len(input_names)),
              c_str_array(input_names),
              ctypes.c_uint(len(all_arg_names)),
              c_str_array(all_arg_names),
              c_array_buf(ctypes.c_int, array("i", all_arg_types)),
              ctypes.c_uint(len(target_dtype_ops)),
              c_str_array(target_dtype_ops),
              ctypes.c_uint(len(fp32_ops)),
              c_str_array(fp32_ops),
              ctypes.c_uint(len(widest_dtype_ops)),
              c_str_array(widest_dtype_ops),
          )
      )
      return type(sym)(out)
  
imports: from array import array
  import ctypes
  import inspect
  import logging
  import contextlib
  import sys
  import numpy
  from mxnet import numpy
  from ..None import symbol
  from ..device import gpu
  from ..symbol import Symbol
  from ..symbol import contrib
  from ..None import ndarray
  from ..ndarray import NDArray, dtype_np_to_mx, get_dtype_type, get_dtype_name, bfloat16
  from .None import lists
  from ..gluon import Block, HybridBlock, trainer
  from ..None import base
  from ..base import _NP_OP_PREFIX, _NP_OP_SUBMODULE_LIST, _NP_EXT_OP_PREFIX, _NP_EXT_OP_SUBMODULE_LIST, _NP_INTERNAL_OP_PREFIX, c_str_array, c_str, c_array_buf, SymbolHandle, check_call, _LIB
  from ..None import optimizer
  from .loss_scaler import LossScaler
  from ..operator import get_all_registered_operators_grouped
  from ..util import wrap_ctx_to_device_func
label_desc: Use image node_id 11 for calling a global function with example usage: convert_symbol(sym, input_dtypes, param_dtypes, target_dtype, target_dtype_ops, fp32_ops, conditional_fp32_ops, excluded_sym_names, cast_params_offline) and returns: type