a
    d#                     @   s`   d dl mZ d dlZd dlmZ d dlmZ d dlmZ eeedddZG dd	 d	ej	Z
dS )
    )ListN)Tensor)KORNIA_CHECK_SHAPEpredtargetreturnc                 C   s  t | g d t |g d | jd dks:td| j | jdd |jdd ksntd| j d|j | j|jkstd	| j d|j | | jd
 | jd d}||jd
 d }|j\}}}|d}g }tj|| jddd	d|d}	t
|D ]}
d||
k }|dd|
f }||  }tj|ddd\}}||	|df }|||}|jddd}||d }|d| d }d||  }|dkr|dddf |dddf  |dddf< | | d }|| q
tj|d
d }|S )u$  Criterion that computes a surrogate multi-class intersection-over-union (IoU) loss.

    According to [1], we compute the IoU as follows:

    .. math::

        \text{IoU}(x, class) = \frac{|X \cap Y|}{|X \cup Y|}

    [1] approximates this fomular with a surrogate, which is fully differentable.

    Where:
       - :math:`X` expects to be the scores of each class.
       - :math:`Y` expects to be the binary tensor with the class labels.

    the loss, is finally computed as:

    .. math::

        \text{loss}(x, class) = 1 - \text{IoU}(x, class)

    Reference:
        [1] https://arxiv.org/pdf/1705.08790.pdf

    . note::
        This loss function only supports multi-class (C > 1) labels. For binary
        labels please use the Lovasz-Hinge loss.

    Args:
        pred: logits tensor with shape :math:`(N, C, H, W)` where C = number of classes > 1.
        labels: labels tensor with shape :math:`(N, H, W)` where each value
          is :math:`0 ≤ targets[i] ≤ C−1`.

    Return:
        a scalar with the computed loss.

    Example:
        >>> N = 5  # num_classes
        >>> pred = torch.randn(1, N, 3, 5, requires_grad=True)
        >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N)
        >>> output = lovasz_softmax_loss(pred, target)
        >>> output.backward()
    )BNHW)r	   r   r      z8Invalid pred shape, we expect BxNxHxW, with N > 1. Got: Nz.pred and target shapes must be the same. Got: z and z1pred and target must be in the same device. Got: r   )deviceg      ?T)dimZ
descending)Zkeepdim.)r   )r   shape
ValueErrorr   ZreshapefloatZsoftmaxtorchZarangerepeatrangeabssortviewsumZcumsumZrelumeanappendstack)r   r   Zpred_flattenZtarget_flattenr	   Cr
   Z	pred_softZlossesZbatch_indexcZ
foregroundZ
class_prederrorsZerrors_sortedZpermutationZtarget_sortedZtarget_sorted_sumintersectionunionZgradientZlossZ
final_loss r$   e/var/www/html/stable-diffusion-webui/venv/lib/python3.9/site-packages/kornia/losses/lovasz_softmax.pylovasz_softmax_loss   s>    +
&
,r&   c                       s8   e Zd ZdZdd fddZeeedddZ  ZS )	LovaszSoftmaxLossuF  Criterion that computes a surrogate multi-class intersection-over-union (IoU) loss.

    According to [1], we compute the IoU as follows:

    .. math::

        \text{IoU}(x, class) = \frac{|X \cap Y|}{|X \cup Y|}

    [1] approximates this fomular with a surrogate, which is fully differentable.

    Where:
       - :math:`X` expects to be the scores of each class.
       - :math:`Y` expects to be the binary tensor with the class labels.

    the loss, is finally computed as:

    .. math::

        \text{loss}(x, class) = 1 - \text{IoU}(x, class)

    Reference:
        [1] https://arxiv.org/pdf/1705.08790.pdf

    . note::
        This loss function only supports multi-class (C > 1) labels. For binary
        labels please use the Lovasz-Hinge loss.

    Args:
        pred: logits tensor with shape :math:`(N, C, H, W)` where C = number of classes > 1.
        labels: labels tensor with shape :math:`(N, H, W)` where each value
          is :math:`0 ≤ targets[i] ≤ C−1`.

    Return:
        a scalar with the computed loss.

    Example:
        >>> N = 5  # num_classes
        >>> criterion = LovaszSoftmaxLoss()
        >>> pred = torch.randn(1, N, 3, 5, requires_grad=True)
        >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N)
        >>> output = criterion(pred, target)
        >>> output.backward()
    N)r   c                    s   t    d S )N)super__init__)self	__class__r$   r%   r)      s    zLovaszSoftmaxLoss.__init__r   c                 C   s   t ||dS )N)r   r   )r&   )r*   r   r   r$   r$   r%   forward   s    zLovaszSoftmaxLoss.forward)__name__
__module____qualname____doc__r)   r   r-   __classcell__r$   r$   r+   r%   r'   e   s   ,r'   )typingr   r   Ztorch.nnnnr   Zkornia.testingr   r&   Moduler'   r$   r$   r$   r%   <module>   s   X