code: def forward(self, inputs):
      self.retain_inputs((0,))
      xp = backend.get_array_module(*inputs)
      x, gy = inputs
      self._gy_shape = gy.shape
      gW = xp.zeros(self.w_shape, dtype=gy.dtype)
  
      if xp is numpy:
          # It is equivalent to `numpy.add.at(gW, x, gy)` but ufunc.at is
          # too slow.
          for ix, igy in six.moves.zip(
              x.ravel(), gy.reshape(x.size, -1)
          ):
              if ix == self.ignore_label:
                  continue
              gW[ix] += igy
      else:
          utils.nondeterministic("atomicAdd")
          if self.ignore_label is None:
              cuda.elementwise(
                  "T gy, S x, S n_out",
                  "raw T gW",
                  "ptrdiff_t w_ind[] = {x, i % n_out};"
                  "atomicAdd(&gW[w_ind], gy)",
                  "embed_id_bwd",
              )(gy, xp.expand_dims(x, -1), gW.shape[1], gW)
          else:
              cuda.elementwise(
                  "T gy, S x, S n_out, S ignore",
                  "raw T gW",
                  """
                      if (x != ignore) {
                        ptrdiff_t w_ind[] = {x, i % n_out};
                        atomicAdd(&gW[w_ind], gy);
                      }
                      """,
                  "embed_id_bwd_ignore_label",
              )(
                  gy,
                  xp.expand_dims(x, -1),
                  gW.shape[1],
                  self.ignore_label,
                  gW,
              )
      return (gW,)
  
imports: import numpy
  import six
  import chainer
  from chainer import backend
  from chainer.backends import cuda
  from chainer import function_node
  from chainer import utils
  from chainer.utils import type_check
label_desc: Use image node_id 2 for calling the EmbedIDGrad obj's underlying member method code with example usage: obj.forward(inputs) and returns: gW