o
    ei                     @   s0  d Z ddlZddlmZ ddlZddlZddlmZ ddl	m  m
Z ddlZddlmZmZ ddlmZ eeZG dd dejZG dd	 d	ejZG d
d dejZG dd dejZG dd dejZG dd dejZG dd dejZdedededefddZdedededededefddZdS )zLibrary implementing convolutional neural networks.

Authors
 * Mirco Ravanelli 2020
 * Jianyuan Zhong 2020
 * Cem Subakan 2021
 * Davide Borra 2021
 * Andreas Nautsch 2022
 * Sarthak Yadav 2022
    N)Tuple)gabor_impulse_response%gabor_impulse_response_legacy_complex)
get_loggerc                       sz   e Zd ZdZ									d fdd		Zd
d Zdd Zdd Zdd Zdd Z	dd Z
dededefddZ  ZS )SincConva  This function implements SincConv (SincNet).

    M. Ravanelli, Y. Bengio, "Speaker Recognition from raw waveform with
    SincNet", in Proc. of  SLT 2018 (https://arxiv.org/abs/1808.00158)

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size: int
        Kernel size of the convolutional filters.
    input_shape : tuple
        The shape of the input. Alternatively use ``in_channels``.
    in_channels : int
        The number of input channels. Alternatively use ``input_shape``.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        a decimation in time is performed.
    dilation : int
        Dilation factor of the convolutional filters.
    padding : str
        (same, valid, causal). If "valid", no padding is performed.
        If "same" and stride is 1, output shape is the same as the input shape.
        "causal" results in causal (dilated) convolutions.
    padding_mode : str
        This flag specifies the type of padding. See torch.nn documentation
        for more information.
    sample_rate : int
        Sampling rate of the input signals. It is only used for sinc_conv.
    min_low_hz : float
        Lowest possible frequency (in Hz) for a filter. It is only used for
        sinc_conv.
    min_band_hz : float
        Lowest possible value (in Hz) for a filter bandwidth.

    Example
    -------
    >>> inp_tensor = torch.rand([10, 16000])
    >>> conv = SincConv(input_shape=inp_tensor.shape, out_channels=25, kernel_size=11)
    >>> out_tensor = conv(inp_tensor)
    >>> out_tensor.shape
    torch.Size([10, 16000, 25])
    N   samereflect>  2   c                    s   t    || _|| _|| _|| _|| _|| _|| _|	| _	|
| _
|| _|d u r0| jd u r0td| jd u r;| || _| j| j dkrGtd|   d S )N.Must provide one of input_shape or in_channelsr   z:Number of output channels must be divisible by in_channels)super__init__in_channelsout_channelskernel_sizestridedilationpaddingpadding_modesample_rate
min_low_hzmin_band_hz
ValueError_check_input_shape_init_sinc_conv)selfr   r   input_shaper   r   r   r   r   r   r   r   	__class__ R/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/speechbrain/nnet/CNN.pyr   K   s(   

zSincConv.__init__c                 C   s   | dd}|j| _|jdk}|r|d}| jdkr'| || j| j| j}n#| jdkr=| jd | j }t	
||df}n| jdkrCntd| j |  }t	j||| jd| j| jd	}|rc|d}| dd}|S )
   Returns the output of the convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve. 2d or 4d tensors are expected.

        Returns
        -------
        wx : torch.Tensor
            The convolved outputs.
        r      r   causalr   validz4Padding must be 'same', 'valid' or 'causal'. Got %s.)r   r   r   groups)	transposedevicendim	unsqueezer   _manage_paddingr   r   r   Fpadr   _get_sinc_filtersconv1dr   squeeze)r   xr+   num_padsinc_filterswxr    r    r!   forwardt   s@   




	
zSincConv.forwardc                 C   s\   t |dkr	d}nt |dkr|d }n
tdtt | | jd dkr,td| j |S )@Checks the input shape and returns the number of input channels.r$   r      r#   z&sincconv expects 2d or 3d inputs. Got r   4The field kernel size must be an odd number. Got %s.lenr   strr   r   shaper   r    r    r!   r      s   
zSincConv._check_input_shapec                 C   s  | j t| j }t|| j t| j | j | jd }|| dddf }| j	| j
| _| j	| j
| _t|| j}t|| j}t|t| | jd  | j }d|dd }tj|dgd}tj|||gdd}	|	d|dddf   }	|	| jd| j}
|
S )z>This functions creates the sinc-filters to used for sinc-conv.r$   Nr   r#   r   )dimsdim)r   torchabslow_hz_clampr   band_hz_r   n_tor)   window_matmulsinviewflipcatr   r   )r   lowhighbandf_times_t_lowf_times_t_highband_pass_leftband_pass_centerband_pass_right	band_passfiltersr    r    r!   r/      s0   
zSincConv._get_sinc_filtersc                 C   s  | j d | j| j  }t| | j| || jd }| |}|dd d| _	|dd |dd  d| _
t| j	| _	t| j
| _
tjd| jd d t| jd d}ddtdtj | | j   | _| jd d	 }dtj t| ddd | j  | _dS )
z2Initializes the parameters of the sinc_conv layer.r$   r   Nr#   r   )stepsgHzG?gq=
ףp?       @)r   r   r   rB   linspace_to_melr   _to_hzr+   rD   rF   nn	Parameterr   intcosmathpirI   arangerL   rG   )r   high_hzmelhzn_linnr    r    r!   r      s(   

 
$zSincConv._init_sinc_convc                 C   s   dt d|d   S )z*Converts frequency in Hz to the mel scale.#
  r     )nplog10)r   rg   r    r    r!   r\     s   zSincConv._to_melc                 C   s   dd|d  d  S )z*Converts frequency in the mel scale to Hz.rk   
   rj   r   r    )r   rf   r    r    r!   r]        zSincConv._to_hzr   r   r   c                 C   *   | j }t||||}tj||| jd}|S )a  This function performs zero-padding on the time axis
        such that their lengths is unchanged after the convolution.

        Arguments
        ---------
        x : torch.Tensor
            Input tensor.
        kernel_size : int
            Size of kernel.
        dilation : int
            Dilation used.
        stride : int
            Stride.

        Returns
        -------
        x : torch.Tensor
        moder   get_padding_elemr-   r.   r   r   r2   r   r   r   L_inr   r    r    r!   r,     s   zSincConv._manage_padding)	NNr   r   r   r	   r
   r   r   )__name__
__module____qualname____doc__r   r6   r   r/   r   r\   r]   r`   r,   __classcell__r    r    r   r!   r      s&    0)8,$r   c                       sh   e Zd ZdZ												d fd	d
	Zdd ZdededefddZdd Zdd Z	  Z
S )Conv1dal  This function implements 1d convolution.

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size : int
        Kernel size of the convolutional filters.
    input_shape : tuple
        The shape of the input. Alternatively use ``in_channels``.
    in_channels : int
        The number of input channels. Alternatively use ``input_shape``.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        a decimation in time is performed.
    dilation : int
        Dilation factor of the convolutional filters.
    padding : str
        (same, valid, causal). If "valid", no padding is performed.
        If "same" and stride is 1, output shape is the same as the input shape.
        "causal" results in causal (dilated) convolutions.
    groups : int
        Number of blocked connections from input channels to output channels.
    bias : bool
        Whether to add a bias term to convolution operation.
    padding_mode : str
        This flag specifies the type of padding. See torch.nn documentation
        for more information.
    skip_transpose : bool
        If False, uses batch x time x channel convention of speechbrain.
        If True, uses batch x channel x time convention.
    weight_norm : bool
        If True, use weight normalization,
        to be removed with self.remove_weight_norm() at inference
    conv_init : str
        Weight initialization for the convolution network
    default_padding: str or int
        This sets the default padding mode that will be used by the pytorch Conv1d backend.

    Example
    -------
    >>> inp_tensor = torch.rand([10, 40, 16])
    >>> cnn_1d = Conv1d(
    ...     input_shape=inp_tensor.shape, out_channels=8, kernel_size=5
    ... )
    >>> out_tensor = cnn_1d(inp_tensor)
    >>> out_tensor.shape
    torch.Size([10, 40, 8])
    Nr   r   Tr	   Fr   c              
      s   t    || _|| _|| _|| _|
| _d| _|| _|d u r&|d u r&t	d|d u r/| 
|}|| _tj||| j| j| j|||	d| _|dkrPtj| jj n|dkr]tj| jj n|dkrktjj| jjdd |rwtj| j| _d S d S )	NFr   r   r   r   r'   biaskaimingzeronormalgư>)std)r   r   r   r   r   r   r   r+   skip_transposer   r   r   r^   r|   convinitkaiming_normal_weightzeros_normal_utilsweight_norm)r   r   r   r   r   r   r   r   r'   r~   r   r   r   	conv_initdefault_paddingr   r    r!   r   k  s@   

zConv1d.__init__c                 C   s   | j s	|dd}| jr|d}| jdkr"| || j| j| j}n#| jdkr8| jd | j }t	||df}n| jdkr>nt
d| j | |}| jrR|d}| j s[|dd}|S )r"   r   r#   r   r%   r   r&   z1Padding must be 'same', 'valid' or 'causal'. Got )r   r(   r+   r   r,   r   r   r   r-   r.   r   r   r1   r   r2   r3   r5   r    r    r!   r6     s0   





zConv1d.forwardr   r   r   c                 C   rp   )a  This function performs zero-padding on the time axis
        such that their lengths is unchanged after the convolution.

        Arguments
        ---------
        x : torch.Tensor
            Input tensor.
        kernel_size : int
            Size of kernel.
        dilation : int
            Dilation used.
        stride : int
            Stride.

        Returns
        -------
        x : torch.Tensor
            The padded outputs.
        rq   rs   ru   r    r    r!   r,     s   zConv1d._manage_paddingc                 C   s|   t |dkrd| _d}n| jr|d }nt |dkr|d }n
tdtt | | jdks<| jd dkr<td| j |S )	r7   r$   Tr   r8   "conv1d expects 2d, 3d inputs. Got r&   r   r9   )r;   r+   r   r   r<   r   r   r=   r    r    r!   r     s"   

zConv1d._check_input_shapec                 C      t j| j| _dS zBRemoves weight normalization at inference if used during training.Nr^   r   remove_weight_normr   r   r    r    r!   r   	  ro   zConv1d.remove_weight_norm)NNr   r   r   r   Tr	   FFNr   )rw   rx   ry   rz   r   r6   r`   r,   r   r   r{   r    r    r   r!   r|   8  s&    67/ r|   c                       s   e Zd ZdZ													d fd	d
	Zdd Zdeeef deeef deeef fddZdd Z	dd Z
  ZS )Conv2da  This function implements 2d convolution.

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size : tuple
        Kernel size of the 2d convolutional filters over time and frequency
        axis.
    input_shape : tuple
        The shape of the input. Alternatively use ``in_channels``.
    in_channels : int
        The number of input channels. Alternatively use ``input_shape``.
    stride: int
        Stride factor of the 2d convolutional filters over time and frequency
        axis.
    dilation : int
        Dilation factor of the 2d convolutional filters over time and
        frequency axis.
    padding : str
        (same, valid, causal).
        If "valid", no padding is performed.
        If "same" and stride is 1, output shape is same as input shape.
        If "causal" then proper padding is inserted to simulate causal convolution on the first spatial dimension.
        (spatial dim 1 is dim 3 for both skip_transpose=False and skip_transpose=True)
    groups : int
        This option specifies the convolutional groups. See torch.nn
        documentation for more information.
    bias : bool
        If True, the additive bias b is adopted.
    padding_mode : str
        This flag specifies the type of padding. See torch.nn documentation
        for more information.
    max_norm : float
        kernel max-norm.
    swap : bool
        If True, the convolution is done with the format (B, C, W, H).
        If False, the convolution is dine with (B, H, W, C).
        Active only if skip_transpose is False.
    skip_transpose : bool
        If False, uses batch x spatial.dim2 x spatial.dim1 x channel convention of speechbrain.
        If True, uses batch x channel x spatial.dim1 x spatial.dim2 convention.
    weight_norm : bool
        If True, use weight normalization,
        to be removed with self.remove_weight_norm() at inference
    conv_init : str
        Weight initialization for the convolution network

    Example
    -------
    >>> inp_tensor = torch.rand([10, 40, 16, 8])
    >>> cnn_2d = Conv2d(
    ...     input_shape=inp_tensor.shape, out_channels=5, kernel_size=(7, 3)
    ... )
    >>> out_tensor = cnn_2d(inp_tensor)
    >>> out_tensor.shape
    torch.Size([10, 40, 16, 5])
    Nr   r   r   r   Tr	   Fc              
      s  t    t|tr||f}t|tr||f}t|tr ||f}|| _|| _|| _|| _|
| _d| _	|| _
|| _|| _|d u rG|d u rGtd|d u rP| |}|| _tj| j|| j| jd| j||	d| _|dkrrtj| jj n|dkr~tj| jj |rtj| j| _d S d S )NFr   r   )r   r   r   r'   r~   r   r   )r   r   
isinstancer`   r   r   r   r   r   r+   max_normswapr   r   _check_inputr   r^   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   r   r   r'   r~   r   r   r   r   r   r   r   r    r!   r   J  sL   




zConv2d.__init__c                 C   s  | j s|dd}| jr|dd}| jr|d}| jdkr+| || j| j| j}n)| jdkrG| jd d | jd  }t	
|dd|df}n| jdkrMntd| j | jd	uritj| jjjd
d| jd| jj_| |}| jrv|d}| j s|dd}| jr|dd
}|S )a'  Returns the output of the convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve. 2d or 4d tensors are expected.

        Returns
        -------
        x : torch.Tensor
            The output of the convolution.
        r   r#   r   r%   r   r&   z0Padding must be 'same','valid' or 'causal'. Got Nr$   )prA   maxnorm)r   r(   r   r+   r   r,   r   r   r   r-   r.   r   r   rB   renormr   r   datar1   r   r    r    r!   r6     s@   






zConv2d.forwardr   r   r   c           	      C   sZ   | j }t||d |d |d }t||d |d |d }|| }tjj||| jd}|S )a  This function performs zero-padding on the time and frequency axes
        such that their lengths is unchanged after the convolution.

        Arguments
        ---------
        x : torch.Tensor
            Input to be padded
        kernel_size : int
            Size of the kernel for computing padding
        dilation : int
            Dilation rate for computing padding
        stride: int
            Stride for computing padding

        Returns
        -------
        x : torch.Tensor
            The padded outputs.
        r#   r   rq   )r   rt   r^   
functionalr.   r   )	r   r2   r   r   r   rv   padding_timepadding_freqr   r    r    r!   r,     s   zConv2d._manage_paddingc                 C   s~   t |dkrd| _d}nt |dkr|d }ntdt | | jdks=| jd d dks6| jd d dkr=td	| j |S )
r7   r8   Tr      zExpected 3d or 4d inputs. Got r&   r   r$   r9   )r;   r+   r   r   r   r=   r    r    r!   r     s   

$zConv2d._check_inputc                 C   r   r   r   r   r    r    r!   r     ro   zConv2d.remove_weight_norm)NNr   r   r   r   Tr	   NFFFN)rw   rx   ry   rz   r   r6   r   r`   r,   r   r   r{   r    r    r   r!   r     s4    ?B7



,r   c                       sP   e Zd ZdZ										d fdd	Zdd	d
Zdd Zdd Z  ZS )ConvTranspose1da>  This class implements 1d transposed convolution with speechbrain.
    Transpose convolution is normally used to perform upsampling.

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size : int
        Kernel size of the convolutional filters.
    input_shape : tuple
        The shape of the input. Alternatively use ``in_channels``.
    in_channels : int
        The number of input channels. Alternatively use ``input_shape``.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        upsampling in time is performed.
    dilation : int
        Dilation factor of the convolutional filters.
    padding : str or int
        To have in output the target dimension, we suggest tuning the kernel
        size and the padding properly. We also support the following function
        to have some control over the padding and the corresponding output
        dimensionality.
        if "valid", no padding is applied
        if "same", padding amount is inferred so that the output size is closest
        to possible to input size. Note that for some kernel_size / stride combinations
        it is not possible to obtain the exact same size, but we return the closest
        possible size.
        if "factor", padding amount is inferred so that the output size is closest
        to inputsize*stride. Note that for some kernel_size / stride combinations
        it is not possible to obtain the exact size, but we return the closest
        possible size.
        if an integer value is entered, a custom padding is used.
    output_padding : int,
        Additional size added to one side of the output shape
    groups: int
        Number of blocked connections from input channels to output channels.
        Default: 1
    bias: bool
        If True, adds a learnable bias to the output
    skip_transpose : bool
        If False, uses batch x time x channel convention of speechbrain.
        If True, uses batch x channel x time convention.
    weight_norm : bool
        If True, use weight normalization,
        to be removed with self.remove_weight_norm() at inference

    Example
    -------
    >>> from speechbrain.nnet.CNN import Conv1d, ConvTranspose1d
    >>> inp_tensor = torch.rand([10, 12, 40]) #[batch, time, fea]
    >>> convtranspose_1d = ConvTranspose1d(
    ...     input_shape=inp_tensor.shape, out_channels=8, kernel_size=3, stride=2
    ... )
    >>> out_tensor = convtranspose_1d(inp_tensor)
    >>> out_tensor.shape
    torch.Size([10, 25, 8])

    >>> # Combination of Conv1d and ConvTranspose1d
    >>> from speechbrain.nnet.CNN import Conv1d, ConvTranspose1d
    >>> signal = torch.tensor([1,100])
    >>> signal = torch.rand([1,100]) #[batch, time]
    >>> conv1d = Conv1d(input_shape=signal.shape, out_channels=1, kernel_size=3, stride=2)
    >>> conv_out = conv1d(signal)
    >>> conv_t = ConvTranspose1d(input_shape=conv_out.shape, out_channels=1, kernel_size=3, stride=2, padding=1)
    >>> signal_rec = conv_t(conv_out, output_size=[100])
    >>> signal_rec.shape
    torch.Size([1, 100])

    >>> signal = torch.rand([1,115]) #[batch, time]
    >>> conv_t = ConvTranspose1d(input_shape=signal.shape, out_channels=1, kernel_size=3, stride=2, padding='same')
    >>> signal_rec = conv_t(signal)
    >>> signal_rec.shape
    torch.Size([1, 115])

    >>> signal = torch.rand([1,115]) #[batch, time]
    >>> conv_t = ConvTranspose1d(input_shape=signal.shape, out_channels=1, kernel_size=7, stride=2, padding='valid')
    >>> signal_rec = conv_t(signal)
    >>> signal_rec.shape
    torch.Size([1, 235])

    >>> signal = torch.rand([1,115]) #[batch, time]
    >>> conv_t = ConvTranspose1d(input_shape=signal.shape, out_channels=1, kernel_size=7, stride=2, padding='factor')
    >>> signal_rec = conv_t(signal)
    >>> signal_rec.shape
    torch.Size([1, 231])

    >>> signal = torch.rand([1,115]) #[batch, time]
    >>> conv_t = ConvTranspose1d(input_shape=signal.shape, out_channels=1, kernel_size=3, stride=2, padding=10)
    >>> signal_rec = conv_t(signal)
    >>> signal_rec.shape
    torch.Size([1, 211])

    Nr   r   TFc              
      s.  t    || _|| _|| _|| _d| _|| _|d u r#|d u r#td|d u r,| 	|}| jdkrF|r7|d n|d }t
||||||d}n2| jdkrb|rQ|d n|d }t
|| |||||d}n| jdkrjd	}nt| jtu rt|}ntd
tj||| j| j| j||	|
d| _|rtj| j| _d S d S )NFr   r   r#   r   )r   r   r   output_paddingfactorr&   r   zNot supported padding typer}   )r   r   r   r   r   r   r+   r   r   r   get_padding_elem_transposedtyper`   r^   r   r   r   r   )r   r   r   r   r   r   r   r   r   r'   r~   r   r   rv   padding_valuer   r    r!   r   l  sb   




zConvTranspose1d.__init__c                 C   sV   | j s	|dd}| jr|d}| j||d}| jr |d}| j s)|dd}|S )aZ  Returns the output of the convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve. 2d or 4d tensors are expected.
        output_size : int
            The size of the output

        Returns
        -------
        x : torch.Tensor
            The convolved output
        r   r#   )output_size)r   r(   r+   r   r1   )r   r2   r   r5   r    r    r!   r6     s   

zConvTranspose1d.forwardc                 C   sX   t |dkrd| _d}|S | jr|d }|S t |dkr"|d }|S tdtt | )r7   r$   Tr   r8   r   )r;   r+   r   r   r<   r=   r    r    r!   r     s   
z"ConvTranspose1d._check_input_shapec                 C   r   r   r   r   r    r    r!   r     ro   z"ConvTranspose1d.remove_weight_norm)
NNr   r   r   r   r   TFFN)	rw   rx   ry   rz   r   r6   r   r   r{   r    r    r   r!   r     s     c
F r   c                       2   e Zd ZdZ				d	 fdd	Zdd Z  ZS )
DepthwiseSeparableConv1dap  This class implements the depthwise separable 1d convolution.

    First, a channel-wise convolution is applied to the input
    Then, a point-wise convolution to project the input to output

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size : int
        Kernel size of the convolutional filters.
    input_shape : tuple
        Expected shape of the input.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        a decimation in time is performed.
    dilation : int
        Dilation factor of the convolutional filters.
    padding : str
        (same, valid, causal). If "valid", no padding is performed.
        If "same" and stride is 1, output shape is the same as the input shape.
        "causal" results in causal (dilated) convolutions.
    bias : bool
        If True, the additive bias b is adopted.

    Example
    -------
    >>> inp = torch.randn([8, 120, 40])
    >>> conv = DepthwiseSeparableConv1d(256, 3, input_shape=inp.shape)
    >>> out = conv(inp)
    >>> out.shape
    torch.Size([8, 120, 256])
    r   r   Tc              
      sV   t    t|dksJ d|\}}	}
t|
||||||
|d| _t|d|d| _d S )Nr8   zinput must be a 3d tensorr   r   r   r   r'   r~   r   r   r   )r   r   r;   r|   	depthwise	pointwise)r   r   r   r   r   r   r   r~   bztimechnr   r    r!   r     s$   


z!DepthwiseSeparableConv1d.__init__c                 C   s   |  | |S )zReturns the output of the convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve. 3d tensors are expected.

        Returns
        -------
        The convolved outputs.
        )r   r   )r   r2   r    r    r!   r6   ,  s   z DepthwiseSeparableConv1d.forward)r   r   r   Trw   rx   ry   rz   r   r6   r{   r    r    r   r!   r     s    '!r   c                       r   )
DepthwiseSeparableConv2da  This class implements the depthwise separable 2d convolution.

    First, a channel-wise convolution is applied to the input
    Then, a point-wise convolution to project the input to output

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size : int
        Kernel size of the convolutional filters.
    input_shape : tuple
        Expected shape of the input tensors.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        a decimation in time is performed.
    dilation : int
        Dilation factor of the convolutional filters.
    padding : str
        (same, valid, causal). If "valid", no padding is performed.
        If "same" and stride is 1, output shape is the same as the input shape.
        "causal" results in causal (dilated) convolutions.
    bias : bool
        If True, the additive bias b is adopted.

    Example
    -------
    >>> inp = torch.randn([8, 120, 40, 1])
    >>> conv = DepthwiseSeparableConv2d(256, (3, 3), input_shape=inp.shape)
    >>> out = conv(inp)
    >>> out.shape
    torch.Size([8, 120, 40, 256])
    r   r   Tc              
      s   t    t|tr||f}t|tr||f}t|tr ||f}t|dv s*J dt|dk| _|\}}	}
}t||||||||d| _t|d|d| _d S )N>   r8   r   zinput must be a 3d or 4d tensorr8   r   r   r   )	r   r   r   r`   r;   r+   r   r   r   )r   r   r   r   r   r   r   r~   r   r   chn1chn2r   r    r!   r   ^  s2   




z!DepthwiseSeparableConv2d.__init__c                 C   s4   | j r| d}| | |}| j r|d}|S )a  Returns the output of the convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve. 3d tensors are expected.

        Returns
        -------
        out : torch.Tensor
            The convolved output.
        r   )r+   r   r   r1   )r   r2   outr    r    r!   r6     s   

z DepthwiseSeparableConv2d.forward)r   r   r   Tr   r    r    r   r!   r   ;  s    '*r   c                       s|   e Zd ZdZ													d fd	d
	Zdd Zdd Zdd Zdd Zdd Z	dd Z
dd Zdd Z  ZS )GaborConv1da  
    This class implements 1D Gabor Convolutions from

    Neil Zeghidour, Olivier Teboul, F{'e}lix de Chaumont Quitry & Marco Tagliasacchi, "LEAF: A LEARNABLE FRONTEND
    FOR AUDIO CLASSIFICATION", in Proc. of ICLR 2021 (https://arxiv.org/abs/2101.08596)

    Arguments
    ---------
    out_channels : int
        It is the number of output channels.
    kernel_size: int
        Kernel size of the convolutional filters.
    stride : int
        Stride factor of the convolutional filters. When the stride factor > 1,
        a decimation in time is performed.
    input_shape : tuple
        Expected shape of the input.
    in_channels : int
        Number of channels expected in the input.
    padding : str
        (same, valid). If "valid", no padding is performed.
        If "same" and stride is 1, output shape is the same as the input shape.
    padding_mode : str
        This flag specifies the type of padding. See torch.nn documentation
        for more information.
    sample_rate : int,
        Sampling rate of the input signals. It is only used for sinc_conv.
    min_freq : float
        Lowest possible frequency (in Hz) for a filter
    max_freq : float
        Highest possible frequency (in Hz) for a filter
    n_fft: int
        number of FFT bins for initialization
    normalize_energy: bool
        whether to normalize energy at initialization. Default is False
    bias : bool
        If True, the additive bias b is adopted.
    sort_filters: bool
        whether to sort filters by center frequencies. Default is False
    use_legacy_complex: bool
        If False, torch.complex64 data type is used for gabor impulse responses
        If True, computation is performed on two real-valued tensors
    skip_transpose: bool
        If False, uses batch x time x channel convention of speechbrain.
        If True, uses batch x channel x time convention.

    Example
    -------
    >>> inp_tensor = torch.rand([10, 8000])
    >>> # 401 corresponds to a window of 25 ms at 16000 kHz
    >>> gabor_conv = GaborConv1d(
    ...     40, kernel_size=401, stride=1, in_channels=1
    ... )
    >>> #
    >>> out_tensor = gabor_conv(inp_tensor)
    >>> out_tensor.shape
    torch.Size([10, 8000, 40])
    Nr   constantr
         N@   Fc                    s   t    |d | _|| _|| _|| _|| _|| _|| _|	| _	|
d u r'|d }
|
| _
|| _|| _|| _|| _|d u rB|d u rBtd|d u rK| |}t|  | _|rdtjt| jd | _d S d | _d S )Nr$   r   )r   r   rX   r   r   r   r   sort_filtersr   min_freqmax_freqn_fftnormalize_energyuse_legacy_complexr   r   r   r^   r_   _initialize_kernelkernelrB   onesr~   )r   r   r   r   r   r   r   r   r   r   r   r   r   r~   r   r   r   r   r    r!   r     s0   



zGaborConv1d.__init__c                 C   sx  | j s	|dd}|jdk}|r|d}| | j}| jr1t|dddf }||ddf }| 	|}| j
sUt|}|dddddf }|dddddf }n|dddddf }|dddddf }tj|d|dgdd}	t|	d| j | jf}	|	d}	| jdkr| || j}n| jdkrntd	| j tj||	| j| jdd
}
| j s|
dd}
|
S )a  Returns the output of the Gabor convolution.

        Arguments
        ---------
        x : torch.Tensor (batch, time, channel)
            input to convolve.

        Returns
        -------
        x : torch.Tensor
            The output of the Gabor convolution
        r   r#   r$   Nr   r@   r   r&   z'Padding must be 'same' or 'valid'. Got )r~   r   r   )r   r(   r*   r+   _gabor_constraintr   r   rB   argsort_gabor_filtersr   view_as_realrN   reshaperX   r   r   r,   r   r-   r0   r~   r   )r   r2   r+   r   idxsrX   tempreal_filtersimg_filtersstacked_filtersoutputr    r    r!   r6     sH   






zGaborConv1d.forwardc              
   C   s   d}t j}dtdttjd|jd  t j }| jtdttjd|jd  t j }t|d d df ||	d}t|d d df ||	d}tj
||gddS )	Ng        r   rZ   )r)   r   r   r#   r@   )rb   rc   rB   sqrtlogtensorr)   r   rE   r+   rN   )r   kernel_datamu_lowermu_uppersigma_lowersigma_upper
clipped_muclipped_sigmar    r    r!   r   E  s:   zGaborConv1d._gabor_constraintc                 C   sz   t j| jd  | jd d |j|jd}| js*t||d d df |d d df dS t||d d df |d d df dS )Nr$   r   )dtyper)   r   )centerfwhm)rB   rd   r   r   r)   r   r   r   )r   r   tr    r    r!   r   ^  s   
zGaborConv1d._gabor_filtersc                 C   s(   dd }||}t j||| jdd}|S )Nc                 S   s@   | f}ddl m} ddlm} ||dd |ddd D }|S )z#Gets the number of elements to pad.r   )reduce)__add__c                 S   s0   g | ]}|d  |d |d     d |d  fqS )r$   r   r    ).0kr    r    r!   
<listcomp>z  s    "zJGaborConv1d._manage_padding.<locals>.get_padding_value.<locals>.<listcomp>Nr#   )	functoolsr   operatorr   )r   kernel_sizesr   r   conv_paddingr    r    r!   get_padding_valuer  s   z6GaborConv1d._manage_padding.<locals>.get_padding_valuer   )rr   value)r-   r.   r   )r   r2   r   r   	pad_valuer    r    r!   r,   n  s   zGaborConv1d._manage_paddingc                    sV    fdd}t jj jd d  j j j jd}|dd} j	r)||| }|S )Nc                    s@   t j| ddd\}}|t j| dk dddd  tj  j S )Nr   TrA   keepdimr   r$   )rB   maxsumfloatrl   rc   r   )rX   peaks_r   r    r!   _mel_filters_areas  s   z4GaborConv1d._mel_filters.<locals>._mel_filters_areasr$   r   )n_freqsf_minf_maxn_melsr   r   )

torchaudior   melscale_fbanksr   r   r   rX   r   r(   r   )r   r   mel_filtersr    r   r!   _mel_filters  s   	zGaborConv1d._mel_filtersc           	      C   s   t dt t d | j }t |  }t j|dd}t j|ddd\}}|d }t j||k	 dd}t j
|d tj | j d|tj|  dgdd}|S )NrZ   r   r@   Tr   r$   r#   )rB   r   r   r   r   r   argmaxr   r   r   rN   rl   rc   r+   )	r   coeffsqrt_filterscenter_frequenciesr   r   half_magnitudesfwhmsr   r    r    r!   _gabor_params_from_mels  s    z#GaborConv1d._gabor_params_from_melsc                 C   s   |   S r   )r  r   r    r    r!   r     s   zGaborConv1d._initialize_kernelc                 C   sX   t |dkr	d}nt |dkrd}n
tdtt | | jd dkr*td| j |S )r7   r$   r   r8   z)GaborConv1d expects 2d or 3d inputs. Got r   r9   r:   r=   r    r    r!   r     s   zGaborConv1d._check_input_shape)NNr   r   r
   r   Nr   FFFFF)rw   rx   ry   rz   r   r6   r   r   r,   r   r  r   r   r{   r    r    r   r!   r     s0    @09r   rv   r   r   r   c                 C   sr   |dkrt |d t |d g}|S t | ||d   d | d }t | | d t | | d g}|S )a  This function computes the number of elements to add for zero-padding.

    Arguments
    ---------
    L_in : int
    stride: int
    kernel_size : int
    dilation : int

    Returns
    -------
    padding : int
        The size of the padding to be added
    r   r$   )rb   floor)rv   r   r   r   r   L_outr    r    r!   rt     s   
 rt   r  r   c                 C   s0   d| |d |  ||d   | d  }t |S )a7  This function computes the required padding size for transposed convolution

    Arguments
    ---------
    L_out : int
    L_in : int
    stride: int
    kernel_size : int
    dilation : int
    output_padding : int

    Returns
    -------
    padding : int
        The size of the padding to be applied
    g      r   )r`   )r  rv   r   r   r   r   r   r    r    r!   r     s   

r   )rz   rb   typingr   numpyrl   rB   torch.nnr^   torch.nn.functionalr   r-   r   (speechbrain.processing.signal_processingr   r   speechbrain.utils.loggerr   rw   loggerModuler   r|   r   r   r   r   r   r`   rt   r   r    r    r    r!   <module>   sN       W  ]Se  %