a
    d6F                     @   s   d dl 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
 d dlmZmZmZ d dlmZmZmZmZmZ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  esddgZ!G dd deZ"G dd deZ#G dd de
Z$dS )    )AnyOptionalSequenceUnionN)Tensor)Literal)_ClassificationTaskWrapper)_exact_match_reduce_multiclass_exact_match_update_multilabel_exact_match_update)&_multiclass_stat_scores_arg_validation_multiclass_stat_scores_format)_multiclass_stat_scores_tensor_validation&_multilabel_stat_scores_arg_validation_multilabel_stat_scores_format)_multilabel_stat_scores_tensor_validation)Metric)dim_zero_cat)ClassificationTaskNoBinary)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEMulticlassExactMatch.plotMultilabelExactMatch.plotc                       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
< dZeed< deed ee 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 )MulticlassExactMatcha
  Compute Exact match (also known as subset accuracy) for multiclass tasks.

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

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

    - ``preds`` (:class:`~torch.Tensor`): An int tensor of shape ``(N, ...)`` or float tensor of shape ``(N, C, ..)``.
      If preds is a floating point we apply ``torch.argmax`` along the ``C`` dimension to automatically convert
      probabilities/logits into an int tensor.
    - ``target`` (:class:`~torch.Tensor`): An int tensor of shape ``(N, ...)``.


    As output to ``forward`` and ``compute`` the metric returns the following output:

    - ``mcem`` (:class:`~torch.Tensor`): A tensor whose returned shape depends on the ``multidim_average`` argument:

        - If ``multidim_average`` is set to ``global`` the output will be a scalar tensor
        - If ``multidim_average`` is set to ``samplewise`` the output will be a tensor of shape ``(N,)``

    Args:
        num_classes: Integer specifing the number of labels
        multidim_average:
            Defines how additionally dimensions ``...`` should be handled. Should be one of the following:

            - ``global``: Additional dimensions are flatted along the batch dimension
            - ``samplewise``: Statistic will be calculated independently for each sample on the ``N`` axis.
              The statistics in this case are calculated over the additional dimensions.

        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Example (multidim tensors):
        >>> from torch import tensor
        >>> from torchmetrics.classification import MulticlassExactMatch
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = MulticlassExactMatch(num_classes=3, multidim_average='global')
        >>> metric(preds, target)
        tensor(0.5000)

    Example (multidim tensors):
        >>> from torchmetrics.classification import MulticlassExactMatch
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = MulticlassExactMatch(num_classes=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([1., 0.])

    Fis_differentiableThigher_is_betterfull_state_update        plot_lower_bound      ?plot_upper_boundZClassplot_legend_nameglobalNr#   
samplewise)num_classesmultidim_averageignore_indexvalidate_argskwargsreturnc                    s   t  jf i | d\}}|r.t||||| || _|| _|| _|| _| jd| jdkrftj	dtj
dng | jdkrvdndd | jd	tj	dtj
d| jdkrdnd
d d S )N)   Ncorrectr#   r,   ZdtypesumcatZdist_reduce_fxtotalmean)super__init__r   r&   r'   r(   r)   	add_statetorchzeroslong)selfr&   r'   r(   r)   r*   Ztop_kaverage	__class__ p/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/classification/exact_match.pyr5   h   s$    zMulticlassExactMatch.__init__predstargetr+   c                 C   s   | j rt||| j| j| j t||d\}}t||| j| j\}}| jdkr`| j| || _	n|  j|7  _|  j	|7  _	dS )z2Update metric states with predictions and targets.r,   r%   N)
r)   r   r&   r'   r(   r   r
   r-   appendr2   r:   rA   rB   r-   r2   r>   r>   r?   update   s    
zMulticlassExactMatch.updater+   c                 C   s(   t | jtrt| jn| j}t|| jS zCompute metric.
isinstancer-   listr   r	   r2   r:   r-   r>   r>   r?   compute   s    zMulticlassExactMatch.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 object and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value per class
            >>> from torch import randint
            >>> from torchmetrics.classification import MulticlassExactMatch
            >>> metric = MulticlassExactMatch(num_classes=3)
            >>> metric.update(randint(3, (20,5)), randint(3, (20,5)))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> from torch import randint
            >>> # Example plotting a multiple values per class
            >>> from torchmetrics.classification import MulticlassExactMatch
            >>> metric = MulticlassExactMatch(num_classes=3)
            >>> values = []
            >>> for _ in range(20):
            ...     values.append(metric(randint(3, (20,5)), randint(3, (20,5))))
            >>> fig_, ax_ = metric.plot(values)

        Z_plotr:   rN   rO   r>   r>   r?   plot   s    (r   )r#   NT)NN__name__
__module____qualname____doc__r   bool__annotations__r   r   r   floatr!   r"   strintr   r   r   r5   r   rE   rL   r   r   r   r   rR   __classcell__r>   r>   r<   r?   r   ,   s2   
4    r   c                	       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
< dZeed< dee
ed ee 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 )MultilabelExactMatchah  Compute Exact match (also known as subset accuracy) for multilabel tasks.

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

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

    - ``preds`` (:class:`~torch.Tensor`): An int tensor or float tensor of shape ``(N, C, ..)``. If preds is a
      floating point tensor with values outside [0,1] range we consider the input to be logits and will auto apply
      sigmoid per element. Addtionally, we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (:class:`~torch.Tensor`): An int tensor of shape ``(N, C, ...)``.


    As output to ``forward`` and ``compute`` the metric returns the following output:

    - ``mlem`` (:class:`~torch.Tensor`): A tensor whose returned shape depends on the ``multidim_average`` argument:

        - If ``multidim_average`` is set to ``global`` the output will be a scalar tensor
        - If ``multidim_average`` is set to ``samplewise`` the output will be a tensor of shape ``(N,)``

    Args:
        num_labels: Integer specifing the number of labels
        threshold: Threshold for transforming probability to binary (0,1) predictions
        multidim_average:
            Defines how additionally dimensions ``...`` should be handled. Should be one of the following:

            - ``global``: Additional dimensions are flatted along the batch dimension
            - ``samplewise``: Statistic will be calculated independently for each sample on the ``N`` axis.
              The statistics in this case are calculated over the additional dimensions.

        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Example (preds is int tensor):
        >>> from torch import tensor
        >>> from torchmetrics.classification import MultilabelExactMatch
        >>> target = tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = tensor([[0, 0, 1], [1, 0, 1]])
        >>> metric = MultilabelExactMatch(num_labels=3)
        >>> metric(preds, target)
        tensor(0.5000)

    Example (preds is float tensor):
        >>> from torchmetrics.classification import MultilabelExactMatch
        >>> target = tensor([[0, 1, 0], [1, 0, 1]])
        >>> preds = tensor([[0.11, 0.22, 0.84], [0.73, 0.33, 0.92]])
        >>> metric = MultilabelExactMatch(num_labels=3)
        >>> metric(preds, target)
        tensor(0.5000)

    Example (multidim tensors):
        >>> from torchmetrics.classification import MultilabelExactMatch
        >>> target = tensor([[[0, 1], [1, 0], [0, 1]], [[1, 1], [0, 0], [1, 0]]])
        >>> preds = tensor([[[0.59, 0.91], [0.91, 0.99], [0.63, 0.04]],
        ...                 [[0.38, 0.04], [0.86, 0.780], [0.45, 0.37]]])
        >>> metric = MultilabelExactMatch(num_labels=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([0., 0.])

    Fr   Tr   r   r   r   r    r!   ZLabelr"         ?r#   Nr$   )
num_labels	thresholdr'   r(   r)   r*   r+   c                    s   t  jf i | |r(t||d ||d || _|| _|| _|| _|| _| jd| jdkrft	j
dt	jdng | jdkrvdndd | jd	t	j
dt	jd| jdkrdnd
d d S )N)r;   r'   r(   r-   r#   r,   r.   r/   r0   r1   r2   r3   )r4   r5   r   r`   ra   r'   r(   r)   r6   r7   r8   r9   )r:   r`   ra   r'   r(   r)   r*   r<   r>   r?   r5     s(    	
zMultilabelExactMatch.__init__r@   c                 C   s   | j rt||| j| j| j t||| j| j| j\}}t||| j| j\}}| jdkrj| j	| || _
n|  j|7  _|  j
|7  _
dS )z*Update state with predictions and targets.r%   N)r)   r   r`   r'   r(   r   ra   r   r-   rC   r2   rD   r>   r>   r?   rE   *  s    
zMultilabelExactMatch.updaterF   c                 C   s(   t | jtrt| jn| j}t|| jS rG   rH   rK   r>   r>   r?   rL   ;  s    zMultilabelExactMatch.computerM   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
            >>> from torch import rand, randint
            >>> from torchmetrics.classification import MultilabelExactMatch
            >>> metric = MultilabelExactMatch(num_labels=3)
            >>> metric.update(randint(2, (20, 3, 5)), randint(2, (20, 3, 5)))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torch import rand, randint
            >>> from torchmetrics.classification import MultilabelExactMatch
            >>> metric = MultilabelExactMatch(num_labels=3)
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(randint(2, (20, 3, 5)), randint(2, (20, 3, 5))))
            >>> fig_, ax_ = metric.plot(values)

        rP   rQ   r>   r>   r?   rR   @  s    (r   )r_   r#   NT)NNrS   r>   r>   r<   r?   r^      s6   
?     r^   c                   @   sD   e Zd ZdZded eee ee ed ee ee	e
d	d	d
ZdS )
ExactMatcha  Compute Exact match (also known as subset accuracy).

    Exact Match is a stricter version of accuracy where all labels have to match exactly for the sample to be
    correctly classified.

    This module is a simple wrapper to get the task specific versions of this metric, which is done by setting the
    ``task`` argument to either ``'multiclass'`` or ``multilabel``. See the documentation of
    :class:`~torchmetrics.classification.MulticlassExactMatch` and
    :class:`~torchmetrics.classification.MultilabelExactMatch` for the specific details of each argument influence and
    examples.

    Legacy Example:
        >>> from torch import tensor
        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = ExactMatch(task="multiclass", num_classes=3, multidim_average='global')
        >>> metric(preds, target)
        tensor(0.5000)

        >>> target = tensor([[[0, 1], [2, 1], [0, 2]], [[1, 1], [2, 0], [1, 2]]])
        >>> preds = tensor([[[0, 1], [2, 1], [0, 2]], [[2, 2], [2, 1], [1, 0]]])
        >>> metric = ExactMatch(task="multiclass", num_classes=3, multidim_average='samplewise')
        >>> metric(preds, target)
        tensor([1., 0.])

    r_   Nr#   T)binaryZ
multiclassZ
multilabelr$   )	taskra   r&   r`   r'   r(   r)   r*   r+   c           	      K   s   t |}||||d |t jkrTt|tsDtdt| dt|fi |S |t j	krt|ts|tdt| dt
||fi |S td| ddS )zInitialize task metric.)r'   r(   r)   z+`num_classes` is expected to be `int` but `z was passed.`z*`num_labels` is expected to be `int` but `zTask z not supported!N)r   Zfrom_strrE   Z
MULTICLASSrI   r\   
ValueErrortyper   Z
MULTILABELr^   )	clsrd   ra   r&   r`   r'   r(   r)   r*   r>   r>   r?   __new__  s    





zExactMatch.__new__)r_   NNr#   NT)rT   rU   rV   rW   r   rZ   r   r\   rX   r   r   rh   r>   r>   r>   r?   rb   k  s$         rb   )%typingr   r   r   r   r7   r   Ztyping_extensionsr   Z torchmetrics.classification.baser   Z2torchmetrics.functional.classification.exact_matchr	   r
   r   Z2torchmetrics.functional.classification.stat_scoresr   r   r   r   r   r   Ztorchmetrics.metricr   Ztorchmetrics.utilities.datar   Ztorchmetrics.utilities.enumsr   Ztorchmetrics.utilities.importsr   Ztorchmetrics.utilities.plotr   r   Z__doctest_skip__r   r^   rb   r>   r>   r>   r?   <module>   s$      (