| """Mamba sequence blocks used by Flexibrain. |
| |
| References: |
| - Mamba: https://github.com/state-spaces/mamba |
| - 3D Mamba MAE: https://github.com/ydchen0806/TokenUnify |
| |
| This file keeps only the block factory pieces needed by the Flexibrain |
| Mamba-JEPA backbone, instead of vendoring the full upstream training project. |
| """ |
|
|
| from functools import partial |
| import inspect |
| import math |
| from typing import Optional |
|
|
| import torch |
| import torch.nn as nn |
| from torch import Tensor |
| from timm.models.layers import DropPath |
|
|
| from mamba_ssm.modules.mamba_simple import Mamba |
| from mamba_ssm.modules.mamba2 import Mamba2 |
| from mamba_ssm.modules.mha import MHA |
| from mamba_ssm.ops.triton.layer_norm import RMSNorm, layer_norm_fn, rms_norm_fn |
|
|
|
|
| class Block(nn.Module): |
| def __init__(self, dim, mixer_cls, mlp_cls, norm_cls=nn.LayerNorm, fused_add_norm=False, residual_in_fp32=False, drop_path=0.0): |
| super().__init__() |
| self.residual_in_fp32 = residual_in_fp32 |
| self.fused_add_norm = fused_add_norm |
| self.norm = norm_cls(dim) |
| self.mixer = mixer_cls(dim) |
| try: |
| self._mixer_kwset = set(inspect.signature(self.mixer.forward).parameters.keys()) |
| except Exception: |
| self._mixer_kwset = set() |
| if mlp_cls is not nn.Identity: |
| self.norm2 = norm_cls(dim) |
| self.mlp = mlp_cls(dim) |
| else: |
| self.mlp = None |
| self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() |
| if self.fused_add_norm: |
| assert RMSNorm is not None, "RMSNorm import failed" |
| assert isinstance(self.norm, (nn.LayerNorm, RMSNorm)) |
|
|
| def forward(self, hidden_states: Tensor, residual: Optional[Tensor] = None, inference_params=None, **mixer_kwargs): |
| if not self.fused_add_norm: |
| residual = (self.drop_path(hidden_states) + residual) if residual is not None else hidden_states |
| hidden_states = self.norm(residual.to(dtype=self.norm.weight.dtype)) |
| if self.residual_in_fp32: |
| residual = residual.to(torch.float32) |
| else: |
| hidden_states, residual = layer_norm_fn( |
| self.drop_path(hidden_states), self.norm.weight, self.norm.bias, |
| residual=residual, prenorm=True, residual_in_fp32=self.residual_in_fp32, |
| eps=self.norm.eps, is_rms_norm=isinstance(self.norm, RMSNorm), |
| ) |
| filtered_kwargs = {k: v for k, v in mixer_kwargs.items() if k in self._mixer_kwset} |
| hidden_states = self.mixer(hidden_states, inference_params=inference_params, **filtered_kwargs) |
| if self.mlp is not None: |
| if not self.fused_add_norm: |
| residual = self.drop_path(hidden_states) + residual |
| residual = self.norm2(residual.to(dtype=self.norm2.weight.dtype)) |
| if self.residual_in_fp32: |
| residual = residual.to(torch.float32) |
| else: |
| hidden_states, residual = layer_norm_fn( |
| self.drop_path(hidden_states), self.norm2.weight, self.norm2.bias, |
| residual=residual, prenorm=True, residual_in_fp32=self.residual_in_fp32, |
| eps=self.norm2.eps, is_rms_norm=isinstance(self.norm2, RMSNorm), |
| ) |
| hidden_states = self.mlp(hidden_states) |
| return hidden_states, residual |
|
|
| def allocate_inference_cache(self, batch_size, max_seqlen, dtype=None, **kwargs): |
| return self.mixer.allocate_inference_cache(batch_size, max_seqlen, dtype=dtype, **kwargs) |
|
|
|
|
| def create_block(d_model, ssm_cfg=None, attn_layer_idx=None, attn_cfg=None, norm_epsilon=1e-5, drop_path=0.0, rms_norm=False, residual_in_fp32=False, fused_add_norm=False, layer_idx=None, device=None, dtype=None, if_bimamba=False, bimamba_type="none", if_devide_out=False, init_layer_scale=None, mixer_type="mamba"): |
| if if_bimamba and bimamba_type == "none": |
| bimamba_type = "v1" |
| if ssm_cfg is None: |
| ssm_cfg = {} |
| if attn_cfg is None: |
| attn_cfg = {} |
| factory_kwargs = {"device": device, "dtype": dtype} |
| if (attn_layer_idx is None) or (layer_idx not in attn_layer_idx): |
| if mixer_type == "mamba": |
| mixer_cls = partial(Mamba, layer_idx=layer_idx, init_layer_scale=init_layer_scale, bimamba_type=bimamba_type, if_devide_out=if_devide_out, **ssm_cfg, **factory_kwargs) |
| elif mixer_type == "mamba2": |
| mixer_cls = partial(Mamba2, layer_idx=layer_idx, **ssm_cfg, **factory_kwargs) |
| else: |
| raise ValueError(f"Unknown mixer_type: {mixer_type}") |
| else: |
| mixer_cls = partial(MHA, layer_idx=layer_idx, **attn_cfg, **factory_kwargs) |
| norm_cls = partial(nn.LayerNorm if not rms_norm else RMSNorm, eps=norm_epsilon, **factory_kwargs) |
| block = Block(d_model, mixer_cls, nn.Identity, norm_cls=norm_cls, drop_path=drop_path, fused_add_norm=fused_add_norm, residual_in_fp32=residual_in_fp32) |
| block.layer_idx = layer_idx |
| return block |
|
|
|
|
| def _init_weights(module, n_layer, initializer_range=0.02, rescale_prenorm_residual=True, n_residuals_per_layer=1): |
| if isinstance(module, nn.Linear): |
| if module.bias is not None and not getattr(module.bias, "_no_reinit", False): |
| nn.init.zeros_(module.bias) |
| elif isinstance(module, nn.Embedding): |
| nn.init.normal_(module.weight, std=initializer_range) |
| if rescale_prenorm_residual: |
| for name, p in module.named_parameters(): |
| if name in ["out_proj.weight", "fc2.weight"]: |
| nn.init.kaiming_uniform_(p, a=math.sqrt(5)) |
| with torch.no_grad(): |
| p /= math.sqrt(n_residuals_per_layer * n_layer)
|
|
|