
    i$                         d dl mZ d dl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 d dlmZ d dlmZ d d	lmZ d d
lmZmZ d dlmZmZ esdgZddgiZ G d de      Zy)    )Sequence)AnyOptionalUnionN)Tensor)Module)NoTrainInceptionV3)Metric)rank_zero_warn)dim_zero_cat)_MATPLOTLIB_AVAILABLE_TORCH_FIDELITY_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEInceptionScore.plot)InceptionScorer   torch_fidelityc                       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<   eed	<   eed
<   d
Zeed<   	 	 	 ddeeeef   dedededdf
 fdZdeddfdZdeeef   fdZ	 ddeeeee   f      dee   defdZ xZS )r   a  Calculate the Inception Score (IS) which is used to access how realistic generated images are.

    .. math::
        IS = exp(\mathbb{E}_x KL(p(y | x ) || p(y)))

    where :math:`KL(p(y | x) || p(y))` is the KL divergence between the conditional distribution :math:`p(y|x)`
    and the marginal distribution :math:`p(y)`. Both the conditional and marginal distribution is calculated
    from features extracted from the images. The score is calculated on random splits of the images such that
    both a mean and standard deviation of the score are returned. The metric was originally proposed in
    `inception ref1`_.

    Using the default feature extraction (Inception v3 using the original weights from `inception ref2`_), the input
    is expected to be mini-batches of 3-channel RGB images of shape ``(3xHxW)``. If argument ``normalize``
    is ``True`` images are expected to be dtype ``float`` and have values in the ``[0,1]`` range, else if
    ``normalize`` is set to ``False`` images are expected to have dtype uint8 and take values in the ``[0, 255]``
    range. All images will be resized to 299 x 299 which is the size of the original training data.

    .. hint::
        Using this metric with the default feature extractor requires that ``torch-fidelity``
        is installed. Either install as ``pip install torchmetrics[image]`` or
        ``pip install torch-fidelity``

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

    - ``imgs`` (:class:`~torch.Tensor`): tensor with images feed to the feature extractor

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

    - ``inception_mean`` (:class:`~torch.Tensor`): float scalar tensor with mean inception score over subsets
    - ``inception_std`` (:class:`~torch.Tensor`): float scalar tensor with standard deviation of inception score
      over subsets

    Args:
        feature:
            Either an str, integer or ``nn.Module``:

            - an str or integer will indicate the inceptionv3 feature layer to choose. Can be one of the following:
              'logits_unbiased', 64, 192, 768, 2048
            - an ``nn.Module`` for using a custom feature extractor. Expects that its forward method returns
              an ``(N,d)`` matrix where ``N`` is the batch size and ``d`` is the feature size.

        splits: integer determining how many splits the inception score calculation should be split among
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``feature`` is set to an ``str`` or ``int`` and ``torch-fidelity`` is not installed
        ValueError:
            If ``feature`` is set to an ``str`` or ``int`` and not one of ``('logits_unbiased', 64, 192, 768, 2048)``
        TypeError:
            If ``feature`` is not an ``str``, ``int`` or ``torch.nn.Module``

    Example:
        >>> from torch import rand
        >>> from torchmetrics.image.inception import InceptionScore
        >>> inception = InceptionScore()
        >>> # generate some images
        >>> imgs = torch.randint(0, 255, (100, 3, 299, 299), dtype=torch.uint8)
        >>> inception.update(imgs)
        >>> inception.compute()
        (tensor(1.0549), tensor(0.0121))

    Fis_differentiableThigher_is_betterfull_state_updateg        plot_lower_boundfeatures	inceptionfeature_networkfeaturesplits	normalizekwargsreturnNc                    t        |   di | t        dt               t	        |t
        t        f      rFt        st        d      d}||vrt        d| d| d      t        dt        |      g      | _        n#t	        |t              r|| _        nt        d	      t	        |t              st        d
      || _        || _        | j#                  dg d        y )NzMetric `InceptionScore` will save all extracted features in buffer. For large datasets this may lead to large memory footprint.zInceptionScore metric requires that `Torch-fidelity` is installed. Either install as `pip install torchmetrics[image]` or `pip install torch-fidelity`.)logits_unbiased@      i   i   z3Integer input to argument `feature` must be one of z
, but got .zinception-v3-compat)namefeatures_listz'Got unknown input to argument `feature`z*Argument `normalize` expected to be a boolr   )dist_reduce_fx )super__init__r   UserWarning
isinstancestrintr   ModuleNotFoundError
ValueErrorr	   r   r   	TypeErrorboolr   r   	add_state)selfr   r   r   r   valid_int_input	__class__s         q/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/image/inception.pyr+   zInceptionScore.__init__m   s     	"6"K	
 gSz*,)l  FOo- I/IZZdeldmmno  05J[^_f[gZhiDN($DNEFF)T*IJJ"z2d;    imgsc                     | j                   r|dz  j                         n|}| j                  |      }| j                  j	                  |       y)z)Update the state with extracted features.   N)r   byter   r   append)r5   r:   r   s      r8   updatezInceptionScore.update   s<    &*nns
  "$>>$'X&r9   c           	         t        | j                        }t        j                  |j                  d         }||   }|j                  d      }|j                  d      }|j                  | j                  d      }|j                  | j                  d      }|D cg c]  }|j                  dd       }}t        |||      D cg c]  \  }}}|||j                         z
  z   }	}}}|	D 
cg c]0  }
|
j                  d      j                         j                         2 }	}
t        j                  |	      }|j                         |j                         fS c c}w c c}}}w c c}
w )zCompute metric.r      )dimT)rB   keepdim)r   r   torchrandpermshapesoftmaxlog_softmaxchunkr   meanziplogsumexpstackstd)r5   r   idxproblog_probp	mean_problog_pm_pkl_kkls               r8   computezInceptionScore.compute   sB   .nnX^^A./C= A&''A'. zz$++1z->>$++1>5 ;??$QQVV4V0$	?<?hPY<Z[<Z=1eSqECGGI%&<Z[256#Qquuu|  "&&(#6[[ wwy"&&("" @[6s   E!!E&55E-valaxc                 T    |xs | j                         d   }| j                  ||      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.inception import InceptionScore
            >>> metric = InceptionScore()
            >>> metric.update(torch.randint(0, 255, (50, 3, 299, 299), dtype=torch.uint8))
            >>> fig_, ax_ = metric.plot()  # the returned plot only shows the mean value by default

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.image.inception import InceptionScore
            >>> metric = InceptionScore()
            >>> values = [ ]
            >>> for _ in range(3):
            ...     # we index by 0 such that only the mean value is plotted
            ...     values.append(metric(torch.randint(0, 255, (50, 3, 299, 299), dtype=torch.uint8))[0])
            >>> fig_, ax_ = metric.plot(values)

        r   )r[   _plot)r5   r\   r]   s      r8   plotzInceptionScore.plot   s+    R &T\\^A&zz#r""r9   )r"   
   F)NN)__name__
__module____qualname____doc__r   r3   __annotations__r   r   r   floatlistr   r   r.   r   r/   r   r+   r   r?   tupler[   r   r   r   r   r`   __classcell__)r7   s   @r8   r   r   #   s    >@ $t#!d!#t#!e!N&OS& ,=	&<sC'(&< &< 	&<
 &< 
&<P'6 'd '#vv~. #2 _c*#E&(6*:":;<*#IQRZI[*#	*#r9   r   )collections.abcr   typingr   r   r   rD   r   torch.nnr   torchmetrics.image.fidr	   torchmetrics.metricr
   torchmetrics.utilitiesr   torchmetrics.utilities.datar   torchmetrics.utilities.importsr   r   torchmetrics.utilities.plotr   r   __doctest_skip____doctest_requires__r   r)   r9   r8   <module>rv      sW    % ' '    5 & 1 4 [ @-. BDTCUV z#V z#r9   