class_docstr: _Sampler decides the order of batches to read from a Keras Sequence, similar to a PyTorch
  Sampler object.  In a data loader, there is one _Sampler in the main thread/process that
  decides the order of data loading for all the dataloader worker threads/processes.
  
  _Sampler therefore makes it possible to shuffle indices without concern for synchronous access,
  as is the case when trying to implement shuffle from inside of a Keras Sequence inside of the
  real Keras OrderedEnqueuer.
class_docstr_tok: ["_Sampler","decides","the","order","of","batches","to","read","from","a","Keras","Sequence",",","similar","to","a","PyTorch","Sampler","object",".","In","a","data","loader",",","there","is","one","_Sampler","in","the","main","thread\/process","that","decides","the","order","of","data","loading","for","all","the","dataloader","worker","threads\/processes",".","_Sampler","therefore","makes","it","possible","to","shuffle","indices","without","concern","for","synchronous","access",",","as","is","the","case","when","trying","to","implement","shuffle","from","inside","of","a","Keras","Sequence","inside","of","the","real","Keras","OrderedEnqueuer","."]
code: def __init__(
      self,
      length: int,
      shard_rank: int,
      num_shards: int,
      shuffle: bool,
      shuffle_seed: int,
      prior_batches_trained: int,
  ) -> None:
      self.indices = list(range(length))
      self.num_shards = num_shards
      self.shuffle = shuffle
  
      check.gt_eq(
          length,
          num_shards,
          "please provide a Sequence that has at least as many batches as the number of slots "
          "used for training",
      )
  
      # Each shard has a certain offset from which it yields data.  When the dataset length is
      # not evenly divisible by the shard size, that offset will change every epoch.
      # Example:
      #   let length=10, shard_rank=0, and num_shards=3:
      #   epoch 1: 0, 3, 6, 9
      #   epoch 2: 2, 5, 8
      #   epoch 3: 1, 4, 7
      #   epoch 4: (same as epoch 1)
      # In this example, the offset in the first three epochs is 0, then 2, then 1.
      # The initial offset is always shard_rank, and the offest is recalculated in _end_epoch().
      self.offset = shard_rank
  
      if self.shuffle:
          assert shuffle_seed is not None
          self.rng = np.random.RandomState(shuffle_seed)
          self.rng.shuffle(self.indices)
  
      # Start in the correct epoch of shuffle.
      batches_to_skip = prior_batches_trained
      while len(self._this_epoch_indices()) <= batches_to_skip:
          batches_to_skip -= len(self._this_epoch_indices())
          self._end_epoch()
  
      self.offset += self.num_shards * batches_to_skip
  
imports: import abc
  import collections
  import multiprocessing
  import multiprocessing.queues
  import queue
  import threading
  from typing import Any, Deque, Dict, Iterator, Optional, Type, Union
  import numpy
  import tensorflow
  from determined.common import check
label_desc: Use image node_id 1 to create a new _Sampler object  with example: obj = _Sampler(length, shard_rank, num_shards, shuffle, shuffle_seed, prior_batches_trained)