              opt_kwargs["clipnorm"] = 1.0
          logger.debug("Optimizer kwargs: %s", opt_kwargs)
          return Adam(**opt_kwargs, cpu_mode=self.optimizer_savings)
  
      def loss_function(self, mask, side, initialize):
          """ Set the loss function
              Side is input so we only log once """
          if self.config.get("dssim_loss", False):
              if side == "a" and not self.predict and initialize:
                  logger.verbose("Using DSSIM Loss")
              loss_func = DSSIMObjective()
          else:
              if side == "a" and not self.predict and initialize:
                  logger.verbose("Using Mean Absolute Error Loss")
              loss_func = losses.mean_absolute_error
  
          if mask and self.config.get("penalized_mask_loss", False):
              loss_mask = mask[0]
              if side == "a" and not self.predict and initialize:
                  logger.verbose("Penalizing mask for Loss")
              loss_func = PenalizedLoss(loss_mask, loss_func)
          return loss_func
  
      def mask_loss_function(self, side, initialize):
          """ Set the mask loss function
              Side is input so we only log once """
          if side == "a" and not self.predict and initialize:
              logger.verbose("Using Mean Squared Error Loss for mask")
          mask_loss_func = losses.mean_squared_error
          return mask_loss_func
  
      def converter(self, swap):
          """ Converter for autoencoder models """
          logger.debug("Getting Converter: (swap: %s)", swap)
          if swap:
              model = self.predictors["a"]
 
</s> remove         if self.is_output and not any(name == "face_out" for name in output_names):
 </s> add         if self.is_output and not any(name.startswith("face_out") for name in output_names): </s> remove         return tuple(out[0])
 </s> add         return [tuple(shape) for shape in out]

    @property
    def output_shape(self):
        """ The output shape of the model (shape of largest face output) """
        return self.output_shapes[self.largest_face_index]

    @property
    def largest_face_index(self):
        """ Return the index from model.outputs of the largest face
            Required for multi-output model prediction. The largest face
            is assumed to be the final output
        """
        sizes = [shape[1] for shape in self.output_shapes if shape[2] == 3]
        if not sizes:
            return None
        max_face = max(sizes)
        retval = [idx for idx, shape in enumerate(self.output_shapes)
                  if shape[1] == max_face and shape[2] == 3][0]
        logger.debug(retval)
        return retval

    @property
    def largest_mask_index(self):
        """ Return the index from model.outputs of the largest mask
            Required for multi-output model prediction. The largest face
            is assumed to be the final output
        """
        sizes = [shape[1] for shape in self.output_shapes if shape[2] == 1]
        if not sizes:
            return None
        max_mask = max(sizes)
        retval = [idx for idx, shape in enumerate(self.output_shapes)
                  if shape[1] == max_mask and shape[2] == 1][0]
        logger.debug(retval)
        return retval </s> remove         target_image = cv2.resize(  # pylint:disable=no-member
            target_image[slices, slices, :], (self.output_size, self.output_size),
            cv2.INTER_AREA)  # pylint:disable=no-member
        logger.trace("Target image shape: %s", target_image.shape)

        warped_image, warped_mask = self.separate_mask(warped_image)
        target_image, target_mask = self.separate_mask(target_image)

        if target_mask is None:
            logger.trace("Randomly warped image")
            return [warped_image, target_image]

        logger.trace("Target mask shape: %s", target_mask.shape)
        logger.trace("Randomly warped image and mask")
        return [warped_image, target_image, target_mask]
 </s> add         target_images = [cv2.resize(target_image[slices, slices, :],  # pylint:disable=no-member
                                    (size, size),
                                    cv2.INTER_AREA)  # pylint:disable=no-member
                         for size in self.output_sizes]

        logger.trace("Target image shapea: %s", [img.shape for img in target_images])
        return self.compile_images(warped_image, target_images)

    def compile_images(self, warped_image, target_images):
        """ Compile the warped images, target images and mask for feed """
        warped_image, _ = self.separate_mask(warped_image)
        final_target_images = list()
        target_mask = None
        for target_image in target_images:
            image, mask = self.separate_mask(target_image)
            final_target_images.append(image)
            # Add the mask if it exists and is the same size as our largest output
            if mask is not None and mask.shape[1] == max(self.output_sizes):
                target_mask = mask

        retval = [warped_image] + final_target_images
        if target_mask is not None:
            logger.trace("Target mask shape: %s", target_mask.shape)
            retval.append(target_mask)

        logger.trace("Final shapes: %s", [img.shape for img in retval])
        return retval </s> remove         logger.debug("Compiled Predictors. Losses: %s", loss_names)
 </s> add         logger.debug("Compiled Predictors. Losses: %s", loss.names)
              opt_kwargs["clipnorm"] = 1.0
          logger.debug("Optimizer kwargs: %s", opt_kwargs)
          return Adam(**opt_kwargs, cpu_mode=self.optimizer_savings)
  



























      def converter(self, swap):
          """ Converter for autoencoder models """
          logger.debug("Getting Converter: (swap: %s)", swap)
          if swap:
              model = self.predictors["a"]
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace keep keep keep keep keep
 Training: Add Multi-Output Support

- Name output nodes of models
- Add support for multiple outputs in models and in training
- Update loss output format for cli and gui
- Sort graphs tabs on training
- Fix analysis graph for new loss names
- Multi output support in convert 
plugins/train/model/_base.py