o
    si                     @   s6   d dl Z d dl mZ ddlmZ G dd dejZdS )    N)nn   )PITLossWrapperc                       sT   e Zd ZdZd fdd	Zedd Zejdd Zdd
dZe	dddZ
  ZS )SinkPITLossWrappera   Permutation invariant loss wrapper.

    Args:
        loss_func: function with signature (targets, est_targets, **kwargs).
        n_iter (int): number of the Sinkhorn iteration (default = 200).
            Supposed to be an even number.
        hungarian_validation (boolean) : Whether to use the Hungarian algorithm
            for the validation. (default = True)

    ``loss_func`` computes pairwise losses and returns a torch.Tensor of shape
    :math:`(batch, n\_src, n\_src)`. Each element :math:`(batch, i, j)` corresponds to
    the loss between :math:`targets[:, i]` and :math:`est\_targets[:, j]`
    It evaluates an approximate value of the PIT loss using Sinkhorn's iterative algorithm.
    See :meth:`~PITLossWrapper.best_softperm_sinkhorn` and http://arxiv.org/abs/2010.11871

    Examples
        >>> import torch
        >>> import pytorch_lightning as pl
        >>> from asteroid.losses import pairwise_neg_sisdr
        >>> sources = torch.randn(10, 3, 16000)
        >>> est_sources = torch.randn(10, 3, 16000)
        >>> # Compute SinkPIT loss based on pairwise losses
        >>> loss_func = SinkPITLossWrapper(pairwise_neg_sisdr)
        >>> loss_val = loss_func(est_sources, sources)
        >>> # A fixed temperature parameter `beta` (=10) is used
        >>> # unless a cooling callback is set. The value can be
        >>> # dynamically changed using a cooling callback module as follows.
        >>> model = NeuralNetworkModel()
        >>> optimizer = optim.Adam(model.parameters(), lr=1e-3)
        >>> dataset = YourDataset()
        >>> loader = data.DataLoader(dataset, batch_size=16)
        >>> system = System(
        >>>     model,
        >>>     optimizer,
        >>>     loss_func=SinkPITLossWrapper(pairwise_neg_sisdr),
        >>>     train_loader=loader,
        >>>     val_loader=loader,
        >>>     )
        >>>
        >>> trainer = pl.Trainer(
        >>>     max_epochs=100,
        >>>     callbacks=[SinkPITBetaScheduler(lambda epoch : 1.02 ** epoch)],
        >>>     )
        >>>
        >>> trainer.fit(system)
       Tc                    s&   t    || _d| _|| _|| _d S )N
   )super__init__	loss_func_betan_iterhungarian_validation)selfr
   r   r   	__class__ S/home/ubuntu/.local/lib/python3.10/site-packages/asteroid/losses/sinkpit_wrapper.pyr	   7   s
   

zSinkPITLossWrapper.__init__c                 C   s   | j S )Nr   )r   r   r   r   beta>   s   zSinkPITLossWrapper.betac                 C   s   |dksJ || _ d S )Nr   r   )r   r   r   r   r   r   B   s   
Fc                 K   s   |j d }|dk sJ d| | j||fi |}|jdks#J d|j d |j d ks1J d|sY| js9| jsK| || j| j\}}t	|}	|	S t
|\}}
t	|}	|	S t
|\}}
t	|}	t
||
}|	|fS )aO  Evaluate the loss using Sinkhorn's algorithm.

        Args:
            est_targets: torch.Tensor. Expected shape :math:`(batch, nsrc, ...)`.
                The batch of target estimates.
            targets: torch.Tensor. Expected shape :math:`(batch, nsrc, ...)`.
                The batch of training targets
            return_est: Boolean. Whether to return the reordered targets
                estimates (To compute metrics or to save example).
            **kwargs: additional keyword argument that will be passed to the
                loss function.

        Returns:
            - Best permutation loss for each batch sample, average over
                the batch. torch.Tensor(loss_value)
            - The reordered targets estimates if return_est is True.
                torch.Tensor of shape :math:`(batch, nsrc, ...)`.
        r   d   z(Expected source axis along dim 1, found    zBSomething went wrong with the loss function, please read the docs.r   z&PIT loss needs same batch dim as input)shaper
   ndimtrainingr   best_softperm_sinkhornr   r   torchmeanr   find_best_permreorder_source)r   est_targetstargets
return_estkwargsn_src	pw_lossesmin_loss	soft_perm	mean_lossbatch_indices	reorderedr   r   r   forwardG   s*   




zSinkPITLossWrapper.forwardr   c                 C   s   |  dd}|jd }| | }t|d D ]}|tj|ddd }|tj|ddd }qtd|||  t|}|| }|t|fS )ap  Compute an approximate PIT loss using Sinkhorn's algorithm.
        See http://arxiv.org/abs/2010.11871

        Args:
            pair_wise_losses (:class:`torch.Tensor`):
                Tensor of shape :math:`(batch, n_src, n_src)`. Pairwise losses.
            beta (float) : Inverse temperature parameter. (default = 10)
            n_iter (int) : Number of iteration. Even number. (default = 200)

        Returns:
            - :class:`torch.Tensor`:
              The loss corresponding to the best permutation of size (batch,).

            - :class:`torch.Tensor`:
              A soft permutation matrix.
           r   T)axiskeepdimz
bij,bij->b)	transposer   ranger   	logsumexpeinsumexp)pair_wise_lossesr   r   Cr#   Zitr%   r   r   r   r   y   s   

z)SinkPITLossWrapper.best_softperm_sinkhorn)r   T)F)r   r   )__name__
__module____qualname____doc__r	   propertyr   setterr*   staticmethodr   __classcell__r   r   r   r   r      s    /


2r   )r   r    r   Moduler   r   r   r   r   <module>   s    