o
    si
                  
   @   s   d dl Z d dlZd dlmZ d dlmZ dd Zdd Zddd	Zd
d Zdd Z	e	ddej
dej
dedej
fddZdd Zdd Ze	dd ZdS )    N)nn)OrderedDictc                 C   sj   t | tjr
|  S t | trdd | D S t | tr,|  D ]
}t| | | |< q| S td	t
| )a{  Transfer tensor, dict or list of tensors to GPU.

    Args:
        tensors (:class:`torch.Tensor`, list or dict): May be a single, a
            list or a dictionary of tensors.

    Returns:
        :class:`torch.Tensor`:
        Same as input but transferred to cuda. Goes through lists and dicts
        and transfers the torch.Tensor to cuda. Leaves the rest untouched.
    c                 S   s   g | ]}t |qS  )to_cuda.0tensr   r   N/home/ubuntu/.local/lib/python3.10/site-packages/asteroid/utils/torch_utils.py
<listcomp>   s    zto_cuda.<locals>.<listcomp>zNtensors must be a tensor or a list or dict of tensors.  Got tensors of type {})
isinstancetorchTensorcudalistdictkeysr   	TypeErrorformattype)tensorskeyr   r   r	   r      s   


r   c                    sh   t | tjr|  S t | ttfr fdd| D S t | tr2|  D ]}t| |  | |< q$| S | S )a  Transfer tensor, dict or list of tensors to device.

    Args:
        tensors (:class:`torch.Tensor`): May be a single, a list or a
            dictionary of tensors.
        device (:class: `torch.device`): the device where to place the tensors.

    Returns:
        Union [:class:`torch.Tensor`, list, tuple, dict]:
            Same as input but transferred to device.
            Goes through lists and dicts and transfers the torch.Tensor to
            device. Leaves the rest untouched.
    c                    s   g | ]}t | qS r   )tensors_to_devicer   devicer   r	   r
   3   s    z%tensors_to_device.<locals>.<listcomp>)	r   r   r   tor   tupler   r   r   )r   r   r   r   r   r	   r   "   s   

r   c                 C   sN   t | dr| jS t | drt|  jS |du r"tdt|  dt|S )as  Get the device of a tensor or a module.

    Args:
        tensor_or_module (Union[torch.Tensor, torch.nn.Module]):
            The object to get the device from. Can be a ``torch.Tensor``,
            a ``torch.nn.Module``, or anything else that has a ``device`` attribute
            or a ``parameters() -> Iterator[torch.Tensor]`` method.
        default (Optional[Union[str, torch.device]]): If the device can not be
            determined, return this device instead. If ``None`` (the default),
            raise a ``TypeError`` instead.

    Returns:
        torch.device: The device that ``tensor_or_module`` is on.
    r   
parametersNz Don't know how to get device of z object)hasattrr   nextr   r   r   r   )tensor_or_moduledefaultr   r   r	   
get_device<   s   


r!   c                   C   s
   t j S )z
    Returns ``True`` in tracing (if a function is called during the tracing of
    code with ``torch.jit.trace``) and ``False`` otherwise.
    )r   _C_is_tracingr   r   r   r	   
is_tracingU   s   
r$   c                    s(   t   fdd _d_S )a  
    Compiles ``fn`` when it is first called during tracing. ``torch.jit.script``
    has a non-negligible start up time when it is first called due to
    lazy-initializations of many compiler builtins. Therefore you should not use
    it in library code. However, you may want to have parts of your library work
    in tracing even if they use control flow. In these cases, you should use
    ``@torch.jit.script_if_tracing`` to substitute for
    ``torch.jit.script``.

    Arguments:
        fn: A function to compile.

    Returns:
        If called during tracing, a :class:`ScriptFunction` created by `
        `torch.jit.script`` is returned. Otherwise, the original function ``fn`` is returned.
    c                     s0   t  s
 | i |S tjj}|| i |S N)r$   r   jitscript__original_fn)argskwargscompiled_fnfnwrapperr   r	   r.   q   s   z"script_if_tracing.<locals>.wrapperT)	functoolswrapsr(   __script_if_tracing_wrapper)r-   r   r,   r	   script_if_tracing^   s
   r2   xyaxisreturnc                 C   s6   |dkrt |j| }| j| }tj| d|| gS )a#  Right-pad or right-trim first argument to have same size as second argument

    Args:
        x (torch.Tensor): Tensor to be padded.
        y (torch.Tensor): Tensor to pad `x` to.
        axis (int): Axis to pad on.

    Returns:
        torch.Tensor, `x` padded to match `y`'s shape.
    r3   r   )NotImplementedErrorshaper   
functionalpad)r4   r5   r6   inp_len
output_lenr   r   r	   
pad_x_to_y   s
   

r>   c                 C   sn   z
|j | dd W |S  ty6   t }|  D ]\}}||dd d }|||< q|j |dd Y |S w )a  Strictly loads state_dict in model, or the next submodel.
        Useful to load standalone model after training it with System.

    Args:
        state_dict (OrderedDict): the state_dict to load.
        model (torch.nn.Module): the model to load it into

    Returns:
        torch.nn.Module: model with loaded weights.

    .. note:: Keys in a state_dict look like ``object1.object2.layer_name.weight.etc``
        We first try to load the model in the classic way.
        If this fail we removes the first left part of the key to obtain
        ``object2.layer_name.weight.etc``.
        Blindly loading with ``strictly=False`` should be done with some logging
        of the missing keys in the state_dict and the model.

    T)strict.   N)load_state_dictRuntimeErrorr   itemsfind)
state_dictmodelnew_state_dictkvnew_kr   r   r	   load_state_dict_in   s   
rL   c                 C   s<   t |  | D ]\}}|j|j dkr dS q	dS )zCheck for weights equality between models.

    Args:
        model1 (nn.Module): model instance to be compared.
        model2 (nn.Module): second model instance to be compared.

    Returns:
        bool: Whether all model weights are equal.
    r   FT)zipr   datanesum)model1model2p1p2r   r   r	   are_models_equal   s
   
rU   c                 C   s   t | jS )aM  Gets shape of ``tensor`` as ``torch.Tensor`` type for jit compiler

    .. note::
        Returning ``tensor.shape`` of ``tensor.size()`` directly is not torchscript
        compatible as return type would not be supported.

    Args:
        tensor (torch.Tensor): Tensor

    Returns:
        torch.Tensor: Shape of ``tensor``
    )r   tensorr9   )rV   r   r   r	   jitable_shape   s   rW   r%   )r3   )r/   r   r   collectionsr   r   r   r!   r$   r2   r   intr>   rL   rU   rW   r   r   r   r	   <module>   s    
	"$%