  
      def _validate_version(self, png_meta, filename):
          """ Validate that there are not a mix of v1.0 extracted faces and v2.x faces.
  
          Parameters
          ----------
          png_meta: dict
              The information held within the Faceswap PNG Header
          filename: str
              The full path to the file being validated
  
          Raises
          ------
          FaceswapError
              If a version 1.0 face appears in a 2.x set or vice versa
 
</s> remove         Raises
        ------
        FaceswapError
            If a version 1.0 face appears in a 2.x set or vice versa
        """
        alignment_version = png_meta["source"]["alignments_version"]

        if not self._extract_version:
            logger.debug("Setting initial extract version: %s", alignment_version)
            self._extract_version = alignment_version
            if alignment_version == 1.0 and self._centering != "legacy":
                self._reset_cache(True)
            return
 </s> add             for future in futures.as_completed(proc):
                batch[proc[future], ..., :3] = future.result() </s> remove         with self._lock:
            for filename, meta in tqdm(read_image_meta_batch(filenames),
                                       desc="WTL: Caching Landmarks ({})".format(side.upper()),
                                       total=len(filenames),
                                       leave=False):
                if "itxt" not in meta or "alignments" not in meta["itxt"]:
                    raise FaceswapError(f"Invalid face image found. Aborting: '{filename}'")

                size = meta["width"]
                meta = meta["itxt"]
                # Version Check
                self._validate_version(meta, filename)
                detected_face = self._add_aligned_face(filename, meta["alignments"], size)
                self._cache[os.path.basename(filename)]["detected_face"] = detected_face
            self._partial_load = True

    def _validate_version(self, png_meta, filename):
        """ Validate that there are not a mix of v1.0 extracted faces and v2.x faces.
 </s> add         logger.trace("Cropping training images info: (filenames: %s, side: '%s')",  # type: ignore
                     filenames, self._side) </s> remove         filename: str
            The file path for the current image
        detected_face: :class:`lib.align.DetectedFace`
            The detected face object that holds the masks
 </s> add         filenames: list
            List of full paths to image file names for a single batch
        images: :class:`numpy.ndarray`
            The batch of faces corresponding to the filenames
        detected_faces: list
            List of :class:`~lib.align.DetectedFace` objects with aligned data and masks loaded for
            the current batch
        batch: :class:`numpy.ndarray`
            The pre-allocated batch with images and masks populated for the selected coverage and
            centering </s> remove         filename: str
            The file path for the current image
        alignments: dict
            The alignments for a single face, extracted from a PNG header
        image_size: int
            The pixel size of the image loaded from disk
 </s> add         filenames: list
            List of full paths to image file names for a single batch </s> remove         Raises
        ------
        FaceswapError
            If the requested mask type is not available an error is returned along with a list
            of available masks
 </s> add         Returns
        -------
        list
            4-dimensional array of faces to feed the training the model.
        list
            List of 4-dimensional :class:`numpy.ndarray`. 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)
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
  
      def _validate_version(self, png_meta, filename):
          """ Validate that there are not a mix of v1.0 extracted faces and v2.x faces.
  
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
        with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
  
          Raises
          ------
          FaceswapError
              If a version 1.0 face appears in a 2.x set or vice versa
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 
lib/training/generator.py