          by the relevant loss functions.
  
          Parameters
          ----------
          targets: list
              The targets for the model, with the mask as the final entry in the list
          masks: list
              The masks for the model
          additional_masks: list or ``None``
              Any additional masks for the model, or ``None`` if no additional masks are required
  
          Returns
          -------
          list
              The targets for the model with the mask compiled into the 4th channel. The original
 
</s> remove         Penalized loss expects the target mask to be included for all outputs in the 4th channel
        of the targets. Any additional masks are placed into subsequent channels for extraction
        by the relevant loss functions.
 </s> add     def generate_preview(self,
                         is_timelapse: bool = False) -> Dict[Literal["a", "b"], List[np.ndarray]]:
        """ Generate the images for preview window or timelapse </s> remove         list
            The targets for the model with the mask compiled into the 4th channel. The original
            mask is still output as the final item in the list
        """
        if not self._model.config["penalized_mask_loss"] and additional_masks is None:
            logger.trace("No masks to compile. Returning targets")
            return targets

        if not self._model.config["penalized_mask_loss"] and additional_masks is not None:
            masks = additional_masks
        elif additional_masks is not None:
            masks = np.concatenate((masks, additional_masks), axis=-1)

        for idx, tgt in enumerate(targets):
            tgt_dim = tgt.shape[1]
            if tgt_dim == masks.shape[1]:
                add_masks = masks
            else:
                add_masks = np.array([cv2.resize(mask, (tgt_dim, tgt_dim))
                                      for mask in masks])
                if add_masks.ndim == 3:
                    add_masks = add_masks[..., None]
            targets[idx] = np.concatenate((tgt, add_masks), axis=-1)
        logger.trace("masks added to targets: %s", [tgt.shape for tgt in targets])
        return targets

    def generate_preview(self, do_preview):
        """ Generate the preview images.

        Parameters
        ----------
        do_preview: bool
            Whether the previews should be generated. ``True`` if they should ``False`` if they
            should not be generated, in which case currently stored previews should be deleted.
 </s> add         dict
            Dictionary for side A and B of list of numpy arrays corresponding to the
            samples, targets and masks for this preview </s> remove     def _compile_mask_targets(self, targets, masks, additional_masks):
        """ Compile the masks into the targets for penalized loss and for targeted learning.
 </s> add         return model_inputs, model_targets </s> remove             for creating the preview. If ``None`` then the masks will be generated from the
            internal random image generator. Default: ``None``
 </s> add             for creating the preview. </s> remove         filenames: list
            The list of filenames that correspond to this batch
        cache: list
            The list of cached items (aligned faces, masks etc.) corresponding to the batch
        batch: :class:`numpy.ndarray`
            The batch of faces that have been loaded from disk
        side: str
            '"a"' or '"b"' the side that is being processed
 </s> add         images: :class:`numpy.ndarray`
            The original batch of images as loaded from disk.
        detected_faces: list
            List of :class:`~lib.align.DetectedFace` for the current batch
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
          by the relevant loss functions.
  
          Parameters
          ----------
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
        is_timelapse, bool, optional
            ``True`` if preview is to be generated for a Timelapse otherwise ``False``.
            Default: ``False``
  
          Returns
          -------
          list
              The targets for the model with the mask compiled into the 4th channel. The original
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