  tqdm>=4.64
  psutil>=5.9.0
  opencv-python>=4.6.0.0
  pillow>=9.2.0
  scikit-learn==1.0.2; python_version < '3.9'  # AMD needs version 1.0.2 and 1.1.0 not available in Python 3.7
  scikit-learn>=1.1.0; python_version >= '3.9'
 
</s> remove         if not self._config["penalized_mask_loss"] and not self._config["learn_mask"]:
            return

        if not self._config["mask_type"]:
            logger.debug("No mask selected. Not validating")
            return

        if self._config["mask_type"] not in detected_face.mask:
            raise FaceswapError(
                "You have selected the mask type '{}' but at least one face does not contain the "
                "selected mask.\nThe face that failed was: '{}'\nThe masks that exist for this "
                "face are: {}".format(
                    self._config["mask_type"], filename, list(detected_face.mask)))

        key = os.path.basename(filename)
        mask = detected_face.mask[self._config["mask_type"]]
        mask.set_blur_and_threshold(blur_kernel=self._config["mask_blur_kernel"],
                                    threshold=self._config["mask_threshold"])
 </s> add         raise NotImplementedError() </s> remove         indices = np.where(batch_random < self._config.get("color_clahe_chance", 50) / 100)[0]
 </s> add         indices = np.where(batch_random < self._constants.clahe_chance)[0] </s> remove         logger.trace("Cropping training images info: (filenames: %s, side: '%s')", filenames, side)
        aligned = [item["aligned_face"] for item in cache]
 </s> add         logger.trace("Caching closest matches")  # type:ignore
        dst_landmarks = list(landmarks.items())
        dst_points = np.array([lm[1] for lm in dst_landmarks])
        batch_closest_matches: List[Tuple[str, ...]] = [] </s> remove         Parameters
        ----------
        png_meta: dict
            The information held within the Faceswap PNG Header
        filename: str
            The full path to the file being validated
 </s> add         with futures.ThreadPoolExecutor() as executor:
            proc = {executor.submit(face.aligned.extract_face, img): idx
                    for idx, (face, img) in enumerate(zip(detected_faces, images))}
numexpr>=2.8.3
  tqdm>=4.64
  psutil>=5.9.0
numexpr>=2.8.3
  opencv-python>=4.6.0.0
  pillow>=9.2.0
  scikit-learn==1.0.2; python_version < '3.9'  # AMD needs version 1.0.2 and 1.1.0 not available in Python 3.7
  scikit-learn>=1.1.0; python_version >= '3.9'
keep add 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 
requirements/_requirements_base.txt