import math import torch import torch.nn.functional as F from einops import rearrange from torch import nn from transformers import PreTrainedModel, PretrainedConfig from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast try: from fla.layers.utils import get_layer_cache, update_layer_cache from fla.models.utils import Cache, FLAUnsupportedCacheGenerationMixin from fla.modules import FusedRMSNormSwishGate, RMSNorm, ShortConvolution from fla.ops.gdn2 import chunk_gdn2, fused_recurrent_gdn2 except (ImportError, AttributeError) as e: raise ImportError('Linear-50M requires a current CUDA build of flash-linear-attention: pip install "flash-linear-attention[cuda]"') from e class Linear50MConfig(PretrainedConfig): model_type = "linear_50m" def __init__(self, vocab_size=32000, hidden_size=384, num_hidden_layers=16, num_heads=6, head_dim=64, intermediate_size=1120, conv_size=4, norm_eps=1e-5, max_position_embeddings=4096, use_cache=True, **kwargs): for key, value in dict(bos_token_id=1, eos_token_id=2, pad_token_id=2, tie_word_embeddings=True).items(): kwargs.setdefault(key, value) super().__init__(**kwargs); self.vocab_size, self.hidden_size, self.num_hidden_layers = vocab_size, hidden_size, num_hidden_layers self.num_heads, self.head_dim, self.intermediate_size = num_heads, head_dim, intermediate_size self.conv_size, self.norm_eps, self.max_position_embeddings, self.use_cache = conv_size, norm_eps, max_position_embeddings, use_cache class NotGDN2(nn.Module): def __init__(self, c, layer_idx): super().__init__(); d, h, hd = c.hidden_size, c.num_heads, c.head_dim; self.h, self.hd, self.layer_idx = h, hd, layer_idx self.qkv = nn.Linear(d, 3*d, bias=False); self.conv = ShortConvolution(3*d, c.conv_size, bias=False, activation="silu") self.f = nn.Sequential(nn.Linear(d, hd, False), nn.Linear(hd, d, False)); self.bw = nn.Linear(d, 2*d, bias=False) self.gate = nn.Sequential(nn.Linear(d, hd, False), nn.Linear(hd, d, True)); self.recover = nn.Sequential(nn.Linear(d, hd, False), nn.Linear(hd, d, True)) self.A_log = nn.Parameter(torch.empty(h).uniform_(1, 16).log()); dt = torch.exp(torch.empty(d).uniform_(math.log(.001), math.log(.1))) self.dt_bias = nn.Parameter(dt + torch.log(-torch.expm1(-dt))); self.A_log._no_weight_decay = self.dt_bias._no_weight_decay = True self.norm = FusedRMSNormSwishGate(hd, eps=c.norm_eps); self.out = nn.Linear(d, d, bias=False) self.apply(self._init) for weight, parts in ((self.qkv.weight, 3), (self.bw.weight, 2)): for part in weight.chunk(parts, 0): nn.init.xavier_uniform_(part, gain=2**-2.5) nn.init.zeros_(self.recover[-1].weight); nn.init.zeros_(self.recover[-1].bias) @staticmethod def _init(m): if getattr(m, "_is_hf_initialized", False): return if isinstance(m, nn.Linear): nn.init.xavier_uniform_(m.weight, gain=2**-2.5) if m.bias is not None: nn.init.zeros_(m.bias) m._is_hf_initialized = True def forward(self, x, attention_mask=None, past_key_values=None, use_cache=False, **kwargs): length = x.shape[1]; last = get_layer_cache(self, past_key_values); conv = None if last is None else last["conv_state"]; cu = kwargs.get("cu_seqlens") qkv, conv = self.conv(self.qkv(x), cache=conv, output_final_state=use_cache, cu_seqlens=cu) q, k, v = (rearrange(z, "b t (h d) -> b t h d", h=self.h) for z in qkv.chunk(3, -1)) g = rearrange(-self.A_log.float().exp().repeat_interleave(self.hd) * F.softplus(self.f(x).float() + self.dt_bias.float()), "b t (h d) -> b t h d", h=self.h) b, w = (rearrange(z.sigmoid(), "b t (h d) -> b t h d", h=self.h) for z in self.bw(x).chunk(2, -1)) state = None if last is None else last["recurrent_state"] op = fused_recurrent_gdn2 if use_cache and not self.training and not torch.is_grad_enabled() and x.shape[1] <= 64 else chunk_gdn2 both, state = op(*(torch.cat(z, 2) for z in ((q, q), (k, k), (v, v), (g, torch.zeros_like(g)), (b, torch.zeros_like(b)), (w, w))), scale=self.hd**-.5, initial_state=state, output_final_state=use_cache, use_qk_l2norm_in_kernel=True, use_gate_in_kernel=False, cu_seqlens=cu) a, archive = both.chunk(2, 2); protected = archive-a support = protected*((a.float().square().mean(-1, True)+1e-6)/(protected.float().square().mean(-1, True)+1e-6)).sqrt().to(protected) theta = rearrange(self.recover(x), "b t (h d) -> b t h d", h=self.h); o = a + theta.sin()*support if use_cache: update_layer_cache(self, past_key_values, recurrent_state=state, conv_state=conv, offset=length) z = rearrange(self.gate(x), "b t (h d) -> b t h d", h=self.h); return self.out(rearrange(self.norm(o, z), "b t h d -> b t (h d)")) class SwiGLU(nn.Module): def __init__(self, c): super().__init__(); self.up, self.down = nn.Linear(c.hidden_size, 2*c.intermediate_size, False), nn.Linear(c.intermediate_size, c.hidden_size, False) def forward(self, x): a, b = self.up(x).chunk(2, -1); return self.down(F.silu(a)*b) class Block(nn.Module): def __init__(self, c, i): super().__init__(); self.n1, self.mix, self.n2, self.mlp = RMSNorm(c.hidden_size), NotGDN2(c, i), RMSNorm(c.hidden_size), SwiGLU(c) def forward(self, x, attention_mask=None, past_key_values=None, use_cache=False, **kwargs): x = x + self.mix(self.n1(x), attention_mask, past_key_values, use_cache, **kwargs); return x + self.mlp(self.n2(x)) class Linear50MPreTrainedModel(PreTrainedModel): config_class, base_model_prefix, _supports_cache_class, _no_split_modules = Linear50MConfig, "model", True, ["Block"] def _init_weights(self, m): if getattr(m, "_is_hf_initialized", False): return if isinstance(m, (nn.Linear, nn.Embedding)): nn.init.normal_(m.weight, std=.02) if getattr(m, "bias", None) is not None: nn.init.zeros_(m.bias) class Linear50MModel(Linear50MPreTrainedModel): def __init__(self, config): super().__init__(config); self.embed = nn.Embedding(config.vocab_size, config.hidden_size); self.blocks = nn.ModuleList(Block(config, i) for i in range(config.num_hidden_layers)); self.norm = RMSNorm(config.hidden_size); self.post_init() def get_input_embeddings(self): return self.embed def set_input_embeddings(self, value): self.embed = value def forward(self, input_ids=None, attention_mask=None, inputs_embeds=None, past_key_values=None, use_cache=None, output_hidden_states=None, return_dict=None, **kwargs): if (input_ids is None) == (inputs_embeds is None): raise ValueError("Pass exactly one of input_ids or inputs_embeds") x = self.embed(input_ids) if inputs_embeds is None else inputs_embeds if x.device.type != "cuda": raise RuntimeError("Linear-50M currently requires CUDA/FLA inference") if attention_mask is not None: if past_key_values is None and not bool(attention_mask.all()): raise ValueError("Variable-length padded batches are not supported yet") attention_mask = None output_hidden_states = self.config.output_hidden_states if output_hidden_states is None else output_hidden_states return_dict = self.config.return_dict if return_dict is None else return_dict use_cache = getattr(self.config, "use_cache", True) if use_cache is None and not self.training else bool(use_cache) if use_cache and not isinstance(past_key_values, Cache): past_key_values = Cache.from_legacy_cache(past_key_values) hidden = () if output_hidden_states else None for block in self.blocks: if output_hidden_states: hidden += (x,) x = block(x, attention_mask, past_key_values, use_cache, **kwargs) x = self.norm(x) if output_hidden_states: hidden += (x,) if not return_dict: return tuple(v for v in (x, past_key_values, hidden) if v is not None) return BaseModelOutputWithPast(last_hidden_state=x, past_key_values=past_key_values, hidden_states=hidden) class Linear50MForCausalLM(Linear50MPreTrainedModel, FLAUnsupportedCacheGenerationMixin): _tied_weights_keys = {"lm_head.weight": "model.embed.weight"} def __init__(self, config): super().__init__(config); self.model = Linear50MModel(config); self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False); self.post_init() def get_input_embeddings(self): return self.model.embed def set_input_embeddings(self, value): self.model.embed = value def get_output_embeddings(self): return self.lm_head def set_output_embeddings(self, value): self.lm_head = value def get_decoder(self): return self.model def set_decoder(self, value): self.model = value def forward(self, input_ids=None, attention_mask=None, inputs_embeds=None, past_key_values=None, labels=None, use_cache=None, output_hidden_states=None, return_dict=None, logits_to_keep=0, **kwargs): return_dict = self.config.return_dict if return_dict is None else return_dict out = self.model(input_ids, attention_mask, inputs_embeds, past_key_values, use_cache, output_hidden_states, return_dict, **kwargs); h = out[0] logits = self.lm_head(h if labels is not None or not logits_to_keep else h[:, -logits_to_keep:]); loss = None if labels is not None: loss = F.cross_entropy(logits[:, :-1].float().flatten(0, 1), labels[:, 1:].flatten(), ignore_index=-100) if not return_dict: return ((loss,) if loss is not None else ()) + (logits,) + out[1:] return CausalLMOutputWithPast(loss=loss, logits=logits, past_key_values=out.past_key_values, hidden_states=out.hidden_states)