  
  import plaidml
  
  
  def pad(data, paddings, mode="CONSTANT", name=None, constant_value=0):
      """ PlaidML Pad """
      # TODO: use / implement other padding method when required
      # CONSTANT -> SpatialPadding ? | Doesn't support first and last axis +
      #             no support for constant_value
      # SYMMETRIC -> Requires implement ?
      if mode.upper() != "REFLECT":
 
</s> remove '''
Multiple plaidml implementation.
'''
 </s> add #!/usr/bin/env python3
""" PlaidML helper Utilities """
from typing import Optional </s> remove def is_plaidml_error(error):
 </s> add def is_plaidml_error(error: Exception) -> bool: </s> remove class DSSIMObjective():  # pylint:disable=too-few-public-methods
    """ DSSIM Loss Function

    Difference of Structural Similarity (DSSIM loss function).

    Adapted from :func:`tensorflow.image.ssim` for a pure keras implentation.

    Notes
    -----
    Channels last only. Assumes all input images are the same size and square

    Parameters
    ----------
    k_1: float, optional
        Parameter of the SSIM. Default: `0.01`
    k_2: float, optional
        Parameter of the SSIM. Default: `0.03`
    filter_size: int, optional
        size of gaussian filter Default: `11`
    filter_sigma: float, optional
        Width of gaussian filter Default: `1.5`
    max_value: float, optional
        Max value of the output. Default: `1.0`

    Notes
    ------
    You should add a regularization term like a l2 loss in addition to this one.
    """
    def __init__(self,
                 k_1: float = 0.01,
                 k_2: float = 0.03,
                 filter_size: int = 11,
                 filter_sigma: float = 1.5,
                 max_value: float = 1.0) -> None:
        self._filter_size = filter_size
        self._filter_sigma = filter_sigma
        self._kernel = self._get_kernel()

        compensation = 1.0
        self._c1 = (k_1 * max_value) ** 2
        self._c2 = ((k_2 * max_value) ** 2) * compensation

    def _get_kernel(self) -> plaidml.tile.Value:
        """ Obtain the base kernel for performing depthwise convolution.

        Returns
        -------
        :class:`plaidml.tile.Value`
            The gaussian kernel based on selected size and sigma
        """
        coords = np.arange(self._filter_size, dtype="float32")
        coords -= (self._filter_size - 1) / 2.

        kernel = np.square(coords)
        kernel *= -0.5 / np.square(self._filter_sigma)
        kernel = np.reshape(kernel, (1, -1)) + np.reshape(kernel, (-1, 1))
        kernel = K.constant(np.reshape(kernel, (1, -1)))
        kernel = K.softmax(kernel)
        kernel = K.reshape(kernel, (self._filter_size, self._filter_size, 1, 1))
        return kernel

    @classmethod
    def _depthwise_conv2d(cls,
                          image: plaidml.tile.Value,
                          kernel: plaidml.tile.Value) -> plaidml.tile.Value:
        """ Perform a standardized depthwise convolution.

        Parameters
        ----------
        image: :class:`plaidml.tile.Value`
            Batch of images, channels last, to perform depthwise convolution
        kernel: :class:`plaidml.tile.Value`
            convolution kernel

        Returns
        -------
        :class:`plaidml.tile.Value`
            The output from the convolution
        """
        return K.depthwise_conv2d(image, kernel, strides=(1, 1), padding="valid")

    def _get_ssim(self,
                  y_true: plaidml.tile.Value,
                  y_pred: plaidml.tile.Value) -> Tuple[plaidml.tile.Value, plaidml.tile.Value]:
        """ Obtain the structural similarity between a batch of true and predicted images.

        Parameters
        ----------
        y_true: :class:`plaidml.tile.Value`
            The input batch of ground truth images
        y_pred: :class:`plaidml.tile.Value`
            The input batch of predicted images

        Returns
        -------
        :class:`plaidml.tile.Value`
            The SSIM for the given images
        :class:`plaidml.tile.Value`
            The Contrast for the given images
        """
        channels = K.int_shape(y_pred)[-1]
        kernel = K.tile(self._kernel, (1, 1, channels, 1))

        # SSIM luminance measure is (2 * mu_x * mu_y + c1) / (mu_x ** 2 + mu_y ** 2 + c1)
        mean_true = self._depthwise_conv2d(y_true, kernel)
        mean_pred = self._depthwise_conv2d(y_pred, kernel)
        num_lum = mean_true * mean_pred * 2.0
        den_lum = K.square(mean_true) + K.square(mean_pred)
        luminance = (num_lum + self._c1) / (den_lum + self._c1)

        # SSIM contrast-structure measure is (2 * cov_{xy} + c2) / (cov_{xx} + cov_{yy} + c2)
        num_con = self._depthwise_conv2d(y_true * y_pred, kernel) * 2.0
        den_con = self._depthwise_conv2d(K.square(y_true) + K.square(y_pred), kernel)

        contrast = (num_con - num_lum + self._c2) / (den_con - den_lum + self._c2)

        # Average over the height x width dimensions
        axes = (-3, -2)
        ssim = K.mean(luminance * contrast, axis=axes)
        contrast = K.mean(contrast, axis=axes)

        return ssim, contrast

    def __call__(self,
                 y_true: plaidml.tile.Value,
                 y_pred: plaidml.tile.Value) -> plaidml.tile.Value:
        """ Call the DSSIM  or MS-DSSIM Loss Function.

        Parameters
        ----------
        y_true: :class:`plaidml.tile.Value`
            The input batch of ground truth images
        y_pred: :class:`plaidml.tile.Value`
            The input batch of predicted images

        Returns
        -------
        :class:`plaidml.tile.Value`
            The DSSIM or MS-DSSIM for the given images
        """
        ssim = self._get_ssim(y_true, y_pred)[0]
        retval = (1. - ssim) / 2.0
        return K.mean(retval)


 </s> add  </s> remove class DSSIMObjective():  # pylint:disable=too-few-public-methods
    """ DSSIM Loss Functions

    Difference of Structural Similarity (DSSIM loss function).

    Adapted from :func:`tensorflow.image.ssim` for a pure keras implentation.

    Notes
    -----
    Channels last only. Assumes all input images are the same size and square

    Parameters
    ----------
    k_1: float, optional
        Parameter of the SSIM. Default: `0.01`
    k_2: float, optional
        Parameter of the SSIM. Default: `0.03`
    filter_size: int, optional
        size of gaussian filter Default: `11`
    filter_sigma: float, optional
        Width of gaussian filter Default: `1.5`
    max_value: float, optional
        Max value of the output. Default: `1.0`

    Notes
    ------
    You should add a regularization term like a l2 loss in addition to this one.
    """
    def __init__(self,
                 k_1: float = 0.01,
                 k_2: float = 0.03,
                 filter_size: int = 11,
                 filter_sigma: float = 1.5,
                 max_value: float = 1.0) -> None:
        self._filter_size = filter_size
        self._filter_sigma = filter_sigma
        self._kernel = self._get_kernel()

        compensation = 1.0
        self._c1 = (k_1 * max_value) ** 2
        self._c2 = ((k_2 * max_value) ** 2) * compensation

    def _get_kernel(self) -> tf.Tensor:
        """ Obtain the base kernel for performing depthwise convolution.

        Returns
        -------
        :class:`tf.Tensor`
            The gaussian kernel based on selected size and sigma
        """
        coords = np.arange(self._filter_size, dtype="float32")
        coords -= (self._filter_size - 1) / 2.

        kernel = np.square(coords)
        kernel *= -0.5 / np.square(self._filter_sigma)
        kernel = np.reshape(kernel, (1, -1)) + np.reshape(kernel, (-1, 1))
        kernel = K.constant(np.reshape(kernel, (1, -1)))
        kernel = K.softmax(kernel)
        kernel = K.reshape(kernel, (self._filter_size, self._filter_size, 1, 1))
        return kernel

    @classmethod
    def _depthwise_conv2d(cls, image: tf.Tensor, kernel: tf.Tensor) -> tf.Tensor:
        """ Perform a standardized depthwise convolution.

        Parameters
        ----------
        image: :class:`tf.Tensor`
            Batch of images, channels last, to perform depthwise convolution
        kernel: :class:`tf.Tensor`
            convolution kernel

        Returns
        -------
        :class:`tf.Tensor`
            The output from the convolution
        """
        return K.depthwise_conv2d(image, kernel, strides=(1, 1), padding="valid")

    def _get_ssim(self, y_true: tf.Tensor, y_pred: tf.Tensor) -> Tuple[tf.Tensor, tf.Tensor]:
        """ Obtain the structural similarity between a batch of true and predicted images.

        Parameters
        ----------
        y_true: :class:`tf.Tensor`
            The input batch of ground truth images
        y_pred: :class:`tf.Tensor`
            The input batch of predicted images

        Returns
        -------
        :class:`tf.Tensor`
            The SSIM for the given images
        :class:`tf.Tensor`
            The Contrast for the given images
        """
        channels = K.int_shape(y_true)[-1]
        kernel = K.tile(self._kernel, (1, 1, channels, 1))

        # SSIM luminance measure is (2 * mu_x * mu_y + c1) / (mu_x ** 2 + mu_y ** 2 + c1)
        mean_true = self._depthwise_conv2d(y_true, kernel)
        mean_pred = self._depthwise_conv2d(y_pred, kernel)
        num_lum = mean_true * mean_pred * 2.0
        den_lum = K.square(mean_true) + K.square(mean_pred)
        luminance = (num_lum + self._c1) / (den_lum + self._c1)

        # SSIM contrast-structure measure is (2 * cov_{xy} + c2) / (cov_{xx} + cov_{yy} + c2)
        num_con = self._depthwise_conv2d(y_true * y_pred, kernel) * 2.0
        den_con = self._depthwise_conv2d(K.square(y_true) + K.square(y_pred), kernel)

        contrast = (num_con - num_lum + self._c2) / (den_con - den_lum + self._c2)

        # Average over the height x width dimensions
        axes = (-3, -2)
        ssim = K.mean(luminance * contrast, axis=axes)
        contrast = K.mean(contrast, axis=axes)

        return ssim, contrast

    def __call__(self, y_true: tf.Tensor, y_pred: tf.Tensor) -> tf.Tensor:
        """ Call the DSSIM  or MS-DSSIM Loss Function.

        Parameters
        ----------
        y_true: :class:`tf.Tensor`
            The input batch of ground truth images
        y_pred: :class:`tf.Tensor`
            The input batch of predicted images

        Returns
        -------
        :class:`tf.Tensor`
            The DSSIM or MS-DSSIM for the given images
        """
        ssim = self._get_ssim(y_true, y_pred)[0]
        retval = (1. - ssim) / 2.0
        return K.mean(retval)


 </s> add  </s> remove class GMSDLoss():  # pylint:disable=too-few-public-methods
    """ Gradient Magnitude Similarity Deviation Loss.

    Improved image quality metric over MS-SSIM with easier calculations

    References
    ----------
    http://www4.comp.polyu.edu.hk/~cslzhang/IQA/GMSD/GMSD.htm
    https://arxiv.org/ftp/arxiv/papers/1308/1308.3052.pdf
    """
    def __call__(self,
                 y_true: plaidml.tile.Value,
                 y_pred: plaidml.tile.Value) -> plaidml.tile.Value:
        """ Return the Gradient Magnitude Similarity Deviation Loss.

        Parameters
        ----------
        y_true: :class:`plaidml.tile.Value`
            The ground truth value
        y_pred: :class:`plaidml.tile.Value`
            The predicted value

        Returns
        -------
        :class:`plaidml.tile.Value`
            The loss value
        """
        image_shape = K.int_shape(y_pred)
        true_edge = self._scharr_edges(y_true, True, image_shape)
        pred_edge = self._scharr_edges(y_pred, True, image_shape)
        ephsilon = 0.0025
        upper = 2.0 * true_edge * pred_edge
        lower = K.square(true_edge) + K.square(pred_edge)
        gms = (upper + ephsilon) / (lower + ephsilon)
        gmsd = K.std(gms, axis=(1, 2, 3), keepdims=True)
        gmsd = K.squeeze(gmsd, axis=-1)
        return gmsd

    @classmethod
    def _scharr_edges(cls,
                      image: plaidml.tile.Value,
                      magnitude: bool,
                      image_shape: Tuple[None, int, int, int]) -> plaidml.tile.Value:
        """ Returns a tensor holding modified Scharr edge maps.

        Parameters
        ----------
        image: :class:`plaidml.tile.Value`
            Image tensor with shape [batch_size, h, w, d] and type float32. The image(s) must be
            2x2 or larger.
        magnitude: bool
            Boolean to determine if the edge magnitude or edge direction is returned
        image_shape: tuple
            The shape of the incoming image

        Returns
        -------
        :class:`plaidml.tile.Value`
            Tensor holding edge maps for each channel. Returns a tensor with shape `[batch_size, h,
            w, d, 2]` where the last two dimensions hold `[[dy[0], dx[0]], [dy[1], dx[1]], ...,
            [dy[d-1], dx[d-1]]]` calculated using the Scharr filter.
        """
        # Define vertical and horizontal Scharr filters.
        # 5x5 modified Scharr kernel ( reshape to (5,5,1,2) )
        matrix = np.array([[[[0.00070, 0.00070]],
                            [[0.00520, 0.00370]],
                            [[0.03700, 0.00000]],
                            [[0.00520, -0.0037]],
                            [[0.00070, -0.0007]]],
                           [[[0.00370, 0.00520]],
                            [[0.11870, 0.11870]],
                            [[0.25890, 0.00000]],
                            [[0.11870, -0.1187]],
                            [[0.00370, -0.0052]]],
                           [[[0.00000, 0.03700]],
                            [[0.00000, 0.25890]],
                            [[0.00000, 0.00000]],
                            [[0.00000, -0.2589]],
                            [[0.00000, -0.0370]]],
                           [[[-0.0037, 0.00520]],
                            [[-0.1187, 0.11870]],
                            [[-0.2589, 0.00000]],
                            [[-0.1187, -0.1187]],
                            [[-0.0037, -0.0052]]],
                           [[[-0.0007, 0.00070]],
                            [[-0.0052, 0.00370]],
                            [[-0.0370, 0.00000]],
                            [[-0.0052, -0.0037]],
                            [[-0.0007, -0.0007]]]])
        # num_kernels = [2]
        kernels = K.constant(matrix, dtype='float32')
        kernels = K.tile(kernels, [1, 1, image_shape[-1], 1])

        # Use depth-wise convolution to calculate edge maps per channel.
        # Output tensor has shape [batch_size, h, w, d * num_kernels].
        pad_sizes = [[0, 0], [2, 2], [2, 2], [0, 0]]
        padded = pad(image, pad_sizes, mode='REFLECT')
        output = K.depthwise_conv2d(padded, kernels)

        # TODO magnitude not implemented for plaidml
        if not magnitude:  # direction of edges
            raise FaceswapError("Magnitude for GMSD Loss is not implemented in PlaidML")
        #    # Reshape to [batch_size, h, w, d, num_kernels].
        #    shape = K.concatenate([image_shape, num_kernels], axis=0)
        #    output = K.reshape(output, shape=shape)
        #    output.set_shape(static_image_shape.concatenate(num_kernels))
        #    output = tf.atan(K.squeeze(output[:, :, :, :, 0] / output[:, :, :, :, 1], axis=None))
        # magnitude of edges -- unified x & y edges don't work well with Neural Networks
        return output


 </s> add 
def pad(data: plaidml.tile.Value,
        paddings,
        mode: str = "CONSTANT",
        name: Optional[str] = None,  # pylint:disable=unused-argument
        constant_value: int = 0) -> plaidml.tile.Value:
    """ PlaidML Pad

    Notes
    -----
    Currently only Reflect padding is supported.

    Parameters
    ----------
    data :class:`plaidm.tile.Value`
        The tensor to pad
    mode: str, optional
        The padding mode to use. Default: `"CONSTANT"`
    name: str, optional
        The name for the operation. Unused but kept for consistency with tf.pad. Default: ``None``
    constant_value: int, optional
        The value to pad the Tensor with. Default: `0`

    Returns
    -------
    :class:`plaidm.tile.Value`
        The padded tensor
    """
  
  import plaidml
  
  
def pad(data: plaidml.tile.Value,
        paddings,
        mode: str = "CONSTANT",
        name: Optional[str] = None,  # pylint:disable=unused-argument
        constant_value: int = 0) -> plaidml.tile.Value:
    """ PlaidML Pad

    Notes
    -----
    Currently only Reflect padding is supported.

    Parameters
    ----------
    data :class:`plaidm.tile.Value`
        The tensor to pad
    mode: str, optional
        The padding mode to use. Default: `"CONSTANT"`
    name: str, optional
        The name for the operation. Unused but kept for consistency with tf.pad. Default: ``None``
    constant_value: int, optional
        The value to pad the Tensor with. Default: `0`

    Returns
    -------
    :class:`plaidm.tile.Value`
        The padded tensor
    """
def pad(data: plaidml.tile.Value,
        paddings,
        mode: str = "CONSTANT",
        name: Optional[str] = None,  # pylint:disable=unused-argument
        constant_value: int = 0) -> plaidml.tile.Value:
    """ PlaidML Pad

    Notes
    -----
    Currently only Reflect padding is supported.

    Parameters
    ----------
    data :class:`plaidm.tile.Value`
        The tensor to pad
    mode: str, optional
        The padding mode to use. Default: `"CONSTANT"`
    name: str, optional
        The name for the operation. Unused but kept for consistency with tf.pad. Default: ``None``
    constant_value: int, optional
        The value to pad the Tensor with. Default: `0`

    Returns
    -------
    :class:`plaidm.tile.Value`
        The padded tensor
    """
      # TODO: use / implement other padding method when required
      # CONSTANT -> SpatialPadding ? | Doesn't support first and last axis +
      #             no support for constant_value
      # SYMMETRIC -> Requires implement ?
      if mode.upper() != "REFLECT":
keep keep keep keep replace replace keep keep keep keep keep
 Add Flip Loss Function
    - Add Flip for AMD and TF
    - Split Perceptual Loss functions to own modules
    - Fix allowed input shape for models
    - Allow GUI tooltip to display at higher width 
lib/plaidml_utils.py