KitsuVp commited on
Commit
5feddac
·
verified ·
1 Parent(s): d07d145

Update modeling_neollm.py

Browse files
Files changed (1) hide show
  1. modeling_neollm.py +768 -19
modeling_neollm.py CHANGED
@@ -12,6 +12,12 @@ factorised attention log-priors (Litman & Guo, 2026), optional StackMemory
12
  (Zhang et al., NeurIPS 2025), and optional HOLA-derived episodic memory for
13
  the FlashAttention-2 IHA seq-expand path (Cui, 2026).
14
 
 
 
 
 
 
 
15
  The FlashAttention training paths deliberately use dense right-padded
16
  attention with a shared dtype and compilation contract across IHA and non-IHA.
17
  See ``NeoLLMModel.forward`` for its padding/packing constraints.
@@ -56,6 +62,8 @@ References:
56
  Towards Flexible and Stable Transformer Attention." arXiv:2602.23057.
57
  Leviathan Generator: Batley & Saha (2026). "A Separable Architecture for
58
  Continuous Token Representation in Language Models." arXiv:2601.22040.
 
 
59
  KHRONOS: Batley & Saha (2025). "KHRONOS: a Kernel-Based Neural Architecture
60
  for Rapid, Resource-Efficient Scientific Computation." arXiv:2505.13315.
61
  Spelling Bee Embeddings: Rabe, Clymo & Dong (2026). "Spelling Bee
@@ -76,6 +84,7 @@ References:
76
 
77
  import inspect
78
  import math
 
79
  from typing import Optional, Union, Tuple
80
 
81
  import torch
@@ -127,6 +136,7 @@ except (ImportError, ModuleNotFoundError, AttributeError):
127
 
128
  _LEV_KERNEL_AVAILABLE = False
129
  _leviathan_embedding_compiler_safe = None
 
130
  _leviathan_supports = None
131
  try:
132
  from cut_cross_entropy.leviathan import ( # type: ignore[import-not-found]
@@ -136,12 +146,40 @@ try:
136
  )
137
 
138
  _LEV_KERNEL_AVAILABLE = bool(_LEV_HAS_KERNEL_FORWARD)
 
 
 
 
 
 
 
 
139
  except (ImportError, ModuleNotFoundError, AttributeError):
140
  # The model must remain usable with a plain CCE installation. In that
141
  # environment the original reference LeviathanGenerator.forward below is
142
  # the complete embedding path.
143
  _LEV_HAS_KERNEL_FORWARD = False
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
  def _leviathan_config_supported(config) -> bool:
147
  """Check LEV shapes without depending on NeoLLM's optional dtype field."""
@@ -185,6 +223,23 @@ from .configuration_neollm import NeoLLMConfig
185
 
186
  from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
187
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  logger = logging.get_logger(__name__)
189
  _NEOLLM_FA_USE_TOP_LEFT_MASK = flash_attn_supports_top_left_mask()
190
 
@@ -443,6 +498,26 @@ class LeviathanGenerator(nn.Module):
443
  torch.empty(self.num_modes, self.krank, self.hidden_size)
444
  )
445
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  def _base_k_decompose(self, token_ids: torch.Tensor) -> torch.Tensor:
447
  """
448
  Deterministic base-b decomposition: i -> (i_0, ..., i_{k-1}).
@@ -463,6 +538,48 @@ class LeviathanGenerator(nn.Module):
463
  ids = ids // self.b
464
  return coords
465
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  @staticmethod
467
  def _normalize_bspline_basis(B: torch.Tensor) -> torch.Tensor:
468
  """
@@ -533,7 +650,8 @@ class LeviathanGenerator(nn.Module):
533
  *,
534
  meap_mask_embedding: Optional[torch.Tensor] = None,
535
  meap_mask_token_id: Optional[int] = None,
536
- ) -> torch.Tensor:
 
537
  """
538
  Generate embeddings from discrete token indices.
539
 
@@ -542,7 +660,10 @@ class LeviathanGenerator(nn.Module):
542
  Args:
543
  token_ids: (batch, seq_len) or (seq_len,).
544
  Returns:
545
- embeddings [*token_ids.shape, hidden_size].
 
 
 
546
  """
547
  has_meap = (
548
  meap_mask_embedding is not None or meap_mask_token_id is not None
@@ -562,7 +683,7 @@ class LeviathanGenerator(nn.Module):
562
  f"({self.hidden_size},)"
563
  )
564
 
565
- if (
566
  self.use_leviathan_triton
567
  and _LEV_KERNEL_AVAILABLE
568
  and _leviathan_embedding_compiler_safe is not None
@@ -580,6 +701,37 @@ class LeviathanGenerator(nn.Module):
580
  self.head_out_weight,
581
  )
582
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  ):
584
  params = {
585
  "codebooks": self.codebooks,
@@ -590,6 +742,23 @@ class LeviathanGenerator(nn.Module):
590
  "head_out_weight": self.head_out_weight,
591
  }
592
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
593
  return _leviathan_embedding_compiler_safe(
594
  token_ids,
595
  params,
@@ -603,6 +772,8 @@ class LeviathanGenerator(nn.Module):
603
  # implementation. A CUDA launch error must propagate: doing
604
  # reference work after a failed launch can poison the next
605
  # CUDA-graph/FlashAttention partition.
 
 
606
  pass
607
 
608
  target_dtype = self.codebooks.dtype
@@ -610,11 +781,7 @@ class LeviathanGenerator(nn.Module):
610
  N = token_ids.numel()
611
 
612
  # -- Stage 1: compositional codebook indexing -------------------------
613
- coords = self._base_k_decompose(token_ids)
614
- coords_flat = coords.reshape(N, self.k)
615
- z = torch.zeros(N, self.d_seed, device=token_ids.device, dtype=target_dtype)
616
- for r in range(self.k):
617
- z = z + self.codebooks[r][coords_flat[:, r]]
618
 
619
  # -- Stages 2-4: per-head projection, spline expansion, sum ----------
620
  e = torch.zeros(
@@ -655,11 +822,393 @@ class LeviathanGenerator(nn.Module):
655
  meap_mask_embedding.to(device=e.device, dtype=e.dtype),
656
  e,
657
  )
 
 
 
 
 
658
  return e
659
 
660
 
661
 
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  # ==================== ORIGINAL COMPONENTS ====================
664
 
665
 
@@ -4676,6 +5225,23 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
4676
  )
4677
  self.self_attn = NeoLLMAttention(config, layer_idx)
4678
  self.mlp = NeoLLMMLP(config)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4679
  if self.use_siamesenorm:
4680
  self.input_layernorm = None
4681
  self.post_attention_layernorm = None
@@ -4971,6 +5537,9 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
4971
  output_attentions: Optional[bool] = False,
4972
  repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
4973
  position_ids: Optional[torch.LongTensor] = None,
 
 
 
4974
  **kwargs: Unpack[FlashAttentionKwargs],
4975
  ) -> Tuple:
4976
  # SiameseNorm keeps two coupled streams with shared Attention/MLP
@@ -4990,6 +5559,7 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
4990
  h_attn, stack_memory, stack_memory_mask = self.apply_stack_memory(
4991
  h_attn, stack_memory, stack_memory_mask
4992
  )
 
4993
 
4994
  h_lns = self.lns_attn(h_attn) if self.use_lns else h_attn
4995
  attn_out, attn_weights, self.current_layer_fan = self.self_attn(
@@ -5020,7 +5590,21 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5020
  h_lns2 = self.lns_mlp(h_mlp) if self.use_lns else h_mlp
5021
  delta_m = self.mlp(h_lns2)
5022
 
5023
- shared_update = delta_m
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5024
 
5025
  x_next = x_after_attn + stream_scale * shared_update
5026
  y_next = y_after_attn + shared_update
@@ -5031,6 +5615,8 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5031
  outputs = (x_next, y_next)
5032
  if self.use_stack_memory:
5033
  outputs += (stack_memory, stack_memory_mask)
 
 
5034
  if output_attentions:
5035
  outputs += (attn_weights,)
5036
  return outputs
@@ -5046,6 +5632,9 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5046
  output_attentions: Optional[bool] = False,
5047
  repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
5048
  position_ids: Optional[torch.LongTensor] = None,
 
 
 
5049
  **kwargs: Unpack[FlashAttentionKwargs],
5050
  ) -> Tuple:
5051
  # ── Snapshot input ────────────────────────────────────────────────
@@ -5083,6 +5672,9 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5083
  h_normed = h_attn
5084
  else:
5085
  h_normed = _apply_norm(self.input_layernorm, h_attn)
 
 
 
5086
 
5087
  h_lns = self.lns_attn(h_normed) if self.use_lns else h_normed
5088
  hidden_states, attn_weights, self.current_layer_fan = self.self_attn(
@@ -5131,6 +5723,20 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5131
  h_lns2 = self.lns_mlp(h_normed2) if self.use_lns else h_normed2
5132
  delta_m = self.mlp(h_lns2)
5133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5134
  # ── Residual junction (MLP sublayer) ────��────────────────────────
5135
  # LAuReL augments the base MLP residual (residual_mlp + delta_m).
5136
  if self.use_laurel:
@@ -5148,6 +5754,8 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
5148
  hidden_states = self.gpas_mlp(mlp_aug) if self.use_gpas else mlp_aug
5149
 
5150
  outputs = (hidden_states,)
 
 
5151
  if output_attentions:
5152
  outputs += (attn_weights,)
5153
  return outputs
@@ -5658,6 +6266,37 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
5658
  # outputs starts with the same variance as a single projection.
5659
  out_std = self.config.initializer_range / math.sqrt(module.num_modes)
5660
  nn.init.normal_(module.head_out_weight, mean=0.0, std=out_std)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5661
 
5662
  elif isinstance(module, StackMemory):
5663
  nn.init.normal_(
@@ -5892,6 +6531,15 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
5892
  if (input_ids is None) ^ (inputs_embeds is not None):
5893
  raise ValueError("Specify exactly one of input_ids or inputs_embeds")
5894
 
 
 
 
 
 
 
 
 
 
5895
  # ── Embedding stage ────────────────────────────────────────────────
5896
  meap_mask_embedding = None
5897
  meap_mask_token_id = None
@@ -5914,13 +6562,33 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
5914
  # selection so byte features cannot alter masked positions.
5915
  fuse_meap_in_leviathan = meap_active and self.spelling_bee is None
5916
  if fuse_meap_in_leviathan:
5917
- inputs_embeds = self.token_generator(
5918
- input_ids,
5919
- meap_mask_embedding=meap_mask_embedding,
5920
- meap_mask_token_id=meap_mask_token_id,
5921
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5922
  else:
5923
- inputs_embeds = self.token_generator(input_ids)
5924
  meap_consumed = fuse_meap_in_leviathan
5925
  else:
5926
  inputs_embeds = self.embed_tokens(input_ids)
@@ -5954,6 +6622,26 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
5954
  inputs_embeds,
5955
  )
5956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5957
  if position_ids is None:
5958
  if attention_mask is not None:
5959
  position_ids = attention_mask.to(dtype=torch.long).cumsum(-1) - 1
@@ -6018,6 +6706,10 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
6018
  all_hidden_states = () if output_hidden_states else None
6019
  all_attentions = () if output_attentions else None
6020
  tweo_activations = () if output_tweo_activations else None
 
 
 
 
6021
 
6022
  # ── StackMemory state ─────────────────────────────────────────────
6023
  # Same source-level idea as StackTrans:
@@ -6130,6 +6822,9 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
6130
  output_attentions=output_attentions,
6131
  repo_rope_args=repo_rope_args,
6132
  position_ids=position_ids,
 
 
 
6133
  **kwargs,
6134
  )
6135
  hidden_states = layer_outputs[0]
@@ -6151,6 +6846,9 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
6151
  output_attentions=output_attentions,
6152
  repo_rope_args=repo_rope_args,
6153
  position_ids=position_ids,
 
 
 
6154
  **kwargs,
6155
  )
6156
  hidden_states = layer_outputs[0]
@@ -6160,6 +6858,16 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
6160
  if use_attn_res:
6161
  attn_res_partial = hidden_states
6162
 
 
 
 
 
 
 
 
 
 
 
6163
  if output_attentions:
6164
  all_attentions = all_attentions + (layer_outputs[extras_start],)
6165
  extras_start += 1
@@ -6191,15 +6899,18 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
6191
  for v in [hidden_states, None, all_hidden_states, all_attentions]
6192
  if v is not None
6193
  )
 
 
6194
  if output_tweo_activations:
6195
  return base_outputs + (tweo_activations,)
6196
  return base_outputs
6197
 
6198
- outputs = BaseModelOutputWithPast(
6199
  last_hidden_state=hidden_states,
6200
  past_key_values=None,
6201
  hidden_states=all_hidden_states,
6202
  attentions=all_attentions,
 
6203
  )
6204
  if output_tweo_activations:
6205
  return outputs, tweo_activations
@@ -8031,6 +8742,7 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8031
  self._last_nextlat_loss = None
8032
  self._last_nextlat_mse_loss = None
8033
  self._last_nextlat_kl_loss = None
 
8034
  self._last_total_loss = None
8035
 
8036
  if config.use_token_generator:
@@ -8211,17 +8923,35 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8211
  )
8212
 
8213
  # Unpack: model returns BaseModelOutputWithPast, or a tuple when
8214
- # return_dict=False (with tweo_activations appended when enabled)
 
8215
  tweo_activations = None
8216
  hidden_states_tuple = None
 
8217
  if isinstance(model_out, tuple):
8218
  outputs = model_out[0]
8219
  if tweo_enabled and len(model_out) >= 2:
8220
  tweo_activations = model_out[-1]
8221
  if isinstance(outputs, torch.Tensor):
8222
  hidden_states = outputs
8223
- if len(model_out) > 1 and isinstance(model_out[1], tuple):
8224
- hidden_states_tuple = model_out[1]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8225
  elif isinstance(outputs, tuple):
8226
  hidden_states = outputs[0]
8227
  if len(outputs) > 2:
@@ -8229,10 +8959,12 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8229
  else:
8230
  hidden_states = outputs.last_hidden_state
8231
  hidden_states_tuple = outputs.hidden_states
 
8232
  else:
8233
  outputs = model_out
8234
  hidden_states = outputs.last_hidden_state
8235
  hidden_states_tuple = outputs.hidden_states
 
8236
 
8237
  loss = None
8238
  ntp_loss = None
@@ -8255,6 +8987,7 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8255
  nextlat_loss = None
8256
  nextlat_mse_loss = None
8257
  nextlat_kl_loss = None
 
8258
  self._last_ntp_loss = None
8259
  self._last_ntp_ce_unweighted = None
8260
  self._last_mile_reweighting_delta = None
@@ -8280,6 +9013,7 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8280
  self._last_nextlat_loss = None
8281
  self._last_nextlat_mse_loss = None
8282
  self._last_nextlat_kl_loss = None
 
8283
  self._last_total_loss = None
8284
  if labels is not None:
8285
  if self.ntp_loss_backend == "liger":
@@ -8513,6 +9247,15 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8513
  )
8514
  loss = loss + nextlat_loss
8515
 
 
 
 
 
 
 
 
 
 
8516
  self._last_ntp_loss = ntp_loss.detach() if ntp_loss is not None else None
8517
  self._last_tweo_loss = tweo_loss.detach() if tweo_loss is not None else None
8518
  self._last_nitp_loss = nitp_loss.detach() if nitp_loss is not None else None
@@ -8608,6 +9351,9 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
8608
  self._last_nextlat_kl_loss = (
8609
  nextlat_kl_loss.detach() if nextlat_kl_loss is not None else None
8610
  )
 
 
 
8611
  self._last_total_loss = loss.detach() if loss is not None else None
8612
  logits = None
8613
  else:
@@ -8635,6 +9381,9 @@ __all__ = [
8635
  "NeoLLMPreTrainedModel",
8636
  "NeoLLMConfig",
8637
  "LeviathanGenerator",
 
 
 
8638
  "SpellingBeeEmbedding",
8639
  "StackMemory",
8640
  "FANLayer",
 
12
  (Zhang et al., NeurIPS 2025), and optional HOLA-derived episodic memory for
13
  the FlashAttention-2 IHA seq-expand path (Cui, 2026).
14
 
15
+ When enabled, Leviathan-JTok/JTok-M uses reference PyTorch operations by
16
+ default. The runtime-only ``config.jtok_kernel_backend = "triton"`` opt-in
17
+ dispatches the same module parameters through the compatible CCE JTok/JTok-M
18
+ adapter. The default ``"torch"`` path is unchanged and the backend choice
19
+ does not add parameters or buffers to the checkpoint.
20
+
21
  The FlashAttention training paths deliberately use dense right-padded
22
  attention with a shared dtype and compilation contract across IHA and non-IHA.
23
  See ``NeoLLMModel.forward`` for its padding/packing constraints.
 
62
  Towards Flexible and Stable Transformer Attention." arXiv:2602.23057.
63
  Leviathan Generator: Batley & Saha (2026). "A Separable Architecture for
64
  Continuous Token Representation in Language Models." arXiv:2601.22040.
65
+ JTok: Yang et al. (2026). "JTok: On Token Embedding as another Axis of
66
+ Scaling Law via Joint Token Self-modulation." arXiv:2602.00800.
67
  KHRONOS: Batley & Saha (2025). "KHRONOS: a Kernel-Based Neural Architecture
68
  for Rapid, Resource-Efficient Scientific Computation." arXiv:2505.13315.
69
  Spelling Bee Embeddings: Rabe, Clymo & Dong (2026). "Spelling Bee
 
84
 
85
  import inspect
86
  import math
87
+ from dataclasses import dataclass
88
  from typing import Optional, Union, Tuple
89
 
90
  import torch
 
136
 
137
  _LEV_KERNEL_AVAILABLE = False
138
  _leviathan_embedding_compiler_safe = None
139
+ _leviathan_embedding_with_seed_compiler_safe = None
140
  _leviathan_supports = None
141
  try:
142
  from cut_cross_entropy.leviathan import ( # type: ignore[import-not-found]
 
146
  )
147
 
148
  _LEV_KERNEL_AVAILABLE = bool(_LEV_HAS_KERNEL_FORWARD)
149
+ try:
150
+ from cut_cross_entropy.leviathan import ( # type: ignore[import-not-found]
151
+ leviathan_embedding_with_seed_compiler_safe as _leviathan_embedding_with_seed_compiler_safe,
152
+ )
153
+ except (ImportError, ModuleNotFoundError, AttributeError):
154
+ # An older CCE package may provide the legacy Leviathan kernel without
155
+ # the opt-in JTok geometry bridge. Keep the legacy path available.
156
+ pass
157
  except (ImportError, ModuleNotFoundError, AttributeError):
158
  # The model must remain usable with a plain CCE installation. In that
159
  # environment the original reference LeviathanGenerator.forward below is
160
  # the complete embedding path.
161
  _LEV_HAS_KERNEL_FORWARD = False
162
 
163
+ _LEV_GEOMETRY_KERNEL_AVAILABLE = (
164
+ _LEV_KERNEL_AVAILABLE
165
+ and _leviathan_embedding_with_seed_compiler_safe is not None
166
+ )
167
+
168
+ # JTok/JTok-M is a separate, strict opt-in path. Keep this import separate
169
+ # from the legacy Leviathan import above: an older CCE installation may expose
170
+ # the original Leviathan kernel but not the newer JTok adapter, and that must
171
+ # not silently disable the legacy path.
172
+ _JTOK_KERNEL_AVAILABLE = False
173
+ _apply_neollm_jtok = None
174
+ try:
175
+ from cut_cross_entropy.leviathan import ( # type: ignore[import-not-found]
176
+ apply_neollm_jtok as _apply_neollm_jtok,
177
+ )
178
+
179
+ _JTOK_KERNEL_AVAILABLE = True
180
+ except (ImportError, ModuleNotFoundError, AttributeError):
181
+ pass
182
+
183
 
184
  def _leviathan_config_supported(config) -> bool:
185
  """Check LEV shapes without depending on NeoLLM's optional dtype field."""
 
223
 
224
  from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
225
 
226
+
227
+ @dataclass
228
+ class NeoLLMBaseModelOutputWithPast(BaseModelOutputWithPast):
229
+ """Backbone output with compact, differentiable JTok-M statistics.
230
+
231
+ When JTok-M is active during training, ``jtokm_aux_stats`` contains one
232
+ ``(P, n, T)`` tuple per decoder layer. ``P`` is the differentiable sum of
233
+ the router probabilities, ``n`` is the detached hard Top-K count, and
234
+ ``T`` is the number of valid routed tokens. Keeping only these reductions
235
+ in the model output avoids retaining per-token router tensors until the
236
+ language-model loss is assembled.
237
+ """
238
+
239
+ jtokm_aux_stats: Optional[
240
+ Tuple[Tuple[torch.Tensor, torch.Tensor, torch.Tensor], ...]
241
+ ] = None
242
+
243
  logger = logging.get_logger(__name__)
244
  _NEOLLM_FA_USE_TOP_LEFT_MASK = flash_attn_supports_top_left_mask()
245
 
 
498
  torch.empty(self.num_modes, self.krank, self.hidden_size)
499
  )
500
 
501
+ # Shared continuous coordinate for Leviathan-JTok/JTok-M. The
502
+ # original JTok paper stores a separate V×D table per layer; NeoLLM
503
+ # replaces that table with a compact surface over one Leviathan seed.
504
+ # These bridge parameters are present only when JTok is requested, so
505
+ # the default Leviathan checkpoint/state-dict contract is unchanged.
506
+ if bool(getattr(config, "use_jtok", False)):
507
+ self.jtok_seed_proj_weight = nn.Parameter(
508
+ torch.empty(self.d_seed, self.d_seed)
509
+ )
510
+ self.jtok_seed_proj_bias = nn.Parameter(torch.zeros(self.d_seed))
511
+ self.jtok_seed_norm_weight = nn.Parameter(torch.ones(self.d_seed))
512
+ self.jtok_seed_norm_bias = nn.Parameter(torch.zeros(self.d_seed))
513
+ self.jtok_seed_norm_eps = 1e-5
514
+ else:
515
+ self.register_parameter("jtok_seed_proj_weight", None)
516
+ self.register_parameter("jtok_seed_proj_bias", None)
517
+ self.register_parameter("jtok_seed_norm_weight", None)
518
+ self.register_parameter("jtok_seed_norm_bias", None)
519
+ self.jtok_seed_norm_eps = 1e-5
520
+
521
  def _base_k_decompose(self, token_ids: torch.Tensor) -> torch.Tensor:
522
  """
523
  Deterministic base-b decomposition: i -> (i_0, ..., i_{k-1}).
 
538
  ids = ids // self.b
539
  return coords
540
 
541
+ def _codebook_seed(self, token_ids: torch.Tensor) -> torch.Tensor:
542
+ """Return the differentiable compositional Leviathan seed ``z``."""
543
+ orig_shape = token_ids.shape
544
+ N = token_ids.numel()
545
+ coords = self._base_k_decompose(token_ids).reshape(N, self.k)
546
+ z = torch.zeros(
547
+ N,
548
+ self.d_seed,
549
+ device=token_ids.device,
550
+ dtype=self.codebooks.dtype,
551
+ )
552
+ for r in range(self.k):
553
+ z = z + self.codebooks[r][coords[:, r]]
554
+ return z.reshape(*orig_shape, self.d_seed)
555
+
556
+ def _jtok_coordinate_from_seed(self, z: torch.Tensor) -> torch.Tensor:
557
+ r"""Map a raw Leviathan seed to the shared bounded JTok coordinate.
558
+
559
+ The bridge is a single learned ``Linear → LayerNorm → sigmoid`` path
560
+ shared by all decoder layers. It preserves the smooth compositional
561
+ geometry of Leviathan while giving every JTok surface the same
562
+ coordinate system.
563
+ """
564
+ if self.jtok_seed_proj_weight is None:
565
+ raise RuntimeError(
566
+ "JTok geometry requested but `use_jtok` was not enabled at "
567
+ "model construction time."
568
+ )
569
+ orig_shape = z.shape[:-1]
570
+ flat = z.reshape(-1, self.d_seed)
571
+ y = F.linear(
572
+ flat.to(self.jtok_seed_proj_weight.dtype),
573
+ self.jtok_seed_proj_weight,
574
+ self.jtok_seed_proj_bias,
575
+ ).float()
576
+ mean = y.mean(dim=-1, keepdim=True)
577
+ var = y.var(dim=-1, keepdim=True, unbiased=False)
578
+ y = (y - mean) * torch.rsqrt(var + self.jtok_seed_norm_eps)
579
+ y = y * self.jtok_seed_norm_weight.float() + self.jtok_seed_norm_bias.float()
580
+ y = torch.sigmoid(0.5 * y).clamp(0.0, 1.0)
581
+ return y.to(z.dtype).reshape(*orig_shape, self.d_seed)
582
+
583
  @staticmethod
584
  def _normalize_bspline_basis(B: torch.Tensor) -> torch.Tensor:
585
  """
 
650
  *,
651
  meap_mask_embedding: Optional[torch.Tensor] = None,
652
  meap_mask_token_id: Optional[int] = None,
653
+ return_jtok_geometry: bool = False,
654
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
655
  """
656
  Generate embeddings from discrete token indices.
657
 
 
660
  Args:
661
  token_ids: (batch, seq_len) or (seq_len,).
662
  Returns:
663
+ embeddings [*token_ids.shape, hidden_size]. When
664
+ ``return_jtok_geometry=True``, returns ``(embeddings, z_tilde)``
665
+ where ``z_tilde`` is the shared differentiable Leviathan/JTok
666
+ coordinate with shape ``[*token_ids.shape, d_seed]``.
667
  """
668
  has_meap = (
669
  meap_mask_embedding is not None or meap_mask_token_id is not None
 
683
  f"({self.hidden_size},)"
684
  )
685
 
686
+ leviathan_kernel_ready = (
687
  self.use_leviathan_triton
688
  and _LEV_KERNEL_AVAILABLE
689
  and _leviathan_embedding_compiler_safe is not None
 
701
  self.head_out_weight,
702
  )
703
  )
704
+ )
705
+ require_leviathan_triton = bool(
706
+ getattr(self.config, "_require_leviathan_triton", False)
707
+ )
708
+ if require_leviathan_triton and not leviathan_kernel_ready:
709
+ raise RuntimeError(
710
+ "This run requires the Triton Leviathan kernel, but the "
711
+ "installed CCE package or the current geometry is not "
712
+ "supported. Refusing a reference fallback."
713
+ )
714
+ if (
715
+ return_jtok_geometry
716
+ and str(getattr(self.config, "jtok_kernel_backend", "torch"))
717
+ .strip()
718
+ .lower()
719
+ == "triton"
720
+ and not (leviathan_kernel_ready and _LEV_GEOMETRY_KERNEL_AVAILABLE)
721
+ ):
722
+ raise RuntimeError(
723
+ "JTok Triton requires a supported CUDA Leviathan kernel and "
724
+ "the CCE geometry adapter; refusing a silent reference fallback."
725
+ )
726
+
727
+ # Ordinary Leviathan calls keep their existing embedding-only custom
728
+ # op. JTok additionally needs the raw compositional seed. The CCE
729
+ # adapter keeps the legacy kernel for the embedding and exposes only a
730
+ # small differentiable base-b/codebook bridge for the geometry; this
731
+ # avoids both a full reference-Leviathan detour and a silent cut in the
732
+ # JTok -> codebook gradient.
733
+ if (
734
+ leviathan_kernel_ready
735
  ):
736
  params = {
737
  "codebooks": self.codebooks,
 
742
  "head_out_weight": self.head_out_weight,
743
  }
744
  try:
745
+ if return_jtok_geometry:
746
+ if not _LEV_GEOMETRY_KERNEL_AVAILABLE:
747
+ raise RuntimeError(
748
+ "JTok geometry requested with the Leviathan kernel, "
749
+ "but the installed CCE package lacks the geometry "
750
+ "adapter."
751
+ )
752
+ embedding, seed = _leviathan_embedding_with_seed_compiler_safe(
753
+ token_ids,
754
+ params,
755
+ self.config,
756
+ self.knot_grid,
757
+ mask_embedding=meap_mask_embedding,
758
+ mask_token_id=meap_mask_token_id,
759
+ )
760
+ embedding = embedding.reshape(*token_ids.shape, self.hidden_size)
761
+ return embedding, self._jtok_coordinate_from_seed(seed)
762
  return _leviathan_embedding_compiler_safe(
763
  token_ids,
764
  params,
 
772
  # implementation. A CUDA launch error must propagate: doing
773
  # reference work after a failed launch can poison the next
774
  # CUDA-graph/FlashAttention partition.
775
+ if require_leviathan_triton:
776
+ raise
777
  pass
778
 
779
  target_dtype = self.codebooks.dtype
 
781
  N = token_ids.numel()
782
 
783
  # -- Stage 1: compositional codebook indexing -------------------------
784
+ z = self._codebook_seed(token_ids).reshape(N, self.d_seed)
 
 
 
 
785
 
786
  # -- Stages 2-4: per-head projection, spline expansion, sum ----------
787
  e = torch.zeros(
 
822
  meap_mask_embedding.to(device=e.device, dtype=e.dtype),
823
  e,
824
  )
825
+ if return_jtok_geometry:
826
+ z_jtok = self._jtok_coordinate_from_seed(
827
+ z.reshape(*orig_shape, self.d_seed)
828
+ )
829
+ return e, z_jtok
830
  return e
831
 
832
 
833
 
834
 
835
+ # ==================== LEVIATHAN-JTOK / JTOK-M MODULATION ====================
836
+
837
+
838
+ class LeviathanJTok(nn.Module):
839
+ r"""Pure-PyTorch Leviathan-coupled implementation of JTok and JTok-M.
840
+
841
+ ``use_jtok=True, use_jtokm=False`` activates JTok. Enabling
842
+ ``use_jtokm=True`` upgrades the same module to JTok-M; the configuration
843
+ validates that JTok and the Leviathan generator are active first.
844
+
845
+ The original JTok paper stores a token table per decoder layer. NeoLLM
846
+ keeps the JTok modulation/routing equations but replaces every table row
847
+ with a continuous CP-separable B-spline surface over the shared
848
+ Leviathan-derived coordinate ``z_tilde``:
849
+
850
+ .. math::
851
+ \hat{\Delta m}_x^l = \Delta m_x^l \odot
852
+ (1+s^l\odot\operatorname{Norm}(S_l(\tilde z_x)))
853
+
854
+ JTok-M evaluates the selected Top-K surfaces and injects their normalized
855
+ mixture as ``Delta_m + Delta_r`` with the paper's
856
+ ``1/sqrt(2L)`` depth factor. The default implementation is reference
857
+ PyTorch. Setting the runtime-only ``config.jtok_kernel_backend`` to
858
+ ``"triton"`` dispatches through the optional CCE JTok/JTok-M adapter while
859
+ preserving this module's parameters, state-dict layout, and decoder return
860
+ contract. The existing optional Leviathan embedding kernel remains a
861
+ separate path for ordinary embedding calls. The Triton choice is strict:
862
+ if the adapter is unavailable, forward raises instead of silently
863
+ changing the training or benchmark path back to Torch.
864
+
865
+ The temporary ``surface_chunk_tokens`` value bounds inference/evaluation
866
+ work tiles only. It is not a context-length, batch-size, or VRAM limit.
867
+ """
868
+
869
+ def __init__(self, config: NeoLLMConfig, layer_idx: int):
870
+ super().__init__()
871
+ self.layer_idx = int(layer_idx)
872
+ self.use_mixture = bool(getattr(config, "use_jtokm", False))
873
+ self.jtok_kernel_backend = str(
874
+ getattr(config, "jtok_kernel_backend", "torch")
875
+ ).strip().lower()
876
+ if self.jtok_kernel_backend not in {"torch", "triton"}:
877
+ raise ValueError(
878
+ "`jtok_kernel_backend` must be either `torch` or `triton`."
879
+ )
880
+ if self.jtok_kernel_backend == "triton" and not _JTOK_KERNEL_AVAILABLE:
881
+ raise RuntimeError(
882
+ "`jtok_kernel_backend='triton'` was requested, but the "
883
+ "installed CCE package does not expose `apply_neollm_jtok`. "
884
+ "Install the compatible JTok/JTok-M CCE implementation or "
885
+ "set `jtok_kernel_backend='torch'`."
886
+ )
887
+ self.hidden_size = int(config.hidden_size)
888
+ self.d_seed = int(config.generator_d_seed)
889
+ self.num_knots = int(config.generator_num_knots)
890
+ self.num_modes = int(getattr(config, "jtok_num_modes", 4))
891
+ self.num_experts = (
892
+ int(getattr(config, "jtok_num_experts", 5))
893
+ if self.use_mixture
894
+ else 1
895
+ )
896
+ self.top_k = (
897
+ int(getattr(config, "jtok_top_k", 2))
898
+ if self.use_mixture
899
+ else 1
900
+ )
901
+ self.norm_eps = float(getattr(config, "jtok_norm_eps", 1e-6))
902
+ # Work-tile size only. The optional attribute is intentionally read
903
+ # with getattr so older config.json files remain loadable.
904
+ self.surface_chunk_tokens = max(
905
+ int(getattr(config, "jtok_surface_chunk_tokens", 2048)), 1
906
+ )
907
+ self.jtokm_residual_scale = 1.0 / math.sqrt(
908
+ 2.0 * float(config.num_hidden_layers)
909
+ )
910
+
911
+ self.register_buffer(
912
+ "knot_grid",
913
+ torch.linspace(0.0, 1.0, self.num_knots),
914
+ persistent=True,
915
+ )
916
+
917
+ # Continuous replacement for the paper's per-token tables. These
918
+ # remain ordinary Parameters so both their surface and the shared
919
+ # Leviathan codebooks receive gradients during pretraining.
920
+ self.spline_coeff = nn.Parameter(
921
+ torch.empty(
922
+ self.num_experts,
923
+ self.num_modes,
924
+ self.d_seed,
925
+ self.num_knots,
926
+ )
927
+ )
928
+ self.W_out = nn.Parameter(
929
+ torch.empty(self.num_experts, self.num_modes, self.hidden_size)
930
+ )
931
+ self.W_res = nn.Parameter(
932
+ torch.empty(self.num_experts, self.d_seed, self.hidden_size)
933
+ )
934
+ self.scaler = nn.Parameter(torch.ones(self.hidden_size))
935
+ self.router = (
936
+ nn.Linear(self.hidden_size, self.num_experts, bias=False)
937
+ if self.use_mixture
938
+ else None
939
+ )
940
+
941
+ def _bspline_basis(self, z_flat: torch.Tensor) -> torch.Tensor:
942
+ """Evaluate the normalized quadratic B-spline basis in FP32."""
943
+ scale = float(self.num_knots - 1)
944
+ z32 = z_flat.float().unsqueeze(-1)
945
+ grid = self.knot_grid.float().view(1, 1, -1)
946
+ d = (z32 - grid).abs() * scale
947
+ B = torch.where(
948
+ d < 0.5,
949
+ 0.75 - d.square(),
950
+ torch.where(
951
+ d < 1.5,
952
+ 0.5 * (1.5 - d).square(),
953
+ torch.zeros_like(d),
954
+ ),
955
+ )
956
+ return B / B.sum(dim=-1, keepdim=True).clamp_min(1e-12)
957
+
958
+ def _eval_surfaces(
959
+ self,
960
+ z_flat: torch.Tensor,
961
+ target_dtype: torch.dtype,
962
+ ) -> torch.Tensor:
963
+ """Evaluate all continuous surfaces, returning ``[N, E, D]``."""
964
+ B = self._bspline_basis(z_flat)
965
+ phi = torch.einsum("emrg,nrg->nemr", self.spline_coeff.float(), B)
966
+ log_mag = torch.log(phi.abs() + 1e-9).sum(dim=-1)
967
+ num_neg = (phi < 0).to(torch.int32).sum(dim=-1)
968
+ prod_sign = 1.0 - 2.0 * (num_neg % 2).float()
969
+ modes = (prod_sign * torch.exp(log_mag)).to(target_dtype)
970
+ out_modes = torch.einsum(
971
+ "nem,emd->ned", modes, self.W_out.to(target_dtype)
972
+ )
973
+ out_res = torch.einsum(
974
+ "nr,erd->ned",
975
+ z_flat.to(target_dtype),
976
+ self.W_res.to(target_dtype),
977
+ )
978
+ return out_modes + out_res
979
+
980
+ def _eval_selected_surfaces(
981
+ self,
982
+ z_flat: torch.Tensor,
983
+ expert_idx: torch.Tensor,
984
+ target_dtype: torch.dtype,
985
+ ) -> torch.Tensor:
986
+ """Evaluate only the selected expert surfaces for each token."""
987
+ if expert_idx.ndim != 2:
988
+ raise ValueError("expert_idx must have shape [tokens, selected_experts]")
989
+ N, selected_k = expert_idx.shape
990
+ basis_all = self._bspline_basis(z_flat)
991
+ selected_flat = torch.zeros(
992
+ N * selected_k,
993
+ self.hidden_size,
994
+ dtype=target_dtype,
995
+ device=z_flat.device,
996
+ )
997
+ # Top-K indices are unique per token, so each flattened destination is
998
+ # written once. This avoids materializing [N,K,M,D] or [N,K,R,D].
999
+ for expert_idx_value in range(self.num_experts):
1000
+ token_idx, slot_idx = torch.where(expert_idx == expert_idx_value)
1001
+ flat_idx = token_idx * selected_k + slot_idx
1002
+ z_selected = z_flat[token_idx]
1003
+ B = basis_all[token_idx]
1004
+ coeff = self.spline_coeff[expert_idx_value].float()
1005
+ phi = torch.einsum("sdg,mdg->smd", B, coeff)
1006
+ log_mag = torch.log(phi.abs() + 1e-9).sum(dim=-1)
1007
+ num_neg = (phi < 0).to(torch.int32).sum(dim=-1)
1008
+ prod_sign = 1.0 - 2.0 * (num_neg % 2).float()
1009
+ modes = prod_sign * torch.exp(log_mag)
1010
+ values = modes.to(target_dtype) @ self.W_out[
1011
+ expert_idx_value
1012
+ ].to(target_dtype)
1013
+ values = values + z_selected.to(target_dtype) @ self.W_res[
1014
+ expert_idx_value
1015
+ ].to(target_dtype)
1016
+ selected_flat = selected_flat.index_copy(0, flat_idx, values)
1017
+ return selected_flat.reshape(N, selected_k, self.hidden_size)
1018
+
1019
+ def _eval_selected_surfaces_tiled(
1020
+ self,
1021
+ z_flat: torch.Tensor,
1022
+ expert_idx: torch.Tensor,
1023
+ target_dtype: torch.dtype,
1024
+ ) -> torch.Tensor:
1025
+ """Route-first surface evaluation with bounded temporary token tiles."""
1026
+ if z_flat.shape[0] != expert_idx.shape[0]:
1027
+ raise ValueError("z_flat and expert_idx must contain the same token count")
1028
+ chunks = []
1029
+ for start in range(0, z_flat.shape[0], self.surface_chunk_tokens):
1030
+ stop = min(start + self.surface_chunk_tokens, z_flat.shape[0])
1031
+ chunks.append(
1032
+ self._eval_selected_surfaces(
1033
+ z_flat[start:stop], expert_idx[start:stop], target_dtype
1034
+ )
1035
+ )
1036
+ if not chunks:
1037
+ return z_flat.new_empty((0, expert_idx.shape[1], self.hidden_size))
1038
+ return torch.cat(chunks, dim=0)
1039
+
1040
+ def _eval_selected_surfaces_dense_tiled(
1041
+ self,
1042
+ z_flat: torch.Tensor,
1043
+ expert_idx: torch.Tensor,
1044
+ target_dtype: torch.dtype,
1045
+ ) -> torch.Tensor:
1046
+ """Compile-friendly selected evaluation over bounded dense tiles."""
1047
+ if z_flat.shape[0] != expert_idx.shape[0]:
1048
+ raise ValueError("z_flat and expert_idx must contain the same token count")
1049
+ chunks = []
1050
+ for start in range(0, z_flat.shape[0], self.surface_chunk_tokens):
1051
+ stop = min(start + self.surface_chunk_tokens, z_flat.shape[0])
1052
+ surfaces = self._eval_surfaces(z_flat[start:stop], target_dtype)
1053
+ gather_idx = expert_idx[start:stop].unsqueeze(-1).expand(
1054
+ stop - start, expert_idx.shape[1], self.hidden_size
1055
+ )
1056
+ chunks.append(surfaces.gather(1, gather_idx))
1057
+ if not chunks:
1058
+ return z_flat.new_empty((0, expert_idx.shape[1], self.hidden_size))
1059
+ return torch.cat(chunks, dim=0)
1060
+
1061
+ def _l2_normalize(self, x: torch.Tensor) -> torch.Tensor:
1062
+ return x / (x.norm(dim=-1, keepdim=True) + self.norm_eps)
1063
+
1064
+ def _valid_mask(
1065
+ self,
1066
+ valid_mask: Optional[torch.Tensor],
1067
+ N: int,
1068
+ device: torch.device,
1069
+ ) -> torch.Tensor:
1070
+ if valid_mask is None:
1071
+ return torch.ones(N, device=device, dtype=torch.bool)
1072
+ return valid_mask.reshape(N).to(device=device, dtype=torch.bool)
1073
+
1074
+ def _jtokm_aux_stats(
1075
+ self,
1076
+ logits: torch.Tensor,
1077
+ topk_idx: torch.Tensor,
1078
+ mask: torch.Tensor,
1079
+ ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
1080
+ """Return differentiable probability and hard Top-K count reductions."""
1081
+ aux_sigmoid = torch.sigmoid(logits.float())
1082
+ # Normalize only the auxiliary probability branch. The forward
1083
+ # mixture remains selected-only Sigmoid+TopK, as in the source design.
1084
+ prob_all = aux_sigmoid / aux_sigmoid.sum(
1085
+ dim=-1, keepdim=True
1086
+ ).clamp_min(self.norm_eps)
1087
+ valid32 = mask.to(prob_all.dtype).unsqueeze(-1)
1088
+ p_sum = (prob_all * valid32).sum(dim=0)
1089
+ onehot = torch.zeros_like(prob_all).scatter(1, topk_idx, 1.0)
1090
+ f_sum = (onehot * valid32).sum(dim=0).detach()
1091
+ T = mask.sum().to(dtype=torch.float32).detach()
1092
+ return p_sum, f_sum, T
1093
+
1094
+ def forward(
1095
+ self,
1096
+ delta_m: torch.Tensor,
1097
+ z_tilde: torch.Tensor,
1098
+ *,
1099
+ router_state: Optional[torch.Tensor] = None,
1100
+ valid_mask: Optional[torch.Tensor] = None,
1101
+ compute_aux: bool = False,
1102
+ ) -> Tuple[
1103
+ torch.Tensor,
1104
+ Optional[Tuple[torch.Tensor, torch.Tensor, torch.Tensor]],
1105
+ ]:
1106
+ """Apply JTok/JTok-M and optionally return training-only router stats."""
1107
+ if self.jtok_kernel_backend == "triton":
1108
+ # Dispatch only: this branch does not change compiler mode,
1109
+ # CUDA-graph policy, training state, optimizer behavior, or any
1110
+ # model-global state. The adapter returns the same
1111
+ # ``(updated_delta, compact_router_stats)`` contract as the Torch
1112
+ # implementation, so the surrounding pretraining graph remains
1113
+ # unchanged when the backend is switched.
1114
+ if _apply_neollm_jtok is None:
1115
+ raise RuntimeError(
1116
+ "JTok Triton adapter became unavailable after module "
1117
+ "construction; refusing an implicit Torch fallback."
1118
+ )
1119
+ return _apply_neollm_jtok(
1120
+ self,
1121
+ delta_m,
1122
+ z_tilde,
1123
+ router_state=router_state,
1124
+ valid_mask=valid_mask,
1125
+ compute_aux=bool(compute_aux and self.use_mixture),
1126
+ backend="triton",
1127
+ )
1128
+
1129
+ orig_shape = delta_m.shape
1130
+ N = delta_m.numel() // self.hidden_size
1131
+ dm = delta_m.reshape(N, self.hidden_size)
1132
+ z = z_tilde.reshape(N, self.d_seed)
1133
+ mask = self._valid_mask(valid_mask, N, dm.device)
1134
+ mask_f = mask.to(dm.dtype).unsqueeze(-1)
1135
+
1136
+ if not self.use_mixture:
1137
+ surfaces = self._eval_surfaces(z, dm.dtype)
1138
+ token_direction = self._l2_normalize(surfaces[:, 0, :])
1139
+ gate = 1.0 + self.scaler.to(dm.dtype) * token_direction
1140
+ gate = torch.where(mask.unsqueeze(-1), gate, torch.ones_like(gate))
1141
+ return (dm * gate).reshape(orig_shape), None
1142
+
1143
+ if router_state is None:
1144
+ raise ValueError("JTok-M requires a pre-attention `router_state`.")
1145
+ h = router_state.reshape(N, self.hidden_size)
1146
+ h = h * torch.rsqrt(h.square().mean(dim=-1, keepdim=True) + self.norm_eps)
1147
+ logits = self.router(h)
1148
+ topk_vals, topk_idx = torch.topk(logits, self.top_k, dim=-1)
1149
+ selected_prob = torch.sigmoid(topk_vals)
1150
+ weights = selected_prob / selected_prob.sum(
1151
+ dim=-1, keepdim=True
1152
+ ).clamp_min(self.norm_eps)
1153
+
1154
+ # Match the Torch reference semantics: keep the small dense path for
1155
+ # gradient-enabled training and use route-first tiles for large eager
1156
+ # evaluation. Both routes implement the same surface equations.
1157
+ if N <= self.surface_chunk_tokens or torch.is_grad_enabled():
1158
+ surfaces = self._eval_surfaces(z, dm.dtype)
1159
+ gather_idx = topk_idx.unsqueeze(-1).expand(
1160
+ N, self.top_k, self.hidden_size
1161
+ )
1162
+ selected = surfaces.gather(1, gather_idx)
1163
+ elif getattr(torch.compiler, "is_compiling", lambda: False)():
1164
+ selected = self._eval_selected_surfaces_dense_tiled(
1165
+ z, topk_idx, dm.dtype
1166
+ )
1167
+ else:
1168
+ selected = self._eval_selected_surfaces_tiled(
1169
+ z, topk_idx, dm.dtype
1170
+ )
1171
+
1172
+ mixed = (weights.unsqueeze(-1) * selected).sum(dim=1)
1173
+ delta_r = (
1174
+ self.jtokm_residual_scale
1175
+ * self.scaler.to(dm.dtype)
1176
+ * self._l2_normalize(mixed)
1177
+ )
1178
+ delta_r = delta_r * mask_f
1179
+ shared_update = dm + delta_r
1180
+ aux_stats = self._jtokm_aux_stats(logits, topk_idx, mask) if compute_aux else None
1181
+ return shared_update.reshape(orig_shape), aux_stats
1182
+
1183
+
1184
+ def compute_jtokm_aux_loss(
1185
+ aux_stats_list: Tuple[Tuple[torch.Tensor, torch.Tensor, torch.Tensor], ...],
1186
+ *,
1187
+ n_e: int,
1188
+ top_k: int,
1189
+ weight: float,
1190
+ ) -> torch.Tensor:
1191
+ r"""Compute the JTok-M load-balancing objective from compact reductions.
1192
+
1193
+ For each layer, ``p_i=P_i/T`` and ``f_i=n_i/(T*K)``; the returned value is
1194
+ the layer-average of ``weight * n_e * sum_i(p_i*f_i)``. ``P_i`` remains
1195
+ attached to the router graph while hard Top-K counts are detached.
1196
+ """
1197
+ if not aux_stats_list:
1198
+ raise ValueError("JTok-M auxiliary loss requires non-empty router stats.")
1199
+ layer_losses = []
1200
+ for p_sum, f_sum, T in aux_stats_list:
1201
+ denom_t = T.to(device=p_sum.device, dtype=torch.float32).clamp_min(1.0)
1202
+ p_i = p_sum.float() / denom_t
1203
+ f_i = f_sum.to(device=p_sum.device, dtype=torch.float32) / (
1204
+ denom_t * float(top_k)
1205
+ )
1206
+ layer_losses.append(float(n_e) * (p_i * f_i).sum())
1207
+ mean_loss = torch.stack(layer_losses).mean()
1208
+ lambda_t = torch.as_tensor(weight, device=mean_loss.device, dtype=torch.float32)
1209
+ return lambda_t * mean_loss
1210
+
1211
+
1212
  # ==================== ORIGINAL COMPONENTS ====================
1213
 
1214
 
 
5225
  )
5226
  self.self_attn = NeoLLMAttention(config, layer_idx)
5227
  self.mlp = NeoLLMMLP(config)
5228
+ # JTok/JTok-M operates on the shared MLP update. It is instantiated
5229
+ # only when the corresponding config flag is active; the default
5230
+ # training graph therefore keeps the original residual topology.
5231
+ self.use_jtok = bool(getattr(config, "use_jtok", False))
5232
+ self.use_jtokm = bool(getattr(config, "use_jtokm", False))
5233
+ if self.use_jtokm and not self.use_jtok:
5234
+ # ``NeoLLMConfig`` validates this relationship, but decoder layers
5235
+ # are also constructed directly by a few checkpoint conversion and
5236
+ # test paths. Fail explicitly there instead of silently dropping
5237
+ # JTok-M while leaving the rest of the model apparently valid.
5238
+ raise ValueError(
5239
+ "`use_jtokm=True` requires `use_jtok=True`; enable the base "
5240
+ "JTok path before enabling JTok-M."
5241
+ )
5242
+ self.jtok = (
5243
+ LeviathanJTok(config, layer_idx) if self.use_jtok else None
5244
+ )
5245
  if self.use_siamesenorm:
5246
  self.input_layernorm = None
5247
  self.post_attention_layernorm = None
 
5537
  output_attentions: Optional[bool] = False,
5538
  repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
5539
  position_ids: Optional[torch.LongTensor] = None,
5540
+ jtok_z_tilde: Optional[torch.Tensor] = None,
5541
+ jtok_valid_mask: Optional[torch.Tensor] = None,
5542
+ jtok_compute_aux: bool = False,
5543
  **kwargs: Unpack[FlashAttentionKwargs],
5544
  ) -> Tuple:
5545
  # SiameseNorm keeps two coupled streams with shared Attention/MLP
 
5559
  h_attn, stack_memory, stack_memory_mask = self.apply_stack_memory(
5560
  h_attn, stack_memory, stack_memory_mask
5561
  )
5562
+ jtok_router_state = h_attn
5563
 
5564
  h_lns = self.lns_attn(h_attn) if self.use_lns else h_attn
5565
  attn_out, attn_weights, self.current_layer_fan = self.self_attn(
 
5590
  h_lns2 = self.lns_mlp(h_mlp) if self.use_lns else h_mlp
5591
  delta_m = self.mlp(h_lns2)
5592
 
5593
+ jtok_aux_stats = None
5594
+ if self.jtok is not None:
5595
+ if jtok_z_tilde is None:
5596
+ raise ValueError(
5597
+ "Active JTok/JTok-M requires Leviathan `jtok_z_tilde`."
5598
+ )
5599
+ shared_update, jtok_aux_stats = self.jtok(
5600
+ delta_m,
5601
+ jtok_z_tilde,
5602
+ router_state=jtok_router_state if self.use_jtokm else None,
5603
+ valid_mask=jtok_valid_mask,
5604
+ compute_aux=bool(jtok_compute_aux and self.use_jtokm),
5605
+ )
5606
+ else:
5607
+ shared_update = delta_m
5608
 
5609
  x_next = x_after_attn + stream_scale * shared_update
5610
  y_next = y_after_attn + shared_update
 
5615
  outputs = (x_next, y_next)
5616
  if self.use_stack_memory:
5617
  outputs += (stack_memory, stack_memory_mask)
5618
+ if jtok_aux_stats is not None:
5619
+ outputs += jtok_aux_stats
5620
  if output_attentions:
5621
  outputs += (attn_weights,)
5622
  return outputs
 
5632
  output_attentions: Optional[bool] = False,
5633
  repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
5634
  position_ids: Optional[torch.LongTensor] = None,
5635
+ jtok_z_tilde: Optional[torch.Tensor] = None,
5636
+ jtok_valid_mask: Optional[torch.Tensor] = None,
5637
+ jtok_compute_aux: bool = False,
5638
  **kwargs: Unpack[FlashAttentionKwargs],
5639
  ) -> Tuple:
5640
  # ── Snapshot input ────────────────────────────────────────────────
 
5672
  h_normed = h_attn
5673
  else:
5674
  h_normed = _apply_norm(self.input_layernorm, h_attn)
5675
+ # JTok-M follows the source design and routes from the fused
5676
+ # pre-attention contextual state, before the attention output is added.
5677
+ jtok_router_state = h_normed
5678
 
5679
  h_lns = self.lns_attn(h_normed) if self.use_lns else h_normed
5680
  hidden_states, attn_weights, self.current_layer_fan = self.self_attn(
 
5723
  h_lns2 = self.lns_mlp(h_normed2) if self.use_lns else h_normed2
5724
  delta_m = self.mlp(h_lns2)
5725
 
5726
+ jtok_aux_stats = None
5727
+ if self.jtok is not None:
5728
+ if jtok_z_tilde is None:
5729
+ raise ValueError(
5730
+ "Active JTok/JTok-M requires Leviathan `jtok_z_tilde`."
5731
+ )
5732
+ delta_m, jtok_aux_stats = self.jtok(
5733
+ delta_m,
5734
+ jtok_z_tilde,
5735
+ router_state=jtok_router_state if self.use_jtokm else None,
5736
+ valid_mask=jtok_valid_mask,
5737
+ compute_aux=bool(jtok_compute_aux and self.use_jtokm),
5738
+ )
5739
+
5740
  # ── Residual junction (MLP sublayer) ────��────────────────────────
5741
  # LAuReL augments the base MLP residual (residual_mlp + delta_m).
5742
  if self.use_laurel:
 
5754
  hidden_states = self.gpas_mlp(mlp_aug) if self.use_gpas else mlp_aug
5755
 
5756
  outputs = (hidden_states,)
5757
+ if jtok_aux_stats is not None:
5758
+ outputs += jtok_aux_stats
5759
  if output_attentions:
5760
  outputs += (attn_weights,)
5761
  return outputs
 
6266
  # outputs starts with the same variance as a single projection.
6267
  out_std = self.config.initializer_range / math.sqrt(module.num_modes)
6268
  nn.init.normal_(module.head_out_weight, mean=0.0, std=out_std)
6269
+ if module.jtok_seed_proj_weight is not None:
6270
+ nn.init.normal_(
6271
+ module.jtok_seed_proj_weight,
6272
+ mean=0.0,
6273
+ std=self.config.initializer_range,
6274
+ )
6275
+ nn.init.zeros_(module.jtok_seed_proj_bias)
6276
+ module.jtok_seed_norm_weight.data.fill_(1.0)
6277
+ module.jtok_seed_norm_bias.data.zero_()
6278
+
6279
+ elif isinstance(module, LeviathanJTok):
6280
+ # Start continuous JTok surfaces close to a neutral residual
6281
+ # modulation while leaving all parameters trainable immediately.
6282
+ nn.init.normal_(module.spline_coeff, mean=1.0, std=0.1)
6283
+ nn.init.normal_(
6284
+ module.W_out,
6285
+ mean=0.0,
6286
+ std=self.config.initializer_range,
6287
+ )
6288
+ nn.init.normal_(
6289
+ module.W_res,
6290
+ mean=0.0,
6291
+ std=self.config.initializer_range,
6292
+ )
6293
+ module.scaler.data.fill_(1.0)
6294
+ if module.router is not None:
6295
+ nn.init.normal_(
6296
+ module.router.weight,
6297
+ mean=0.0,
6298
+ std=self.config.initializer_range,
6299
+ )
6300
 
6301
  elif isinstance(module, StackMemory):
6302
  nn.init.normal_(
 
6531
  if (input_ids is None) ^ (inputs_embeds is not None):
6532
  raise ValueError("Specify exactly one of input_ids or inputs_embeds")
6533
 
6534
+ use_jtok = bool(getattr(self.config, "use_jtok", False))
6535
+ use_jtokm = bool(getattr(self.config, "use_jtokm", False))
6536
+ if use_jtok and input_ids is None:
6537
+ raise ValueError(
6538
+ "Active JTok/JTok-M requires `input_ids`; precomputed "
6539
+ "`inputs_embeds` do not carry the Leviathan token coordinate."
6540
+ )
6541
+ jtok_z_tilde = None
6542
+
6543
  # ── Embedding stage ────────────────────────────────────────────────
6544
  meap_mask_embedding = None
6545
  meap_mask_token_id = None
 
6562
  # selection so byte features cannot alter masked positions.
6563
  fuse_meap_in_leviathan = meap_active and self.spelling_bee is None
6564
  if fuse_meap_in_leviathan:
6565
+ if use_jtok:
6566
+ generator_result = self.token_generator(
6567
+ input_ids,
6568
+ meap_mask_embedding=meap_mask_embedding,
6569
+ meap_mask_token_id=meap_mask_token_id,
6570
+ return_jtok_geometry=True,
6571
+ )
6572
+ else:
6573
+ # Keep the pre-JTok call signature for custom or
6574
+ # checkpoint-restored token generators.
6575
+ generator_result = self.token_generator(
6576
+ input_ids,
6577
+ meap_mask_embedding=meap_mask_embedding,
6578
+ meap_mask_token_id=meap_mask_token_id,
6579
+ )
6580
+ else:
6581
+ if use_jtok:
6582
+ generator_result = self.token_generator(
6583
+ input_ids,
6584
+ return_jtok_geometry=True,
6585
+ )
6586
+ else:
6587
+ generator_result = self.token_generator(input_ids)
6588
+ if use_jtok:
6589
+ inputs_embeds, jtok_z_tilde = generator_result
6590
  else:
6591
+ inputs_embeds = generator_result
6592
  meap_consumed = fuse_meap_in_leviathan
6593
  else:
6594
  inputs_embeds = self.embed_tokens(input_ids)
 
6622
  inputs_embeds,
6623
  )
6624
 
6625
+ # The valid mask serves two separate purposes: JTok/JTok-M must not
6626
+ # modulate padding or MEAP-masked positions, and JTok-M must exclude
6627
+ # those positions from its load-balancing counts. The original
6628
+ # attention mask remains unchanged for positions/loss computation.
6629
+ if use_jtok:
6630
+ jtok_valid_mask = (
6631
+ attention_mask.to(
6632
+ device=input_ids.device,
6633
+ dtype=torch.bool,
6634
+ )
6635
+ if attention_mask is not None
6636
+ else torch.ones_like(input_ids, dtype=torch.bool)
6637
+ )
6638
+ if meap_active:
6639
+ jtok_valid_mask = jtok_valid_mask & input_ids.ne(
6640
+ int(meap_mask_token_id)
6641
+ )
6642
+ else:
6643
+ jtok_valid_mask = None
6644
+
6645
  if position_ids is None:
6646
  if attention_mask is not None:
6647
  position_ids = attention_mask.to(dtype=torch.long).cumsum(-1) - 1
 
6706
  all_hidden_states = () if output_hidden_states else None
6707
  all_attentions = () if output_attentions else None
6708
  tweo_activations = () if output_tweo_activations else None
6709
+ collect_jtokm_aux = bool(
6710
+ use_jtokm and self.training and torch.is_grad_enabled()
6711
+ )
6712
+ all_jtokm_aux_stats = () if collect_jtokm_aux else None
6713
 
6714
  # ── StackMemory state ─────────────────────────────────────────────
6715
  # Same source-level idea as StackTrans:
 
6822
  output_attentions=output_attentions,
6823
  repo_rope_args=repo_rope_args,
6824
  position_ids=position_ids,
6825
+ jtok_z_tilde=jtok_z_tilde,
6826
+ jtok_valid_mask=jtok_valid_mask,
6827
+ jtok_compute_aux=collect_jtokm_aux,
6828
  **kwargs,
6829
  )
6830
  hidden_states = layer_outputs[0]
 
6846
  output_attentions=output_attentions,
6847
  repo_rope_args=repo_rope_args,
6848
  position_ids=position_ids,
6849
+ jtok_z_tilde=jtok_z_tilde,
6850
+ jtok_valid_mask=jtok_valid_mask,
6851
+ jtok_compute_aux=collect_jtokm_aux,
6852
  **kwargs,
6853
  )
6854
  hidden_states = layer_outputs[0]
 
6858
  if use_attn_res:
6859
  attn_res_partial = hidden_states
6860
 
6861
+ if collect_jtokm_aux:
6862
+ all_jtokm_aux_stats = all_jtokm_aux_stats + (
6863
+ (
6864
+ layer_outputs[extras_start],
6865
+ layer_outputs[extras_start + 1],
6866
+ layer_outputs[extras_start + 2],
6867
+ ),
6868
+ )
6869
+ extras_start += 3
6870
+
6871
  if output_attentions:
6872
  all_attentions = all_attentions + (layer_outputs[extras_start],)
6873
  extras_start += 1
 
6899
  for v in [hidden_states, None, all_hidden_states, all_attentions]
6900
  if v is not None
6901
  )
6902
+ if all_jtokm_aux_stats is not None:
6903
+ base_outputs = base_outputs + (all_jtokm_aux_stats,)
6904
  if output_tweo_activations:
6905
  return base_outputs + (tweo_activations,)
6906
  return base_outputs
6907
 
6908
+ outputs = NeoLLMBaseModelOutputWithPast(
6909
  last_hidden_state=hidden_states,
6910
  past_key_values=None,
6911
  hidden_states=all_hidden_states,
6912
  attentions=all_attentions,
6913
+ jtokm_aux_stats=all_jtokm_aux_stats,
6914
  )
6915
  if output_tweo_activations:
6916
  return outputs, tweo_activations
 
8742
  self._last_nextlat_loss = None
8743
  self._last_nextlat_mse_loss = None
8744
  self._last_nextlat_kl_loss = None
8745
+ self._last_jtokm_aux_loss = None
8746
  self._last_total_loss = None
8747
 
8748
  if config.use_token_generator:
 
8923
  )
8924
 
8925
  # Unpack: model returns BaseModelOutputWithPast, or a tuple when
8926
+ # return_dict=False (with compact JTok-M stats and/or tweo activations
8927
+ # appended when enabled).
8928
  tweo_activations = None
8929
  hidden_states_tuple = None
8930
+ jtokm_aux_stats = None
8931
  if isinstance(model_out, tuple):
8932
  outputs = model_out[0]
8933
  if tweo_enabled and len(model_out) >= 2:
8934
  tweo_activations = model_out[-1]
8935
  if isinstance(outputs, torch.Tensor):
8936
  hidden_states = outputs
8937
+ if model_output_hidden_states:
8938
+ tuple_candidates = [
8939
+ candidate
8940
+ for candidate in model_out[1:]
8941
+ if isinstance(candidate, tuple)
8942
+ and (not candidate or not isinstance(candidate[0], tuple))
8943
+ ]
8944
+ if tuple_candidates:
8945
+ hidden_states_tuple = tuple_candidates[0]
8946
+ for candidate in model_out[1:]:
8947
+ if (
8948
+ isinstance(candidate, tuple)
8949
+ and candidate
8950
+ and isinstance(candidate[0], tuple)
8951
+ and len(candidate[0]) == 3
8952
+ ):
8953
+ jtokm_aux_stats = candidate
8954
+ break
8955
  elif isinstance(outputs, tuple):
8956
  hidden_states = outputs[0]
8957
  if len(outputs) > 2:
 
8959
  else:
8960
  hidden_states = outputs.last_hidden_state
8961
  hidden_states_tuple = outputs.hidden_states
8962
+ jtokm_aux_stats = getattr(outputs, "jtokm_aux_stats", None)
8963
  else:
8964
  outputs = model_out
8965
  hidden_states = outputs.last_hidden_state
8966
  hidden_states_tuple = outputs.hidden_states
8967
+ jtokm_aux_stats = getattr(outputs, "jtokm_aux_stats", None)
8968
 
8969
  loss = None
8970
  ntp_loss = None
 
8987
  nextlat_loss = None
8988
  nextlat_mse_loss = None
8989
  nextlat_kl_loss = None
8990
+ jtokm_aux_loss = None
8991
  self._last_ntp_loss = None
8992
  self._last_ntp_ce_unweighted = None
8993
  self._last_mile_reweighting_delta = None
 
9013
  self._last_nextlat_loss = None
9014
  self._last_nextlat_mse_loss = None
9015
  self._last_nextlat_kl_loss = None
9016
+ self._last_jtokm_aux_loss = None
9017
  self._last_total_loss = None
9018
  if labels is not None:
9019
  if self.ntp_loss_backend == "liger":
 
9247
  )
9248
  loss = loss + nextlat_loss
9249
 
9250
+ if bool(getattr(self.config, "use_jtokm", False)) and jtokm_aux_stats:
9251
+ jtokm_aux_loss = compute_jtokm_aux_loss(
9252
+ jtokm_aux_stats,
9253
+ n_e=int(getattr(self.config, "jtok_num_experts", 5)),
9254
+ top_k=int(getattr(self.config, "jtok_top_k", 2)),
9255
+ weight=float(getattr(self.config, "jtok_aux_loss_weight", 1e-4)),
9256
+ )
9257
+ loss = loss + jtokm_aux_loss
9258
+
9259
  self._last_ntp_loss = ntp_loss.detach() if ntp_loss is not None else None
9260
  self._last_tweo_loss = tweo_loss.detach() if tweo_loss is not None else None
9261
  self._last_nitp_loss = nitp_loss.detach() if nitp_loss is not None else None
 
9351
  self._last_nextlat_kl_loss = (
9352
  nextlat_kl_loss.detach() if nextlat_kl_loss is not None else None
9353
  )
9354
+ self._last_jtokm_aux_loss = (
9355
+ jtokm_aux_loss.detach() if jtokm_aux_loss is not None else None
9356
+ )
9357
  self._last_total_loss = loss.detach() if loss is not None else None
9358
  logits = None
9359
  else:
 
9381
  "NeoLLMPreTrainedModel",
9382
  "NeoLLMConfig",
9383
  "LeviathanGenerator",
9384
+ "LeviathanJTok",
9385
+ "NeoLLMBaseModelOutputWithPast",
9386
+ "compute_jtokm_aux_loss",
9387
  "SpellingBeeEmbedding",
9388
  "StackMemory",
9389
  "FANLayer",