  
      As the cache is populated at run-time, thread safe writes are required for the first epoch.
      Following that, the cache is only used for reads, which is thread safe intrinsically.
  
      It would probably be quicker to set locks on each individual face, but for code complexity
      reasons, and the fact that the lock is only taken up during cache population, and it should
      only be being read multiple times on save iterations, we lock the whole cache during writes.
  
      Parameters
      ----------
      filenames: list
          The filenames of all the images. This can either be the full path or the base name. If the
 
</s> remove     As the cache is populated at run-time, thread safe writes are required for the first epoch.
    Following that, the cache is only used for reads, which is thread safe intrinsically.
 </s> add class DataGenerator():
    """ Parent class for Training and Preview Data Generators. </s> remove     Each side may have up to 3 generators (training, preview and time-lapse). To conserve VRAM
    these need to share access to the same face information for the images they are processing.
 </s> add  </s> remove     filenames: list
        The filenames of all the images. This can either be the full path or the base name. If the
        full paths are passed in, they are stripped to base name for use as the cache key.
 </s> add     model: :class:`~plugins.train.model.ModelBase`
        The model that this data generator is feeding </s> remove class _Cache():
    """ A thread safe mechanism for collecting and holding face meta information (masks, "
    "alignments data etc.) for multiple :class:`TrainingDataGenerator`s.
 </s> add logger = logging.getLogger(__name__)
ConfigType = Dict[str, Union[bool, int, float, str]]  # TODO Dataclass
BatchType = Tuple[np.ndarray, List[np.ndarray]] </s> remove logger = logging.getLogger(__name__)  # pylint: disable=invalid-name

_FACE_CACHES = dict()


def _get_cache(side, filenames, config):
    """ Obtain a :class:`_Cache` object for the given side. If the object does not pre-exist then
    create it.

    Parameters
    ----------
    side: str
        `"a"` or `"b"`. The side of the model to obtain the cache for
    filenames: list
        The filenames of all the images. This can either be the full path or the base name. If the
        full paths are passed in, they are stripped to base name for use as the cache key.
    config: dict
        The user selected training configuration options

    Returns
    -------
    :class:`_Cache`
        The face meta information cache for the requested side
    """
    if not _FACE_CACHES.get(side):
        logger.debug("Creating cache. Side: %s", side)
        _FACE_CACHES[side] = _Cache(filenames, config)
    return _FACE_CACHES[side]


def _check_reset(face_cache):
    """ Check whether a given cache needs to be reset because a face centering change has been
    detected in the other cache.

    Parameters
    ----------
    face_cache: :class:`_Cache`
        The cache object that is checking whether it should reset

    Returns
    -------
    bool
        ``True`` if the given object should reset the cache, otherwise ``False``
    """
    check_cache = next((cache for cache in _FACE_CACHES.values() if cache != face_cache), None)
    retval = check_cache if check_cache is None else check_cache.check_reset()
    return retval
 </s> add if sys.version_info < (3, 8):
    from typing_extensions import get_args, Literal
else:
    from typing import get_args, Literal
    This class is called from :mod:`plugins.train.trainer._base` and launches a background
    iterator that compiles augmented data, target data and sample data.
  
      As the cache is populated at run-time, thread safe writes are required for the first epoch.
      Following that, the cache is only used for reads, which is thread safe intrinsically.
  
    This class is called from :mod:`plugins.train.trainer._base` and launches a background
    iterator that compiles augmented data, target data and sample data.
    This class is called from :mod:`plugins.train.trainer._base` and launches a background
    iterator that compiles augmented data, target data and sample data.
    This class is called from :mod:`plugins.train.trainer._base` and launches a background
    iterator that compiles augmented data, target data and sample data.
  
      Parameters
      ----------
      filenames: list
          The filenames of all the images. This can either be the full path or the base name. If the
keep keep keep keep 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