class_docstr: Node embedding optimizer using the Adagrad algorithm.
  
  This optimizer implements a sparse version of Adagrad algorithm for
  optimizing :class:`dgl.nn.NodeEmbedding`. 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.nn.NodeEmbedding]
      The list of dgl.nn.NodeEmbedding.
  lr : float
      The learning rate.
  eps : float, Optional
      The term added to the denominator to improve numerical stability
      Default: 1e-10
  
  Examples
  --------
  >>> def initializer(emb):
          th.nn.init.xavier_uniform_(emb)
          return emb
  >>> emb = dgl.nn.NodeEmbedding(g.num_nodes(), 10, 'emb', init_func=initializer)
  >>> optimizer = dgl.optim.SparseAdagrad([emb], lr=0.001)
  >>> for blocks in dataloader:
  ...     ...
  ...     feats = emb(nids, gpu_0)
  ...     loss = F.sum(feats + 1, 0)
  ...     loss.backward()
  ...     optimizer.step()
code: def __init__(self, params, lr, eps=1e-10):
      super(SparseAdagrad, self).__init__(params, lr)
      self._eps = eps
  
      # setup tensors for optimizer states
      self.setup(self._params)
  
imports: import abc
  from abc import abstractmethod
  import torch
  from ...cuda import nccl
  from ...nn.pytorch import NodeEmbedding
  from ...partition import NDArrayPartition
  from ...utils import create_shared_mem_array, gather_pinned_tensor_rows, get_shared_mem_array, pin_memory_inplace, scatter_pinned_tensor_rows
label_desc: Use image node_id 1 to create a new SparseAdagrad object from inherited base classes: SparseGradOptimizer with example: obj = SparseAdagrad(params, lr, eps)