class_docstr: Samples a mini-batch of indices for a balanced class batching
  
  Args:
      dataset_items(list): dataset items to sample from.
      classes (list): list of classes of dataset_items to sample from.
      batch_size (int): total number of samples to be sampled in a mini-batch.
      num_gpus (int): number of GPU in the data parallel mode.
      shuffle (bool): if True, samples randomly, otherwise samples sequentially.
      drop_last (bool): if True, drops last incomplete batch.
class_docstr_tok: ["Samples","a","mini-batch","of","indices","for","a","balanced","class","batching","Args",":","dataset_items","(","list",")",":","dataset","items","to","sample","from",".","classes","(","list",")",":","list","of","classes","of","dataset_items","to","sample","from",".","batch_size","(","int",")",":","total","number","of","samples","to","be","sampled","in","a","mini-batch",".","num_gpus","(","int",")",":","number","of","GPU","in","the","data","parallel","mode",".","shuffle","(","bool",")",":","if","True",",","samples","randomly",",","otherwise","samples","sequentially",".","drop_last","(","bool",")",":","if","True",",","drops","last","incomplete","batch","."]
code: def __iter__(self):
      batch = []
      if self._num_classes_in_batch != len(self._samplers):
          valid_samplers_idx = random.sample(
              range(len(self._samplers)), self._num_classes_in_batch
          )
      else:
          valid_samplers_idx = None
  
      iters = [iter(s) for s in self._samplers]
      done = False
  
      while True:
          b = []
          for i, it in enumerate(iters):
              if (
                  valid_samplers_idx is not None
                  and i not in valid_samplers_idx
              ):
                  continue
              idx = next(it, None)
              if idx is None:
                  done = True
                  break
              b.append(idx)
          if done:
              break
          batch += b
          if len(batch) == self._batch_size:
              yield batch
              batch = []
              if valid_samplers_idx is not None:
                  valid_samplers_idx = random.sample(
                      range(len(self._samplers)),
                      self._num_classes_in_batch,
                  )
  
      if not self._drop_last:
          if len(batch) > 0:
              groups = len(batch) // self._num_classes_in_batch
              if groups % self._dp_devices == 0:
                  yield batch
              else:
                  batch = batch[
                      : (groups // self._dp_devices)
                      * self._dp_devices
                      * self._num_classes_in_batch
                  ]
                  if len(batch) > 0:
                      yield batch
  
imports: import math
  import random
  from typing import Callable, List, Union
  from torch.utils.data.sampler import BatchSampler, Sampler, SubsetRandomSampler
label_desc: Use image node_id 2 for calling the PerfectBatchSampler obj's underlying member method code with example usage: obj.__iter__() without return types