""" Hetman-2.0B: Complete Architecture Implementation (Frontier Edition) 4-Stage Sequential DAG v2: Denoising Stem (Global L8), Triad Concurrent DAG (Hypo Global L6), Verified Logic Arbiter (Global L4, L8, L12, L16), and Multi-Highway Exit Stem. Includes YaRN 256k RoPE with Layer-Wise Temperature Cooling, Bounded QK-Norm, SwiGLU Limit Clamping, LM Head Logit Soft-Capping, Multi-Token Prediction (MTP), and Elastic Thinking Compaction. """ import math from dataclasses import dataclass from typing import Optional, Tuple, Dict, Any, List import torch import torch.nn as nn import torch.nn.functional as F from .configuration_hetman import HetmanConfig from .quantization import BitLinear from .deltanet import GatedDeltaNet from .hopfield_core import SpeculativeLatentHopfieldCore @dataclass class HetmanCausalLMOutput: loss: Optional[torch.Tensor] = None logits: Optional[torch.Tensor] = None ce_loss: Optional[torch.Tensor] = None mtp_loss: Optional[torch.Tensor] = None hopfield_loss: Optional[torch.Tensor] = None past_states: Optional[Any] = None def __getitem__(self, item): return getattr(self, item) def __setitem__(self, key, value): setattr(self, key, value) def __contains__(self, item): return hasattr(self, item) def get(self, key, default=None): return getattr(self, key, default) class YaRNRotaryEmbedding(nn.Module): """ YaRN (Yet another RoPE extensioN) Rotary Positional Embedding Scales context window smoothly from 4k to 262,144 tokens with base theta = 10,000,000 Implements 3-zone frequency ramp interpolation (beta_fast=32, beta_slow=1) and temperature cooling factor. """ def __init__( self, dim: int, max_position_embeddings: int = 262144, base: float = 10000000.0, scale: float = 64.0, original_max_position: int = 4096, beta_fast: float = 32.0, beta_slow: float = 1.0, temp_cooling: float = 2.0 ): super().__init__() self.dim = dim self.max_position_embeddings = max_position_embeddings self.base = base self.scale = scale self.original_max_position = original_max_position self.beta_fast = beta_fast self.beta_slow = beta_slow self.temp_cooling = temp_cooling # Base inverse frequencies: theta_i = 1 / base^(2i / dim) pos = torch.arange(0, dim, 2).float() inv_freq = 1.0 / (base ** (pos / dim)) if scale > 1.0: r = (original_max_position * inv_freq) / (2.0 * math.pi) gamma = torch.clamp((r - beta_slow) / (beta_fast - beta_slow), 0.0, 1.0) yarn_inv_freq = inv_freq * (gamma + (1.0 - gamma) / scale) self.register_buffer("inv_freq", yarn_inv_freq, persistent=False) else: self.register_buffer("inv_freq", inv_freq, persistent=False) def forward(self, x: torch.Tensor, seq_len: int, offset: int = 0, position_ids: Optional[torch.Tensor] = None) -> Tuple[torch.Tensor, torch.Tensor]: device = x.device if position_ids is not None: if position_ids.dim() == 2: # [B, L] -> freqs: [B, L, dim // 2] freqs = position_ids.unsqueeze(-1).to(self.inv_freq.dtype) * self.inv_freq.view(1, 1, -1) emb = torch.cat((freqs, freqs), dim=-1) # [B, L, dim] return emb.cos().to(x.dtype), emb.sin().to(x.dtype) else: t = position_ids.to(self.inv_freq.dtype) else: t = torch.arange(offset, offset + seq_len, device=device, dtype=self.inv_freq.dtype) freqs = torch.outer(t, self.inv_freq) # [seq_len, dim // 2] emb = torch.cat((freqs, freqs), dim=-1) # [seq_len, dim] return emb.cos().to(x.dtype), emb.sin().to(x.dtype) def rotate_half(x: torch.Tensor) -> torch.Tensor: x1 = x[..., :x.shape[-1] // 2] x2 = x[..., x.shape[-1] // 2:] return torch.cat((-x2, x1), dim=-1) def apply_rotary_pos_emb(q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: if cos.dim() == 2: cos = cos.unsqueeze(0).unsqueeze(2) # [1, L, 1, D] sin = sin.unsqueeze(0).unsqueeze(2) elif cos.dim() == 3: cos = cos.unsqueeze(2) # [B, L, 1, D] sin = sin.unsqueeze(2) q_embed = (q * cos) + (rotate_half(q) * sin) k_embed = (k * cos) + (rotate_half(k) * sin) return q_embed, k_embed class SwiGLUFFN(nn.Module): """Ternary SwiGLU Feed-Forward Network (d_ffn = 6144) with Activation Clamping""" def __init__(self, config: HetmanConfig): super().__init__() self.swiglu_limit = getattr(config, "swiglu_limit", 10.0) self.gate_proj = BitLinear(config.hidden_size, config.intermediate_size, bias=False) self.up_proj = BitLinear(config.hidden_size, config.intermediate_size, bias=False) self.down_proj = BitLinear(config.intermediate_size, config.hidden_size, bias=False) def forward(self, x: torch.Tensor) -> torch.Tensor: gated = F.silu(self.gate_proj(x)) * self.up_proj(x) if self.swiglu_limit > 0.0: gated = torch.clamp(gated, -self.swiglu_limit, self.swiglu_limit) return self.down_proj(gated) class GlobalAttention(nn.Module): """ Global Gated Softmax FlashAttention with YaRN RoPE, Bounded QK-Norm (|S_ij| <= sqrt(128) ≈ 11.31), Grouped-Query Attention (GQA, 12 Q heads, 2 KV heads) and Layer-Wise Temperature Cooling. """ def __init__(self, config: HetmanConfig, yarn_cooling: float = 2.0): super().__init__() self.hidden_size = config.hidden_size self.num_heads = config.global_attention_heads # 12 self.num_kv_heads = config.global_kv_heads # 2 self.head_dim = config.global_head_dim # 128 self.qk_norm_bound = config.qk_norm_bound # 11.3137 self.yarn_cooling = yarn_cooling # Layer-wise entropy cooling factor self.q_proj = BitLinear(self.hidden_size, self.num_heads * self.head_dim, bias=False) self.k_proj = BitLinear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False) self.v_proj = BitLinear(self.hidden_size, self.num_kv_heads * self.head_dim, bias=False) self.out_proj = BitLinear(self.num_heads * self.head_dim, self.hidden_size, bias=False) self.gate_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False) # Learnable QK-Norm scaling gains: initialized to sqrt(head_dim) to avoid step 0 entropy collapse self.gamma_q = nn.Parameter(torch.full((self.num_heads, self.head_dim), math.sqrt(self.head_dim))) self.gamma_k = nn.Parameter(torch.full((self.num_kv_heads, self.head_dim), math.sqrt(self.head_dim))) # Positional Embeddings: YaRN RoPE self.rotary_emb = YaRNRotaryEmbedding( dim=self.head_dim, max_position_embeddings=config.max_position_embeddings, base=config.rope_theta, scale=64.0, temp_cooling=yarn_cooling ) def forward( self, x: torch.Tensor, mask: Optional[torch.Tensor] = None, past_kv: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, offset: int = 0, position_ids: Optional[torch.Tensor] = None ) -> Tuple[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]: B, L, _ = x.shape q = self.q_proj(x).view(B, L, self.num_heads, self.head_dim) k = self.k_proj(x).view(B, L, self.num_kv_heads, self.head_dim) v = self.v_proj(x).view(B, L, self.num_kv_heads, self.head_dim) # 1. Apply YaRN Rotary Positional Embeddings cos, sin = self.rotary_emb(q, seq_len=L, offset=offset, position_ids=position_ids) q, k = apply_rotary_pos_emb(q, k, cos, sin) # 2. Bounded QK-Norm: Unit-normalize, scale by clamped gamma (bounded by sqrt(head_dim)) q_norm = F.normalize(q, p=2, dim=-1, eps=1e-5) * torch.clamp(self.gamma_q, 0.1, math.sqrt(self.head_dim)) k_norm = F.normalize(k, p=2, dim=-1, eps=1e-5) * torch.clamp(self.gamma_k, 0.1, math.sqrt(self.head_dim)) # 3. Handle KV-cache if past_kv is not None: past_k, past_v = past_kv k_norm = torch.cat([past_k, k_norm], dim=1) v = torch.cat([past_v, v], dim=1) current_kv = (k_norm, v) # 4. Expand KV heads for GQA (6x repeat to match 12 Q heads) k_exp = k_norm.repeat_interleave(self.num_heads // self.num_kv_heads, dim=2) v_exp = v.repeat_interleave(self.num_heads // self.num_kv_heads, dim=2) # 5. Scaled dot-product attention via native SDPA with Layer-wise YaRN temperature cooling q_t = q_norm.transpose(1, 2) # [B, H, L, D] k_t = k_exp.transpose(1, 2) # [B, H, S, D] v_t = v_exp.transpose(1, 2) # [B, H, S, D] is_causal = (mask is None) and (past_kv is None) and (L > 1) scale = self.yarn_cooling / math.sqrt(self.head_dim) out_sdpa = F.scaled_dot_product_attention(q_t, k_t, v_t, attn_mask=mask, is_causal=is_causal, scale=scale) out = out_sdpa.transpose(1, 2).reshape(B, L, -1) # 6. Channel gating gate = F.silu(self.gate_proj(x)) return self.out_proj(out) * gate, current_kv class HetmanLayer(nn.Module): """Single Transformer Block: either DeltaNet (Recurrent O(1)) or Global Attention + SwiGLU FFN""" def __init__(self, config: HetmanConfig, is_global: bool = False, yarn_cooling: float = 2.0): super().__init__() self.is_global = is_global self.attn = GlobalAttention(config, yarn_cooling=yarn_cooling) if is_global else GatedDeltaNet(config) self.ffn = SwiGLUFFN(config) self.norm1 = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) self.norm2 = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) def forward( self, x: torch.Tensor, prev_state=None, offset: int = 0, mask: Optional[torch.Tensor] = None, state_reset_mask: Optional[torch.Tensor] = None, position_ids: Optional[torch.Tensor] = None ): norm_x = self.norm1(x) if self.is_global: attn_out, next_state = self.attn(norm_x, mask=mask, past_kv=prev_state, offset=offset, position_ids=position_ids) else: attn_out, next_state = self.attn(norm_x, prev_state=prev_state, state_reset_mask=state_reset_mask) x = x + attn_out x = x + self.ffn(self.norm2(x)) return x, next_state class MTPHead(nn.Module): """ Multi-Token Prediction (MTP) Auxiliary Block (+34.6M parameters) Predicts token representation for step t+2 given hidden state at step t. """ def __init__(self, config: HetmanConfig): super().__init__() self.norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) self.ffn = SwiGLUFFN(config) self.final_norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) def forward(self, h: torch.Tensor) -> torch.Tensor: return self.final_norm(h + self.ffn(self.norm(h))) try: from transformers import PreTrainedModel except ImportError: class PreTrainedModel(nn.Module): def __init__(self, config, *args, **kwargs): super().__init__() self.config = config class HetmanPreTrainedModel(PreTrainedModel): config_class = HetmanConfig base_model_prefix = "model" supports_gradient_checkpointing = True class HetmanModel(HetmanPreTrainedModel): def __init__(self, config: HetmanConfig): super().__init__() self.config = config self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size) # Stage 1: Denoising Stem (8 Layers: 7 DeltaNet + 1 Global Softmax at Layer 8 / idx 7) # YaRN cooling: 1.6 self.stem_layers = nn.ModuleList([ HetmanLayer(config, is_global=(i == 7), yarn_cooling=1.6) for i in range(8) ]) # Stage 2: Triad Concurrent Processing self.hopfield_core = SpeculativeLatentHopfieldCore(config) self.domain_backbone = nn.ModuleList([SwiGLUFFN(config) for _ in range(8)]) # Hypothesis subnet: 6 Layers (5 DeltaNet + 1 Global Softmax at Layer 6 / idx 5, cooling: 1.8) self.hypothesis_subnet = nn.ModuleList([ HetmanLayer(config, is_global=(i == 5), yarn_cooling=1.8) for i in range(6) ]) # Adaptive Dynamic Fusion Gate (3 * 1536 -> 1536) self.fusion_gate = nn.Linear(config.hidden_size, config.hidden_size, bias=False) self.fusion_proj = BitLinear(3 * config.hidden_size, config.hidden_size, bias=False) self.fusion_norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) # Stage 3: Verified Logic Arbiter (16 Layers: 12 DeltaNet + 4 Global at layers 4, 8, 12, 16) # Cooling: 2.0 for L4-L8 (idx 3, 7), 2.4 for L12-L16 (idx 11, 15) arbiter_list = [] for i in range(16): if i in [3, 7]: arbiter_list.append(HetmanLayer(config, is_global=True, yarn_cooling=2.0)) elif i in [11, 15]: arbiter_list.append(HetmanLayer(config, is_global=True, yarn_cooling=2.4)) else: arbiter_list.append(HetmanLayer(config, is_global=False)) self.arbiter_layers = nn.ModuleList(arbiter_list) # Stage 4: Multi-Highway Residual Integration & Exit Stem (4 Layers DeltaNet) self.exit_norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) self.exit_layers = nn.ModuleList([ HetmanLayer(config, is_global=False) for _ in range(4) ]) self.final_norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps) def forward( self, input_ids: torch.Tensor, past_states: Optional[Dict[str, List[Any]]] = None, offset: int = 0, attention_mask: Optional[torch.Tensor] = None, state_reset_mask: Optional[torch.Tensor] = None, position_ids: Optional[torch.Tensor] = None ) -> Tuple[torch.Tensor, torch.Tensor, Dict[str, List[Any]]]: B, L = input_ids.shape x = self.embed_tokens(input_ids) if attention_mask is not None: if attention_mask.dim() == 2: # Expand 2D [B, S] padding mask into 4D causal boolean mask [B, 1, L, S] B_m, S_m = attention_mask.shape causal_triangle = torch.tril(torch.ones((L, S_m), device=input_ids.device, dtype=torch.bool), diagonal=offset) pad_bool = attention_mask.bool().unsqueeze(1).unsqueeze(2) # [B, 1, 1, S] attention_mask = causal_triangle.unsqueeze(0).unsqueeze(0) & pad_bool elif attention_mask.dim() == 3: # Expand 3D [B, L, S] to 4D [B, 1, L, S] attention_mask = attention_mask.unsqueeze(1).bool() elif attention_mask.dtype not in (torch.bool, torch.float16, torch.bfloat16, torch.float32): attention_mask = attention_mask.bool() new_states = {"stem": [], "arbiter": [], "exit": [], "hypo": []} # 1. Stage 1: Denoising Stem for i, layer in enumerate(self.stem_layers): prev_st = past_states["stem"][i] if past_states else None x, st = layer(x, prev_state=prev_st, offset=offset, mask=attention_mask, state_reset_mask=state_reset_mask, position_ids=position_ids) new_states["stem"].append(st) x_stem = x # 2. Stage 2: Triad Processing # Branch A: Hopfield Core fact retrieval (Aux-loss-free PID routing) y_know, hopfield_loss = self.hopfield_core(x_stem) # Branch B: Continuous Domain Representation (8 SwiGLU layers) y_domain = x_stem for swiglu in self.domain_backbone: y_domain = y_domain + swiglu(y_domain) # Branch C: Hypothesis Subnetwork (6 layers: 5 DeltaNet + 1 Global Attention) y_hypo = x_stem for i, layer in enumerate(self.hypothesis_subnet): prev_st = past_states["hypo"][i] if past_states else None y_hypo, st = layer(y_hypo, prev_state=prev_st, offset=offset, mask=attention_mask, state_reset_mask=state_reset_mask, position_ids=position_ids) new_states["hypo"].append(st) # Adaptive Fusion y_triad = torch.cat([y_know, y_domain, y_hypo], dim=-1) gate = torch.sigmoid(self.fusion_gate(x_stem)) x_fused = self.fusion_norm(x_stem + self.fusion_proj(y_triad) * gate) # 3. Stage 3: Logic Arbiter (16 layers: 12 DeltaNet + 4 Global Attention) x_arb = x_fused for i, layer in enumerate(self.arbiter_layers): prev_st = past_states["arbiter"][i] if past_states else None x_arb, st = layer(x_arb, prev_state=prev_st, offset=offset, mask=attention_mask, state_reset_mask=state_reset_mask, position_ids=position_ids) new_states["arbiter"].append(st) x_arbiter = x_arb # 4. Stage 4: Multi-Highway Residual Integration & Exit Stem (4 layers DeltaNet) x_exit = self.exit_norm((x_stem + x_fused + x_arbiter) / math.sqrt(3.0)) for i, layer in enumerate(self.exit_layers): prev_st = past_states["exit"][i] if past_states else None x_exit, st = layer(x_exit, prev_state=prev_st, offset=offset, mask=attention_mask, state_reset_mask=state_reset_mask, position_ids=position_ids) new_states["exit"].append(st) x_out = self.final_norm(x_exit) return x_out, hopfield_loss, new_states class HetmanForCausalLM(HetmanPreTrainedModel): def __init__(self, config: HetmanConfig): super().__init__() self.config = config self.logit_softcap = getattr(config, "logit_softcap", 30.0) self.model = HetmanModel(config) # Weight tying with embeddings self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False) self.lm_head.weight = self.model.embed_tokens.weight # Multi-Token Prediction (MTP) Auxiliary Head self.mtp_head = MTPHead(config) def forward( self, input_ids: torch.Tensor, labels: Optional[torch.Tensor] = None, past_states: Optional[Dict[str, List[Any]]] = None, offset: int = 0, attention_mask: Optional[torch.Tensor] = None, state_reset_mask: Optional[torch.Tensor] = None, position_ids: Optional[torch.Tensor] = None ) -> Dict[str, Any]: hidden_states, hopfield_loss, new_states = self.model( input_ids, past_states=past_states, offset=offset, attention_mask=attention_mask, state_reset_mask=state_reset_mask, position_ids=position_ids ) logits = self.lm_head(hidden_states) # Apply LM head logit soft-capping to prevent logits divergence if self.logit_softcap > 0.0: logits = self.logit_softcap * torch.tanh(logits / self.logit_softcap) loss = None ce_loss = None mtp_loss = None if labels is not None: # 1. Primary Next-Token Prediction (t + 1) shift_logits = logits[..., :-1, :].contiguous() shift_labels = labels[..., 1:].contiguous() valid_mask = (shift_labels != -100) if valid_mask.any(): ce_loss = F.cross_entropy(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1)) else: ce_loss = torch.tensor(0.0, device=input_ids.device, requires_grad=True) # 2. Multi-Token Prediction (t + 2) if input_ids.shape[1] > 2: h_mtp = self.mtp_head(hidden_states) logits_mtp = self.lm_head(h_mtp) if self.logit_softcap > 0.0: logits_mtp = self.logit_softcap * torch.tanh(logits_mtp / self.logit_softcap) shift_logits_mtp = logits_mtp[..., :-2, :].contiguous() shift_labels_mtp = labels[..., 2:].contiguous() valid_mask_mtp = (shift_labels_mtp != -100) if valid_mask_mtp.any(): mtp_loss = F.cross_entropy(shift_logits_mtp.view(-1, self.config.vocab_size), shift_labels_mtp.view(-1)) else: mtp_loss = torch.tensor(0.0, device=input_ids.device) else: mtp_loss = torch.tensor(0.0, device=input_ids.device) # Composite loss: CE + 0.3 * MTP + 0.005 * Hopfield commitment loss = ce_loss + 0.3 * mtp_loss + 0.005 * hopfield_loss return HetmanCausalLMOutput( loss=loss, logits=logits, ce_loss=ce_loss, mtp_loss=mtp_loss, hopfield_loss=hopfield_loss, past_states=new_states ) @torch.no_grad() def generate( self, input_ids: Optional[torch.Tensor] = None, max_new_tokens: int = 256, temperature: float = 0.7, top_p: float = 0.9, eos_token_id: Any = (2, 5), # (2) and <|im_end|> (5) pad_token_id: int = 3, do_sample: Optional[bool] = None, attention_mask: Optional[torch.Tensor] = None, **kwargs ) -> torch.Tensor: """ Autoregressive generation with KV-cache / recurrent state preservation. Fully compatible with Hugging Face generate() callers and standard sampling pipelines. """ device = next(self.parameters()).device if input_ids is None or input_ids.numel() == 0: input_ids = torch.tensor([[1]], dtype=torch.long, device=device) # BOS token elif input_ids.dim() == 1: input_ids = input_ids.unsqueeze(0) B, seq_len = input_ids.shape if seq_len == 0: input_ids = torch.tensor([[1]], dtype=torch.long, device=device).expand(B, 1) seq_len = 1 current_ids = input_ids.clone() past_states = None if isinstance(eos_token_id, int): eos_set = {eos_token_id} else: eos_set = set(eos_token_id) unfinished_sequences = torch.ones(B, dtype=torch.bool, device=device) # If do_sample is explicitly False, force greedy argmax decoding if do_sample is False: temperature = 0.0 # Initial prefill pass outputs = self(current_ids, past_states=None, offset=0) past_states = outputs["past_states"] next_token_logits = outputs["logits"][:, -1, :] for step in range(max_new_tokens): if temperature >= 1e-4: scaled_logits = next_token_logits / temperature probs = F.softmax(scaled_logits, dim=-1) # Top-p (nucleus) filtering sorted_probs, sorted_indices = torch.sort(probs, descending=True) cumulative_probs = torch.cumsum(sorted_probs, dim=-1) sorted_indices_to_remove = cumulative_probs > top_p sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone() sorted_indices_to_remove[..., 0] = 0 indices_to_remove = sorted_indices_to_remove.scatter(1, sorted_indices, sorted_indices_to_remove) probs = probs.masked_fill(indices_to_remove, 0.0) probs = probs / probs.sum(dim=-1, keepdim=True) next_token = torch.multinomial(probs, num_samples=1) else: next_token = torch.argmax(next_token_logits, dim=-1, keepdim=True) tokens_to_append = torch.where( unfinished_sequences.unsqueeze(-1), next_token, torch.full_like(next_token, pad_token_id) ) current_ids = torch.cat([current_ids, tokens_to_append], dim=-1) for i in range(B): if next_token[i, 0].item() in eos_set: unfinished_sequences[i] = False if not unfinished_sequences.any(): break if step < max_new_tokens - 1: step_outputs = self(tokens_to_append, past_states=past_states, offset=seq_len + step) past_states = step_outputs["past_states"] next_token_logits = step_outputs["logits"][:, -1, :] return current_ids def count_parameters(self) -> Tuple[int, int]: total_params = sum(p.numel() for p in self.parameters()) # Hopfield V is 16 groups * 512 * 512 * 128 = 536,870,912 params, but only Top-32 + 1 shared is active per token active_hopfield = self.config.hopfield_num_groups * (32 + 1) * self.config.hopfield_val_dim inactive_hopfield = self.model.hopfield_core.V.numel() - active_hopfield active_params = total_params - inactive_hopfield return total_params, active_params