class_docstr: Distributed Node embedding optimizer using the Adagrad algorithm.
  
  This optimizer implements a distributed sparse version of Adagrad algorithm for
  optimizing :class:`dgl.distributed.DistEmbedding`. Being sparse means it only updates
  the embeddings whose gradients have updates, which are usually a very
  small portion of the total embeddings.
  
  Adagrad maintains a :math:`G_{t,i,j}` for every parameter in the embeddings, where
  :math:`G_{t,i,j}=G_{t-1,i,j} + g_{t,i,j}^2` and :math:`g_{t,i,j}` is the gradient of
  the dimension :math:`j` of embedding :math:`i` at step :math:`t`.
  
  NOTE: The support of sparse Adagrad optimizer is experimental.
  
  Parameters
  ----------
  params : list[dgl.distributed.DistEmbedding]
      The list of dgl.distributed.DistEmbedding.
  lr : float
      The learning rate.
  eps : float, Optional
      The term added to the denominator to improve numerical stability
      Default: 1e-10
docstr: Update embeddings in a sparse manner
  Sparse embeddings are updated in mini batches. We maintain gradient states for
  each embedding so they can be updated separately.
  
  Parameters
  ----------
  idx : tensor
      Index of the embeddings to be updated.
  grad : tensor
      Gradient of each embedding.
  emb : dgl.distributed.DistEmbedding
      Sparse embedding to update.
docstr_tok: ["Update","embeddings","in","a","sparse","manner","Sparse","embeddings","are","updated","in","mini","batches",".","We","maintain","gradient","states","for","each","embedding","so","they","can","be","updated","separately",".","Parameters","--","--","--","--","--","idx",":","tensor","Index","of","the","embeddings","to","be","updated",".","grad",":","tensor","Gradient","of","each","embedding",".","emb",":","dgl.distributed.DistEmbedding","Sparse","embedding","to","update","."]
code: def update(self, idx, grad, emb):
      """Update embeddings in a sparse manner
      Sparse embeddings are updated in mini batches. We maintain gradient states for
      each embedding so they can be updated separately.
  
      Parameters
      ----------
      idx : tensor
          Index of the embeddings to be updated.
      grad : tensor
          Gradient of each embedding.
      emb : dgl.distributed.DistEmbedding
          Sparse embedding to update.
      """
      eps = self._eps
      clr = self._lr
  
      state_dev = th.device("cpu")
      exec_dev = grad.device
  
      # only perform async copies cpu -> gpu, or gpu-> gpu, but block
      # when copying to the cpu, so as to ensure the copy is finished
      # before operating on the data on the cpu
      state_block = (
          state_dev == th.device("cpu") and exec_dev != state_dev
      )
  
      # the update is non-linear so indices must be unique
      grad_indices, inverse, cnt = th.unique(
          idx, return_inverse=True, return_counts=True
      )
      grad_values = th.zeros(
          (grad_indices.shape[0], grad.shape[1]), device=exec_dev
      )
      grad_values.index_add_(0, inverse, grad)
      grad_values = grad_values / cnt.unsqueeze(1)
      grad_sum = grad_values * grad_values
  
      # update grad state
      grad_state = self._state[emb.name][grad_indices].to(exec_dev)
      grad_state += grad_sum
      grad_state_dst = grad_state.to(state_dev, non_blocking=True)
      if state_block:
          # use events to try and overlap CPU and GPU as much as possible
          update_event = th.cuda.Event()
          update_event.record()
  
      # update emb
      std_values = grad_state.sqrt_().add_(eps)
      tmp = clr * grad_values / std_values
      tmp_dst = tmp.to(state_dev, non_blocking=True)
  
      if state_block:
          std_event = th.cuda.Event()
          std_event.record()
          # wait for our transfers from exec_dev to state_dev to finish
          # before we can use them
          update_event.wait()
      self._state[emb.name][grad_indices] = grad_state_dst
  
      if state_block:
          # wait for the transfer of std_values to finish before we
          # can use it
          std_event.wait()
      emb._tensor[grad_indices] -= tmp_dst
  
imports: import abc
  import warnings
  from abc import abstractmethod
  from os.path import exists
  import torch
  import dgl
  from ....None import backend
  from ...dist_tensor import DistTensor
  from ...graph_partition_book import EDGE_PART_POLICY, NODE_PART_POLICY
  from ...nn.pytorch import DistEmbedding
  from .utils import alltoall, alltoallv
label_desc: Use image node_id 2 for calling the SparseAdagrad obj's underlying member method code with example usage: obj.update(idx, grad, emb) without return types