code: def half_test(
      rng,
      func,
      finputs,
      hinputs,
      func_args,
      func_kwargs,
      backward,
      ctx,
      func_name,
      atol=1e-1,
  ):
      # 0. Define utility functions
      def _filter_inputs(vinputs):
          return [v for v in vinputs if v is not None]
  
      def _zero_grad(vs):
          for v in vs:
              if v is None:
                  continue
              v.grad.zero()
  
      def _get_grad_copy(vinputs, backward):
          return [
              i.g.copy()
              for i, b in zip(vinputs, backward)
              if b and i is not None
          ]
  
      def _set_output_grad_and_copy(os, grads=None):
          if grads is None:
              grads = [randn(rng, *o.shape) for o in os]
          for o, g in zip(os, grads):
              o.g = g
          return grads
  
      # 1. Create a float32 function.
      with nn.context_scope(ctx):
          o_f = force_tuple(func(*(finputs + func_args), **func_kwargs))
      if True in backward:
          grad_copy = _set_output_grad_and_copy(o_f)
  
      # 2. Get outputs of forward and backward of the float32 function.
      o_f[0].parent.forward(_filter_inputs(finputs), o_f)
      y_f = [o.d.copy() for o in o_f]
      if True in backward:
          _zero_grad(finputs)
          o_f[0].parent.backward(_filter_inputs(finputs), o_f)
          g_f = _get_grad_copy(finputs, backward)
  
      # 3. Create a float16 (half) function.
      ext, dtype = ctx.backend[0].split(":")
      assert dtype == "float"
      ctx_h = ext_utils.get_extension_context(ext, type_config="half")
      ctx_h.device_id = ctx.device_id
      with nn.context_scope(ctx_h):
          o_h = force_tuple(func(*(hinputs + func_args), **func_kwargs))
      if True in backward:
          _set_output_grad_and_copy(o_h, grad_copy)
  
      # 4. Get outputs of forward and backward of the float16 function.
      o_h[0].parent.forward(_filter_inputs(hinputs), o_h)
      y_h = [o.d.copy() for o in o_h]
      if True in backward:
          _zero_grad(hinputs)
          o_h[0].parent.backward(_filter_inputs(hinputs), o_h)
          g_h = _get_grad_copy(hinputs, backward)
  
      # 5. Check if output values are close between function data types.
      for ff, hh in zip(y_f, y_h):
          # TODO: set tol param
          assert_allclose(
              ff,
              hh,
              atol=atol,
              err_msg="{} half forward test fails.".format(func_name),
          )
      if True not in backward:
          return
      for ff, hh in zip(g_f, g_h):
          # TODO: set tol param
          assert_allclose(
              ff,
              hh,
              atol=atol,
              err_msg="{} half backward test fails.".format(func_name),
          )
  
imports: from nnabla.utils import nnabla_pb2
  from six.moves import filter
  import copy
  import nnabla
  import nnabla.ext_utils
  import nnabla.functions
  import nnabla.utils.converter
  import nnabla.dtypes
  from nnabla.testing import assert_allclose
  import numpy
  import numpy
  import platform
label_desc: Use image node_id 13 for calling a global function with example usage: half_test(rng, func, finputs, hinputs, func_args, func_kwargs, backward, ctx, func_name, atol) and returns: unknown, unknown, grads