class_docstr: Samples according to the underlying instance of ``Sampler``, but splits
  the index sequences into smaller chunks.
  
  Used to split large logical batches into physical batches of a smaller size,
  while coordinating with DPOptimizer when the logical batch has ended.
code: def __iter__(self):
      for batch_idxs in self.sampler:
          if len(batch_idxs) == 0:
              self.optimizer.signal_skip_step(do_skip=False)
              yield []
              continue
  
          split_idxs = np.array_split(
              batch_idxs,
              math.ceil(len(batch_idxs) / self.max_batch_size),
          )
          split_idxs = [s.tolist() for s in split_idxs]
          for x in split_idxs[:-1]:
              self.optimizer.signal_skip_step(do_skip=True)
              yield x
          self.optimizer.signal_skip_step(do_skip=False)
          yield split_idxs[-1]
  
file_path: opacus/opacus/utils/batch_memory_manager.py
imports: import math
  from typing import List
  import numpy
  from opacus.optimizers import DPOptimizer
  from opacus.utils.uniform_sampler import DistributedUniformWithReplacementSampler, UniformWithReplacementSampler
  from torch.utils.data import BatchSampler, DataLoader, Sampler
label_desc: Use image node_id 2 for calling the BatchSplittingSampler obj's underlying member method code with example usage: obj.__iter__() without return types