class_docstr: Base class for DistributedDataParallel Sampler.
  
  Every subclass should implement `__iter__` method, providing a way to iterate
  over indices of dataset elements.
  
  Args:
      opts: command line argument
      n_data_samples: Number of samples in the dataset
      is_training: Training or validation mode. Default: False
class_docstr_tok: ["Base","class","for","DistributedDataParallel","Sampler",".","Every","subclass","should","implement","`","__iter__","`","method",",","providing","a","way","to","iterate","over","indices","of","dataset","elements",".","Args",":","opts",":","command","line","argument","n_data_samples",":","Number","of","samples","in","the","dataset","is_training",":","Training","or","validation","mode",".","Default",":","False"]
docstr: Returns a list of indices of dataset elements for each rank to iterate over.
  
  ...note:
      1. If repeated augmentation is enabled, then indices will be repeated.
      2. If sharding is enabled, then each rank will process a subset of the dataset.
docstr_tok: ["Returns","a","list","of","indices","of","dataset","elements","for","each","rank","to","iterate","over",".","...","note",":","1",".","If","repeated","augmentation","is","enabled",",","then","indices","will","be","repeated",".","2",".","If","sharding","is","enabled",",","then","each","rank","will","process","a","subset","of","the","dataset","."]
code: def get_indices_rank_i(self) -> List[int]:
      """Returns a list of indices of dataset elements for each rank to iterate over.
  
      ...note:
          1. If repeated augmentation is enabled, then indices will be repeated.
          2. If sharding is enabled, then each rank will process a subset of the dataset.
      """
      img_indices = copy.deepcopy(self.img_indices)
      if self.shuffle:
          random.seed(self.epoch)
  
          if self.sharding:
              """If we have 8 samples, say [0, 1, 2, 3, 4, 5, 6, 7], and we have two nodes,
              then node 0 will receive first 4 samples and node 1 will receive last 4 samples.
  
              note:
                  This strategy is useful when dataset is large and we want to process subset of dataset on each node.
              """
  
              # compute number pf samples per node.
              # Each node may have multiple GPUs
              # Node id = rank // num_gpus_per_rank
              samples_per_node = int(
                  math.ceil(len(img_indices) / self.num_nodes)
              )
              indices_node_i = img_indices[
                  self.node_id
                  * samples_per_node : (self.node_id + 1)
                  * samples_per_node
              ]
  
              # Ensure that each node has equal number of samples
              if len(indices_node_i) < samples_per_node:
                  indices_node_i += indices_node_i[
                      : (samples_per_node - len(indices_node_i))
                  ]
  
              # Note: For extremely large datasets, we may want to disable shuffling for efficient data loading
              if not self.disable_shuffle_sharding:
                  # shuffle the indices within a node.
                  random.shuffle(indices_node_i)
  
              if self.num_repeats > 1:
                  """Assume that we have [0, 1, 2, 3] samples in rank_i. With repeated augmentation,
                  we first repeat the samples [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3] and then select 4
                  samples [0, 0, 0, 1]. Note shuffling at the beginning
                  """
                  # Apply repeated augmentation
                  n_samples_before_repeat = len(indices_node_i)
                  indices_node_i = np.repeat(
                      indices_node_i, repeats=self.num_repeats
                  )
                  indices_node_i = list(indices_node_i)
                  if self.trunc_rep_aug:
                      indices_node_i = indices_node_i[
                          :n_samples_before_repeat
                      ]
  
              # divide the samples among each GPU in a node
              indices_rank_i = indices_node_i[
                  self.local_rank : len(
                      indices_node_i
                  ) : self.num_gpus_node_i
              ]
          else:
              """If we have 8 samples, say [0, 1, 2, 3, 4, 5, 6, 7], and we have two nodes,
              then node 0 will receive [0, 2, 4, 6] and node 1 will receive [1, 3, 4, 7].
  
              note:
                  This strategy is useful when each data sample is stored independently, and is
                  default in many frameworks
              """
              random.shuffle(img_indices)
  
              if self.num_repeats > 1:
                  # Apply repeated augmentation
                  n_samples_before_repeat = len(img_indices)
                  img_indices = np.repeat(
                      img_indices, repeats=self.num_repeats
                  )
                  img_indices = list(img_indices)
                  if self.trunc_rep_aug:
                      img_indices = img_indices[
                          :n_samples_before_repeat
                      ]
  
              # divide the samples among each GPU in a node
              indices_rank_i = img_indices[
                  self.rank : len(img_indices) : self.num_replicas
              ]
      else:
          indices_rank_i = img_indices[
              self.rank : len(self.img_indices) : self.num_replicas
          ]
      return indices_rank_i
  
imports: import argparse
  import copy
  import math
  import random
  from typing import Any, Iterator, List, Tuple
  import numpy
  import torch
  import torch.distributed
  from torch.utils.data.sampler import Sampler
label_desc: Use image node_id 2 for calling the BaseSamplerDDP obj's underlying member method code with example usage: obj.get_indices_rank_i() and returns: indices_rank_i