CoolFace
Modelpublic

Synthyra/FastESMFold

sourceHugging Facemitupdated 2d agoView on Hugging Face
0likes65downloads
modeling_fast_esmfold.py1973 linesDownload Raw Back to root
1from __future__ import annotations
2
3import torch
4import torch._inductor.config as inductor_config
5import torch._dynamo as dynamo
6
7# Enable TensorFloat32 tensor cores for float32 matmul (Ampere+ GPUs)
8# Provides significant speedup with minimal precision loss
9torch.set_float32_matmul_precision('high')
10
11# Enable TF32 for matrix multiplications and cuDNN operations
12torch.backends.cuda.matmul.allow_tf32 = True
13torch.backends.cudnn.allow_tf32 = True
14
15# Enable cuDNN autotuner - finds fastest algorithms for your hardware
16# Best when input sizes are consistent; may slow down first iterations
17torch.backends.cudnn.benchmark = True
18
19# Deterministic operations off for speed (set True if reproducibility needed)
20torch.backends.cudnn.deterministic = False
21inductor_config.max_autotune_gemm_backends = "ATEN,CUTLASS,FBGEMM"    
22
23dynamo.config.capture_scalar_outputs = True
24torch._dynamo.config.recompile_limit = 16
25
26"""Shared attention infrastructure for all FastPLMs models.
27
28Contains: AttentionBackend enum, backend resolution, mask creation,
29flex attention helpers, flash kernel detection/dispatch, and pad/unpad utilities.
30"""
31from enum import Enum
32from typing import Dict, List, Optional, Tuple
33
34import torch
35import torch.nn as nn
36from torch.nn import functional as F
37from einops import rearrange
38
39try:
40    from torch.nn.attention.flex_attention import create_block_mask, flex_attention, BlockMask
41except ImportError:
42    create_block_mask = None
43    flex_attention = None
44    BlockMask = None
45
46_compiled_flex_attention = None
47
48
49def _get_flex_attention_fn():
50    """Return flex_attention callable: compiled (fused kernel) by default, or eager when debug flag is set."""
51    global _compiled_flex_attention
52    if flex_attention is None:
53        return None
54    flex_mod = torch.nn.attention.flex_attention
55    if getattr(flex_mod, "_FLEX_ATTENTION_DISABLE_COMPILE_DEBUG", False):
56        return flex_attention
57    if _compiled_flex_attention is None:
58        _compiled_flex_attention = torch.compile(
59            flex_attention,
60            dynamic=False,
61        )
62    return _compiled_flex_attention
63
64
65# HuggingFace `kernels` exposes slightly different APIs for Flash Attention 2
66# and 3. Detect the loaded variant once so every caller uses the same dispatch.
67def _infer_kernels_flash_variant(kernel) -> Optional[str]:
68    if hasattr(kernel, "fwd") and hasattr(kernel, "varlen_fwd"):
69        return "flash_attn2"
70    if hasattr(kernel, "flash_attn_func") and hasattr(kernel, "flash_attn_varlen_func"):
71        return "flash_attn3"
72    return None
73
74
75def _try_get_kernels_flash():
76    try:
77        from kernels import get_kernel
78    except ImportError:
79        return None, None
80
81    flash_kernel = None
82    flash_kernel_variant = None
83    try:
84        flash_kernel = get_kernel("kernels-community/flash-attn3")
85        flash_kernel_variant = _infer_kernels_flash_variant(flash_kernel)
86        assert flash_kernel_variant is not None, "Loaded flash-attn3 kernel does not expose a supported API."
87    except Exception:
88        try:
89            flash_kernel = get_kernel("kernels-community/flash-attn2")
90            flash_kernel_variant = _infer_kernels_flash_variant(flash_kernel)
91            assert flash_kernel_variant is not None, "Loaded flash-attn2 kernel does not expose a supported API."
92        except Exception:
93            flash_kernel = None
94            flash_kernel_variant = None
95    return flash_kernel, flash_kernel_variant
96
97
98_FLASH_KERNELS_LOADED = False
99FLASH_KERNEL = None
100FLASH_KERNEL_VARIANT = None
101
102
103def _ensure_flash_kernels_loaded():
104    global _FLASH_KERNELS_LOADED, FLASH_KERNEL, FLASH_KERNEL_VARIANT
105    if _FLASH_KERNELS_LOADED:
106        return
107    _FLASH_KERNELS_LOADED = True
108    FLASH_KERNEL, FLASH_KERNEL_VARIANT = _try_get_kernels_flash()
109
110
111def _kernels_flash_forward(
112    query_states: torch.Tensor,
113    key_states: torch.Tensor,
114    value_states: torch.Tensor,
115    causal: bool = False,
116    softmax_scale: Optional[float] = None,
117) -> torch.Tensor:
118    """Flash-attention forward, optionally overriding the softmax scale.
119
120    When `softmax_scale is None`, the flash kernel applies its default
121    `1 / sqrt(head_dim)`. Pass `softmax_scale=1.0` if the caller has already
122    pre-scaled Q (the convention used by ESM2, DPLM, DPLM2, E1, ESMFold).
123    Failing to override when Q is pre-scaled applies the scale twice. On
124    DPLM-150M, that produced pooled-embedding cosine around -0.12 and argmax
125    agreement around 0.27 vs SDPA.
126    """
127    assert FLASH_KERNEL is not None, "Kernel Flash Attention is not available in this environment."
128    if FLASH_KERNEL_VARIANT == "flash_attn2":
129        return FLASH_KERNEL.fwd(
130            q=query_states, k=key_states, v=value_states,
131            softmax_scale=softmax_scale, is_causal=causal,
132        )[0]
133    if FLASH_KERNEL_VARIANT == "flash_attn3":
134        try:
135            output = FLASH_KERNEL.flash_attn_func(
136                q=query_states, k=key_states, v=value_states,
137                softmax_scale=softmax_scale, causal=causal,
138            )
139        except TypeError:
140            output = FLASH_KERNEL.flash_attn_func(
141                query_states, key_states, value_states,
142                0.0, softmax_scale, causal,
143            )
144        if isinstance(output, tuple):
145            return output[0]
146        return output
147    raise AssertionError(f"Unsupported kernels flash attention variant: {FLASH_KERNEL_VARIANT}")
148
149
150def _kernels_flash_varlen_forward(
151    query_states: torch.Tensor,
152    key_states: torch.Tensor,
153    value_states: torch.Tensor,
154    cu_seqlens_q: torch.Tensor,
155    cu_seqlens_k: torch.Tensor,
156    max_seqlen_in_batch_q: int,
157    max_seqlen_in_batch_k: int,
158    causal: bool = False,
159    softmax_scale: Optional[float] = None,
160) -> torch.Tensor:
161    """Varlen flash-attention forward, optionally overriding the softmax scale.
162
163    See `_kernels_flash_forward` docstring for why `softmax_scale=1.0` must be
164    passed when Q has been pre-scaled by the caller.
165    """
166    assert FLASH_KERNEL is not None, "Kernel Flash Attention is not available in this environment."
167    if FLASH_KERNEL_VARIANT == "flash_attn2":
168        return FLASH_KERNEL.varlen_fwd(
169            q=query_states, k=key_states, v=value_states,
170            cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_k,
171            max_seqlen_q=max_seqlen_in_batch_q, max_seqlen_k=max_seqlen_in_batch_k,
172            softmax_scale=softmax_scale, is_causal=causal,
173        )[0]
174    if FLASH_KERNEL_VARIANT == "flash_attn3":
175        try:
176            output = FLASH_KERNEL.flash_attn_varlen_func(
177                q=query_states, k=key_states, v=value_states,
178                cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_k,
179                max_seqlen_q=max_seqlen_in_batch_q, max_seqlen_k=max_seqlen_in_batch_k,
180                softmax_scale=softmax_scale, causal=causal,
181            )
182        except TypeError:
183            output = FLASH_KERNEL.flash_attn_varlen_func(
184                query_states, key_states, value_states,
185                cu_seqlens_q, cu_seqlens_k,
186                max_seqlen_in_batch_q, max_seqlen_in_batch_k,
187                0.0, softmax_scale, causal,
188            )
189        if isinstance(output, tuple):
190            return output[0]
191        return output
192    raise AssertionError(f"Unsupported kernels flash attention variant: {FLASH_KERNEL_VARIANT}")
193
194
195# Varlen flash attention runs only on real tokens. These helpers remove padding
196# before the kernel call and restore the original padded batch shape afterward.
197class IndexFirstAxis(torch.autograd.Function):
198    @staticmethod
199    def forward(ctx, input, indices) -> torch.Tensor:
200        ctx.save_for_backward(indices)
201        assert input.ndim >= 2
202        ctx.first_axis_dim, other_shape = input.shape[0], input.shape[1:]
203        second_dim = other_shape.numel()
204        return torch.gather(
205            rearrange(input, "b ... -> b (...)"), 0, indices.unsqueeze(1).expand(-1, second_dim)
206        ).reshape(-1, *other_shape)
207
208    @staticmethod
209    def backward(ctx, grad_output) -> Tuple[torch.Tensor, None]:
210        (indices,) = ctx.saved_tensors
211        assert grad_output.ndim >= 2
212        other_shape = grad_output.shape[1:]
213        grad_output = rearrange(grad_output, "b ... -> b (...)")
214        grad_input = torch.zeros(
215            [ctx.first_axis_dim, grad_output.shape[1]], device=grad_output.device, dtype=grad_output.dtype
216        )
217        grad_input.scatter_(0, indices.unsqueeze(1).expand(-1, grad_output.shape[1]), grad_output)
218        return grad_input.reshape(ctx.first_axis_dim, *other_shape), None
219
220
221class IndexPutFirstAxis(torch.autograd.Function):
222    @staticmethod
223    def forward(ctx, values, indices, first_axis_dim) -> torch.Tensor:
224        ctx.save_for_backward(indices)
225        assert indices.ndim == 1
226        assert values.ndim >= 2
227        output = torch.zeros(first_axis_dim, *values.shape[1:], device=values.device, dtype=values.dtype)
228        output[indices] = values
229        return output
230
231    @staticmethod
232    def backward(ctx, grad_output) -> Tuple[torch.Tensor, None, None]:
233        (indices,) = ctx.saved_tensors
234        return grad_output[indices], None, None
235
236
237index_first_axis = IndexFirstAxis.apply
238index_put_first_axis = IndexPutFirstAxis.apply
239
240
241def pad_input(hidden_states: torch.Tensor, indices: torch.Tensor, batch: int, seqlen: int) -> torch.Tensor:
242    output = index_put_first_axis(hidden_states, indices, batch * seqlen)
243    return rearrange(output, "(b s) ... -> b s ...", b=batch)
244
245
246def _unpad_input(
247    query_layer: torch.Tensor,
248    key_layer: torch.Tensor,
249    value_layer: torch.Tensor,
250    attention_mask_2d: torch.Tensor,
251) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, Tuple[torch.Tensor, torch.Tensor], Tuple[int, int]]:
252    batch_size, seq_len, num_heads, head_dim = query_layer.shape
253    seqlens = attention_mask_2d.sum(dim=1).int()
254    cu_seqlens = F.pad(seqlens.cumsum(0, dtype=torch.int32), (1, 0))
255    max_seqlen = int(seqlens.max().item())
256    indices = attention_mask_2d.flatten().nonzero(as_tuple=False).flatten()
257    query_layer = index_first_axis(query_layer.reshape(batch_size * seq_len, num_heads, head_dim), indices)
258    key_layer = index_first_axis(key_layer.reshape(batch_size * seq_len, num_heads, head_dim), indices)
259    value_layer = index_first_axis(value_layer.reshape(batch_size * seq_len, num_heads, head_dim), indices)
260    return query_layer, key_layer, value_layer, indices, (cu_seqlens, cu_seqlens), (max_seqlen, max_seqlen)
261
262
263def kernels_flash_attention_func(
264    query_states: torch.Tensor,
265    key_states: torch.Tensor,
266    value_states: torch.Tensor,
267    attention_mask_2d: Optional[torch.Tensor] = None,
268    causal: bool = False,
269    softmax_scale: Optional[float] = None,
270) -> torch.Tensor:
271    """Public flash-attention entry point with optional padding handling.
272
273    `softmax_scale`:
274        None -> kernel applies its default `1 / sqrt(head_dim)`.
275        float -> kernel uses the given scale (pass 1.0 when Q is pre-scaled
276        by the caller).
277
278    Caller contract: if a model family pre-scales Q by `1/sqrt(head_dim)`
279    before calling this function (ESM2, DPLM, DPLM2, E1, and ESMFold do), pass
280    `softmax_scale=1.0`. Otherwise the flash kernel applies its default scale
281    again, yielding an effective `1/head_dim` scale that drifts across layers.
282    """
283    assert FLASH_KERNEL is not None, "Kernel Flash Attention is not available in this environment."
284    if not causal and attention_mask_2d is not None:
285        batch_size, q_len = query_states.shape[:2]
286        (
287            query_states, key_states, value_states,
288            indices_q, (cu_seqlens_q, cu_seqlens_k), (max_seqlen_q, max_seqlen_k),
289        ) = _unpad_input(query_states, key_states, value_states, attention_mask_2d)
290        attn_output_unpad = _kernels_flash_varlen_forward(
291            query_states=query_states, key_states=key_states, value_states=value_states,
292            cu_seqlens_q=cu_seqlens_q, cu_seqlens_k=cu_seqlens_k,
293            max_seqlen_in_batch_q=max_seqlen_q, max_seqlen_in_batch_k=max_seqlen_k,
294            softmax_scale=softmax_scale,
295        )
296        return pad_input(attn_output_unpad, indices_q, batch_size, q_len)
297    else:
298        return _kernels_flash_forward(
299            query_states=query_states, key_states=key_states, value_states=value_states,
300            causal=causal, softmax_scale=softmax_scale,
301        )
302
303
304# User-facing backend strings resolve to this enum before attention dispatch.
305class AttentionBackend(Enum):
306    AUTO = "auto"
307    KERNELS_FLASH = "kernels_flash"
308    FLEX = "flex"
309    SDPA = "sdpa"
310
311
312VALID_ATTENTION_BACKENDS = tuple(b.value for b in AttentionBackend)
313
314
315_BACKEND_CONFIRMED = False
316
317
318def resolve_attention_backend(requested_backend: str) -> AttentionBackend:
319    global _BACKEND_CONFIRMED
320    assert requested_backend in VALID_ATTENTION_BACKENDS, (
321        f"Unsupported attention backend: {requested_backend}. Expected one of {VALID_ATTENTION_BACKENDS}."
322    )
323    if requested_backend in (AttentionBackend.AUTO.value, AttentionBackend.KERNELS_FLASH.value):
324        _ensure_flash_kernels_loaded()
325    if requested_backend == AttentionBackend.AUTO.value:
326        if FLASH_KERNEL is not None:
327            resolved = AttentionBackend.KERNELS_FLASH
328        elif flex_attention is not None:
329            resolved = AttentionBackend.FLEX
330        else:
331            resolved = AttentionBackend.SDPA
332    elif requested_backend == AttentionBackend.KERNELS_FLASH.value:
333        assert FLASH_KERNEL is not None, "Kernels Flash Attention is not available in this environment."
334        resolved = AttentionBackend.KERNELS_FLASH
335    elif requested_backend == AttentionBackend.FLEX.value:
336        assert flex_attention is not None, "Flex Attention is not available in this environment."
337        resolved = AttentionBackend.FLEX
338    elif requested_backend == AttentionBackend.SDPA.value:
339        resolved = AttentionBackend.SDPA
340    else:
341        raise AssertionError(f"Unsupported attention backend: {requested_backend}")
342    if not _BACKEND_CONFIRMED:
343        print(f"Attention backend: config='{requested_backend}' -> resolved='{resolved.value}'")
344        _BACKEND_CONFIRMED = True
345    return resolved
346
347
348@torch.compiler.disable
349def get_attention_mask(
350    effective_backend: AttentionBackend,
351    batch_size: int,
352    seq_len: int,
353    device: torch.device,
354    attention_mask: Optional[torch.Tensor] = None,
355) -> Tuple[Optional[torch.Tensor], Optional[torch.Tensor], Optional[BlockMask]]:
356    """Build padding masks once for all encoder layers.
357
358    Returns (attention_mask_2d, attention_mask_4d, flex_block_mask).
359    """
360    if attention_mask is None:
361        return None, None, None
362
363    attention_mask_2d = attention_mask.bool()
364
365    if effective_backend == AttentionBackend.KERNELS_FLASH:
366        return attention_mask_2d, None, None
367
368    if effective_backend == AttentionBackend.FLEX:
369        assert create_block_mask is not None, "Flex attention backend requested but torch.create_block_mask is unavailable."
370        valid_lens = attention_mask_2d.sum(dim=-1)
371
372        def mask_mod(batch_idx, head_idx, q_idx, kv_idx):
373            return (q_idx < valid_lens[batch_idx]) & (kv_idx < valid_lens[batch_idx])
374
375        flex_block_mask = create_block_mask(mask_mod, batch_size, 1, seq_len, seq_len, device=device)
376        return attention_mask_2d, None, flex_block_mask
377
378    # SDPA/manual masks only keys. Padding queries still attend to real keys, so
379    # their outputs stay finite instead of softmaxing over all -inf scores.
380    attention_mask_4d = attention_mask_2d[:, None, None, :]
381    return attention_mask_2d, attention_mask_4d, None
382
383
384def bool_to_additive_mask(
385    bool_mask: torch.Tensor,
386    dtype: torch.dtype,
387) -> torch.Tensor:
388    """Convert a bool mask (True = valid) to a float additive mask (0.0 valid, -inf invalid).
389
390    Why this exists: calling `bool_mask.masked_fill(bool_mask.logical_not(), float('-inf'))`
391    directly on a bool tensor returns a bool tensor because `-inf` casts to `True`.
392    That silently drops the mask. Always allocate a float tensor first, then fill it.
393    This helper is the sanctioned way to build an SDPA additive mask from a bool validity mask.
394    """
395    assert bool_mask.dtype == torch.bool, (
396        f"bool_to_additive_mask requires a bool tensor, got dtype={bool_mask.dtype}"
397    )
398    additive = torch.zeros_like(bool_mask, dtype=dtype)
399    additive.masked_fill_(bool_mask.logical_not(), float("-inf"))
400    return additive
401
402import typing as T
403from dataclasses import dataclass, fields
404
405import torch
406import torch.nn as nn
407import torch.nn.functional as F
408
409
410@dataclass
411class TTTConfig:
412    lr: float = 4e-4
413    steps: int = 30
414    ags: int = 16
415    batch_size: int = 2
416    mask_ratio: float = 0.15
417    crop_size: int = 1024
418    bert_leave_prob: float = 0.1
419    bert_replace_prob: float = 0.1
420    optimizer: str = "sgd"
421    momentum: float = 0.0
422    weight_decay: float = 0.0
423    seed: int | None = 0
424    lora_rank: int = 8
425    lora_alpha: float = 32.0
426    lora_target_replace_module: str | None = None
427    lora_target_modules: tuple[str, ...] | None = None
428    initial_state_reset: bool = True
429    automatic_best_state_reset: bool = False
430    eval_each_step: bool = False
431    gradient_clip: bool = False
432    gradient_clip_max_norm: float = 1.0
433
434    @classmethod
435    def from_kwargs(cls, **kwargs: T.Any) -> "TTTConfig":
436        valid_names = {field.name for field in fields(cls)}
437        unknown_names = set(kwargs) - valid_names
438        assert len(unknown_names) == 0, f"Unknown TTTConfig fields: {sorted(unknown_names)}"
439        return cls(**kwargs)
440
441    def merged(self, overrides: T.Mapping[str, T.Any] | "TTTConfig" | None) -> "TTTConfig":
442        if overrides is None:
443            return self
444        if isinstance(overrides, TTTConfig):
445            return overrides
446        values = {field.name: self.__dict__[field.name] for field in fields(self)}
447        for name, value in overrides.items():
448            assert name in values, f"Unknown TTTConfig field: {name}"
449            values[name] = value
450        return TTTConfig(**values)
451
452    def verify(self) -> None:
453        assert self.lr > 0.0, "TTT learning rate must be positive."
454        assert self.steps >= 1, "TTT steps must be >= 1."
455        assert self.ags >= 1, "TTT gradient accumulation steps must be >= 1."
456        assert self.batch_size >= 1, "TTT batch_size must be >= 1."
457        assert 0.0 < self.mask_ratio <= 1.0, "TTT mask_ratio must be in (0, 1]."
458        assert self.crop_size >= 1, "TTT crop_size must be >= 1."
459        assert self.lora_rank >= 1, "TTT v1 is LoRA-only, so lora_rank must be >= 1."
460        assert self.lora_alpha > 0.0, "TTT lora_alpha must be positive."
461        assert self.optimizer in {"adamw", "sgd"}, "TTT optimizer must be 'adamw' or 'sgd'."
462        assert 0.0 <= self.bert_leave_prob <= 1.0, "bert_leave_prob must be in [0, 1]."
463        assert 0.0 <= self.bert_replace_prob <= 1.0, "bert_replace_prob must be in [0, 1]."
464        assert self.bert_leave_prob + self.bert_replace_prob <= 1.0, (
465            "bert_leave_prob + bert_replace_prob must be <= 1."
466        )
467        if self.gradient_clip:
468            assert self.gradient_clip_max_norm > 0.0, "gradient_clip_max_norm must be positive."
469
470
471class LoraInjectedLinear(nn.Module):
472    def __init__(self, linear: nn.Module, rank: int, alpha: float) -> None:
473        super().__init__()
474        weight = linear._parameters["weight"]
475        assert weight.ndim == 2, "LoRA can only wrap 2D linear weights."
476        self.linear = linear
477        self.linear.requires_grad_(False)
478        self.rank = rank
479        self.scale = alpha
480        in_features = weight.shape[1]
481        out_features = weight.shape[0]
482        self.lora_down = nn.Linear(in_features, rank, bias=False, dtype=torch.float32)
483        self.lora_up = nn.Linear(rank, out_features, bias=False, dtype=torch.float32)
484        self.lora_down.to(device=weight.device)
485        self.lora_up.to(device=weight.device)
486        nn.init.normal_(self.lora_down.weight, std=1.0 / rank)
487        nn.init.zeros_(self.lora_up.weight)
488
489    @property
490    def weight(self) -> torch.Tensor:
491        return self.linear._parameters["weight"]
492
493    @property
494    def bias(self) -> torch.Tensor | None:
495        return self.linear._parameters["bias"]
496
497    def forward(self, x: torch.Tensor) -> torch.Tensor:
498        base = self.linear(x)
499        delta = self.lora_up(self.lora_down(x.to(dtype=torch.float32))) * self.scale
500        return base + delta.to(dtype=base.dtype)
501
502
503class FastPLMTestTimeTrainingMixin:
504    def init_ttt(self, ttt_config: TTTConfig | T.Mapping[str, T.Any] | None = None) -> None:
505        base_config = TTTConfig()
506        self._ttt_cfg = base_config.merged(ttt_config)
507        self._ttt_cfg.verify()
508        self._ttt_initialized = False
509        self._ttt_initial_state: list[dict[str, torch.Tensor]] | None = None
510
511    @property
512    def ttt_config(self) -> TTTConfig:
513        if "_ttt_cfg" not in self.__dict__:
514            self.init_ttt()
515        return self._ttt_cfg
516
517    def _ttt_get_trainable_modules(self) -> list[nn.Module]:
518        return [self]
519
520    def _ttt_get_frozen_modules(self) -> list[nn.Module]:
521        return []
522
523    def _ttt_tokenize(
524        self,
525        seq: str | list[str] | None = None,
526        input_ids: torch.Tensor | None = None,
527        **kwargs: T.Any,
528    ) -> torch.Tensor | dict[str, torch.Tensor]:
529        del kwargs
530        if input_ids is not None:
531            return input_ids
532        assert seq is not None, "Pass either seq or input_ids for TTT."
533        tokenized = self.tokenizer(seq, return_tensors="pt", padding=True)
534        return tokenized["input_ids"]
535
536    def _ttt_mask_token(self) -> int:
537        return int(self.tokenizer.mask_token_id)
538
539    def _ttt_padding_token(self) -> int:
540        return int(self.tokenizer.pad_token_id)
541
542    def _ttt_replacement_tokens(self, input_ids: torch.Tensor) -> torch.Tensor:
543        tokenizer = self.tokenizer
544        special_ids = set(tokenizer.all_special_ids)
545        vocab_size = int(self.config.vocab_size)
546        ids = [idx for idx in range(vocab_size) if idx not in special_ids]
547        assert len(ids) > 0, "TTT replacement token set is empty."
548        return torch.tensor(ids, device=input_ids.device, dtype=input_ids.dtype)
549
550    def _ttt_predict_logits(
551        self,
552        batch: torch.Tensor | dict[str, torch.Tensor],
553        **kwargs: T.Any,
554    ) -> torch.Tensor:
555        del kwargs
556        if isinstance(batch, dict):
557            output = self(**batch)
558            return output.logits
559        attention_mask = batch.ne(self._ttt_padding_token())
560        output = self(input_ids=batch, attention_mask=attention_mask)
561        return output.logits
562
563    def _ttt_eval_step(
564        self,
565        step: int,
566        loss: float,
567        seq: str | list[str] | None = None,
568        input_ids: torch.Tensor | None = None,
569        **kwargs: T.Any,
570    ) -> tuple[dict[str, T.Any], float | None]:
571        del step, loss, seq, input_ids, kwargs
572        return {}, None
573
574    def _ttt_is_lora_target(
575        self,
576        name: str,
577        full_name: str,
578        module: nn.Module,
579        active: bool,
580        target_modules: tuple[str, ...] | None,
581    ) -> bool:
582        if not active:
583            return False
584        if isinstance(module, LoraInjectedLinear):
585            return False
586        if (
587            target_modules is not None
588            and name not in target_modules
589            and full_name not in target_modules
590        ):
591            return False
592        if isinstance(module, nn.Linear):
593            return True
594        if "weight" not in module._parameters:
595            return False
596        weight = module._parameters["weight"]
597        if weight is None or weight.ndim != 2:
598            return False
599        return "Linear" in module.__class__.__name__
600
601    def _ttt_inject_lora(self) -> int:
602        cfg = self.ttt_config
603        cfg.verify()
604        target_class = cfg.lora_target_replace_module
605        target_modules = cfg.lora_target_modules
606        wrapped = 0
607
608        def inject(module: nn.Module, prefix: str, active: bool) -> None:
609            nonlocal wrapped
610            for name, child in list(module.named_children()):
611                full_name = f"{prefix}.{name}" if prefix else name
612                child_active = active
613                if target_class is not None:
614                    child_active = active or child.__class__.__name__ == target_class
615                if self._ttt_is_lora_target(name, full_name, child, child_active, target_modules):
616                    setattr(
617                        module,
618                        name,
619                        LoraInjectedLinear(child, rank=cfg.lora_rank, alpha=cfg.lora_alpha),
620                    )
621                    wrapped += 1
622                    continue
623                inject(child, full_name, child_active)
624
625        for trainable_module in self._ttt_get_trainable_modules():
626            inject(trainable_module, "", target_class is None)
627        assert wrapped > 0, "TTT LoRA injection did not find any target modules."
628        return wrapped
629
630    def _ttt_lora_modules(self) -> list[LoraInjectedLinear]:
631        return [module for module in self.modules() if isinstance(module, LoraInjectedLinear)]
632
633    def _ttt_lora_parameters(self) -> list[nn.Parameter]:
634        params: list[nn.Parameter] = []
635        for module in self._ttt_lora_modules():
636            params.extend(module.lora_down.parameters())
637            params.extend(module.lora_up.parameters())
638        assert len(params) > 0, "TTT has no LoRA parameters."
639        return params
640
641    def _ttt_snapshot_lora_state(self) -> list[dict[str, torch.Tensor]]:
642        snapshot = []
643        for module in self._ttt_lora_modules():
644            snapshot.append(
645                {
646                    "lora_down.weight": module.lora_down.weight.detach().clone(),
647                    "lora_up.weight": module.lora_up.weight.detach().clone(),
648                }
649            )
650        assert len(snapshot) > 0, "TTT has no LoRA state to snapshot."
651        return snapshot
652
653    def _ttt_restore_lora_state(self, state: list[dict[str, torch.Tensor]]) -> None:
654        modules = self._ttt_lora_modules()
655        assert len(modules) == len(state), "TTT LoRA state/module count mismatch."
656        with torch.no_grad():
657            for module, module_state in zip(modules, state):
658                module.lora_down.weight.copy_(module_state["lora_down.weight"])
659                module.lora_up.weight.copy_(module_state["lora_up.weight"])
660
661    def _ttt_ensure_initialized(self) -> None:
662        if "_ttt_cfg" not in self.__dict__:
663            self.init_ttt()
664        if self._ttt_initialized:
665            return
666        self._ttt_inject_lora()
667        self._ttt_initial_state = self._ttt_snapshot_lora_state()
668        self._ttt_initialized = True
669
670    def ttt_reset(self) -> None:
671        self._ttt_ensure_initialized()
672        assert self._ttt_initial_state is not None, "TTT initial state is not available."
673        self._ttt_restore_lora_state(self._ttt_initial_state)
674
675    def _ttt_make_optimizer(self) -> torch.optim.Optimizer:
676        cfg = self.ttt_config
677        params = self._ttt_lora_parameters()
678        if cfg.optimizer == "sgd":
679            return torch.optim.SGD(
680                params,
681                lr=cfg.lr,
682                momentum=cfg.momentum,
683                weight_decay=cfg.weight_decay,
684            )
685        return torch.optim.AdamW(params, lr=cfg.lr, weight_decay=cfg.weight_decay)
686
687    def _ttt_to_device(
688        self,
689        batch: torch.Tensor | dict[str, torch.Tensor],
690        device: torch.device,
691    ) -> torch.Tensor | dict[str, torch.Tensor]:
692        if isinstance(batch, dict):
693            return {name: tensor.to(device) for name, tensor in batch.items()}
694        return batch.to(device)
695
696    def _ttt_input_ids_from_batch(
697        self,
698        batch: torch.Tensor | dict[str, torch.Tensor],
699    ) -> torch.Tensor:
700        if isinstance(batch, dict):
701            return batch["input_ids"]
702        return batch
703
704    def _ttt_set_input_ids(
705        self,
706        batch: torch.Tensor | dict[str, torch.Tensor],
707        input_ids: torch.Tensor,
708    ) -> torch.Tensor | dict[str, torch.Tensor]:
709        if isinstance(batch, dict):
710            updated = dict(batch)
711            updated["input_ids"] = input_ids
712            return updated
713        return input_ids
714
715    def _ttt_non_special_mask(self, input_ids: torch.Tensor) -> torch.Tensor:
716        pad_token = self._ttt_padding_token()
717        mask = input_ids.ne(pad_token)
718        special_ids = set(self.tokenizer.all_special_ids)
719        for special_id in special_ids:
720            mask = mask & input_ids.ne(int(special_id))
721        return mask
722
723    def _ttt_sample_crop(
724        self,
725        batch: torch.Tensor | dict[str, torch.Tensor],
726        generator: torch.Generator,
727    ) -> torch.Tensor | dict[str, torch.Tensor]:
728        input_ids = self._ttt_input_ids_from_batch(batch)
729        cfg = self.ttt_config
730        if input_ids.shape[1] <= cfg.crop_size:
731            return batch
732        high = input_ids.shape[1] - cfg.crop_size + 1
733        start = int(
734            torch.randint(
735                high,
736                (1,),
737                generator=generator,
738                device=input_ids.device,
739            ).item()
740        )
741        end = start + cfg.crop_size
742        if isinstance(batch, dict):
743            cropped = {}
744            for name, tensor in batch.items():
745                if tensor.ndim >= 2 and tensor.shape[1] == input_ids.shape[1]:
746                    cropped[name] = tensor[:, start:end]
747                else:
748                    cropped[name] = tensor
749            return cropped
750        return input_ids[:, start:end]
751
752    def _ttt_sample_batch(
753        self,
754        tokenized: torch.Tensor | dict[str, torch.Tensor],
755        generator: torch.Generator,
756    ) -> tuple[torch.Tensor | dict[str, torch.Tensor], torch.Tensor]:
757        cfg = self.ttt_config
758        batch = self._ttt_sample_crop(tokenized, generator)
759        input_ids = self._ttt_input_ids_from_batch(batch)
760        rows = torch.randint(
761            input_ids.shape[0],
762            (cfg.batch_size,),
763            generator=generator,
764            device=input_ids.device,
765        )
766        if isinstance(batch, dict):
767            sampled: torch.Tensor | dict[str, torch.Tensor] = {}
768            for name, tensor in batch.items():
769                if tensor.ndim >= 1 and tensor.shape[0] == input_ids.shape[0]:
770                    sampled[name] = tensor.index_select(0, rows)
771                else:
772                    sampled[name] = tensor
773        else:
774            sampled = input_ids.index_select(0, rows)
775
776        sampled_ids = self._ttt_input_ids_from_batch(sampled)
777        labels = sampled_ids.clone()
778        non_special = self._ttt_non_special_mask(sampled_ids)
779        label_mask = torch.zeros_like(non_special)
780        for row_idx in range(sampled_ids.shape[0]):
781            candidate_positions = torch.where(non_special[row_idx])[0]
782            if candidate_positions.numel() == 0:
783                continue
784            num_mask = max(1, int(round(candidate_positions.numel() * cfg.mask_ratio)))
785            order = torch.randperm(
786                candidate_positions.numel(),
787                generator=generator,
788                device=sampled_ids.device,
789            )
790            chosen = candidate_positions[order[:num_mask]]
791            label_mask[row_idx, chosen] = True
792        labels = labels.masked_fill(~label_mask, -100)
793
794        masked_ids = sampled_ids.clone()
795        chosen_positions = torch.where(label_mask)
796        if chosen_positions[0].numel() > 0:
797            random_values = torch.rand(
798                chosen_positions[0].shape,
799                generator=generator,
800                device=sampled_ids.device,
801            )
802            leave = random_values < cfg.bert_leave_prob
803            replace = (random_values >= cfg.bert_leave_prob) & (
804                random_values < cfg.bert_leave_prob + cfg.bert_replace_prob
805            )
806            mask = ~(leave | replace)
807            if mask.any():
808                masked_ids[
809                    chosen_positions[0][mask],
810                    chosen_positions[1][mask],
811                ] = self._ttt_mask_token()
812            if replace.any():
813                replacement_tokens = self._ttt_replacement_tokens(sampled_ids)
814                replacement_idx = torch.randint(
815                    replacement_tokens.shape[0],
816                    (int(replace.sum().item()),),
817                    generator=generator,
818                    device=sampled_ids.device,
819                )
820                masked_ids[
821                    chosen_positions[0][replace],
822                    chosen_positions[1][replace],
823                ] = replacement_tokens[replacement_idx]
824
825        return self._ttt_set_input_ids(sampled, masked_ids), labels
826
827    def ttt(
828        self,
829        seq: str | list[str] | None = None,
830        input_ids: torch.Tensor | None = None,
831        ttt_config: TTTConfig | T.Mapping[str, T.Any] | None = None,
832        **kwargs: T.Any,
833    ) -> dict[str, T.Any]:
834        if ttt_config is not None:
835            if "_ttt_initialized" in self.__dict__ and self._ttt_initialized:
836                next_cfg = self.ttt_config.merged(ttt_config)
837                assert next_cfg.lora_rank == self.ttt_config.lora_rank, (
838                    "Changing lora_rank after TTT initialization is not supported."
839                )
840                assert next_cfg.lora_alpha == self.ttt_config.lora_alpha, (
841                    "Changing lora_alpha after TTT initialization is not supported."
842                )
843                assert (
844                    next_cfg.lora_target_replace_module
845                    == self.ttt_config.lora_target_replace_module
846                ), "Changing LoRA target class after TTT initialization is not supported."
847                assert next_cfg.lora_target_modules == self.ttt_config.lora_target_modules, (
848                    "Changing LoRA target modules after TTT initialization is not supported."
849                )
850                self._ttt_cfg = next_cfg
851            else:
852                self.init_ttt(ttt_config)
853
854        self._ttt_ensure_initialized()
855        cfg = self.ttt_config
856        if cfg.initial_state_reset:
857            self.ttt_reset()
858
859        device = next(self.parameters()).device
860        tokenized = self._ttt_tokenize(seq=seq, input_ids=input_ids, **kwargs)
861        tokenized = self._ttt_to_device(tokenized, device)
862        generator_device = device if device.type == "cuda" else torch.device("cpu")
863        generator = torch.Generator(device=generator_device)
864        if cfg.seed is not None:
865            generator.manual_seed(cfg.seed)
866
867        module_modes = {module: module.training for module in self.modules()}
868        requires_grad = {param: param.requires_grad for param in self.parameters()}
869        losses: list[float] = []
870        step_metrics: list[dict[str, T.Any]] = []
871        best_state: list[dict[str, torch.Tensor]] | None = None
872        best_metric: float | None = None
873        best_step = 0
874
875        try:
876            self.train()
877            for param in self.parameters():
878                param.requires_grad_(False)
879            for param in self._ttt_lora_parameters():
880                param.requires_grad_(True)
881
882            optimizer = self._ttt_make_optimizer()
883            optimizer.zero_grad(set_to_none=True)
884            total_micro_steps = cfg.steps * cfg.ags
885            for micro_step in range(total_micro_steps):
886                batch, labels = self._ttt_sample_batch(tokenized, generator)
887                logits = self._ttt_predict_logits(batch, **kwargs)
888                labels = labels.to(device=logits.device)
889                loss = F.cross_entropy(
890                    logits.reshape(-1, logits.shape[-1]),
891                    labels.reshape(-1),
892                    ignore_index=-100,
893                )
894                (loss / cfg.ags).backward()
895                if (micro_step + 1) % cfg.ags != 0:
896                    continue
897
898                if cfg.gradient_clip:
899                    torch.nn.utils.clip_grad_norm_(
900                        self._ttt_lora_parameters(),
901                        cfg.gradient_clip_max_norm,
902                    )
903                optimizer.step()
904                optimizer.zero_grad(set_to_none=True)
905                step = (micro_step + 1) // cfg.ags
906                loss_value = float(loss.detach().item())
907                losses.append(loss_value)
908                if cfg.eval_each_step:
909                    metrics, metric = self._ttt_eval_step(
910                        step=step,
911                        loss=loss_value,
912                        seq=seq,
913                        input_ids=input_ids,
914                        **kwargs,
915                    )
916                    if len(metrics) > 0:
917                        step_metrics.append(metrics)
918                    if metric is not None and (
919                        best_metric is None or metric > best_metric
920                    ):
921                        best_metric = metric
922                        best_step = step
923                        best_state = self._ttt_snapshot_lora_state()
924
925            if cfg.automatic_best_state_reset and best_state is not None:
926                self._ttt_restore_lora_state(best_state)
927        finally:
928            for param, value in requires_grad.items():
929                param.requires_grad_(value)
930            for module, training in module_modes.items():
931                module.train(training)
932
933        return {
934            "losses": losses,
935            "step_metrics": step_metrics,
936            "best_step": best_step,
937            "best_metric": best_metric,
938        }
939
940"""FastESMFold: self-contained ESMFold with FastESM2 attention and opt-in TTT.
941
942Usage:
943    from transformers import AutoModel
944    model = AutoModel.from_pretrained("Synthyra/FastESMFold", trust_remote_code=True).cuda()
945
946    # Basic folding, no TTT
947    result = model.fold_protein("MKTLLILAVVA...")
948    print(result["plddt"], result["pdb_string"][:100])
949
950    # Experimental folding with TTT
951    result = model.fold_protein("MKTLLILAVVA...", ttt=True)
952
953Dependencies: torch, transformers, einops
954No dependency on: esm (fair-esm), proteinttt, openfold
955"""
956import copy
957from dataclasses import dataclass, field
958from functools import wraps
959from typing import Any, Callable, Dict, List, Optional, Tuple, Union
960
961import torch
962import torch.nn as nn
963from torch.nn import functional as F
964
965from einops import rearrange
966from transformers import EsmTokenizer, PretrainedConfig, PreTrainedModel
967from transformers.modeling_outputs import ModelOutput
968from transformers.models.esm.configuration_esm import EsmConfig
969from transformers.models.esm.modeling_esm import (
970    EsmContactPredictionHead,
971    EsmEmbeddings,
972    EsmIntermediate,
973    EsmLMHead,
974    EsmOutput,
975    EsmSelfOutput,
976    RotaryEmbedding,
977)
978from transformers.models.esm.modeling_esmfold import EsmForProteinFolding
979
980
981
982
983# =============================================================================
984# Output Dataclass
985# =============================================================================
986
987@dataclass
988class FastEsmEncoderOutput(ModelOutput):
989    last_hidden_state: Optional[torch.Tensor] = None
990    hidden_states: Optional[Tuple[torch.Tensor, ...]] = None
991    attentions: Optional[Tuple[torch.Tensor, ...]] = None
992
993
994# =============================================================================
995# FastESM2 Attention Layers (multi-backend: SDPA, Flash, Flex)
996# =============================================================================
997
998class EsmSelfAttention(nn.Module):
999    def __init__(self, config, position_embedding_type: Optional[str] = None):
1000        super().__init__()
1001        assert config.hidden_size % config.num_attention_heads == 0, (
1002            f"The hidden size ({config.hidden_size}) is not a multiple of the number of attention "
1003            f"heads ({config.num_attention_heads})"
1004        )
1005        self.num_attention_heads = config.num_attention_heads
1006        self.attention_head_size = int(config.hidden_size / config.num_attention_heads)
1007        self.all_head_size = self.num_attention_heads * self.attention_head_size
1008
1009        self.query = nn.Linear(config.hidden_size, self.all_head_size)
1010        self.key = nn.Linear(config.hidden_size, self.all_head_size)
1011        self.value = nn.Linear(config.hidden_size, self.all_head_size)
1012        self.scale = self.attention_head_size**-0.5
1013
1014        self.dropout_prob = config.attention_probs_dropout_prob
1015        self.config = config
1016        self.attn_backend = resolve_attention_backend(config.attn_backend)
1017        self.position_embedding_type = position_embedding_type or config.position_embedding_type
1018        self.rotary_embeddings = None
1019        if self.position_embedding_type == "rotary":
1020            self.rotary_embeddings = RotaryEmbedding(dim=self.attention_head_size)
1021
1022    def forward(
1023        self,
1024        hidden_states: torch.Tensor,
1025        attention_mask_2d: Optional[torch.Tensor] = None,
1026        attention_mask_4d: Optional[torch.Tensor] = None,
1027        flex_block_mask: Optional[BlockMask] = None,
1028        output_attentions: bool = False,
1029    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
1030        batch_size, seq_length = hidden_states.shape[:-1]
1031        hidden_shape = (batch_size, seq_length, -1, self.attention_head_size)
1032        query_BHLD = self.query(hidden_states).view(hidden_shape).transpose(1, 2)
1033        key_BHLD = self.key(hidden_states).view(hidden_shape).transpose(1, 2)
1034        value_BHLD = self.value(hidden_states).view(hidden_shape).transpose(1, 2)
1035
1036        query_BHLD = query_BHLD * self.scale
1037
1038        if self.position_embedding_type == "rotary":
1039            query_BHLD, key_BHLD = self.rotary_embeddings(query_BHLD, key_BHLD)
1040
1041        attn_output, attn_weights = self._attn(
1042            query_BHLD, key_BHLD, value_BHLD,
1043            attention_mask_2d=attention_mask_2d,
1044            attention_mask_4d=attention_mask_4d,
1045            flex_block_mask=flex_block_mask,
1046            output_attentions=output_attentions,
1047        )
1048        return attn_output, attn_weights
1049
1050    def _attn(
1051        self,
1052        query_BHLD: torch.Tensor,
1053        key_BHLD: torch.Tensor,
1054        value_BHLD: torch.Tensor,
1055        attention_mask_2d: Optional[torch.Tensor] = None,
1056        attention_mask_4d: Optional[torch.Tensor] = None,
1057        flex_block_mask: Optional[BlockMask] = None,
1058        output_attentions: bool = False,
1059    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
1060        if output_attentions:
1061            return self._manual_attn(query_BHLD, key_BHLD, value_BHLD, attention_mask_4d)
1062
1063        if self.attn_backend == AttentionBackend.KERNELS_FLASH:
1064            return self._kernels_flash_attn(query_BHLD, key_BHLD, value_BHLD, attention_mask_2d)
1065        elif self.attn_backend == AttentionBackend.FLEX:
1066            return self._flex_attn(query_BHLD, key_BHLD, value_BHLD, flex_block_mask)
1067        elif self.attn_backend == AttentionBackend.SDPA:
1068            return self._sdpa_attn(query_BHLD, key_BHLD, value_BHLD, attention_mask_4d)
1069        else:
1070            raise AssertionError(f"Unsupported resolved backend: {self.attn_backend}")
1071
1072    def _manual_attn(
1073        self,
1074        query_BHLD: torch.Tensor,
1075        key_BHLD: torch.Tensor,
1076        value_BHLD: torch.Tensor,
1077        attention_mask_4d: Optional[torch.Tensor] = None,
1078    ) -> Tuple[torch.Tensor, torch.Tensor]:
1079        attn_weights = torch.matmul(query_BHLD, key_BHLD.transpose(-1, -2))
1080        if attention_mask_4d is not None:
1081            attn_weights = attn_weights.masked_fill(attention_mask_4d.logical_not(), float("-inf"))
1082        attn_weights = F.softmax(attn_weights, dim=-1)
1083        if self.dropout_prob > 0 and self.training:
1084            attn_weights = F.dropout(attn_weights, p=self.dropout_prob, training=self.training)
1085        context_BHLD = torch.matmul(attn_weights, value_BHLD)
1086        attn_output = rearrange(context_BHLD, "b h s d -> b s (h d)")
1087        return attn_output, attn_weights
1088
1089    def _kernels_flash_attn(
1090        self,
1091        query_BHLD: torch.Tensor,
1092        key_BHLD: torch.Tensor,
1093        value_BHLD: torch.Tensor,
1094        attention_mask_2d: Optional[torch.Tensor] = None,
1095    ) -> Tuple[torch.Tensor, None]:
1096        query_BLHD = query_BHLD.transpose(1, 2).contiguous()
1097        key_BLHD = key_BHLD.transpose(1, 2).contiguous()
1098        value_BLHD = value_BHLD.transpose(1, 2).contiguous()
1099        # Q is pre-scaled by self.scale in forward() -- pass softmax_scale=1.0
1100        # to prevent the kernel from applying its default 1/sqrt(head_dim).
1101        attn_output = kernels_flash_attention_func(
1102            query_states=query_BLHD, key_states=key_BLHD, value_states=value_BLHD,
1103            attention_mask_2d=attention_mask_2d, causal=False,
1104            softmax_scale=1.0,
1105        )
1106        return rearrange(attn_output, "b s h d -> b s (h d)"), None
1107
1108    def _flex_attn(
1109        self,
1110        query_BHLD: torch.Tensor,
1111        key_BHLD: torch.Tensor,
1112        value_BHLD: torch.Tensor,
1113        flex_block_mask: Optional[BlockMask] = None,
1114    ) -> Tuple[torch.Tensor, None]:
1115        assert flex_attention is not None, "Flex attention is not available in this environment."
1116        fn = _get_flex_attention_fn()
1117        context_BHLD = fn(query_BHLD, key_BHLD, value_BHLD, block_mask=flex_block_mask, scale=1.0)
1118        return rearrange(context_BHLD, "b h s d -> b s (h d)"), None
1119
1120    def _sdpa_attn(
1121        self,
1122        query_BHLD: torch.Tensor,
1123        key_BHLD: torch.Tensor,
1124        value_BHLD: torch.Tensor,
1125        attention_mask_4d: Optional[torch.Tensor] = None,
1126    ) -> Tuple[torch.Tensor, None]:
1127        context_BHLD = F.scaled_dot_product_attention(
1128            query_BHLD, key_BHLD, value_BHLD,
1129            attn_mask=attention_mask_4d,
1130            dropout_p=self.dropout_prob if self.training else 0.0,
1131            scale=1.0,
1132        )
1133        return rearrange(context_BHLD, "b h s d -> b s (h d)"), None
1134
1135
1136class EsmAttention(nn.Module):
1137    def __init__(self, config):
1138        super().__init__()
1139        self.self = EsmSelfAttention(config)
1140        self.output = EsmSelfOutput(config)
1141        self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
1142
1143    def forward(
1144        self,
1145        hidden_states: torch.Tensor,
1146        attention_mask_2d: Optional[torch.Tensor] = None,
1147        attention_mask_4d: Optional[torch.Tensor] = None,
1148        flex_block_mask: Optional[BlockMask] = None,
1149        output_attentions: bool = False,
1150    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
1151        hidden_states_ln = self.LayerNorm(hidden_states)
1152        attn_output, attn_weights = self.self(
1153            hidden_states_ln,
1154            attention_mask_2d=attention_mask_2d,
1155            attention_mask_4d=attention_mask_4d,
1156            flex_block_mask=flex_block_mask,
1157            output_attentions=output_attentions,
1158        )
1159        attention_output = self.output(attn_output, hidden_states)
1160        return attention_output, attn_weights
1161
1162
1163class EsmLayer(nn.Module):
1164    def __init__(self, config):
1165        super().__init__()
1166        self.attention = EsmAttention(config)
1167        self.intermediate = EsmIntermediate(config)
1168        self.output = EsmOutput(config)
1169        self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
1170
1171    def forward(
1172        self,
1173        hidden_states: torch.Tensor,
1174        attention_mask_2d: Optional[torch.Tensor] = None,
1175        attention_mask_4d: Optional[torch.Tensor] = None,
1176        flex_block_mask: Optional[BlockMask] = None,
1177        output_attentions: bool = False,
1178    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
1179        attention_output, attn_weights = self.attention(
1180            hidden_states,
1181            attention_mask_2d=attention_mask_2d,
1182            attention_mask_4d=attention_mask_4d,
1183            flex_block_mask=flex_block_mask,
1184            output_attentions=output_attentions,
1185        )
1186        layer_output = self._feed_forward(attention_output)
1187        return layer_output, attn_weights
1188
1189    def _feed_forward(self, attention_output: torch.Tensor) -> torch.Tensor:
1190        attention_output_ln = self.LayerNorm(attention_output)
1191        intermediate_output = self.intermediate(attention_output_ln)
1192        return self.output(intermediate_output, attention_output)
1193
1194
1195class FastEsmEncoder(nn.Module):
1196    def __init__(self, config):
1197        super().__init__()
1198        self.config = config
1199        self.attention_backend = resolve_attention_backend(config.attn_backend)
1200        self.layer = nn.ModuleList([EsmLayer(config) for _ in range(config.num_hidden_layers)])

Showing the first 1,200 of 1973 lines. Download the file for the rest.