class_docstr: Wraps another sampler to yield a mini-batch of indices.
  It enforces that the batch only contain elements from the same group.
  It also tries to provide mini-batches which follows an ordering which is
  as close as possible to the ordering from the original sampler.
  Args:
      sampler (Sampler): Base sampler.
      group_ids (list[int]): If the sampler produces indices in range [0, N),
          `group_ids` must be a list of `N` ints which contains the group id of each sample.
          The group ids must be a continuous set of integers starting from
          0, i.e. they must be in the range [0, num_groups).
      batch_size (int): Size of mini-batch.
class_docstr_tok: ["Wraps","another","sampler","to","yield","a","mini-batch","of","indices",".","It","enforces","that","the","batch","only","contain","elements","from","the","same","group",".","It","also","tries","to","provide","mini-batches","which","follows","an","ordering","which","is","as","close","as","possible","to","the","ordering","from","the","original","sampler",".","Args",":","sampler","(","Sampler",")",":","Base","sampler",".","group_ids","(","list","[","int","]",")",":","If","the","sampler","produces","indices","in","range","[","0",",","N",")",",","`","group_ids","`","must","be","a","list","of","`","N","`","ints","which","contains","the","group","id","of","each","sample",".","The","group","ids","must","be","a","continuous","set","of","integers","starting","from","0",",","i.e",".","they","must","be","in","the","range","[","0",",","num_groups",")",".","batch_size","(","int",")",":","Size","of","mini-batch","."]
code: def __iter__(self):
      buffer_per_group = defaultdict(list)
      samples_per_group = defaultdict(list)
  
      num_batches = 0
      for idx in self.sampler:
          group_id = self.group_ids[idx]
          buffer_per_group[group_id].append(idx)
          samples_per_group[group_id].append(idx)
          if len(buffer_per_group[group_id]) == self.batch_size:
              yield buffer_per_group[group_id]
              num_batches += 1
              del buffer_per_group[group_id]
          assert len(buffer_per_group[group_id]) < self.batch_size
  
      # now we have run out of elements that satisfy
      # the group criteria, let's return the remaining
      # elements so that the size of the sampler is
      # deterministic
      expected_num_batches = len(self)
      num_remaining = expected_num_batches - num_batches
      if num_remaining > 0:
          # for the remaining batches, take first the buffers with largest number
          # of elements
          for group_id, _ in sorted(
              buffer_per_group.items(),
              key=lambda x: len(x[1]),
              reverse=True,
          ):
              remaining = self.batch_size - len(
                  buffer_per_group[group_id]
              )
              samples_from_group_id = _repeat_to_at_least(
                  samples_per_group[group_id], remaining
              )
              buffer_per_group[group_id].extend(
                  samples_from_group_id[:remaining]
              )
              assert len(buffer_per_group[group_id]) == self.batch_size
              yield buffer_per_group[group_id]
              num_remaining -= 1
              if num_remaining == 0:
                  break
      assert num_remaining == 0
  
imports: import bisect
  import copy
  import math
  from collections import defaultdict
  from itertools import repeat, chain
  import numpy
  import torch
  import torch.utils.data
  import torchvision
  from PIL import Image
  from torch.utils.data.sampler import BatchSampler, Sampler
  from torch.utils.model_zoo import tqdm
label_desc: Use image node_id 2 for calling the GroupedBatchSampler obj's underlying member method code with example usage: obj.__iter__() without return types