          num_images = min(batch_size, num_images) if batch_size is not None else num_images
          retval = {}
          for side in ("a", "b"):
              logger.debug("Compiling samples: (side: '%s', samples: %s)", side, num_images)
              side_images = images[side] if images is not None else self._target[side]
              side_masks = masks[side] if masks is not None else self._masks[side]
              side_samples = samples[side] if samples is not None else self._samples[side]
              retval[side] = [side_samples[0:num_images],
                              side_images[0:num_images],
                              side_masks[0:num_images]]
          return retval
  
      def compile_timelapse_sample(self):
          """ Compile the sample images for creating a time-lapse frame.
  
 
</s> remove         num_images = self._config.get("preview_images", 14)
        num_images = min(batch_size, num_images) if batch_size is not None else num_images
        retval = {}
        for side in ("a", "b"):
 </s> add         num_images = min(image_count, int(self._config.get("preview_images", 14)))
        retval: Dict[Literal["a", "b"], List[np.ndarray]] = {}
        for side in get_args(Literal["a", "b"]): </s> remove     def compile_timelapse_sample(self):
        """ Compile the sample images for creating a time-lapse frame.

        Returns
        -------
        dict
            For sides "a" and "b"; The list of samples, targets and masks as
            :class:`numpy.ndarrays` for creating a time-lapse frame
        """
        batchsizes = []
        samples = {}
        images = {}
        masks = {}
        for side in ("a", "b"):
            batch = next(self._display_feeds["timelapse"][side])
            batchsizes.append(len(batch["samples"]))
            samples[side] = batch["samples"]
            images[side] = batch["targets"][-1]
            masks[side] = batch["masks"]
        batchsize = min(batchsizes)
        sample = self.compile_sample(batchsize, samples=samples, images=images, masks=masks)
        return sample

    def set_timelapse_feed(self, images, batch_size):
 </s> add     def set_timelapse_feed(self,
                           images: Dict[Literal["a", "b"], List[str]],
                           batch_size: int) -> None: </s> remove         if not do_preview:
            self._samples = {}
            self._target = {}
            self._masks = {}
            return
        logger.debug("Generating preview")
        for side in ("a", "b"):
            batch = next(self._display_feeds["preview"][side])
            self._samples[side] = batch["samples"]
            self._target[side] = batch["targets"][-1]
            self._masks[side] = batch["masks"]

    def compile_sample(self, batch_size, samples=None, images=None, masks=None):
 </s> add         logger.debug("Generating preview (is_timelapse: %s)", is_timelapse)

        batchsizes: List[int] = []
        feed: Dict[Literal["a", "b"], np.ndarray] = {}
        samples: Dict[Literal["a", "b"], np.ndarray] = {}
        masks: Dict[Literal["a", "b"], np.ndarray] = {}

        # MyPy can't recurse into nested dicts to get the type :(
        iterator = cast(Dict[Literal["a", "b"], Generator[BatchType, None, None]],
                        self._display_feeds["timelapse" if is_timelapse else "preview"])
        for side in get_args(Literal["a", "b"]):
            side_feed, side_samples = next(iterator[side])
            batchsizes.append(len(side_samples[0]))
            samples[side] = side_samples[0]
            feed[side] = side_feed[..., :3]
            masks[side] = side_feed[..., 3][..., None]

        logger.debug("Generated samples: is_timelapse: %s, images: %s", is_timelapse,
                     {key: {k: v.shape for k, v in item.items()}
                      for key, item
                      in zip(("feed", "samples", "sides"), (feed, samples, masks))})
        return self.compile_sample(min(batchsizes), feed, samples, masks)

    def compile_sample(self,
                       image_count: int,
                       feed: Dict[Literal["a", "b"], np.ndarray],
                       samples: Dict[Literal["a", "b"], np.ndarray],
                       masks: Dict[Literal["a", "b"], np.ndarray]
                       ) -> Dict[Literal["a", "b"], List[np.ndarray]]: </s> remove         logger.debug("Loading generator")
        input_size = self._model.model.input_shape[output_index][1]
        output_shapes = self._model.output_shapes[output_index]
        logger.debug("input_size: %s, output_shapes: %s", input_size, output_shapes)
        generator = TrainingDataGenerator(input_size,
                                          output_shapes,
                                          self._model.coverage_ratio,
                                          self._model.color_order,
                                          not self._model.command_line_arguments.no_augment_color,
                                          self._model.command_line_arguments.no_flip,
                                          self._model.command_line_arguments.no_warp,
                                          self._model.command_line_arguments.warp_to_landmarks,
                                          self._config)
        return generator

    def _set_preview_feed(self):
 </s> add         logger.debug("Loading generator, side: %s, is_display: %s,  batch_size: %s",
                     side, is_display, batch_size)
        generator = PreviewDataGenerator if is_display else TrainingDataGenerator
        retval = generator(self._config,
                           self._model,
                           side,
                           self._images[side] if images is None else images,
                           self._batch_size if batch_size is None else batch_size)
        return retval

    def _set_preview_feed(self) -> Dict[Literal["a", "b"], Generator[BatchType, None, None]]:
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
          num_images = min(batch_size, num_images) if batch_size is not None else num_images
          retval = {}
          for side in ("a", "b"):
              logger.debug("Compiling samples: (side: '%s', samples: %s)", side, num_images)
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
            retval[side] = [feed[side][0:num_images],
                            samples[side][0:num_images],
                            masks[side][0:num_images]]
        logger.debug("Compiled Samples: %s", {k: [i.shape for i in v] for k, v in retval.items()})
          return retval
  
      def compile_timelapse_sample(self):
          """ Compile the sample images for creating a time-lapse frame.
  
keep keep keep keep replace replace replace replace replace replace keep keep keep keep keep
 Data Augmentation update (#1263)

- lib.detected_face
    - Subclass Masks for Landmark based masks
    - Add training mask propery + methods to DetectedFace
  - lib.training_training
    - subclass TrainingDataGenerator for training and preview data
    - Split cache into own module
    - Reduce thread count to 1 to prevent image corruption + data re-use
    - Process on largest model input/output size rather than stored image size
    - Size and crop masks during caching stage
    - Implement ring buffer for data flow
    - Fix preview reload bug
  - augmentation
    - typing
    - switch color aug order
    - better initialization
    - Fix warp + landmark warp to correctly apply at different image scales
    - Slightly improved warp caching
    - Don't store whether image is_preview. Handle all data as training images implicitly
  - plugins.trainer: Typing and fixes to work with trainingdata refactor 
plugins/train/trainer/_base.py