a
    di                     @   s  d dl mZ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 d dlmZ d dlmZ d dlmZmZ d d	lmZ esg d
ZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZdS )    )AnyCallableListOptionalSequenceTupleUnionN)Tensor)Metric)rank_zero_warn)dim_zero_cat)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPE)Running)SumMetric.plotMeanMetric.plotMaxMetric.plotMinMetric.plotc                       s   e Zd ZU dZdZdZdZeed< de	e
ef e	eef e	eef eedd fdd	Zde	eef ee	eef  eeef d
ddZe	eef ddddZedddZ  ZS )BaseAggregatora  Base class for aggregation metrics.

    Args:
        fn: string specifying the reduction function
        default_value: default tensor value to use for the metric state
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        state_name: name of the metric state
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    NFfull_state_updateerrorvalue)fndefault_valuenan_strategy
state_namekwargsreturnc                    s^   t  jf i | d}||vr>t|ts>td| d| d|| _| j|||d || _d S )N)r   warnignorez6Arg `nan_strategy` should either be a float or one of z	 but got .defaultZdist_reduce_fx)super__init__
isinstancefloat
ValueErrorr   	add_stater   )selfr   r   r   r   r   Zallowed_nan_strategy	__class__ a/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/torchmetrics/aggregation.pyr%   7   s    zBaseAggregator.__init__)xweightr   c                 C   s"  t |tstj|tj| jd}|durDt |tsDtj|tj| jd}t|}|durbt|}nt| }t	|}|
 s|
 r| jdkrtd| jdv r| jdkrtdt |||B   }|||B   }n8t | jtstd| j | j|||B < | j|||B < | | fS )	z3Convert input ``x`` to a tensor and check for Nans.ZdtypedeviceNr   z Encounted `nan` values in tensor)r    r   r   z2Encounted `nan` values in tensor. Will be removed.z+`nan_strategy` shall be float but you pass )r&   r	   torch	as_tensorfloat32r2   isnanZ
zeros_likeboolZ	ones_likeanyr   RuntimeErrorr   UserWarningr'   r(   )r*   r/   r0   ZnansZnans_weightr-   r-   r.   _cast_and_nan_check_inputK   s,    






z(BaseAggregator._cast_and_nan_check_inputr   r   c                 C   s   dS )zOverwrite in child class.Nr-   )r*   r   r-   r-   r.   updatej   s    zBaseAggregator.updater   c                 C   s   t | | jS zCompute the aggregated value.)getattrr   r*   r-   r-   r.   computem   s    zBaseAggregator.compute)r   r   )N)__name__
__module____qualname____doc__Zis_differentiableZhigher_is_betterr   r7   __annotations__r   r   strr	   r   r'   r   r%   r   r   r;   r=   rB   __classcell__r-   r-   r+   r.   r      s*   
  


 
r   c                       s   e Zd ZU dZdZeed< eed< dee	e
f edd fdd	Zee
ef dd
ddZdeeeee f  ee edddZ  ZS )	MaxMetrica5  Aggregate a stream of value into their maximum value.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated maximum value over all inputs received

    Args:
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import MaxMetric
        >>> metric = MaxMetric()
        >>> metric.update(1)
        >>> metric.update(tensor([2, 3]))
        >>> metric.compute()
        tensor(3.)

    Tr   	max_valuer   Nr   r   r   c                    s,   t  jdttd |fddi| d S )Nmaxinfr   rK   r$   r%   r3   tensorr'   r*   r   r   r+   r-   r.   r%      s    zMaxMetric.__init__r<   c                 C   s0   |  |\}}| r,t| jt|| _dS zUpdate state with data.

        Args:
            value: Either a float or tensor containing data. Additional tensor
                dimensions will be flattened

        N)r;   numelr3   rM   rK   r*   r   _r-   r-   r.   r=      s    zMaxMetric.update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
            >>> from torchmetrics.aggregation import MaxMetric
            >>> metric = MaxMetric()
            >>> metric.update([1, 2, 3])
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torchmetrics.aggregation import MaxMetric
            >>> metric = MaxMetric()
            >>> values = [ ]
            >>> for i in range(10):
            ...     values.append(metric(i))
            >>> fig_, ax_ = metric.plot(values)

        Z_plotr*   rW   rX   r-   r-   r.   plot   s    &r   )r   )NNrC   rD   rE   rF   r   r7   rG   r	   r   rH   r'   r   r%   r=   r   r   r   r   r[   rI   r-   r-   r+   r.   rJ   r   s   
# 
 rJ   c                       s   e Zd ZU dZdZeed< eed< dee	e
f edd fdd	Zee
ef dd
ddZdeeeee f  ee edddZ  ZS )	MinMetrica5  Aggregate a stream of value into their minimum value.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated minimum value over all inputs received

    Args:
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import MinMetric
        >>> metric = MinMetric()
        >>> metric.update(1)
        >>> metric.update(tensor([2, 3]))
        >>> metric.compute()
        tensor(1.)

    Tr   	min_valuer   NrL   c                    s*   t  jdttd|fddi| d S )NminrN   r   r^   rO   rQ   r+   r-   r.   r%     s    zMinMetric.__init__r<   c                 C   s0   |  |\}}| r,t| jt|| _dS rR   )r;   rS   r3   r_   r^   rT   r-   r-   r.   r=     s    zMinMetric.updaterV   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 torchmetrics.aggregation import MinMetric
            >>> metric = MinMetric()
            >>> metric.update([1, 2, 3])
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torchmetrics.aggregation import MinMetric
            >>> metric = MinMetric()
            >>> values = [ ]
            >>> for i in range(10):
            ...     values.append(metric(i))
            >>> fig_, ax_ = metric.plot(values)

        rY   rZ   r-   r-   r.   r[     s    &r   )r   )NNr\   r-   r-   r+   r.   r]      s   
# 
 r]   c                       s~   e Zd ZU dZeed< deeef e	dd fddZ
eeef ddd	d
Zdeeeee f  ee edddZ  ZS )	SumMetrica!  Aggregate a stream of value into their sum.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated sum over all inputs received

    Args:
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import SumMetric
        >>> metric = SumMetric()
        >>> metric.update(1)
        >>> metric.update(tensor([2, 3]))
        >>> metric.compute()
        tensor(6.)

    	sum_valuer   NrL   c                    s&   t  jdtd|fddi| d S )Nsum        r   ra   )r$   r%   r3   rP   rQ   r+   r-   r.   r%   j  s    zSumMetric.__init__r<   c                 C   s,   |  |\}}| r(|  j| 7  _dS rR   )r;   rS   ra   rb   rT   r-   r-   r.   r=   w  s    zSumMetric.updaterV   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 torchmetrics.aggregation import SumMetric
            >>> metric = SumMetric()
            >>> metric.update([1, 2, 3])
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torch import rand, randint
            >>> from torchmetrics.aggregation import SumMetric
            >>> metric = SumMetric()
            >>> values = [ ]
            >>> for i in range(10):
            ...     values.append(metric([i, i+1]))
            >>> fig_, ax_ = metric.plot(values)

        rY   rZ   r-   r-   r.   r[     s    'r   )r   )NN)rC   rD   rE   rF   r	   rG   r   rH   r'   r   r%   r=   r   r   r   r   r[   rI   r-   r-   r+   r.   r`   D  s   
# 
 r`   c                       sd   e Zd ZU dZeed< deeef e	dd fddZ
eeef ddd	d
ZedddZ  ZS )	CatMetrica#  Concatenate a stream of values.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with concatenated values over all input received

    Args:
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import CatMetric
        >>> metric = CatMetric()
        >>> metric.update(1)
        >>> metric.update(tensor([2, 3]))
        >>> metric.compute()
        tensor([1., 2., 3.])

    r   r   NrL   c                    s   t  jdg |fi | d S )Ncat)r$   r%   rQ   r+   r-   r.   r%     s    zCatMetric.__init__r<   c                 C   s&   |  |\}}| r"| j| dS rR   )r;   rS   r   appendrT   r-   r-   r.   r=     s    zCatMetric.updater>   c                 C   s"   t | jtr| jrt| jS | jS r?   )r&   r   listr   rA   r-   r-   r.   rB     s    
zCatMetric.compute)r   )rC   rD   rE   rF   r	   rG   r   rH   r'   r   r%   r=   rB   rI   r-   r-   r+   r.   rd     s   
# 
rd   c                       s   e Zd ZU dZeed< deeef e	dd fddZ
deeef eeef 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 )
MeanMetrica  Aggregate a stream of value into their mean value.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.
    - ``weight`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float value with
      arbitary shape ``(...,)``. Needs to be broadcastable with the shape of ``value`` tensor.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated (weighted) mean over all inputs received

    Args:
       nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torchmetrics.aggregation import MeanMetric
        >>> metric = MeanMetric()
        >>> metric.update(1)
        >>> metric.update(torch.tensor([2, 3]))
        >>> metric.compute()
        tensor(2.)

    
mean_valuer   NrL   c                    s<   t  jdtd|fddi| | jdtddd d S )Nrb   rc   r   ri   r0   r"   )r$   r%   r3   rP   r)   rQ   r+   r-   r.   r%     s    zMeanMetric.__init__      ?)r   r0   r   c                 C   s   t |tstj|tj| jd}|durDt |tsDtj|tj| jd}t||j}| ||\}}|	 dkrrdS |  j
||  7  _
|  j| 7  _dS )a  Update state with data.

        Args:
            value: Either a float or tensor containing data. Additional tensor
                dimensions will be flattened
            weight: Either a float or tensor containing weights for calculating
                the average. Shape of weight should be able to broadcast with
                the shape of `value`. Default to `1.0` corresponding to simple
                harmonic average.

        r1   Nr   )r&   r	   r3   r4   r5   r2   Zbroadcast_toshaper;   rS   ri   rb   r0   )r*   r   r0   r-   r-   r.   r=   "  s    
zMeanMetric.updater>   c                 C   s   | j | j S r?   )ri   r0   rA   r-   r-   r.   rB   ;  s    zMeanMetric.computerV   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 torchmetrics.aggregation import MeanMetric
            >>> metric = MeanMetric()
            >>> metric.update([1, 2, 3])
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torchmetrics.aggregation import MeanMetric
            >>> metric = MeanMetric()
            >>> values = [ ]
            >>> for i in range(10):
            ...     values.append(metric([i, i+1]))
            >>> fig_, ax_ = metric.plot(values)

        rY   rZ   r-   r-   r.   r[   ?  s    &r   )r   )rj   )NN)rC   rD   rE   rF   r	   rG   r   rH   r'   r   r%   r=   rB   r   r   r   r   r[   rI   r-   r-   r+   r.   rh     s   
$ 
$ rh   c                       s6   e Zd ZdZdeeeef edd fddZ	  Z
S )	RunningMeanaQ	  Aggregate a stream of value into their mean over a running window.

    Using this metric compared to `MeanMetric` allows for calculating metrics over a running window of values, instead
    of the whole history of values. This is beneficial when you want to get a better estimate of the metric during
    training and don't want to wait for the whole training to finish to get epoch level estimates.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated sum over all inputs received

    Args:
        window: The size of the running window.
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import RunningMean
        >>> metric = RunningMean(window=3)
        >>> for i in range(6):
        ...     current_val = metric(tensor([i]))
        ...     running_val = metric.compute()
        ...     total_val = tensor(sum(list(range(i+1)))) / (i+1)  # total mean over all samples
        ...     print(f"{current_val=}, {running_val=}, {total_val=}")
        current_val=tensor(0.), running_val=tensor(0.), total_val=tensor(0.)
        current_val=tensor(1.), running_val=tensor(0.5000), total_val=tensor(0.5000)
        current_val=tensor(2.), running_val=tensor(1.), total_val=tensor(1.)
        current_val=tensor(3.), running_val=tensor(2.), total_val=tensor(1.5000)
        current_val=tensor(4.), running_val=tensor(3.), total_val=tensor(2.)
        current_val=tensor(5.), running_val=tensor(4.), total_val=tensor(2.5000)

       r   Nwindowr   r   r   c                    s"   t  jtf d|i||d d S Nr   )Zbase_metricro   )r$   r%   rh   r*   ro   r   r   r+   r-   r.   r%     s    zRunningMean.__init__)rm   r   rC   rD   rE   rF   intr   rH   r'   r   r%   rI   r-   r-   r+   r.   rl   h  s   1  
rl   c                       s6   e Zd ZdZdeeeef edd fddZ	  Z
S )	
RunningSuma1	  Aggregate a stream of value into their sum over a running window.

    Using this metric compared to `SumMetric` allows for calculating metrics over a running window of values, instead
    of the whole history of values. This is beneficial when you want to get a better estimate of the metric during
    training and don't want to wait for the whole training to finish to get epoch level estimates.

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

    - ``value`` (:class:`~float` or :class:`~torch.Tensor`): a single float or an tensor of float values with
      arbitary shape ``(...,)``.

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

    - ``agg`` (:class:`~torch.Tensor`): scalar float tensor with aggregated sum over all inputs received

    Args:
        window: The size of the running window.
        nan_strategy: options:
            - ``'error'``: if any `nan` values are encounted will give a RuntimeError
            - ``'warn'``: if any `nan` values are encounted will give a warning and continue
            - ``'ignore'``: all `nan` values are silently removed
            - a float: if a float is provided will impude any `nan` values with this value

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``nan_strategy`` is not one of ``error``, ``warn``, ``ignore`` or a float

    Example:
        >>> from torch import tensor
        >>> from torchmetrics.aggregation import RunningSum
        >>> metric = RunningSum(window=3)
        >>> for i in range(6):
        ...     current_val = metric(tensor([i]))
        ...     running_val = metric.compute()
        ...     total_val = tensor(sum(list(range(i+1))))  # total sum over all samples
        ...     print(f"{current_val=}, {running_val=}, {total_val=}")
        current_val=tensor(0.), running_val=tensor(0.), total_val=tensor(0)
        current_val=tensor(1.), running_val=tensor(1.), total_val=tensor(1)
        current_val=tensor(2.), running_val=tensor(3.), total_val=tensor(3)
        current_val=tensor(3.), running_val=tensor(6.), total_val=tensor(6)
        current_val=tensor(4.), running_val=tensor(9.), total_val=tensor(10)
        current_val=tensor(5.), running_val=tensor(12.), total_val=tensor(15)

    rm   r   Nrn   c                    s"   t  jtf d|i||d d S rp   )r$   r%   r`   rq   r+   r-   r.   r%     s    zRunningSum.__init__)rm   r   rr   r-   r-   r+   r.   rt     s   1  
rt   ) typingr   r   r   r   r   r   r   r3   r	   Ztorchmetrics.metricr
   Ztorchmetrics.utilitiesr   Ztorchmetrics.utilities.datar   Ztorchmetrics.utilities.importsr   Ztorchmetrics.utilities.plotr   r   Ztorchmetrics.wrappers.runningr   Z__doctest_skip__r   rJ   r]   r`   rd   rh   rl   rt   r-   r-   r-   r.   <module>   s$   $Tiii@{9