              predict=False)
          logger.debug("Loaded Model")
          return model
  
      @property
      def image_size(self):
          """ Get the training set image size for storing in model data """
          image = read_image(self.images["a"][0], raise_error=True)
          size = image.shape[0]
          logger.debug("Training image size: %s", size)
          return size
  
      @property
      def alignments_paths(self):
          """ Set the alignments path to input folder if not provided """
          alignments_paths = dict()
 
</s> remove     @property
    def alignments_paths(self):
        """ Set the alignments path to input folder if not provided """
        alignments_paths = dict()
        for side in ("a", "b"):
            alignments_path = getattr(self.args, "alignments_path_{}".format(side))
            if not alignments_path:
                image_path = getattr(self.args, "input_{}".format(side))
                alignments_path = os.path.join(image_path, "alignments.fsa")
            alignments_paths[side] = alignments_path
        logger.debug("Alignments paths: %s", alignments_paths)
        return alignments_paths
 </s> add         Parameters
        ----------
        model: :file:`plugins.train.model` plugin
            The requested model plugin </s> remove     def set_timelapse(self):
        """ Set time-lapse paths if requested """
        if (not self.args.timelapse_input_a and
                not self.args.timelapse_input_b and
                not self.args.timelapse_output):
 </s> add     @property
    def _image_size(self):
        """ int: The training image size. Reads the first image in the training folder and returns
        the size. """
        image = read_image(self._images["a"][0], raise_error=True)
        size = image.shape[0]
        logger.debug("Training image size: %s", size)
        return size

    @property
    def _alignments_paths(self):
        """ dict: The alignments paths for each of the source and destination faces. Key is the
            side, value is the path to the alignments file """
        alignments_paths = dict()
        for side in ("a", "b"):
            alignments_path = getattr(self._args, "alignments_path_{}".format(side))
            if not alignments_path:
                image_path = getattr(self._args, "input_{}".format(side))
                alignments_path = os.path.join(image_path, "alignments.fsa")
            alignments_paths[side] = alignments_path
        logger.debug("Alignments paths: %s", alignments_paths)
        return alignments_paths

    def _set_timelapse(self):
        """ Set time-lapse paths if requested.

        Returns
        -------
        dict
            The time-lapse keyword arguments for passing to the trainer

        """
        if (not self._args.timelapse_input_a and
                not self._args.timelapse_input_b and
                not self._args.timelapse_output): </s> remove         to_landmarks = self._training_opts["warp_to_landmarks"]
 </s> add  </s> remove         """ Perform timelapse """
        logger.debug("Getting timelapse samples: '%s'", side)
        if not self.output_file:
            self.setup(**timelapse_kwargs)
        self.samples.images[side] = self.batchers[side].compile_timelapse_sample()
        logger.debug("Got timelapse samples: '%s' - %s", side, len(self.samples.images[side]))

    def setup(self, input_a=None, input_b=None, output=None):
        """ Set the timelapse output folder """
        logger.debug("Setting up timelapse")
 </s> add         """ Compile the time-lapse preview

        Parameters
        ----------
        side: {"a" or "b"}
            The side that the time-lapse is being generated for
        timelapse_kwargs: dict
            The keyword arguments for setting up the time-lapse. All values should be full paths
            the keys being `input_a`, `input_b`, `output`
        """
        logger.debug("Getting time-lapse samples: '%s'", side)
        if not self._output_file:
            self._setup(**timelapse_kwargs)
        self._samples.images[side] = self._batchers[side].compile_timelapse_sample()
        logger.debug("Got time-lapse samples: '%s' - %s", side, len(self._samples.images[side]))

    def _setup(self, input_a=None, input_b=None, output=None):
        """ Setup the time-lapse folder locations and the time-lapse feed.

        Parameters
        ----------
        input_a: str
            The full path to the time-lapse input folder containing faces for the "a" side
        input_b: str
            The full path to the time-lapse input folder containing faces for the "b" side
        output: str, optional
            The full path to the time-lapse output folder. If ``None`` is provided this will
            default to the model folder
        """
        logger.debug("Setting up time-lapse") </s> remove         return self.config.get("mask_type", None) is not None
 </s> add         return self.config.get("learn_mask", False)
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
              predict=False)
          logger.debug("Loaded Model")
          return model
  
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
    def _load_trainer(self, model):
        """ Load the trainer requested for training.
  
      @property
      def alignments_paths(self):
          """ Set the alignments path to input folder if not provided """
          alignments_paths = dict()
keep keep keep keep replace replace replace replace replace replace replace keep keep keep keep keep
 Smart Masks - Training Implementation (#914)

* Smart Masks - Training

- Reinstate smart mask training code
- Reinstate mask_type back to model.config
- change 'replicate_input_mask to 'learn_mask'
- Add learn mask option
- Add mask loading from alignments to plugins.train.trainer
- Add mask_blur and mask threshold options
- _base.py - Pass mask options through training_opts dict
- plugins.train.model - check for mask_type not None for learn_mask and penalized_mask_loss
- Limit alignments loading to just those faces that appear in the training folder
- Raise error if not all training images have an alignment, and alignment file is required
- lib.training_data - Mask generation code
- lib.faces_detect - cv2 dimension stripping bugfix
- Remove cv2 linting code

* Update mask helptext in cli.py

* Fix Warp to Landmarks
Remove SHA1 hashing from training data

* Update mask training config

* Capture missing masks at training init

* lib.image.read_image_batch - Return filenames with batch for ordering

* scripts.train - Documentation

* plugins.train.trainer - documentation

* Ensure backward compatibility.
Fix convert for new predicted masks

* Update removed masks to components for legacy models. 
scripts/train.py