# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 # This file was automatically generated from src/transformers/models/axk2/modular_axk2.py. # Do NOT edit this file manually as any edits will be overwritten by the generation of # the file from the modular. If any change should be done, please apply the change to the # modular_axk2.py file directly. One of our CI enforces this. # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 # Copyright 2026 SK Telecom and the HuggingFace Inc. team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import math from collections.abc import Callable import torch import torch.nn.functional as F from torch import nn from ... import initialization as init from ...activations import ACT2FN from ...cache_utils import Cache, DynamicCache from ...generation import GenerationMixin from ...integrations import use_experts_implementation, use_kernel_forward_from_hub from ...masking_utils import create_causal_mask from ...modeling_flash_attention_utils import FlashAttentionKwargs from ...modeling_layers import ( GenericForSequenceClassification, GenericForTokenClassification, GradientCheckpointingLayer, ) from ...modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel from ...processing_utils import Unpack from ...utils import TransformersKwargs, auto_docstring from ...utils.generic import can_return_tuple, merge_with_config_defaults from ...utils.output_capturing import OutputRecorder, capture_outputs from .configuration_axk2 import AXK2Config @use_kernel_forward_from_hub("RMSNorm") class AXK2RMSNorm(nn.Module): def __init__(self, hidden_size, eps: float = 1e-6) -> None: """ AXK2RMSNorm is equivalent to T5LayerNorm """ super().__init__() self.weight = nn.Parameter(torch.ones(hidden_size)) self.variance_epsilon = eps def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: input_dtype = hidden_states.dtype hidden_states = hidden_states.to(torch.float32) variance = hidden_states.pow(2).mean(-1, keepdim=True) hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) return self.weight * hidden_states.to(input_dtype) def extra_repr(self): return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}" class AXK2GateMLP(nn.Module): def __init__(self, config: AXK2Config): super().__init__() self.config = config self.activation_fn = nn.SiLU() self.fc1 = nn.Linear(config.hidden_size, config.gated_norm_rank, bias=False) self.fc2 = nn.Linear(config.gated_norm_rank, config.hidden_size, bias=False) def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: hidden_states = self.fc1(hidden_states) hidden_states = self.activation_fn(hidden_states) hidden_states = self.fc2(hidden_states) return hidden_states class AXK2GatedRMSNorm(nn.Module): """RMSNorm followed by a low-rank input-dependent sigmoid gate (Megatron `GatedNormWrapper`): y = RMSNorm(x) return y * sigmoid(gate_mlp(y)) """ def __init__(self, config: AXK2Config): super().__init__() self.norm = AXK2RMSNorm(config.hidden_size, eps=config.rms_norm_eps) self.mlp = AXK2GateMLP(config) def forward(self, x: torch.Tensor) -> torch.Tensor: y = self.norm(x) return (y * torch.sigmoid(self.mlp(y).float())).to(y.dtype) class AXK2RotaryEmbedding(nn.Module): def __init__(self, config: AXK2Config): super().__init__() self.max_seq_len_cached = config.max_position_embeddings self.original_max_seq_len = config.max_position_embeddings self.config = config self.rope_type = self.config.rope_parameters["rope_type"] rope_init_fn: Callable = self.compute_default_rope_parameters if self.rope_type != "default": rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type] inv_freq, self.attention_scaling = rope_init_fn(self.config) self.inv_freq = nn.Buffer(inv_freq, persistent=False) self.original_inv_freq = nn.Buffer(inv_freq.clone(), persistent=False) @staticmethod def compute_default_rope_parameters(config: AXK2Config, **kwargs) -> tuple[torch.Tensor, float]: """ Computes the inverse frequencies according to the original RoPE implementation Args: config ([`~transformers.PreTrainedConfig`]): The model configuration. Returns: Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE). """ base = config.rope_parameters["rope_theta"] dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads attention_factor = 1.0 # Unused in this type of RoPE # Compute the inverse frequencies inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim)) return inv_freq, attention_factor @torch.no_grad() @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope) def forward(self, x, position_ids): freqs = position_ids[..., None].float() * self.inv_freq.to(device=x.device, dtype=torch.float) emb = torch.cat((freqs, freqs), dim=-1) cos = emb.cos() * self.attention_scaling sin = emb.sin() * self.attention_scaling return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype) def rotate_half(x): """Rotates half the hidden dims of the input.""" x1 = x[..., : x.shape[-1] // 2] x2 = x[..., x.shape[-1] // 2 :] return torch.cat((-x2, x1), dim=-1) @use_kernel_forward_from_hub("rotary_pos_emb") def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1): """Applies Rotary Position Embedding to the query and key tensors. Args: q (`torch.Tensor`): The query tensor. k (`torch.Tensor`): The key tensor. cos (`torch.Tensor`): The cosine part of the rotary embedding. sin (`torch.Tensor`): The sine part of the rotary embedding. unsqueeze_dim (`int`, *optional*, defaults to 1): The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2. Returns: `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding. """ cos = cos.unsqueeze(unsqueeze_dim) sin = sin.unsqueeze(unsqueeze_dim) q_embed = (q * cos) + (rotate_half(q) * sin) k_embed = (k * cos) + (rotate_half(k) * sin) return q_embed, k_embed class AXK2Indexer(nn.Module): """ DeepSeek Sparse Attention (DSA) indexer for selecting top-k tokens. The Indexer has its own lightweight projections (wq_b, wk) separate from the main MLA attention, and returns the additive top-k sparse mask directly (`0` at the selected tokens, `-inf` elsewhere); the raw top-k indices are only ever scattered into that mask, so they are not surfaced. **Cache strategy**: the indexer key cache lives on the per-layer `DynamicIndexedLayer` (or the `StaticIndexedLayer` for static caches) inside the shared cache, accessed via `past_key_values.update_indexer()`. """ def __init__(self, config: "AXK2Config", layer_idx: int): super().__init__() self.config = config self.layer_idx = layer_idx self.hidden_size: int = config.hidden_size self.n_heads: int = config.index_n_heads self.head_dim: int = config.index_head_dim self.qk_rope_head_dim: int = config.qk_rope_head_dim self.index_topk: int = config.index_topk self.q_lora_rank: int = config.q_lora_rank self.wq_b = nn.Linear(self.q_lora_rank, self.n_heads * self.head_dim, bias=False) self.wk = nn.Linear(self.hidden_size, self.head_dim, bias=False) self.k_norm = nn.LayerNorm(self.head_dim, eps=1e-6) self.weights_proj = nn.Linear(self.hidden_size, self.n_heads, bias=False) self.softmax_scale = self.head_dim**-0.5 @torch.no_grad() def forward( self, hidden_states: torch.Tensor, q_resid: torch.Tensor, position_embeddings: tuple[torch.Tensor, torch.Tensor], attention_mask: torch.Tensor, position_ids: torch.Tensor, # Kept for BC past_key_values: Cache | None = None, ) -> torch.Tensor: """ Selects the top-k tokens per query for DeepSeek Sparse Attention (DSA). This is the bf16 equivalent of the reference Indexer which uses `rotate_activation` (Hadamard transform) and `fp8_index` (FP8 quantized scoring kernel). Since the Hadamard transform is orthogonal (dot products are preserved: Hq·Hk = q·k), and FP8 quantization is a precision optimization, we skip both and compute scores directly in bf16/fp32. The scoring logic computes: index_score[b,s,t] = Σ_h (weight[b,s,h] · softmax_scale · q[b,s,h,:] · k[b,t,:]) Args: hidden_states: Input hidden states `[B, S, hidden_size]`. q_resid: Query residual from `q_a_layernorm(q_a_proj(x))`, shape `[B, S, q_lora_rank]`. position_embeddings: `(cos, sin)` from RotaryEmbedding. attention_mask: Causal mask, broadcastable to `[B, S, T]`. past_key_values: Cache object containing the indexer key cache for this layer. Returns: `torch.Tensor`: the `int32` top-k token indices of shape `[B, S, topk]`. The eager / SDPA paths turn these into an additive sparse mask; the `flash-mla` kernel consumes them directly. """ batch_size, seq_len, _ = hidden_states.shape cos, sin = position_embeddings q = self.wq_b(q_resid) # [B, S, H*D] q = q.view(batch_size, seq_len, self.n_heads, self.head_dim) # [B, S, H, D] q_rot, q_pass = torch.split(q, [self.qk_rope_head_dim, self.head_dim - self.qk_rope_head_dim], dim=-1) k = self.k_norm(self.wk(hidden_states)).unsqueeze(2) # [B, S, 1, D] k_rot, k_pass = torch.split(k, [self.qk_rope_head_dim, self.head_dim - self.qk_rope_head_dim], dim=-1) # The indexer uses NON-interleaved (half-split) RoPE — unlike the main MLA attention q_rot, k_rot = apply_rotary_pos_emb(q_rot, k_rot, cos, sin, unsqueeze_dim=2) q = torch.cat([q_rot, q_pass], dim=-1) # [B, S, H, D] k = torch.cat([k_rot, k_pass], dim=-1).squeeze(2) # [B, S, D] if past_key_values is not None: k = past_key_values.update_indexer(k, self.layer_idx) scores = torch.matmul(q.float(), k.transpose(-1, -2).float().unsqueeze(1)) * self.softmax_scale scores = F.relu(scores) # Weight per head and sum across heads: [B, S, 1, H] @ [B, S, H, T] → [B, S, T] weights = self.weights_proj(hidden_states.to(self.weights_proj.weight.dtype)).float() * (self.n_heads**-0.5) index_scores = torch.matmul(weights.unsqueeze(-2), scores).squeeze(-2) # Causality needs to be taken into account when computing scores so padding tokens don't affect computation if attention_mask.dtype == torch.bool: index_scores = index_scores.masked_fill(~attention_mask, float("-inf")) else: index_scores = index_scores + attention_mask topk = min(self.index_topk, index_scores.shape[-1]) return index_scores.topk(topk, dim=-1).indices.to(torch.int32) # [B, S, topk] class AXK2TopkRouter(nn.Module): def __init__(self, config: AXK2Config): super().__init__() self.top_k = config.num_experts_per_tok self.num_experts = config.num_local_experts self.hidden_dim = config.hidden_size self.weight = nn.Parameter(torch.zeros(self.num_experts, self.hidden_dim)) self.routed_scaling_factor = config.routed_scaling_factor self.num_group = config.n_group self.topk_group = config.topk_group self.norm_topk_prob = config.norm_topk_prob self.e_score_correction_bias = nn.Buffer(torch.zeros((self.num_experts), dtype=torch.float32)) def forward(self, hidden_states): hidden_states = hidden_states.view(-1, self.hidden_dim) router_logits = F.linear(hidden_states.type(torch.float32), self.weight.type(torch.float32)) scores = router_logits.sigmoid() scores_for_choice = scores + self.e_score_correction_bias # Key difference: light checkpoints do not use group based routing and skip this path if self.num_group is not None: scores_for_choice = self.apply_group_scoring(scores_for_choice) topk_indices = torch.topk(scores_for_choice, k=self.top_k, dim=-1, sorted=False)[1] topk_weights = scores.gather(1, topk_indices) if self.norm_topk_prob: denominator = topk_weights.sum(dim=-1, keepdim=True) + 1e-20 topk_weights /= denominator topk_weights = topk_weights * self.routed_scaling_factor return router_logits, topk_weights, topk_indices def apply_group_scoring(self, scores_for_choice): """Apply DeepSeek style grouped scoring""" group_scores = ( scores_for_choice.view(-1, self.num_group, self.num_experts // self.num_group) .topk(2, dim=-1)[0] .sum(dim=-1) ) group_idx = torch.topk(group_scores, k=self.topk_group, dim=-1, sorted=False)[1] group_mask = torch.zeros_like(group_scores) group_mask.scatter_(1, group_idx, 1) score_mask = ( group_mask.unsqueeze(-1) .expand(-1, self.num_group, self.num_experts // self.num_group) .reshape(-1, self.num_experts) ) # NOTE: fill with `0.0` intentionally to match reference implementation scores_for_choice = scores_for_choice.masked_fill(~score_mask.bool(), 0.0) return scores_for_choice @use_experts_implementation class AXK2Experts(nn.Module): """Collection of expert weights stored as 3D tensors.""" def __init__(self, config): super().__init__() self.num_experts = config.num_local_experts self.hidden_dim = config.hidden_size self.intermediate_dim = config.moe_intermediate_size self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_dim)) self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_dim, self.intermediate_dim)) self.act_fn = ACT2FN[config.hidden_act] def forward( self, hidden_states: torch.Tensor, top_k_index: torch.Tensor, top_k_weights: torch.Tensor, ) -> torch.Tensor: final_hidden_states = torch.zeros_like(hidden_states) with torch.no_grad(): expert_mask = torch.nn.functional.one_hot(top_k_index, num_classes=self.num_experts + 1) expert_mask = expert_mask.permute(2, 1, 0) expert_hit = torch.greater(expert_mask.sum(dim=(-1, -2)), 0).nonzero() for expert_idx in expert_hit: expert_idx = expert_idx[0] if expert_idx == self.num_experts: continue top_k_pos, token_idx = torch.where(expert_mask[expert_idx]) current_state = hidden_states[token_idx] gate, up = nn.functional.linear(current_state, self.gate_up_proj[expert_idx]).chunk(2, dim=-1) current_hidden_states = self.act_fn(gate) * up current_hidden_states = nn.functional.linear(current_hidden_states, self.down_proj[expert_idx]) current_hidden_states = current_hidden_states * top_k_weights[token_idx, top_k_pos, None] final_hidden_states.index_add_(0, token_idx, current_hidden_states.to(final_hidden_states.dtype)) return final_hidden_states class AXK2MLP(nn.Module): def __init__(self, config, intermediate_size=None): super().__init__() self.config = config self.hidden_size = config.hidden_size self.intermediate_size = config.intermediate_size if intermediate_size is None else intermediate_size self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False) self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False) self.act_fn = ACT2FN[config.hidden_act] def forward(self, x): down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x)) return down_proj class AXK2MoE(nn.Module): """ A mixed expert module containing shared experts. """ def __init__(self, config: AXK2Config): super().__init__() self.config = config self.experts = AXK2Experts(config) self.gate = AXK2TopkRouter(config) self.shared_experts = AXK2MLP( config=config, intermediate_size=config.moe_intermediate_size * config.n_shared_experts ) def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: residuals = hidden_states orig_shape = hidden_states.shape _, topk_weights, topk_indices = self.gate(hidden_states) hidden_states = hidden_states.view(-1, hidden_states.shape[-1]) hidden_states = self.experts(hidden_states, topk_indices, topk_weights).view(*orig_shape) hidden_states = hidden_states + self.shared_experts(residuals) return hidden_states def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor: """ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch, num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim) """ batch, num_key_value_heads, slen, head_dim = hidden_states.shape if n_rep == 1: return hidden_states hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim) return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim) def eager_attention_forward( module: nn.Module, query: torch.Tensor, key: torch.Tensor, value: torch.Tensor, attention_mask: torch.Tensor | None, scaling: float, dropout: float = 0.0, **kwargs: Unpack[TransformersKwargs], ): key_states = repeat_kv(key, module.num_key_value_groups) value_states = repeat_kv(value, module.num_key_value_groups) attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling if attention_mask is not None: attn_weights = attn_weights + attention_mask attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype) attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training) attn_output = torch.matmul(attn_weights, value_states) attn_output = attn_output.transpose(1, 2).contiguous() return attn_output, attn_weights def yarn_get_mscale(scale=1, mscale=1): if scale <= 1: return 1.0 return 0.1 * mscale * math.log(scale) + 1.0 def yarn_apply_mscale(rope_parameters, scaling): if rope_parameters.get("rope_type", "default") != "default": mscale_all_dim = rope_parameters.get("mscale_all_dim", 0) scaling_factor = rope_parameters["factor"] if mscale_all_dim: mscale = yarn_get_mscale(scaling_factor, mscale_all_dim) scaling = scaling * mscale * mscale return scaling def apply_rotary_pos_emb_interleave(q, k, cos, sin, position_ids=None, unsqueeze_dim=1): r""" Applies interleaved Rotary Position Embedding to the query and key tensors. DeepSeek lays the rotary dimensions out in interleaved pairs `(x0, x1), (x2, x3), ...`, each rotated by a single frequency. We compute that rotation directly on the even/odd slices instead of de-interleaving with a `view`/`transpose`/`reshape`; the output is bit-identical to the de-interleaved `rotate_half` formulation while avoiding the extra contiguous copy. Args: q (`torch.Tensor`): The query tensor. k (`torch.Tensor`): The key tensor. cos (`torch.Tensor`): The cosine part of the rotary embedding. sin (`torch.Tensor`): The sine part of the rotary embedding. position_ids (`torch.Tensor`): The position indices of the tokens corresponding to the query and key tensors. For example, this can be used to pass offsetted position ids when working with a KV-cache. unsqueeze_dim (`int`, *optional*, defaults to 1): The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2. Returns: `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding. """ # `cos`/`sin` are `cat(freqs, freqs)`; the first half holds the per-pair angle. cos = cos[..., : cos.shape[-1] // 2].unsqueeze(unsqueeze_dim) sin = sin[..., : sin.shape[-1] // 2].unsqueeze(unsqueeze_dim) q1, q2 = q[..., 0::2], q[..., 1::2] k1, k2 = k[..., 0::2], k[..., 1::2] q_embed = torch.cat([q1 * cos - q2 * sin, q2 * cos + q1 * sin], dim=-1) k_embed = torch.cat([k1 * cos - k2 * sin, k2 * cos + k1 * sin], dim=-1) return q_embed, k_embed class AXK2Attention(nn.Module): """ DeepSeek-V3 MLA, with a DSA indexer whose top-k sparse mask is folded into the attention mask. Qlora rank formulation is dropped as it is never used in released models. """ def __init__(self, config: AXK2Config, layer_idx: int): super().__init__() self.config = config self.layer_idx = layer_idx self.attention_dropout = config.attention_dropout self.hidden_size = config.hidden_size self.num_heads = config.num_attention_heads self.q_lora_rank = config.q_lora_rank self.qk_rope_head_dim = config.qk_rope_head_dim self.kv_lora_rank = config.kv_lora_rank self.v_head_dim = config.v_head_dim self.qk_nope_head_dim = config.qk_nope_head_dim self.qk_head_dim = config.qk_nope_head_dim + config.qk_rope_head_dim self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads self.is_causal = True # Unlike DeepseekV3.2, this model does not use q_b_proj self.q_a_proj = nn.Linear(self.hidden_size, self.q_lora_rank, bias=config.attention_bias) self.q_a_layernorm = AXK2RMSNorm(self.q_lora_rank) # Fused projection for q and gate, needs to be kept fused as the FP8 scales won't match otherwise when split self.q_gate_proj = nn.Linear( 2 * self.q_lora_rank, self.num_heads * (self.qk_head_dim + self.v_head_dim), bias=False ) self.kv_a_proj_with_mqa = nn.Linear( self.hidden_size, self.kv_lora_rank + self.qk_rope_head_dim, bias=config.attention_bias, ) self.kv_a_layernorm = AXK2RMSNorm(self.kv_lora_rank) self.kv_b_proj = nn.Linear( self.kv_lora_rank, self.num_heads * (self.qk_nope_head_dim + self.v_head_dim), bias=False, ) self.o_proj = nn.Linear( self.num_heads * self.v_head_dim, self.hidden_size, bias=config.attention_bias, ) self.scaling = yarn_apply_mscale(config.rope_parameters, self.qk_head_dim ** (-0.5)) self.indexer = AXK2Indexer(config, layer_idx) def expand_kv(self, kv_nope: torch.Tensor, k_rot: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]: """Expands the compressed latents into key and value states. Args: - kv_nope: key + value without positional encoding, shape [batch_size, 1, seqlen, self.kv_lora_rank] - k_rot: shared key with positional encoding, shape [batch_size, 1, seqlen, self.qk_rope_head_dim] Returns the key and value states, two tensors of shape [batch, num_heads, seq, (k or v)_head_dim]. """ batch_size, _, seq_length, _ = kv_nope.shape key_shape = (batch_size, seq_length, -1, self.qk_nope_head_dim + self.v_head_dim) kv_nope = self.kv_b_proj(kv_nope).view(key_shape).transpose(1, 2) k_nope, value_states = torch.split(kv_nope, [self.qk_nope_head_dim, self.v_head_dim], dim=-1) k_rot = k_rot.expand(-1, k_nope.shape[1], -1, -1) # does not affect the underlying storage # Concatenate k_nope and k_rot in a new tensor key_states = kv_nope.new_empty(*kv_nope.shape[:-1], self.qk_nope_head_dim + self.qk_rope_head_dim) key_states[..., : self.qk_nope_head_dim].copy_(k_nope) key_states[..., self.qk_nope_head_dim :].copy_(k_rot) return key_states, value_states def forward( self, hidden_states: torch.Tensor, position_embeddings: tuple[torch.Tensor, torch.Tensor], attention_mask: torch.Tensor, past_key_values: Cache | None = None, position_ids: torch.Tensor | None = None, **kwargs: Unpack[FlashAttentionKwargs], ) -> tuple[torch.Tensor, torch.Tensor | None]: batch_size, seq_length = hidden_states.shape[:-1] query_gate_shape = (batch_size, seq_length, -1, self.qk_head_dim + self.v_head_dim) # Key change: Additional gate and fused projection (blocked to split due to FP8 scale mismatches) q_compressed = self.q_a_proj(hidden_states) q_resid = self.q_a_layernorm(q_compressed) query_gate_states = self.q_gate_proj(torch.cat([q_resid, q_compressed], dim=-1)).view(query_gate_shape) query_states, gate_states = torch.split(query_gate_states, [self.qk_head_dim, self.v_head_dim], dim=-1) query_states = query_states.transpose(1, 2) gate_states = gate_states.reshape(batch_size, seq_length, -1) q_pass, q_rot = torch.split(query_states, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1) compressed_kv = self.kv_a_proj_with_mqa(hidden_states) kv_pass, k_rot = torch.split(compressed_kv, [self.kv_lora_rank, self.qk_rope_head_dim], dim=-1) # Both latents are viewed as single-head, 4D tensors, as expected by `expand_kv` k_pass = self.kv_a_layernorm(kv_pass).view(batch_size, 1, seq_length, self.kv_lora_rank) k_rot = k_rot.view(batch_size, 1, seq_length, self.qk_rope_head_dim) cos, sin = position_embeddings q_rot, k_rot = apply_rotary_pos_emb_interleave(q_rot, k_rot, cos, sin) # Cache read / write is performed while latent KV is still compressed if past_key_values is not None: k_pass, k_rot = past_key_values.update(k_pass, k_rot, self.layer_idx) query_states = torch.cat((q_pass, q_rot), dim=-1) key_states, value_states = self.expand_kv(k_pass, k_rot) # The indexer scores against a 3D `[B, S, T]` mask; the attention mask is 4D `[B, 1, S, T]`. topk_indices = self.indexer( hidden_states, q_resid, position_embeddings, attention_mask[:, 0, :, :], position_ids, # Kept for BC past_key_values=past_key_values, ) sparse_indices = None if self.config._attn_implementation in ("eager", "sdpa"): index_mask = ( topk_indices.new_ones((batch_size, seq_length, key_states.shape[2]), dtype=torch.bool) .scatter(-1, topk_indices.long(), False) .unsqueeze(1) ) if attention_mask.dtype == torch.bool: attention_mask = attention_mask & ~index_mask else: attention_mask = attention_mask.masked_fill(index_mask, torch.finfo(hidden_states.dtype).min) else: sparse_indices = topk_indices attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface( self.config._attn_implementation, eager_attention_forward ) attn_output, attn_weights = attention_interface( self, query_states, key_states, value_states, attention_mask, dropout=0.0 if not self.training else self.attention_dropout, scaling=self.scaling, indices=sparse_indices, # consumed by flash_mla_with_kvcache; ignored by eager / SDPA **kwargs, ) attn_output = attn_output.reshape(batch_size, seq_length, -1).contiguous() # Input-dependent sigmoid gate on the attention output (the gate half of the fused projection). attn_output = (attn_output * torch.sigmoid(gate_states.float())).to(attn_output.dtype) attn_output = self.o_proj(attn_output) return attn_output, attn_weights class AXK2DecoderLayer(GradientCheckpointingLayer): def __init__(self, config: AXK2Config, layer_idx: int): super().__init__() self.hidden_size = config.hidden_size self.self_attn = AXK2Attention(config, layer_idx) self.mlp = AXK2MoE(config) if config.mlp_layer_types[layer_idx] == "sparse" else AXK2MLP(config) self.input_layernorm = AXK2GatedRMSNorm(config) self.post_attention_layernorm = ( AXK2GatedRMSNorm(config) if config.mlp_layer_types[layer_idx] == "sparse" else AXK2RMSNorm(config.hidden_size, eps=config.rms_norm_eps) ) def forward( self, hidden_states: torch.Tensor, attention_mask: torch.Tensor | None = None, position_ids: torch.LongTensor | None = None, past_key_values: Cache | None = None, use_cache: bool | None = False, position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None, **kwargs: Unpack[TransformersKwargs], ) -> torch.Tensor: residual = hidden_states hidden_states = self.input_layernorm(hidden_states) # Self Attention hidden_states, _ = self.self_attn( hidden_states=hidden_states, attention_mask=attention_mask, position_ids=position_ids, past_key_values=past_key_values, use_cache=use_cache, position_embeddings=position_embeddings, **kwargs, ) hidden_states = residual + hidden_states # Fully Connected residual = hidden_states hidden_states = self.post_attention_layernorm(hidden_states) hidden_states = self.mlp(hidden_states) hidden_states = residual + hidden_states return hidden_states @auto_docstring class AXK2PreTrainedModel(PreTrainedModel): config: AXK2Config base_model_prefix = "model" supports_gradient_checkpointing = True _no_split_modules = ["AXK2DecoderLayer"] _skip_keys_device_placement = ["past_key_values"] _supports_flash_attn = False # flash-mla kernels need a bit more work in the way we enable them! _supports_sdpa = True _supports_flex_attn = False _can_compile_fullgraph = True _supports_attention_backend = True _can_record_outputs = { "hidden_states": AXK2DecoderLayer, "attentions": AXK2Attention, "router_logits": OutputRecorder(AXK2TopkRouter, index=0), } _keep_in_fp32_modules_strict = ["e_score_correction_bias"] _keys_to_ignore_on_load_unexpected = ["inv_freq"] _keep_in_fp32_modules = ["indexer.weights_proj"] @torch.no_grad() def _init_weights(self, module): super()._init_weights(module) if isinstance(module, AXK2TopkRouter): init.normal_(module.weight, mean=0.0, std=self.config.initializer_range) init.zeros_(module.e_score_correction_bias) elif isinstance(module, AXK2Experts): init.normal_(module.gate_up_proj, mean=0.0, std=self.config.initializer_range) init.normal_(module.down_proj, mean=0.0, std=self.config.initializer_range) @auto_docstring class AXK2Model(AXK2PreTrainedModel): def __init__(self, config: AXK2Config): super().__init__(config) self.padding_idx = config.pad_token_id self.vocab_size = config.vocab_size self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx) self.layers = nn.ModuleList( [AXK2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)] ) self.norm = AXK2RMSNorm(config.hidden_size, eps=config.rms_norm_eps) self.rotary_emb = AXK2RotaryEmbedding(config=config) self.gradient_checkpointing = False # Initialize weights and apply final processing self.post_init() @merge_with_config_defaults @capture_outputs @auto_docstring def forward( self, input_ids: torch.LongTensor | None = None, attention_mask: torch.Tensor | None = None, position_ids: torch.LongTensor | None = None, past_key_values: Cache | None = None, inputs_embeds: torch.FloatTensor | None = None, use_cache: bool | None = None, **kwargs: Unpack[TransformersKwargs], ) -> MoeModelOutputWithPast: if (input_ids is None) ^ (inputs_embeds is not None): raise ValueError("You must specify exactly one of input_ids or inputs_embeds") if inputs_embeds is None: inputs_embeds: torch.Tensor = self.embed_tokens(input_ids) if use_cache and past_key_values is None: past_key_values = DynamicCache(config=self.config) if position_ids is None: past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0 position_ids = torch.arange(inputs_embeds.shape[1], device=inputs_embeds.device) + past_seen_tokens position_ids = position_ids.unsqueeze(0) # It may already have been prepared by e.g. `generate` if not isinstance(causal_mask_mapping := attention_mask, dict): mask_kwargs = { "config": self.config, "inputs_embeds": inputs_embeds, "attention_mask": attention_mask, "past_key_values": past_key_values, "position_ids": position_ids, "allow_is_causal_skip": False, # Always force creation to account for causality in the indexer } causal_mask_mapping = {"indexed_attention": create_causal_mask(**mask_kwargs)} hidden_states = inputs_embeds position_embeddings = self.rotary_emb(hidden_states, position_ids=position_ids) for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]): hidden_states = decoder_layer( hidden_states, attention_mask=causal_mask_mapping["indexed_attention"], position_embeddings=position_embeddings, position_ids=position_ids, past_key_values=past_key_values, use_cache=use_cache, **kwargs, ) hidden_states = self.norm(hidden_states) return MoeModelOutputWithPast( last_hidden_state=hidden_states, past_key_values=past_key_values, ) @auto_docstring class AXK2ForCausalLM(AXK2PreTrainedModel, GenerationMixin): _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"} _tp_plan = {"lm_head": "colwise_gather_output"} _pp_plan = {"lm_head": (["hidden_states"], ["logits"])} _fsdp_plan = {"lm_head": "keep_full_weight"} def __init__(self, config): super().__init__(config) self.model = AXK2Model(config) self.vocab_size = config.vocab_size self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False) # Initialize weights and apply final processing self.post_init() @can_return_tuple @auto_docstring def forward( self, input_ids: torch.LongTensor | None = None, attention_mask: torch.Tensor | None = None, position_ids: torch.LongTensor | None = None, past_key_values: Cache | None = None, inputs_embeds: torch.FloatTensor | None = None, labels: torch.LongTensor | None = None, use_cache: bool | None = None, logits_to_keep: int | torch.Tensor = 0, **kwargs: Unpack[TransformersKwargs], ) -> MoeCausalLMOutputWithPast: r""" Example: ```python >>> from transformers import AutoTokenizer, AXK2ForCausalLM >>> model = AXK2ForCausalLM.from_pretrained("meta-axk2/AXK2-2-7b-hf") >>> tokenizer = AutoTokenizer.from_pretrained("meta-axk2/AXK2-2-7b-hf") >>> prompt = "Hey, are you conscious? Can you talk to me?" >>> inputs = tokenizer(prompt, return_tensors="pt") >>> # Generate >>> generate_ids = model.generate(inputs.input_ids, max_length=30) >>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0] "Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you." ```""" outputs: MoeModelOutputWithPast = self.model( input_ids=input_ids, attention_mask=attention_mask, position_ids=position_ids, past_key_values=past_key_values, inputs_embeds=inputs_embeds, use_cache=use_cache, **kwargs, ) hidden_states = outputs.last_hidden_state # Only compute necessary logits, and do not upcast them to float if we are not computing the loss slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep logits = self.lm_head(hidden_states[:, slice_indices, :]) loss = None if labels is not None: loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs) return MoeCausalLMOutputWithPast( loss=loss, logits=logits, past_key_values=outputs.past_key_values, hidden_states=outputs.hidden_states, attentions=outputs.attentions, router_logits=outputs.router_logits, ) class AXK2ForSequenceClassification(GenericForSequenceClassification, AXK2PreTrainedModel): pass class AXK2ForTokenClassification(GenericForTokenClassification, AXK2PreTrainedModel): pass __all__ = [ "AXK2PreTrainedModel", "AXK2Model", "AXK2ForCausalLM", "AXK2ForSequenceClassification", "AXK2ForTokenClassification", ]