class_docstr: A regular replay buffer which stores transition without any additional structure
docstr: Get an generator for iterating through the shuffled replay buffer, for processing the data in epochs.
  If the requested size is larger than the number of samples available in the replay buffer then the batch will
  return empty. The last returned batch may be smaller than the size requested, to accommodate for all the
  transitions in the replay buffer.
  
  :param size: the size of the batch to return
  :return: a batch (list) of selected transitions from the replay buffer
docstr_tok: ["Get","an","generator","for","iterating","through","the","shuffled","replay","buffer",",","for","processing","the","data","in","epochs",".","If","the","requested","size","is","larger","than","the","number","of","samples","available","in","the","replay","buffer","then","the","batch","will","return","empty",".","The","last","returned","batch","may","be","smaller","than","the","size","requested",",","to","accommodate","for","all","the","transitions","in","the","replay","buffer",".",":","param","size",":","the","size","of","the","batch","to","return",":","return",":","a","batch","(","list",")","of","selected","transitions","from","the","replay","buffer"]
code: def get_shuffled_training_data_generator(
      self, size: int
  ) -> List[Transition]:
      """
      Get an generator for iterating through the shuffled replay buffer, for processing the data in epochs.
      If the requested size is larger than the number of samples available in the replay buffer then the batch will
      return empty. The last returned batch may be smaller than the size requested, to accommodate for all the
      transitions in the replay buffer.
  
      :param size: the size of the batch to return
      :return: a batch (list) of selected transitions from the replay buffer
      """
      self.reader_writer_lock.lock_writing()
      shuffled_transition_indices = list(range(len(self.transitions)))
      random.shuffle(shuffled_transition_indices)
  
      # we deliberately drop some of the ending data which is left after dividing to batches of size `size`
      # for i in range(math.ceil(len(shuffled_transition_indices) / size)):
      for i in range(int(len(shuffled_transition_indices) / size)):
          sample_data = [
              self.transitions[j]
              for j in shuffled_transition_indices[
                  i * size : (i + 1) * size
              ]
          ]
          self.reader_writer_lock.release_writing()
  
          yield sample_data
  
imports: from typing import List, Tuple, Union
  import pickle
  import random
  import math
  import numpy
  from rl_coach.core_types import Transition
  from rl_coach.logger import screen
  from rl_coach.memories.memory import Memory, MemoryGranularity, MemoryParameters
  from rl_coach.utils import ReaderWriterLock, ProgressBar
label_desc: Use image node_id 5 for calling the ExperienceReplay obj's underlying member method code with example usage: obj.get_shuffled_training_data_generator(size) without return types