      def extract_version(self):
          """ float: The alignments file version used to extract the faces. """
          return self._extract_version
  
      @property
      def aligned_landmarks(self):
          """ dict: The filename as key, aligned landmarks as value """
          if self._aligned_landmarks is None:
              with self._lock:
                  # For Warp-To-Landmarks a race condition can occur where this is referenced from
                  # the opposite side prior to it being populated, so block on a lock.
                  self._aligned_landmarks = {key: val["aligned_face"].landmarks
                                             for key, val in self._cache.items()}
          return self._aligned_landmarks
  
      @property
      def crop_size(self):
          """ int: The pixel size of the cropped aligned face """
          return self._size
 
</s> remove     @property
    def extract_version(self):
        """ float: The alignments file version used to extract the faces. """
        return self._extract_version
 </s> add         The exit point from this class and the sole attribute that should be referenced. Called
        from :mod:`plugins.train.trainer._base`. Returns an iterator that yields images for
        training, preview and time-lapses. </s> remove     @property
    def crop_size(self):
        """ int: The pixel size of the cropped aligned face """
        return self._size
 </s> add         Yields
        ------
        feed: list
            4-dimensional array of faces to feed the training the model (:attr:`x` parameter for
            :func:`keras.models.model.train_on_batch`.). The array returned is in the format
            (`batch size`, `height`, `width`, `channels`).
        targets: list
            List of 4-dimensional :class:`numpy.ndarray` objects in the order and size of each
            output of the model. The format of these arrays will be (`batch size`, `height`,
            `width`, `x`). This is the :attr:`y` parameter for
            :func:`keras.models.model.train_on_batch`. The number of channels here will vary.
            The first 3 channels are (rgb/bgr). The 4th channel is the face mask. Any subsequent
            channels are area masks (e.g. eye/mouth masks)
        """
        logger.debug("do_shuffle: %s", do_shuffle)
        args = (do_shuffle, )
        batcher = BackgroundGenerator(self._minibatch, thread_count=1, args=args)
        return batcher.iterator() </s> remove     def cache_full(self):
        """bool: ``True`` if the cache has been fully populated. ``False`` if there are items still
        to be cached. """
        if self._cache_full:
            return self._cache_full
        with self._lock:
            return self._cache_full

    @property
    def partially_loaded(self):
        """ bool: ``True`` if the cache has been partially loaded for Warp To Landmarks otherwise
        ``False`` """
        if self._partial_load:
            return self._partial_load
        with self._lock:
            return self._partial_load
 </s> add     def _total_channels(self) -> int:
        """int: The total number of channels, including mask channels that the target image
        should hold. """
        channels = 3
        if self._config["mask_type"] and (self._config["learn_mask"] or
                                          self._config["penalized_mask_loss"]):
            channels += 1

        mults = [area for area in ["eye", "mouth"] if int(self._config[f"{area}_multiplier"]) > 1]
        if self._config["penalized_mask_loss"] and mults:
            channels += len(mults)
        return channels

    def minibatch_ab(self, do_shuffle: bool = True) -> Generator[BatchType, None, None]:
        """ A Background iterator to return augmented images, samples and targets. </s> remove     def check_reset(self):
        """ Check whether this cache has been reset due to a face centering change, and reset the
        flag if it has.
 </s> add     # << INTERNAL METHODS >> #
    def _validate_samples(self) -> None:
        """ Ensures that the total number of images within :attr:`images` is greater or equal to
        the selected :attr:`batch_size`. </s> remove         batch: :class:`numpy.ndarray`
            The centered faces cropped out of the loaded batch
        landmarks: :class:`numpy.ndarray`
            The aligned landmarks for this batch. NB: The aligned landmarks do not directly
            correspond to the size of the extracted face. They are scaled to the source training
            image, not the sub-image.
 </s> add         :class:`np.ndarray`
            Randomly selected closest matches from the other side's landmarks
        """
        logger.trace("Retrieving closest matched landmarks: (filenames: '%s', "  # type: ignore
                     "src_points: '%s')", filenames, batch_src_points)
        lm_side: Literal["a", "b"] = "a" if self._side == "b" else "b"
        other_cache = get_cache(lm_side)
        landmarks = other_cache.aligned_landmarks

        try:
            closest_matches = [self._nearest_landmarks[os.path.basename(filename)]
                               for filename in filenames]
        except KeyError:
            # Resize mismatched training image size landmarks
            sizes = {side: cache.size for side, cache in zip((self._side, lm_side),
                                                             (self._face_cache, other_cache))}
            if len(set(sizes.values())) > 1:
                scale = sizes[self._side] / sizes[lm_side]
                landmarks = {key: lms * scale for key, lms in landmarks.items()}
            closest_matches = self._cache_closest_matches(filenames, batch_src_points, landmarks)

        batch_dst_points = np.array([landmarks[choice(fname)] for fname in closest_matches])
        logger.trace("Returning: (batch_dst_points: %s)", batch_dst_points.shape)  # type: ignore
        return batch_dst_points

    def _cache_closest_matches(self,
                               filenames: List[str],
                               batch_src_points: np.ndarray,
                               landmarks: Dict[str, np.ndarray]) -> List[Tuple[str, ...]]:
        """ Cache the nearest landmarks for this batch

        Parameters
        ----------
        filenames: list
            Filenames for current batch
        batch_src_points: :class:`np.ndarray`
            The source landmarks for the current batch
        landmarks: dict
            The destination landmarks with associated filenames
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
      def extract_version(self):
          """ float: The alignments file version used to extract the faces. """
          return self._extract_version
  
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
        Parameters
        ----------
        do_shuffle: bool, optional
            Whether data should be shuffled prior to loading from disk. If true, each time the full
            list of filenames are processed, the data will be reshuffled to make sure they are not
            returned in the same order. Default: ``True``
  
      @property
      def crop_size(self):
          """ int: The pixel size of the cropped aligned face """
          return self._size
keep keep keep keep replace replace replace replace 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 
lib/training/generator.py