CoolFace
Modelpublic

MIT-SLS/USAD-Small

sourceHugging Facecc-by-nc-sa-4.0updated 4mo agoView on Hugging Face
0likes11downloads
usad_modules.py1096 linesDownload Raw Back to root
1# Reference: https://github.com/sooftware/conformer2 3import contextlib4import math5from collections import defaultdict6from typing import Dict, List, Optional, Tuple7 8import torch9import torch.nn.functional as F10from torch import nn11from torch.nn.attention import SDPBackend, sdpa_kernel12 13 14def lengths_to_padding_mask(15    lengths: torch.Tensor, max_len: Optional[int] = None16) -> torch.Tensor:17    """Create padding mask from lengths.18 19    Args:20        lengths: A 1-D tensor of shape (B,).21        max_len: An integer. It will be automatically set to the max value of lengths22            if not given.23 24    Returns:25        A bool tensor of shape (B, max_len), where padded positions are indicated by True.26    """27    batch_size = lengths.size(0)28    max_len = lengths.max().item() if max_len is None else max_len29    seq_range = torch.arange(30        0, max_len, dtype=torch.long, device=lengths.device31    )32    seq_range_expand = seq_range.unsqueeze(0).expand(batch_size, max_len)33    lengths_expand = lengths.unsqueeze(1).expand_as(seq_range_expand)34    padding_mask = seq_range_expand >= lengths_expand35    return padding_mask36 37 38class SamePad(nn.Module):39    def __init__(self, kernel_size, causal=False):40        super().__init__()41        if causal:42            self.remove = kernel_size - 143        else:44            self.remove = 1 if kernel_size % 2 == 0 else 045 46    def forward(self, x):47        if self.remove > 0:48            x = x[:, :, : -self.remove]49        return x50 51 52class TransposeLast(nn.Module):53    def __init__(self, deconstruct_idx=None, tranpose_dim=-2):54        super().__init__()55        self.deconstruct_idx = deconstruct_idx56        self.tranpose_dim = tranpose_dim57 58    def forward(self, x):59        if self.deconstruct_idx is not None:60            x = x[self.deconstruct_idx]61        return x.transpose(self.tranpose_dim, -1)62 63 64class Swish(nn.Module):65    def __init__(self):66        super(Swish, self).__init__()67 68    def forward(self, inputs: torch.Tensor) -> torch.Tensor:69        return inputs * inputs.sigmoid()70 71 72class GLU(nn.Module):73    def __init__(self, dim: int) -> None:74        super(GLU, self).__init__()75        self.dim = dim76 77    def forward(self, inputs: torch.Tensor) -> torch.Tensor:78        outputs, gate = inputs.chunk(2, dim=self.dim)79        return outputs * gate.sigmoid()80 81 82class RMSNorm(torch.nn.Module):83    def __init__(self, dim: int, eps: float = 1e-5):84        super().__init__()85        self.eps = eps86        self.weight = nn.Parameter(torch.ones(dim))87 88    def _norm(self, x):89        return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)90 91    def forward(self, x):92        output = self._norm(x.float()).type_as(x)93        return output * self.weight94 95 96class ResidualConnectionModule(nn.Module):97    def __init__(98        self,99        module: nn.Module,100        module_factor: float = 1.0,101        input_factor: float = 1.0,102    ):103        super(ResidualConnectionModule, self).__init__()104        self.module = module105        self.module_factor = module_factor106        self.input_factor = input_factor107 108    def forward(self, inputs: torch.Tensor) -> torch.Tensor:109        return (self.module(inputs) * self.module_factor) + (110            inputs * self.input_factor111        )112 113 114class Linear(nn.Module):115    def __init__(116        self, in_features: int, out_features: int, bias: bool = True117    ) -> None:118        super(Linear, self).__init__()119        self.linear = nn.Linear(in_features, out_features, bias=bias)120        nn.init.xavier_uniform_(self.linear.weight)121        if bias:122            nn.init.zeros_(self.linear.bias)123 124    def forward(self, x: torch.Tensor) -> torch.Tensor:125        return self.linear(x)126 127 128class View(nn.Module):129    def __init__(self, shape: tuple, contiguous: bool = False):130        super(View, self).__init__()131        self.shape = shape132        self.contiguous = contiguous133 134    def forward(self, x: torch.Tensor) -> torch.Tensor:135        if self.contiguous:136            x = x.contiguous()137 138        return x.view(*self.shape)139 140 141class Transpose(nn.Module):142    def __init__(self, shape: tuple):143        super(Transpose, self).__init__()144        self.shape = shape145 146    def forward(self, x: torch.Tensor) -> torch.Tensor:147        return x.transpose(*self.shape)148 149 150class FeedForwardModule(nn.Module):151    def __init__(152        self,153        encoder_dim: int = 512,154        expansion_factor: int = 4,155        dropout_p: float = 0.1,156        rms_norm: bool = False,157    ) -> None:158        super(FeedForwardModule, self).__init__()159        self.sequential = nn.Sequential(160            (161                nn.LayerNorm(encoder_dim)162                if not rms_norm163                else RMSNorm(encoder_dim)164            ),165            Linear(encoder_dim, encoder_dim * expansion_factor, bias=True),166            Swish(),167            nn.Dropout(p=dropout_p),168            Linear(encoder_dim * expansion_factor, encoder_dim, bias=True),169            nn.Dropout(p=dropout_p),170        )171 172    def forward(self, inputs: torch.Tensor) -> torch.Tensor:173        return self.sequential(inputs)174 175 176class DepthwiseConv1d(nn.Module):177    def __init__(178        self,179        in_channels: int,180        out_channels: int,181        kernel_size: int,182        stride: int = 1,183        padding: int = 0,184        bias: bool = False,185    ) -> None:186        super(DepthwiseConv1d, self).__init__()187        assert (188            out_channels % in_channels == 0189        ), "out_channels should be constant multiple of in_channels"190        self.conv = nn.Conv1d(191            in_channels=in_channels,192            out_channels=out_channels,193            kernel_size=kernel_size,194            groups=in_channels,195            stride=stride,196            padding=padding,197            bias=bias,198        )199 200    def forward(self, inputs: torch.Tensor) -> torch.Tensor:201        return self.conv(inputs)202 203 204class PointwiseConv1d(nn.Module):205    def __init__(206        self,207        in_channels: int,208        out_channels: int,209        stride: int = 1,210        padding: int = 0,211        bias: bool = True,212    ) -> None:213        super(PointwiseConv1d, self).__init__()214        self.conv = nn.Conv1d(215            in_channels=in_channels,216            out_channels=out_channels,217            kernel_size=1,218            stride=stride,219            padding=padding,220            bias=bias,221        )222 223    def forward(self, inputs: torch.Tensor) -> torch.Tensor:224        return self.conv(inputs)225 226 227class ConformerConvModule(nn.Module):228    def __init__(229        self,230        in_channels: int,231        kernel_size: int = 31,232        expansion_factor: int = 2,233        dropout_p: float = 0.1,234        rms_norm: bool = False,235    ) -> None:236        super(ConformerConvModule, self).__init__()237        assert (238            kernel_size - 1239        ) % 2 == 0, "kernel_size should be a odd number for 'SAME' padding"240        assert (241            expansion_factor == 2242        ), "Currently, Only Supports expansion_factor 2"243 244        self.sequential = nn.Sequential(245            (246                nn.LayerNorm(in_channels)247                if not rms_norm248                else RMSNorm(in_channels)249            ),250            Transpose(shape=(1, 2)),251            PointwiseConv1d(252                in_channels,253                in_channels * expansion_factor,254                stride=1,255                padding=0,256                bias=True,257            ),258            GLU(dim=1),259            DepthwiseConv1d(260                in_channels,261                in_channels,262                kernel_size,263                stride=1,264                padding=(kernel_size - 1) // 2,265            ),266            nn.BatchNorm1d(in_channels),267            Swish(),268            PointwiseConv1d(269                in_channels, in_channels, stride=1, padding=0, bias=True270            ),271            nn.Dropout(p=dropout_p),272        )273 274    def forward(self, inputs: torch.Tensor) -> torch.Tensor:275        return self.sequential(inputs).transpose(1, 2)276 277 278class FramewiseConv2dSubampling(nn.Module):279    def __init__(self, out_channels: int, subsample_rate: int = 2) -> None:280        super(FramewiseConv2dSubampling, self).__init__()281        assert subsample_rate in {2, 4}, "subsample_rate should be 2 or 4"282        self.subsample_rate = subsample_rate283        self.cnn = nn.Sequential(284            nn.Conv2d(1, out_channels, kernel_size=3, stride=2),285            nn.ReLU(),286            nn.Conv2d(287                out_channels,288                out_channels,289                kernel_size=3,290                stride=(2 if subsample_rate == 4 else 1, 2),291                padding=(0 if subsample_rate == 4 else 1, 0),292            ),293            nn.ReLU(),294        )295 296    def forward(297        self, inputs: torch.Tensor, input_lengths: torch.Tensor298    ) -> Tuple[torch.Tensor, torch.Tensor]:299        # inputs: (B, T, C) -> (B, 1, T, C)300        if self.subsample_rate == 2 and inputs.shape[1] % 2 == 0:301            inputs = F.pad(inputs, (0, 0, 0, 1), "constant", 0)302        if self.subsample_rate == 4 and inputs.shape[1] % 4 < 3:303            inputs = F.pad(304                inputs, (0, 0, 0, 3 - inputs.shape[1] % 4), "constant", 0305            )306        outputs = self.cnn(inputs.unsqueeze(1))307        batch_size, channels, subsampled_lengths, sumsampled_dim = (308            outputs.size()309        )310 311        outputs = outputs.permute(0, 2, 1, 3)312        outputs = outputs.contiguous().view(313            batch_size, subsampled_lengths, channels * sumsampled_dim314        )315 316        if self.subsample_rate == 4:317            output_lengths = input_lengths >> 2318        else:319            output_lengths = input_lengths >> 1320 321        return outputs, output_lengths322 323    def get_out_dim(self, input_dim: int) -> int:324        # dummy input to get the output dimension325        with torch.no_grad():326            device = next(self.parameters()).device327            inputs = torch.zeros(1, 16, input_dim, device=device)328            input_lengths = torch.tensor([16], device=device)329            outputs, _ = self.forward(inputs, input_lengths)330        return outputs.size(-1)331 332 333class PatchwiseConv2dSubampling(nn.Module):334    def __init__(335        self,336        mel_dim: int,337        out_channels: int,338        patch_size_time: int = 16,339        patch_size_freq: int = 16,340    ) -> None:341        super(PatchwiseConv2dSubampling, self).__init__()342 343        self.mel_dim = mel_dim344        self.patch_size_time = patch_size_time345        self.patch_size_freq = patch_size_freq346 347        self.proj = nn.Conv2d(348            1,349            out_channels,350            kernel_size=(patch_size_time, patch_size_freq),351            stride=(patch_size_time, patch_size_freq),352            padding=0,353        )354        self.cnn = nn.Sequential(355            nn.Conv2d(356                out_channels, out_channels, kernel_size=3, stride=1, padding=1357            ),358            nn.ReLU(),359            nn.Conv2d(360                out_channels, out_channels, kernel_size=3, stride=1, padding=1361            ),362            nn.ReLU(),363        )364 365    @property366    def subsample_rate(self) -> int:367        return self.patch_size_time * self.patch_size_freq // self.mel_dim368 369    def forward(370        self, inputs: torch.Tensor, input_lengths: torch.Tensor371    ) -> Tuple[torch.Tensor, torch.Tensor]:372        assert (373            inputs.shape[2] == self.mel_dim374        ), "inputs.shape[2] should be equal to mel_dim"375 376        # inputs: (B, Time, Freq) -> (B, 1, Time, Freq)377        outputs = self.proj(inputs.unsqueeze(1))378        outputs = self.cnn(outputs)379        # (B, channels, Time // patch_size_time, Freq // patch_size_freq)380        outputs = outputs.flatten(2, 3).transpose(1, 2)381        # (B, (Time // patch_size_time) * (Freq // patch_size_freq), channels)382 383        output_lengths = (384            input_lengths385            // self.patch_size_time386            * (self.mel_dim // self.patch_size_freq)387        )388 389        return outputs, output_lengths390 391 392class RelPositionalEncoding(nn.Module):393    def __init__(self, d_model: int) -> None:394        super(RelPositionalEncoding, self).__init__()395        self.d_model = d_model396        self.pe = None397 398    def extend_pe(self, x: torch.Tensor) -> None:399        if self.pe is not None:400            if self.pe.size(1) >= x.size(1) * 2 - 1:401                if self.pe.dtype != x.dtype or self.pe.device != x.device:402                    self.pe = self.pe.to(dtype=x.dtype, device=x.device)403                return404 405        length = x.size(1)406        pe_positive = torch.zeros(length, self.d_model, device="cpu")407        pe_negative = torch.zeros(length, self.d_model, device="cpu")408        position = torch.arange(409            0, length, dtype=torch.float32, device="cpu"410        ).unsqueeze(1)411        div_term = torch.exp(412            torch.arange(0, self.d_model, 2, dtype=torch.float32, device="cpu")413            * -(math.log(10000.0) / self.d_model)414        )415        pe_positive[:, 0::2] = torch.sin(position * div_term)416        pe_positive[:, 1::2] = torch.cos(position * div_term)417        pe_negative[:, 0::2] = torch.sin(-1 * position * div_term)418        pe_negative[:, 1::2] = torch.cos(-1 * position * div_term)419 420        pe_positive = torch.flip(pe_positive, [0]).unsqueeze(0)421        pe_negative = pe_negative[1:].unsqueeze(0)422        pe = torch.cat([pe_positive, pe_negative], dim=1)423        self.pe = pe.to(device=x.device, dtype=x.dtype)424 425    def forward(self, x: torch.Tensor) -> torch.Tensor:426        # x: (B, T, C)427        self.extend_pe(x)428        assert self.pe is not None429        pos_emb = self.pe[430            :,431            self.pe.size(1) // 2432            - x.size(1)433            + 1 : self.pe.size(1) // 2434            + x.size(1),435        ]436        return pos_emb437 438 439class RelativeMultiHeadAttention(nn.Module):440    def __init__(441        self,442        d_model: int = 512,443        num_heads: int = 16,444        dropout_p: float = 0.1,445    ):446        super(RelativeMultiHeadAttention, self).__init__()447        assert d_model % num_heads == 0, "d_model % num_heads should be zero."448        self.d_model = d_model449        self.d_head = int(d_model / num_heads)450        self.num_heads = num_heads451        self.sqrt_dim = math.sqrt(self.d_head)452 453        self.query_proj = Linear(d_model, d_model)454        self.key_proj = Linear(d_model, d_model)455        self.value_proj = Linear(d_model, d_model)456        self.pos_proj = Linear(d_model, d_model, bias=False)457 458        self.dropout = nn.Dropout(p=dropout_p)459        self.u_bias = nn.Parameter(torch.Tensor(self.num_heads, self.d_head))460        self.v_bias = nn.Parameter(torch.Tensor(self.num_heads, self.d_head))461        torch.nn.init.xavier_uniform_(self.u_bias)462        torch.nn.init.xavier_uniform_(self.v_bias)463 464        self.out_proj = Linear(d_model, d_model)465 466    @staticmethod467    def _relative_shift(pos_score: torch.Tensor) -> torch.Tensor:468        # pos_score: (B, H, T, 2T-1)469        B, H, T, L = pos_score.size()470 471        # Pad on the left of the last dimension: (B, H, T, 2T)472        pos_score = F.pad(pos_score, (1, 0))473 474        # Reshape to (B, H, 2T, T)475        pos_score = pos_score.view(B, H, L + 1, T)476 477        # Slice and reshape back to (B, H, T, 2T-1)478        pos_score = pos_score[:, :, 1:].view(B, H, T, L)479 480        # Keep only first T positions => (B, H, T, T)481        return pos_score[:, :, :, : (L // 2 + 1)]482 483    def forward(484        self,485        query: torch.Tensor,486        key: torch.Tensor,487        value: torch.Tensor,488        pos_embedding: torch.Tensor,489        padding_mask: Optional[torch.Tensor] = None,490        *,491        need_weights: bool = False,492        use_sdpa: Optional[bool] = None,493    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:494        """495        - If need_weights=True: returns (output, attn) like your original code.496        - If need_weights=False: returns (output, None) and uses SDPA in eval for speed/memory.497        """498        B, Tq, _ = query.size()499        _, Tk, _ = key.size()500 501        # Project502        q = self.query_proj(query)  # (B, Tq, C)503        k = self.key_proj(key)  # (B, Tk, C)504        v = self.value_proj(value)  # (B, Tk, C)505 506        # Reshape to (B, H, T, Dh)507        q = q.view(B, Tq, self.num_heads, self.d_head).transpose(508            1, 2509        )  # (B,H,Tq,Dh)510        k = k.view(B, Tk, self.num_heads, self.d_head).transpose(511            1, 2512        )  # (B,H,Tk,Dh)513        v = v.view(B, Tk, self.num_heads, self.d_head).transpose(514            1, 2515        )  # (B,H,Tk,Dh)516 517        # Positional projection.518        # IMPORTANT: allow pos_embedding to be (1, 2T-1, C) and broadcast across batch.519        # pos_embedding expected length: 2Tq - 1 for self-attn.520        pB = pos_embedding.size(0)521        p = self.pos_proj(pos_embedding)  # (pB, L, C)522        p = p.view(pB, -1, self.num_heads, self.d_head).transpose(523            1, 2524        )  # (pB,H,L,Dh)525 526        # Compute position-based bias (scaled) to feed SDPA or add to scores527        # q_pos: (B,H,Tq,Dh), p^T: (pB,H,Dh,L) -> broadcast on pB if pB==1528        q_pos = q + self.v_bias.unsqueeze(0).unsqueeze(2)  # (B,H,Tq,Dh)529        pos_score = torch.matmul(q_pos, p.transpose(-2, -1))  # (B,H,Tq,L)530        pos_bias = self._relative_shift(pos_score)  # (B,H,Tq,Tq) for self-attn531        pos_bias = pos_bias.mul(532            1.0 / self.sqrt_dim533        )  # scale matches SDPA scaling534 535        if padding_mask is not None:536            # padding_mask: (B, T) -> (B, 1, 1, T) to broadcast with pos_bias (B, H, Tq, Tk)537            # This masks out key positions that are padded across all heads and queries538            if padding_mask.dtype != torch.bool:539                padding_mask = padding_mask.to(torch.bool)540            pos_bias = pos_bias.masked_fill(541                padding_mask[:, None, None, :], -1e9542            )543 544        if use_sdpa is None:545            use_sdpa = (not self.training) and (not need_weights)546 547        # ---- Fast inference path: no attention matrix materialized ----548        if use_sdpa:549            # Content term uses u_bias550            q_content = q + self.u_bias.unsqueeze(0).unsqueeze(551                2552            )  # (B,H,Tq,Dh)553 554            with sdpa_kernel(555                [556                    SDPBackend.FLASH_ATTENTION,557                    SDPBackend.EFFICIENT_ATTENTION,558                    SDPBackend.MATH,559                ]560            ):561                out = F.scaled_dot_product_attention(562                    q_content,  # (B,H,Tq,Dh)563                    k,  # (B,H,Tk,Dh)564                    v,  # (B,H,Tk,Dh)565                    attn_mask=pos_bias,  # (B,H,Tq,Tk) additive bias566                    dropout_p=0.0,  # dropout disabled in inference567                    is_causal=False,568                )  # (BH, Tq, Dh)569 570            out = out.transpose(1, 2).contiguous().view(B, Tq, self.d_model)571 572            return self.out_proj(out), None573 574        # ---- Reference path (training / if you need attn weights): matches your math ----575        q_content = q + self.u_bias.unsqueeze(0).unsqueeze(2)  # (B,H,Tq,Dh)576        content_score = torch.matmul(577            q_content, k.transpose(-2, -1)578        )  # (B,H,Tq,Tk)579        content_score = content_score.mul(1.0 / self.sqrt_dim)580 581        score = content_score + pos_bias  # already scaled582 583        attn = F.softmax(score, dim=-1)584        attn = self.dropout(attn)585 586        context = torch.matmul(attn, v)  # (B,H,Tq,Dh)587        context = (588            context.transpose(1, 2).contiguous().view(B, Tq, self.d_model)589        )590 591        return self.out_proj(context), attn592 593 594class MultiHeadedSelfAttentionModule(nn.Module):595    def __init__(596        self,597        d_model: int,598        num_heads: int,599        dropout_p: float = 0.1,600        rms_norm: bool = False,601    ):602        super(MultiHeadedSelfAttentionModule, self).__init__()603        self.positional_encoding = RelPositionalEncoding(d_model)604        self.layer_norm = (605            nn.LayerNorm(d_model) if not rms_norm else RMSNorm(d_model)606        )607        self.attention = RelativeMultiHeadAttention(608            d_model, num_heads, dropout_p609        )610        self.dropout = nn.Dropout(p=dropout_p)611 612    def forward(613        self,614        inputs: torch.Tensor,615        padding_mask: Optional[torch.Tensor] = None,616        pos_embedding: Optional[torch.Tensor] = None,617    ) -> Tuple[torch.Tensor, torch.Tensor, Optional[torch.Tensor]]:618        if pos_embedding is None:619            pos_embedding = self.positional_encoding(inputs)620 621        inputs = self.layer_norm(inputs)622        outputs, attn = self.attention(623            inputs,624            inputs,625            inputs,626            pos_embedding=pos_embedding,627            padding_mask=padding_mask,628        )629 630        return self.dropout(outputs), attn, pos_embedding631 632 633class ConformerBlock(nn.Module):634    def __init__(635        self,636        encoder_dim: int = 512,637        attention_type: str = "mhsa",638        num_attention_heads: int = 8,639        feed_forward_expansion_factor: int = 4,640        conv_expansion_factor: int = 2,641        feed_forward_dropout_p: float = 0.1,642        attention_dropout_p: float = 0.1,643        conv_dropout_p: float = 0.1,644        conv_kernel_size: int = 31,645        half_step_residual: bool = True,646        transformer_style: bool = False,647        usad_v2: bool = False,648        pre_norm: bool = False,649        rms_norm: bool = False,650    ):651        super(ConformerBlock, self).__init__()652 653        self.transformer_style = transformer_style654        self.attention_type = attention_type655        self.usad_v2 = usad_v2656        self.pre_norm = pre_norm657 658        if half_step_residual and not transformer_style:659            self.feed_forward_residual_factor = 0.5660        else:661            self.feed_forward_residual_factor = 1662 663        assert (664            attention_type == "mhsa"665        ), "Only 'mhsa' attention is supported in this implementation."666        attention = MultiHeadedSelfAttentionModule(667            d_model=encoder_dim,668            num_heads=num_attention_heads,669            dropout_p=attention_dropout_p,670            rms_norm=rms_norm,671        )672 673        self.ffn_1 = FeedForwardModule(674            encoder_dim=encoder_dim,675            expansion_factor=feed_forward_expansion_factor,676            dropout_p=feed_forward_dropout_p,677            rms_norm=rms_norm,678        )679        self.attention = attention680        if not transformer_style:681            self.conv = ConformerConvModule(682                in_channels=encoder_dim,683                kernel_size=conv_kernel_size,684                expansion_factor=conv_expansion_factor,685                dropout_p=conv_dropout_p,686                rms_norm=rms_norm,687            )688            self.ffn_2 = FeedForwardModule(689                encoder_dim=encoder_dim,690                expansion_factor=feed_forward_expansion_factor,691                dropout_p=feed_forward_dropout_p,692                rms_norm=rms_norm,693            )694        self.layernorm = (695            (696                nn.LayerNorm(encoder_dim)697                if not rms_norm698                else RMSNorm(encoder_dim)699            )700            if not pre_norm701            else nn.Identity()702        )703 704    def forward_attention(705        self,706        x: torch.Tensor,707        pos_embedding: Optional[torch.Tensor] = None,708        padding_mask: Optional[torch.Tensor] = None,709    ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[torch.Tensor]]:710        attn_out, attn, pos_embedding = self.attention(711            x, pos_embedding=pos_embedding, padding_mask=padding_mask712        )713        return attn_out, attn, pos_embedding714 715    def forward_legacy(716        self,717        x: torch.Tensor,718        pos_embedding: Optional[torch.Tensor] = None,719        padding_mask: Optional[torch.Tensor] = None,720    ) -> Tuple[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:721        # FFN 1722        ffn_1_out = self.ffn_1(x)723        x = ffn_1_out * self.feed_forward_residual_factor + x724 725        # Attention726        attn_out, attn, pos_embedding = self.forward_attention(727            x, pos_embedding, padding_mask728        )729        x = attn_out + x730 731        if self.transformer_style:732            x = self.layernorm(x)733            return x, {734                "ffn_1": ffn_1_out,735                "attn": attn,736                "conv": None,737                "ffn_2": None,738            }739 740        # Convolution741        conv_out = self.conv(x)742        x = conv_out + x743 744        # FFN 2745        ffn_2_out = self.ffn_2(x)746        x = ffn_2_out * self.feed_forward_residual_factor + x747        x = self.layernorm(x)748 749        other = {750            "ffn_1": ffn_1_out,751            "attn": attn,752            "conv": conv_out,753            "ffn_2": ffn_2_out,754            "pos_embedding": pos_embedding,755        }756 757        return x, other758 759    def forward_transformer(760        self,761        x: torch.Tensor,762        pos_embedding: Optional[torch.Tensor] = None,763        padding_mask: Optional[torch.Tensor] = None,764    ) -> Tuple[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:765        # Attention766        attn_out, attn, pos_embedding = self.forward_attention(767            x, pos_embedding, padding_mask768        )769        x = attn_out + x770 771        # FFN772        ffn_out = self.ffn_1(x)773        x = ffn_out * self.feed_forward_residual_factor + x774 775        x = self.layernorm(x)776        return x, {777            "ffn_1": ffn_out,778            "attn": attn,779            "conv": None,780            "ffn_2": None,781            "pos_embedding": pos_embedding,782        }783 784    def forward_conformer(785        self,786        x: torch.Tensor,787        pos_embedding: Optional[torch.Tensor] = None,788        padding_mask: Optional[torch.Tensor] = None,789    ) -> Tuple[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:790        # FFN 1791        ffn_1_out = self.ffn_1(x)792        x = ffn_1_out * self.feed_forward_residual_factor + x793 794        # Attention795        attn_out, attn, pos_embedding = self.forward_attention(796            x, pos_embedding, padding_mask797        )798        x = attn_out + x799 800        # Convolution801        conv_out = self.conv(x)802        x = conv_out + x803 804        # FFN 2805        ffn_2_out = self.ffn_2(x)806        x = ffn_2_out * self.feed_forward_residual_factor + x807        x = self.layernorm(x)808 809        other = {810            "ffn_1": ffn_1_out,811            "attn": attn,812            "conv": conv_out,813            "ffn_2": ffn_2_out,814            "pos_embedding": pos_embedding,815        }816 817        return x, other818 819    def forward(820        self,821        x: torch.Tensor,822        pos_embedding: Optional[torch.Tensor] = None,823        padding_mask: Optional[torch.Tensor] = None,824    ) -> Tuple[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:825        if not self.usad_v2:826            return self.forward_legacy(x, pos_embedding, padding_mask)827 828        if self.transformer_style:829            return self.forward_transformer(x, pos_embedding, padding_mask)830 831        return self.forward_conformer(x, pos_embedding, padding_mask)832 833 834class ConformerEncoder(nn.Module):835    def __init__(self, cfg):836        super(ConformerEncoder, self).__init__()837 838        self.cfg = cfg839        self.framewise_subsample = None840        self.patchwise_subsample = None841        self.framewise_in_proj = None842        self.patchwise_in_proj = None843        assert (844            cfg.use_framewise_subsample or cfg.use_patchwise_subsample845        ), "At least one subsampling method should be used"846        if cfg.use_framewise_subsample:847            self.framewise_subsample = FramewiseConv2dSubampling(848                out_channels=cfg.conv_subsample_channels,849                subsample_rate=cfg.conv_subsample_rate,850            )851            self.framewise_in_proj = nn.Sequential(852                Linear(853                    self.framewise_subsample.get_out_dim(cfg.input_dim),854                    cfg.encoder_dim,855                ),856                nn.Dropout(p=cfg.input_dropout_p),857            )858        if cfg.use_patchwise_subsample:859            self.patchwise_subsample = PatchwiseConv2dSubampling(860                mel_dim=cfg.input_dim,861                out_channels=cfg.conv_subsample_channels,862                patch_size_time=cfg.patch_size_time,863                patch_size_freq=cfg.patch_size_freq,864            )865            self.patchwise_in_proj = nn.Sequential(866                Linear(867                    cfg.conv_subsample_channels,868                    cfg.encoder_dim,869                ),870                nn.Dropout(p=cfg.input_dropout_p),871            )872            assert not cfg.use_framewise_subsample or (873                cfg.conv_subsample_rate874                == self.patchwise_subsample.subsample_rate875            ), (876                f"conv_subsample_rate ({cfg.conv_subsample_rate}) != patchwise_subsample.subsample_rate"877                f"({self.patchwise_subsample.subsample_rate})"878            )879 880        self.framewise_norm, self.patchwise_norm = None, None881        if getattr(cfg, "subsample_normalization", False):882            if cfg.use_framewise_subsample:883                self.framewise_norm = (884                    nn.LayerNorm(cfg.encoder_dim)885                    if not getattr(cfg, "rms_norm", False)886                    else RMSNorm(cfg.encoder_dim)887                )888            if cfg.use_patchwise_subsample:889                self.patchwise_norm = (890                    nn.LayerNorm(cfg.encoder_dim)891                    if not getattr(cfg, "rms_norm", False)892                    else RMSNorm(cfg.encoder_dim)893                )894 895        self.conv_pos = None896        self.conv_pos_post_ln = None897        if cfg.conv_pos:898            num_pos_layers = cfg.conv_pos_depth899            k = max(3, cfg.conv_pos_width // num_pos_layers)900            self.conv_pos = nn.Sequential(901                TransposeLast(),902                *[903                    nn.Sequential(904                        nn.Conv1d(905                            cfg.encoder_dim,906                            cfg.encoder_dim,907                            kernel_size=k,908                            padding=k // 2,909                            groups=cfg.conv_pos_groups,910                        ),911                        SamePad(k),912                        TransposeLast(),913                        nn.LayerNorm(914                            cfg.encoder_dim, elementwise_affine=False915                        ),916                        TransposeLast(),917                        nn.GELU(),918                    )919                    for _ in range(num_pos_layers)920                ],921                TransposeLast(),922            )923            self.conv_pos_post_ln = (924                (925                    nn.LayerNorm(cfg.encoder_dim)926                    if not getattr(cfg, "rms_norm", False)927                    else RMSNorm(cfg.encoder_dim)928                )929                if not getattr(cfg, "pre_norm", False)930                else nn.Identity()931            )932 933        self.layers = nn.ModuleList(934            [935                ConformerBlock(936                    encoder_dim=cfg.encoder_dim,937                    attention_type=cfg.attention_type,938                    num_attention_heads=cfg.num_attention_heads,939                    feed_forward_expansion_factor=cfg.feed_forward_expansion_factor,940                    conv_expansion_factor=cfg.conv_expansion_factor,941                    feed_forward_dropout_p=cfg.feed_forward_dropout_p,942                    attention_dropout_p=cfg.attention_dropout_p,943                    conv_dropout_p=cfg.conv_dropout_p,944                    conv_kernel_size=cfg.conv_kernel_size,945                    half_step_residual=cfg.half_step_residual,946                    transformer_style=getattr(cfg, "transformer_style", False),947                    usad_v2=getattr(cfg, "usad_v2", False),948                    pre_norm=getattr(cfg, "pre_norm", False),949                    rms_norm=getattr(cfg, "rms_norm", False),950                )951                for _ in range(cfg.num_layers)952            ]953        )954        self.layerdrop_p = getattr(cfg, "layerdrop_p", 0.0)955 956        if cfg.attention_type == "mhsa" and len(self.layers) > 0:957            # Share positional encoding across layers958            shared_pos = None959            for layer in self.layers:960                if isinstance(layer.attention, MultiHeadedSelfAttentionModule):961                    if shared_pos is None:962                        shared_pos = layer.attention.positional_encoding963                    else:964                        layer.attention.positional_encoding = shared_pos965            if shared_pos is not None:966                # precompute positional encodings967                # expecting most mel inputs to be fewer than 2000 frames (20 seconds)968                max_len = 2000 // cfg.conv_subsample_rate969                shared_pos.extend_pe(torch.tensor(0.0).expand(1, max_len))970 971    def count_parameters(self) -> int:972        """Count parameters of encoder"""973        return sum([p.numel() for p in self.parameters() if p.requires_grad])974 975    def update_dropout(self, dropout_p: float) -> None:976        """Update dropout probability of encoder"""977        for name, child in self.named_children():978            if isinstance(child, nn.Dropout):979                child.p = dropout_p980 981    def forward(982        self,983        inputs: torch.Tensor,984        input_lengths: Optional[torch.Tensor] = None,985        padding_mask: Optional[torch.Tensor] = None,986        *,987        return_hidden: bool = False,988        freeze_input_layers: bool = False,989        target_layer: Optional[int] = None,990    ) -> Tuple[torch.Tensor, torch.Tensor, Dict[str, List[torch.Tensor]]]:991        if input_lengths is None:992            input_lengths = torch.full(993                (inputs.size(0),),994                inputs.size(1),995                dtype=torch.long,996                device=inputs.device,997            )998 999        with (1000            torch.no_grad() if freeze_input_layers else contextlib.ExitStack()1001        ):1002            frame_feat, patch_feat = None, None1003            frame_lengths, patch_lengths = None, None1004            if self.framewise_subsample is not None:1005                assert self.framewise_in_proj is not None1006                frame_feat, frame_lengths = self.framewise_subsample(1007                    inputs, input_lengths1008                )1009                frame_feat = self.framewise_in_proj(frame_feat)1010                if self.framewise_norm is not None:1011                    frame_feat = self.framewise_norm(frame_feat)1012 1013            if self.patchwise_subsample is not None:1014                assert self.patchwise_in_proj is not None1015                patch_feat, patch_lengths = self.patchwise_subsample(1016                    inputs, input_lengths1017                )1018                patch_feat = self.patchwise_in_proj(patch_feat)1019                if self.patchwise_norm is not None:1020                    patch_feat = self.patchwise_norm(patch_feat)1021 1022            assert frame_feat is not None or patch_feat is not None1023            assert frame_lengths is not None or patch_lengths is not None1024 1025            if frame_feat is not None and patch_feat is not None:1026                assert frame_lengths is not None and patch_lengths is not None1027                min_len = min(frame_feat.size(1), patch_feat.size(1))1028                frame_feat = frame_feat[:, :min_len]1029                patch_feat = patch_feat[:, :min_len]1030 1031                features = frame_feat + patch_feat1032                output_lengths = (1033                    frame_lengths1034                    if frame_lengths.max().item() < patch_lengths.max().item()1035                    else patch_lengths1036                )1037            elif frame_feat is not None:1038                features = frame_feat1039                output_lengths = frame_lengths1040            else:1041                features = patch_feat1042                output_lengths = patch_lengths1043 1044            assert features is not None1045            assert output_lengths is not None1046 1047        # Positional encoding with convolutional layers1048        if self.conv_pos is not None and self.conv_pos_post_ln is not None:1049            pos = self.conv_pos(features)1050            if not self.training:1051                features = features.add_(pos)1052            else:1053                features = features + pos1054            features = self.conv_pos_post_ln(features)1055 1056        # Create padding mask for attention1057        if padding_mask is not None:1058            # downsample to match features length1059            input_len = padding_mask.size(1)1060            feat_len = features.size(1)1061            factor = input_len / feat_len1062            indices = (1063                torch.arange(feat_len, device=padding_mask.device) * factor1064            ).long()1065            padding_mask = padding_mask.index_select(1, indices)1066        else:1067            # create from output_lengths1068            padding_mask = lengths_to_padding_mask(1069                output_lengths, max_len=features.size(1)1070            )1071 1072        layer_results = defaultdict(list)1073        outputs = features1074        other = {}1075        for i, layer in enumerate(self.layers):1076            if (1077                self.training1078                and self.layerdrop_p > 01079                and torch.rand(1).item() < self.layerdrop_p1080            ):1081                continue1082            outputs, other = layer(1083                outputs,1084                pos_embedding=other.get("pos_embedding"),1085                padding_mask=padding_mask,1086            )1087            if return_hidden:1088                layer_results["hidden_states"].append(outputs)1089                for k, v in other.items():1090                    layer_results[k].append(v)1091 1092            if target_layer is not None and i + 1 == target_layer:1093                break1094 1095        return outputs, output_lengths, layer_results1096