a
    dw                     @   s   d dl mZmZmZmZmZmZ d dlZd dlmZ d dl	m
Z
 d dlmZmZmZmZ d dlmZ d dlmZmZ d dlmZmZ d d	lmZmZ esd
gZerddddZereesdd
gZndd
gZG dd deZdS )    )AnyClassVarListOptionalSequenceUnionN)Tensor)Literal)_LPIPS_lpips_compute_lpips_update_NoTrainLpips)Metric)_SKIP_SLOW_DOCTEST_try_proceed_with_timeout)_MATPLOTLIB_AVAILABLE_TORCHVISION_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPE*LearnedPerceptualImagePatchSimilarity.plotreturnc                   C   s   t ddd d S )NTvgg)Z
pretrainednet)r
    r   r   `/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/image/lpip.py_download_lpips   s    r   %LearnedPerceptualImagePatchSimilarityc                       s   e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< d	Ze
ed
< eed< eed< dgZeee  ed< d ed ed eedd fddZeeddddZedddZd!eeeee f  ee edddZ  ZS )"r   a
  The Learned Perceptual Image Patch Similarity (`LPIPS_`) calculates the perceptual similarity between two images.

    LPIPS essentially computes the similarity between the activations of two image patches for some pre-defined network.
    This measure has been shown to match human perception well. A low LPIPS score means that image patches are
    perceptual similar.

    Both input image patches are expected to have shape ``(N, 3, H, W)``. The minimum size of `H, W` depends on the
    chosen backbone (see `net_type` arg).

    .. note:: using this metrics requires you to have ``lpips`` package installed. Either install
        as ``pip install torchmetrics[image]`` or ``pip install lpips``

    .. note:: this metric is not scriptable when using ``torch<1.8``. Please update your pytorch installation
        if this is a issue.

    As input to ``forward`` and ``update`` the metric accepts the following input

    - ``img1`` (:class:`~torch.Tensor`): tensor with images of shape ``(N, 3, H, W)``
    - ``img2`` (:class:`~torch.Tensor`): tensor with images of shape ``(N, 3, H, W)``

    As output of `forward` and `compute` the metric returns the following output

    - ``lpips`` (:class:`~torch.Tensor`): returns float scalar tensor with average LPIPS value over samples

    Args:
        net_type: str indicating backbone network type to use. Choose between `'alex'`, `'vgg'` or `'squeeze'`
        reduction: str indicating how to reduce over the batch dimension. Choose between `'sum'` or `'mean'`.
        normalize: by default this is ``False`` meaning that the input is expected to be in the [-1,1] range. If set
            to ``True`` will instead expect input to be in the ``[0,1]`` range.
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ModuleNotFoundError:
            If ``lpips`` package is not installed
        ValueError:
            If ``net_type`` is not one of ``"vgg"``, ``"alex"`` or ``"squeeze"``
        ValueError:
            If ``reduction`` is not one of ``"mean"`` or ``"sum"``

    Example:
        >>> import torch
        >>> _ = torch.manual_seed(123)
        >>> from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity
        >>> lpips = LearnedPerceptualImagePatchSimilarity(net_type='squeeze')
        >>> # LPIPS needs the images to be in the [-1, 1] range.
        >>> img1 = (torch.rand(10, 3, 100, 100) * 2) - 1
        >>> img2 = (torch.rand(10, 3, 100, 100) * 2) - 1
        >>> lpips(img1, img2)
        tensor(0.1046, grad_fn=<SqueezeBackward0>)

    Tis_differentiableFhigher_is_betterfull_state_update        plot_lower_boundg      ?plot_upper_bound
sum_scorestotalr   __jit_ignored_attributes__alexmeanr   r'   Zsqueeze)sumr(   N)net_type	reduction	normalizekwargsr   c                    s   t  jf i | tstdd}||vr@td| d| dt|d| _d}||vrltd| d| || _t|t	std	| || _
| jd
tddd | jdtddd d S )NzLPIPS metric requires that torchvision is installed. Either install as `pip install torchmetrics[image]` or `pip install torchvision`.r)   z#Argument `net_type` must be one of z
, but got .)r   )r(   r*   z$Argument `reduction` must be one of z/Argument `normalize` should be an bool but got r$   r!   r*   )Zdist_reduce_fxr%   )super__init__r   ModuleNotFoundError
ValueErrorr   r   r,   
isinstanceboolr-   Z	add_statetorchZtensor)selfr+   r,   r-   r.   Zvalid_net_typeZvalid_reduction	__class__r   r   r1   i   s$    
z.LearnedPerceptualImagePatchSimilarity.__init__)img1img2r   c                 C   s<   t ||| j| jd\}}|  j| 7  _|  j|7  _dS )z(Update internal states with lpips score.)r   r-   N)r   r   r-   r$   r*   r%   )r7   r:   r;   Zlossr%   r   r   r   update   s    z,LearnedPerceptualImagePatchSimilarity.updater   c                 C   s   t | j| j| jS )z+Compute final perceptual similarity metric.)r   r$   r%   r,   )r7   r   r   r   compute   s    z-LearnedPerceptualImagePatchSimilarity.compute)valaxr   c                 C   s   |  ||S )a  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value
            >>> import torch
            >>> from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity
            >>> metric = LearnedPerceptualImagePatchSimilarity(net_type='squeeze')
            >>> metric.update(torch.rand(10, 3, 100, 100), torch.rand(10, 3, 100, 100))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity
            >>> metric = LearnedPerceptualImagePatchSimilarity(net_type='squeeze')
            >>> values = [ ]
            >>> for _ in range(3):
            ...     values.append(metric(torch.rand(10, 3, 100, 100), torch.rand(10, 3, 100, 100)))
            >>> fig_, ax_ = metric.plot(values)

        )Z_plot)r7   r>   r?   r   r   r   plot   s    (r   )r'   r(   F)NN)__name__
__module____qualname____doc__r   r5   __annotations__r   r    r"   floatr#   r   r&   r   r   strr	   r   r1   r<   r=   r   r   r   r   r   r@   __classcell__r   r   r8   r   r   (   s4   
4     )typingr   r   r   r   r   r   r6   r   Ztyping_extensionsr	   Z#torchmetrics.functional.image.lpipsr
   r   r   r   Ztorchmetrics.metricr   Ztorchmetrics.utilities.checksr   r   Ztorchmetrics.utilities.importsr   r   Ztorchmetrics.utilities.plotr   r   Z__doctest_skip__r   r   r   r   r   r   <module>   s     
