Update modeling_neollm.py
Browse files- modeling_neollm.py +745 -239
modeling_neollm.py
CHANGED
|
@@ -72,6 +72,7 @@ References:
|
|
| 72 |
FP8 Training And Quantization For Dummies." arXiv:2511.23225.
|
| 73 |
"""
|
| 74 |
|
|
|
|
| 75 |
import math
|
| 76 |
from typing import Optional, Union, Tuple
|
| 77 |
|
|
@@ -87,6 +88,11 @@ except ImportError:
|
|
| 87 |
linear_cross_entropy = None
|
| 88 |
_CCE_AVAILABLE = False
|
| 89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
try:
|
| 91 |
from liger_kernel.transformers import ( # type: ignore[import-not-found]
|
| 92 |
LigerFusedLinearCrossEntropyLoss,
|
|
@@ -109,7 +115,7 @@ from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_u
|
|
| 109 |
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 110 |
from transformers.processing_utils import Unpack
|
| 111 |
from transformers.utils import TransformersKwargs, logging
|
| 112 |
-
from
|
| 113 |
|
| 114 |
from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
|
| 115 |
|
|
@@ -5238,6 +5244,12 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 5238 |
- down_proj: normal(0, 0.01) — keeps the residual transition close
|
| 5239 |
to identity initially without blocking gradients into
|
| 5240 |
the centered condition gate.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5241 |
- context_norm/condition_norm: weight=1.
|
| 5242 |
NeoLLMAttention (Affine-Scaled Attention):
|
| 5243 |
- alpha_proj: normal(0, 0.02) — near-zero so linear_clipping(≈0) ≈ 0.5
|
|
@@ -5277,6 +5289,8 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 5277 |
nn.init.xavier_uniform_(module.context_up_proj.weight)
|
| 5278 |
nn.init.xavier_uniform_(module.condition_modulation_proj.weight)
|
| 5279 |
nn.init.normal_(module.down_proj.weight, mean=0.0, std=0.01)
|
|
|
|
|
|
|
| 5280 |
module.context_norm.weight.data.fill_(1.0)
|
| 5281 |
module.condition_norm.weight.data.fill_(1.0)
|
| 5282 |
|
|
@@ -5885,6 +5899,27 @@ def _resolve_liger_accum_dtype(accum_dtype):
|
|
| 5885 |
)
|
| 5886 |
|
| 5887 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5888 |
@torch.compiler.disable
|
| 5889 |
def compute_cce_loss(
|
| 5890 |
hidden_states,
|
|
@@ -5893,6 +5928,11 @@ def compute_cce_loss(
|
|
| 5893 |
lm_head_bias=None,
|
| 5894 |
pad_token_id=None,
|
| 5895 |
cce_impl="cce_kahan_full_c",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5896 |
):
|
| 5897 |
"""CCE loss excluded from torch.compile, preserving the configured CCE impl."""
|
| 5898 |
if linear_cross_entropy is None:
|
|
@@ -5905,6 +5945,22 @@ def compute_cce_loss(
|
|
| 5905 |
processed_labels = _prepare_lm_labels(
|
| 5906 |
labels, device=hidden_states.device, pad_token_id=pad_token_id
|
| 5907 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5908 |
return linear_cross_entropy(
|
| 5909 |
hidden_states,
|
| 5910 |
lm_head_weight,
|
|
@@ -5913,6 +5969,7 @@ def compute_cce_loss(
|
|
| 5913 |
shift=1,
|
| 5914 |
impl=cce_impl,
|
| 5915 |
reduction="mean",
|
|
|
|
| 5916 |
)
|
| 5917 |
|
| 5918 |
|
|
@@ -6063,15 +6120,38 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6063 |
h_bar = RMSNorm_h(h_t)
|
| 6064 |
z_bar = RMSNorm_z(stopgrad(P_NITP(h_t)))
|
| 6065 |
u_h = SiLU(W_gate h_bar) * (W_up h_bar)
|
| 6066 |
-
|
| 6067 |
-
|
| 6068 |
-
|
|
|
|
|
|
|
| 6069 |
|
| 6070 |
-
The centered signed gate satisfies ``
|
| 6071 |
positive sigmoid gate, it can attenuate, activate, or reverse an
|
| 6072 |
-
individual contextual feature.
|
| 6073 |
-
|
| 6074 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6075 |
|
| 6076 |
All projections are bias-free. Therefore the NITP condition has no
|
| 6077 |
additive route to the output and the transition still satisfies:
|
|
@@ -6085,17 +6165,21 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6085 |
|
| 6086 |
Parameter count, excluding the already-existing NITP projector:
|
| 6087 |
|
| 6088 |
-
4 * d * m + 2d
|
| 6089 |
|
| 6090 |
-
where ``m = nitp_temporal_intermediate_size``
|
| 6091 |
-
affine RMSNorm scales. With d=512
|
| 6092 |
-
parameters
|
|
|
|
| 6093 |
"""
|
| 6094 |
|
| 6095 |
def __init__(self, config: NeoLLMConfig):
|
| 6096 |
super().__init__()
|
| 6097 |
hidden_size = int(config.hidden_size)
|
| 6098 |
intermediate_size = int(config.nitp_temporal_intermediate_size)
|
|
|
|
|
|
|
|
|
|
| 6099 |
|
| 6100 |
# The two inputs have different semantics and are normalized
|
| 6101 |
# independently: a final-layer causal state and a predicted shallow
|
|
@@ -6112,17 +6196,33 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6112 |
)
|
| 6113 |
|
| 6114 |
# NITP-condition path: controls contextual features but has no additive
|
| 6115 |
-
# route to the output. The
|
| 6116 |
-
#
|
|
|
|
| 6117 |
self.condition_modulation_proj = nn.Linear(
|
| 6118 |
hidden_size, intermediate_size, bias=False
|
| 6119 |
)
|
| 6120 |
self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
|
| 6121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6122 |
def forward(
|
| 6123 |
self,
|
| 6124 |
current_states: torch.Tensor,
|
| 6125 |
next_shallow_conditions: torch.Tensor,
|
|
|
|
| 6126 |
) -> torch.Tensor:
|
| 6127 |
context = self.context_norm(current_states)
|
| 6128 |
condition = self.condition_norm(next_shallow_conditions)
|
|
@@ -6131,11 +6231,22 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6131 |
F.silu(self.context_gate_proj(context))
|
| 6132 |
* self.context_up_proj(context)
|
| 6133 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6134 |
signed_modulation = torch.tanh(
|
| 6135 |
self.condition_modulation_proj(condition)
|
|
|
|
| 6136 |
)
|
| 6137 |
delta = self.down_proj(context_update * signed_modulation)
|
| 6138 |
-
|
|
|
|
|
|
|
|
|
|
| 6139 |
|
| 6140 |
|
| 6141 |
class NextLatDynamicsModel(nn.Module):
|
|
@@ -6531,6 +6642,170 @@ def _off_diagonal_pair_mean(
|
|
| 6531 |
return _masked_mean(selected.mean(dim=-1), window_mask)
|
| 6532 |
|
| 6533 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6534 |
def compute_nitp_temporal_objective(
|
| 6535 |
hidden_states: torch.Tensor,
|
| 6536 |
shallow_target_states: torch.Tensor,
|
|
@@ -6538,6 +6813,8 @@ def compute_nitp_temporal_objective(
|
|
| 6538 |
attention_mask: Optional[torch.Tensor],
|
| 6539 |
transition_model: NITPTemporalTransition,
|
| 6540 |
nitp_projector: NITPProjector,
|
|
|
|
|
|
|
| 6541 |
horizon: int,
|
| 6542 |
dynamics_weight: float,
|
| 6543 |
identification_weight: float,
|
|
@@ -6547,48 +6824,77 @@ def compute_nitp_temporal_objective(
|
|
| 6547 |
eos_token_id: Optional[int] = None,
|
| 6548 |
) -> Tuple[torch.Tensor, ...]:
|
| 6549 |
"""
|
| 6550 |
-
Causal NITP
|
| 6551 |
-
|
| 6552 |
-
|
| 6553 |
-
|
| 6554 |
-
|
| 6555 |
-
|
| 6556 |
-
|
| 6557 |
-
|
| 6558 |
-
|
| 6559 |
-
|
| 6560 |
-
|
| 6561 |
-
|
| 6562 |
-
|
| 6563 |
-
|
| 6564 |
-
|
| 6565 |
-
is
|
| 6566 |
-
|
| 6567 |
-
|
| 6568 |
-
|
| 6569 |
-
|
| 6570 |
-
|
| 6571 |
-
|
| 6572 |
-
|
| 6573 |
-
|
| 6574 |
-
|
| 6575 |
-
|
| 6576 |
-
|
| 6577 |
-
|
| 6578 |
-
``
|
| 6579 |
-
|
| 6580 |
-
|
| 6581 |
-
|
| 6582 |
-
|
| 6583 |
-
|
| 6584 |
-
|
| 6585 |
-
|
| 6586 |
-
|
| 6587 |
-
|
| 6588 |
-
|
| 6589 |
-
|
| 6590 |
-
|
| 6591 |
-
displacement
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6592 |
"""
|
| 6593 |
horizon = int(horizon)
|
| 6594 |
seq_len = int(hidden_states.shape[1])
|
|
@@ -6596,11 +6902,11 @@ def compute_nitp_temporal_objective(
|
|
| 6596 |
zero = hidden_states.new_zeros((), dtype=torch.float32)
|
| 6597 |
if max_horizon == 0:
|
| 6598 |
return (
|
| 6599 |
-
*((zero,) *
|
| 6600 |
-
zero.new_zeros((
|
| 6601 |
-
zero.new_zeros((
|
| 6602 |
-
zero.new_zeros((
|
| 6603 |
-
zero.new_zeros((
|
| 6604 |
)
|
| 6605 |
|
| 6606 |
device = hidden_states.device
|
|
@@ -6613,29 +6919,71 @@ def compute_nitp_temporal_objective(
|
|
| 6613 |
if pad_token_id is not None:
|
| 6614 |
valid_tokens = valid_tokens & (labels_on_device != pad_token_id)
|
| 6615 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6616 |
current_states = hidden_states
|
| 6617 |
shifted_targets = hidden_states
|
| 6618 |
predicted_by_step: list[torch.Tensor] = []
|
| 6619 |
condition_by_step: list[torch.Tensor] = []
|
| 6620 |
step_masks: list[torch.Tensor] = []
|
|
|
|
| 6621 |
state_loss_by_step: list[torch.Tensor] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6622 |
delta_cosine_by_step: list[torch.Tensor] = []
|
| 6623 |
delta_norm_ratio_by_step: list[torch.Tensor] = []
|
| 6624 |
rollout_nitp_cosine_by_step: list[torch.Tensor] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6625 |
predicted_turn_by_step: list[torch.Tensor] = []
|
| 6626 |
target_turn_by_step: list[torch.Tensor] = []
|
| 6627 |
|
| 6628 |
state_loss_total = zero
|
|
|
|
|
|
|
| 6629 |
path_predicted_norm_sum = zero
|
| 6630 |
path_target_norm_sum = zero
|
| 6631 |
previous_predicted_delta: Optional[torch.Tensor] = None
|
| 6632 |
previous_real_delta: Optional[torch.Tensor] = None
|
| 6633 |
|
| 6634 |
for step in range(max_horizon):
|
| 6635 |
-
# The projector weights are detached but the derivative with respect to
|
| 6636 |
-
# the rollout state is preserved for the Z component. The transition
|
| 6637 |
-
# consumes a fully detached copy, preventing a private projector/
|
| 6638 |
-
# transition code.
|
| 6639 |
source_states = current_states[:, :-1, :]
|
| 6640 |
shifted_targets = shifted_targets[:, 1:, :]
|
| 6641 |
next_shallow_signature = _project_nitp_with_frozen_weights(
|
|
@@ -6645,6 +6993,7 @@ def compute_nitp_temporal_objective(
|
|
| 6645 |
predicted_states = transition_model(
|
| 6646 |
source_states,
|
| 6647 |
next_shallow_signature.detach(),
|
|
|
|
| 6648 |
)
|
| 6649 |
|
| 6650 |
step_mask = _valid_temporal_span_mask(
|
|
@@ -6663,13 +7012,125 @@ def compute_nitp_temporal_objective(
|
|
| 6663 |
state_loss_total = state_loss_total + step_state_loss
|
| 6664 |
state_loss_by_step.append(step_state_loss.detach().float())
|
| 6665 |
|
| 6666 |
-
|
| 6667 |
-
|
| 6668 |
-
|
| 6669 |
-
|
| 6670 |
-
|
| 6671 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6672 |
|
|
|
|
| 6673 |
step_delta_cosine = F.cosine_similarity(
|
| 6674 |
predicted_delta.float(),
|
| 6675 |
real_delta.float(),
|
|
@@ -6743,15 +7204,32 @@ def compute_nitp_temporal_objective(
|
|
| 6743 |
|
| 6744 |
inv_horizon = 1.0 / float(max_horizon)
|
| 6745 |
state_loss = state_loss_total * inv_horizon
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6746 |
state_step_tensor = torch.stack(state_loss_by_step)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6747 |
delta_step_tensor = torch.stack(delta_cosine_by_step)
|
| 6748 |
delta_norm_ratio_tensor = torch.stack(delta_norm_ratio_by_step)
|
| 6749 |
rollout_nitp_step_tensor = torch.stack(rollout_nitp_cosine_by_step)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6750 |
predicted_turn_tensor = torch.stack(predicted_turn_by_step)
|
| 6751 |
target_turn_tensor = torch.stack(target_turn_by_step)
|
| 6752 |
-
delta_cosine = delta_step_tensor.mean()
|
| 6753 |
-
rollout_nitp_cosine = rollout_nitp_step_tensor.mean()
|
| 6754 |
-
last_step_state_loss = state_step_tensor[-1]
|
| 6755 |
path_length_ratio = (
|
| 6756 |
path_predicted_norm_sum
|
| 6757 |
/ path_target_norm_sum.clamp_min(1.0e-8)
|
|
@@ -6763,38 +7241,38 @@ def compute_nitp_temporal_objective(
|
|
| 6763 |
step_metrics = torch.stack(
|
| 6764 |
(
|
| 6765 |
state_step_tensor,
|
|
|
|
| 6766 |
delta_step_tensor,
|
| 6767 |
delta_norm_ratio_tensor,
|
| 6768 |
rollout_nitp_step_tensor,
|
| 6769 |
-
|
| 6770 |
-
|
|
|
|
|
|
|
| 6771 |
zero_steps,
|
| 6772 |
zero_steps,
|
| 6773 |
predicted_turn_tensor,
|
| 6774 |
target_turn_tensor,
|
| 6775 |
-
|
|
|
|
|
|
|
| 6776 |
)
|
| 6777 |
)
|
| 6778 |
-
weighted_total = float(dynamics_weight) *
|
| 6779 |
return (
|
| 6780 |
weighted_total,
|
| 6781 |
state_loss,
|
|
|
|
|
|
|
| 6782 |
zero,
|
| 6783 |
zero,
|
| 6784 |
zero,
|
| 6785 |
zero,
|
| 6786 |
zero,
|
| 6787 |
-
zero,
|
| 6788 |
-
last_step_state_loss,
|
| 6789 |
-
delta_cosine,
|
| 6790 |
-
rollout_nitp_cosine,
|
| 6791 |
-
zero,
|
| 6792 |
-
zero,
|
| 6793 |
-
zero,
|
| 6794 |
-
zero.new_zeros((4, 4)),
|
| 6795 |
step_metrics,
|
| 6796 |
-
zero.new_zeros((
|
| 6797 |
-
torch.stack((path_length_ratio, zero, zero, zero, zero
|
| 6798 |
)
|
| 6799 |
|
| 6800 |
(
|
|
@@ -6845,12 +7323,14 @@ def compute_nitp_temporal_objective(
|
|
| 6845 |
(row_prediction - expected_offsets).abs().float().mean(dim=-1),
|
| 6846 |
window_mask,
|
| 6847 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6848 |
|
| 6849 |
-
#
|
| 6850 |
-
#
|
| 6851 |
-
# matrices used by the live identification objective.
|
| 6852 |
component_matrices = (
|
| 6853 |
-
similarity.detach(),
|
| 6854 |
displacement_similarity.detach(),
|
| 6855 |
relational_similarity.detach(),
|
| 6856 |
nitp_signature_similarity.detach(),
|
|
@@ -6867,9 +7347,6 @@ def compute_nitp_temporal_objective(
|
|
| 6867 |
for component in component_matrices
|
| 6868 |
]
|
| 6869 |
)
|
| 6870 |
-
diagonal_cosine = component_metrics[0, 0]
|
| 6871 |
-
off_diagonal_cosine = component_metrics[0, 1]
|
| 6872 |
-
identification_margin = component_metrics[0, 2]
|
| 6873 |
|
| 6874 |
with torch.no_grad():
|
| 6875 |
initial_common = hidden_states[:, :common_length, :].detach()
|
|
@@ -6958,97 +7435,56 @@ def compute_nitp_temporal_objective(
|
|
| 6958 |
cross_predicted_tensor = torch.stack(cross_predicted_by_step)
|
| 6959 |
cross_target_tensor = torch.stack(cross_target_by_step)
|
| 6960 |
|
| 6961 |
-
# Reuse the existing counterfactual rollout and retain each horizon's
|
| 6962 |
-
# specificity instead of discarding it into one final average.
|
| 6963 |
-
if int(hidden_states.shape[0]) > 1:
|
| 6964 |
-
wrong_current = torch.roll(hidden_states.detach(), shifts=1, dims=0)
|
| 6965 |
-
wrong_targets = hidden_states.detach()
|
| 6966 |
-
wrong_state_loss_by_step = []
|
| 6967 |
-
for step in range(max_horizon):
|
| 6968 |
-
wrong_source = wrong_current[:, :-1, :]
|
| 6969 |
-
wrong_targets = wrong_targets[:, 1:, :]
|
| 6970 |
-
wrong_condition = nitp_projector(wrong_source)
|
| 6971 |
-
wrong_predicted = transition_model(
|
| 6972 |
-
wrong_source,
|
| 6973 |
-
wrong_condition,
|
| 6974 |
-
)
|
| 6975 |
-
wrong_step_loss = _masked_smooth_l1(
|
| 6976 |
-
predicted=wrong_predicted,
|
| 6977 |
-
target=wrong_targets,
|
| 6978 |
-
mask=step_masks[step],
|
| 6979 |
-
)
|
| 6980 |
-
wrong_state_loss_by_step.append(wrong_step_loss.float())
|
| 6981 |
-
wrong_current = wrong_predicted
|
| 6982 |
-
|
| 6983 |
-
wrong_step_tensor = torch.stack(wrong_state_loss_by_step)
|
| 6984 |
-
correct_step_tensor = state_step_tensor.detach().float()
|
| 6985 |
-
trajectory_specificity_by_step = (
|
| 6986 |
-
(wrong_step_tensor - correct_step_tensor)
|
| 6987 |
-
/ (wrong_step_tensor + correct_step_tensor + 1.0e-8)
|
| 6988 |
-
).clamp(min=-1.0, max=1.0)
|
| 6989 |
-
wrong_state_loss = wrong_step_tensor.mean()
|
| 6990 |
-
full_state_loss = correct_step_tensor.mean()
|
| 6991 |
-
trajectory_specificity = (
|
| 6992 |
-
(wrong_state_loss - full_state_loss)
|
| 6993 |
-
/ (wrong_state_loss + full_state_loss + 1.0e-8)
|
| 6994 |
-
).clamp(min=-1.0, max=1.0)
|
| 6995 |
-
else:
|
| 6996 |
-
trajectory_specificity_by_step = zero.new_zeros((max_horizon,))
|
| 6997 |
-
trajectory_specificity = zero
|
| 6998 |
-
|
| 6999 |
step_metrics = torch.stack(
|
| 7000 |
(
|
| 7001 |
state_step_tensor,
|
|
|
|
| 7002 |
delta_step_tensor,
|
| 7003 |
delta_norm_ratio_tensor,
|
| 7004 |
rollout_nitp_step_tensor,
|
| 7005 |
-
|
|
|
|
|
|
|
|
|
|
| 7006 |
cross_predicted_tensor,
|
| 7007 |
cross_target_tensor,
|
| 7008 |
-
cross_predicted_tensor - cross_target_tensor,
|
| 7009 |
predicted_turn_tensor,
|
| 7010 |
target_turn_tensor,
|
| 7011 |
-
|
|
|
|
|
|
|
| 7012 |
)
|
| 7013 |
)
|
| 7014 |
scalar_metrics = torch.stack(
|
| 7015 |
(
|
| 7016 |
path_length_ratio,
|
|
|
|
| 7017 |
target_pair_cosine,
|
| 7018 |
-
rollout_pair_cosine - target_pair_cosine,
|
| 7019 |
rollout_displacement_pair_cosine,
|
| 7020 |
target_displacement_pair_cosine,
|
| 7021 |
-
rollout_displacement_pair_cosine
|
| 7022 |
-
- target_displacement_pair_cosine,
|
| 7023 |
)
|
| 7024 |
)
|
| 7025 |
|
| 7026 |
weighted_total = (
|
| 7027 |
-
float(dynamics_weight) *
|
| 7028 |
+ float(identification_weight) * identification_loss
|
| 7029 |
)
|
| 7030 |
return (
|
| 7031 |
weighted_total,
|
| 7032 |
state_loss,
|
|
|
|
|
|
|
| 7033 |
identification_loss,
|
| 7034 |
temporal_top1_accuracy,
|
| 7035 |
mean_absolute_offset,
|
| 7036 |
-
diagonal_cosine,
|
| 7037 |
-
off_diagonal_cosine,
|
| 7038 |
identification_margin,
|
| 7039 |
-
last_step_state_loss,
|
| 7040 |
-
delta_cosine,
|
| 7041 |
-
rollout_nitp_cosine,
|
| 7042 |
-
rollout_pair_cosine,
|
| 7043 |
valid_window_fraction,
|
| 7044 |
-
trajectory_specificity,
|
| 7045 |
component_metrics,
|
| 7046 |
step_metrics,
|
| 7047 |
offset_metrics,
|
| 7048 |
scalar_metrics,
|
| 7049 |
)
|
| 7050 |
|
| 7051 |
-
|
| 7052 |
def _categorical_kl_loss(
|
| 7053 |
teacher_logits: torch.Tensor,
|
| 7054 |
student_logits: torch.Tensor,
|
|
@@ -7204,25 +7640,44 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7204 |
"`ntp_loss_backend` must be 'cce' or 'liger'. "
|
| 7205 |
f"Got {self.ntp_loss_backend!r}."
|
| 7206 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7207 |
self._last_ntp_loss = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7208 |
self._last_tweo_loss = None
|
| 7209 |
self._last_nitp_loss = None
|
| 7210 |
self._last_nitp_temporal_loss = None
|
| 7211 |
self._last_nitp_temporal_state_loss = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7212 |
self._last_nitp_temporal_identification_loss = None
|
| 7213 |
self._last_nitp_temporal_top1_accuracy = None
|
| 7214 |
self._last_nitp_temporal_mean_absolute_offset = None
|
| 7215 |
-
self._last_nitp_temporal_diagonal_cosine = None
|
| 7216 |
-
self._last_nitp_temporal_off_diagonal_cosine = None
|
| 7217 |
self._last_nitp_temporal_identification_margin = None
|
| 7218 |
-
self._last_nitp_temporal_last_step_state_loss = None
|
| 7219 |
-
self._last_nitp_temporal_rollout_nitp_cosine = None
|
| 7220 |
-
self._last_nitp_temporal_rollout_pair_cosine = None
|
| 7221 |
self._last_nitp_temporal_valid_window_fraction = None
|
| 7222 |
-
self._last_nitp_temporal_delta_cosine = None
|
| 7223 |
-
self._last_nitp_temporal_trajectory_specificity = None
|
| 7224 |
-
self._last_nitp_temporal_to_nitp_ratio = None
|
| 7225 |
-
self._last_nitp_temporal_loss_applied = None
|
| 7226 |
self._last_nitp_temporal_component_metrics = None
|
| 7227 |
self._last_nitp_temporal_step_metrics = None
|
| 7228 |
self._last_nitp_temporal_offset_metrics = None
|
|
@@ -7281,11 +7736,71 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7281 |
position_ids: Optional[torch.LongTensor] = None,
|
| 7282 |
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 7283 |
labels: Optional[torch.LongTensor] = None,
|
|
|
|
| 7284 |
logits_to_keep: Union[int, torch.Tensor] = 0,
|
| 7285 |
output_hidden_states: Optional[bool] = None,
|
| 7286 |
return_dict: Optional[bool] = None,
|
| 7287 |
**kwargs: Unpack[TransformersKwargs],
|
| 7288 |
) -> CausalLMOutputWithPast:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7289 |
tweo_enabled = (
|
| 7290 |
bool(getattr(self.config, "use_tweo", False))
|
| 7291 |
and labels is not None
|
|
@@ -7366,46 +7881,39 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7366 |
nitp_loss = None
|
| 7367 |
nitp_temporal_loss = None
|
| 7368 |
nitp_temporal_state_loss = None
|
|
|
|
|
|
|
| 7369 |
nitp_temporal_identification_loss = None
|
| 7370 |
nitp_temporal_top1_accuracy = None
|
| 7371 |
nitp_temporal_mean_absolute_offset = None
|
| 7372 |
-
nitp_temporal_diagonal_cosine = None
|
| 7373 |
-
nitp_temporal_off_diagonal_cosine = None
|
| 7374 |
nitp_temporal_identification_margin = None
|
| 7375 |
-
nitp_temporal_last_step_state_loss = None
|
| 7376 |
-
nitp_temporal_rollout_nitp_cosine = None
|
| 7377 |
-
nitp_temporal_rollout_pair_cosine = None
|
| 7378 |
nitp_temporal_valid_window_fraction = None
|
| 7379 |
-
nitp_temporal_delta_cosine = None
|
| 7380 |
-
nitp_temporal_trajectory_specificity = None
|
| 7381 |
nitp_temporal_component_metrics = None
|
| 7382 |
nitp_temporal_step_metrics = None
|
| 7383 |
nitp_temporal_offset_metrics = None
|
| 7384 |
nitp_temporal_scalar_metrics = None
|
| 7385 |
-
nitp_temporal_to_nitp_ratio = None
|
| 7386 |
nitp_target_hidden_states = None
|
| 7387 |
nextlat_loss = None
|
| 7388 |
nextlat_mse_loss = None
|
| 7389 |
nextlat_kl_loss = None
|
| 7390 |
self._last_ntp_loss = None
|
|
|
|
|
|
|
|
|
|
| 7391 |
self._last_tweo_loss = None
|
| 7392 |
self._last_nitp_loss = None
|
| 7393 |
self._last_nitp_temporal_loss = None
|
| 7394 |
self._last_nitp_temporal_state_loss = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7395 |
self._last_nitp_temporal_identification_loss = None
|
| 7396 |
self._last_nitp_temporal_top1_accuracy = None
|
| 7397 |
self._last_nitp_temporal_mean_absolute_offset = None
|
| 7398 |
-
self._last_nitp_temporal_diagonal_cosine = None
|
| 7399 |
-
self._last_nitp_temporal_off_diagonal_cosine = None
|
| 7400 |
self._last_nitp_temporal_identification_margin = None
|
| 7401 |
-
self._last_nitp_temporal_last_step_state_loss = None
|
| 7402 |
-
self._last_nitp_temporal_rollout_nitp_cosine = None
|
| 7403 |
-
self._last_nitp_temporal_rollout_pair_cosine = None
|
| 7404 |
self._last_nitp_temporal_valid_window_fraction = None
|
| 7405 |
-
self._last_nitp_temporal_delta_cosine = None
|
| 7406 |
-
self._last_nitp_temporal_trajectory_specificity = None
|
| 7407 |
-
self._last_nitp_temporal_to_nitp_ratio = None
|
| 7408 |
-
self._last_nitp_temporal_loss_applied = None
|
| 7409 |
self._last_nitp_temporal_component_metrics = None
|
| 7410 |
self._last_nitp_temporal_step_metrics = None
|
| 7411 |
self._last_nitp_temporal_offset_metrics = None
|
|
@@ -7425,14 +7933,41 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7425 |
self.liger_ntp_loss,
|
| 7426 |
)
|
| 7427 |
else:
|
| 7428 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7429 |
hidden_states,
|
| 7430 |
labels,
|
| 7431 |
self.lm_head.weight,
|
| 7432 |
getattr(self.lm_head, "bias", None),
|
| 7433 |
self.config.pad_token_id,
|
| 7434 |
getattr(self.config, "cce_loss_impl", "cce_kahan_full_c"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7435 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7436 |
loss = ntp_loss
|
| 7437 |
|
| 7438 |
if tweo_enabled:
|
|
@@ -7508,6 +8043,8 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7508 |
attention_mask=attention_mask,
|
| 7509 |
transition_model=self.nitp_temporal_transition,
|
| 7510 |
nitp_projector=self.nitp_projector,
|
|
|
|
|
|
|
| 7511 |
horizon=self.config.nitp_temporal_horizon,
|
| 7512 |
dynamics_weight=self.config.nitp_temporal_dynamics_weight,
|
| 7513 |
identification_weight=(
|
|
@@ -7534,6 +8071,8 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7534 |
attention_mask=attention_mask,
|
| 7535 |
transition_model=self.nitp_temporal_transition,
|
| 7536 |
nitp_projector=self.nitp_projector,
|
|
|
|
|
|
|
| 7537 |
horizon=self.config.nitp_temporal_horizon,
|
| 7538 |
dynamics_weight=(
|
| 7539 |
self.config.nitp_temporal_dynamics_weight
|
|
@@ -7554,18 +8093,13 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7554 |
(
|
| 7555 |
nitp_temporal_loss,
|
| 7556 |
nitp_temporal_state_loss,
|
|
|
|
|
|
|
| 7557 |
nitp_temporal_identification_loss,
|
| 7558 |
nitp_temporal_top1_accuracy,
|
| 7559 |
nitp_temporal_mean_absolute_offset,
|
| 7560 |
-
nitp_temporal_diagonal_cosine,
|
| 7561 |
-
nitp_temporal_off_diagonal_cosine,
|
| 7562 |
nitp_temporal_identification_margin,
|
| 7563 |
-
nitp_temporal_last_step_state_loss,
|
| 7564 |
-
nitp_temporal_delta_cosine,
|
| 7565 |
-
nitp_temporal_rollout_nitp_cosine,
|
| 7566 |
-
nitp_temporal_rollout_pair_cosine,
|
| 7567 |
nitp_temporal_valid_window_fraction,
|
| 7568 |
-
nitp_temporal_trajectory_specificity,
|
| 7569 |
nitp_temporal_component_metrics,
|
| 7570 |
nitp_temporal_step_metrics,
|
| 7571 |
nitp_temporal_offset_metrics,
|
|
@@ -7575,12 +8109,6 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7575 |
if temporal_apply_loss:
|
| 7576 |
loss = loss + nitp_temporal_loss
|
| 7577 |
|
| 7578 |
-
if nitp_loss is not None:
|
| 7579 |
-
nitp_temporal_to_nitp_ratio = (
|
| 7580 |
-
nitp_temporal_loss.detach().float()
|
| 7581 |
-
/ nitp_loss.detach().float().clamp_min(1e-8)
|
| 7582 |
-
)
|
| 7583 |
-
|
| 7584 |
if nextlat_enabled:
|
| 7585 |
if hidden_states_tuple is None or len(hidden_states_tuple) < 2:
|
| 7586 |
raise ValueError(
|
|
@@ -7628,6 +8156,16 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7628 |
if nitp_temporal_state_loss is not None
|
| 7629 |
else None
|
| 7630 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7631 |
self._last_nitp_temporal_identification_loss = (
|
| 7632 |
nitp_temporal_identification_loss.detach()
|
| 7633 |
if nitp_temporal_identification_loss is not None
|
|
@@ -7643,51 +8181,16 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7643 |
if nitp_temporal_mean_absolute_offset is not None
|
| 7644 |
else None
|
| 7645 |
)
|
| 7646 |
-
self._last_nitp_temporal_diagonal_cosine = (
|
| 7647 |
-
nitp_temporal_diagonal_cosine.detach()
|
| 7648 |
-
if nitp_temporal_diagonal_cosine is not None
|
| 7649 |
-
else None
|
| 7650 |
-
)
|
| 7651 |
-
self._last_nitp_temporal_off_diagonal_cosine = (
|
| 7652 |
-
nitp_temporal_off_diagonal_cosine.detach()
|
| 7653 |
-
if nitp_temporal_off_diagonal_cosine is not None
|
| 7654 |
-
else None
|
| 7655 |
-
)
|
| 7656 |
self._last_nitp_temporal_identification_margin = (
|
| 7657 |
nitp_temporal_identification_margin.detach()
|
| 7658 |
if nitp_temporal_identification_margin is not None
|
| 7659 |
else None
|
| 7660 |
)
|
| 7661 |
-
self._last_nitp_temporal_last_step_state_loss = (
|
| 7662 |
-
nitp_temporal_last_step_state_loss.detach()
|
| 7663 |
-
if nitp_temporal_last_step_state_loss is not None
|
| 7664 |
-
else None
|
| 7665 |
-
)
|
| 7666 |
-
self._last_nitp_temporal_rollout_nitp_cosine = (
|
| 7667 |
-
nitp_temporal_rollout_nitp_cosine.detach()
|
| 7668 |
-
if nitp_temporal_rollout_nitp_cosine is not None
|
| 7669 |
-
else None
|
| 7670 |
-
)
|
| 7671 |
-
self._last_nitp_temporal_rollout_pair_cosine = (
|
| 7672 |
-
nitp_temporal_rollout_pair_cosine.detach()
|
| 7673 |
-
if nitp_temporal_rollout_pair_cosine is not None
|
| 7674 |
-
else None
|
| 7675 |
-
)
|
| 7676 |
self._last_nitp_temporal_valid_window_fraction = (
|
| 7677 |
nitp_temporal_valid_window_fraction.detach()
|
| 7678 |
if nitp_temporal_valid_window_fraction is not None
|
| 7679 |
else None
|
| 7680 |
)
|
| 7681 |
-
self._last_nitp_temporal_delta_cosine = (
|
| 7682 |
-
nitp_temporal_delta_cosine.detach()
|
| 7683 |
-
if nitp_temporal_delta_cosine is not None
|
| 7684 |
-
else None
|
| 7685 |
-
)
|
| 7686 |
-
self._last_nitp_temporal_trajectory_specificity = (
|
| 7687 |
-
nitp_temporal_trajectory_specificity.detach()
|
| 7688 |
-
if nitp_temporal_trajectory_specificity is not None
|
| 7689 |
-
else None
|
| 7690 |
-
)
|
| 7691 |
self._last_nitp_temporal_component_metrics = (
|
| 7692 |
nitp_temporal_component_metrics.detach()
|
| 7693 |
if nitp_temporal_component_metrics is not None
|
|
@@ -7698,6 +8201,24 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7698 |
if nitp_temporal_step_metrics is not None
|
| 7699 |
else None
|
| 7700 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7701 |
self._last_nitp_temporal_offset_metrics = (
|
| 7702 |
nitp_temporal_offset_metrics.detach()
|
| 7703 |
if nitp_temporal_offset_metrics is not None
|
|
@@ -7708,21 +8229,6 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7708 |
if nitp_temporal_scalar_metrics is not None
|
| 7709 |
else None
|
| 7710 |
)
|
| 7711 |
-
self._last_nitp_temporal_to_nitp_ratio = (
|
| 7712 |
-
nitp_temporal_to_nitp_ratio.detach()
|
| 7713 |
-
if nitp_temporal_to_nitp_ratio is not None
|
| 7714 |
-
else None
|
| 7715 |
-
)
|
| 7716 |
-
self._last_nitp_temporal_loss_applied = (
|
| 7717 |
-
hidden_states.new_tensor(
|
| 7718 |
-
1.0
|
| 7719 |
-
if bool(getattr(self.config, "nitp_temporal_apply_loss", True))
|
| 7720 |
-
else 0.0,
|
| 7721 |
-
dtype=torch.float32,
|
| 7722 |
-
)
|
| 7723 |
-
if nitp_temporal_enabled
|
| 7724 |
-
else None
|
| 7725 |
-
)
|
| 7726 |
self._last_nextlat_loss = (
|
| 7727 |
nextlat_loss.detach() if nextlat_loss is not None else None
|
| 7728 |
)
|
|
|
|
| 72 |
FP8 Training And Quantization For Dummies." arXiv:2511.23225.
|
| 73 |
"""
|
| 74 |
|
| 75 |
+
import inspect
|
| 76 |
import math
|
| 77 |
from typing import Optional, Union, Tuple
|
| 78 |
|
|
|
|
| 88 |
linear_cross_entropy = None
|
| 89 |
_CCE_AVAILABLE = False
|
| 90 |
|
| 91 |
+
try:
|
| 92 |
+
from cut_cross_entropy import meap_mask_inputs # type: ignore[import-not-found]
|
| 93 |
+
except ImportError:
|
| 94 |
+
meap_mask_inputs = None
|
| 95 |
+
|
| 96 |
try:
|
| 97 |
from liger_kernel.transformers import ( # type: ignore[import-not-found]
|
| 98 |
LigerFusedLinearCrossEntropyLoss,
|
|
|
|
| 115 |
from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
|
| 116 |
from transformers.processing_utils import Unpack
|
| 117 |
from transformers.utils import TransformersKwargs, logging
|
| 118 |
+
from configuration_neollm import NeoLLMConfig
|
| 119 |
|
| 120 |
from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
|
| 121 |
|
|
|
|
| 5244 |
- down_proj: normal(0, 0.01) — keeps the residual transition close
|
| 5245 |
to identity initially without blocking gradients into
|
| 5246 |
the centered condition gate.
|
| 5247 |
+
- temporal_step_bias: zeros — all horizons start with the same phase.
|
| 5248 |
+
During the forward pass the bias table is projected to
|
| 5249 |
+
zero mean over the horizon, so it can represent only
|
| 5250 |
+
relative phase differences, not one shared phase offset.
|
| 5251 |
+
- temporal_step_gain_logits: zeros — 2*sigmoid(0)=1, so every horizon
|
| 5252 |
+
starts with exact unit residual gain.
|
| 5253 |
- context_norm/condition_norm: weight=1.
|
| 5254 |
NeoLLMAttention (Affine-Scaled Attention):
|
| 5255 |
- alpha_proj: normal(0, 0.02) — near-zero so linear_clipping(≈0) ≈ 0.5
|
|
|
|
| 5289 |
nn.init.xavier_uniform_(module.context_up_proj.weight)
|
| 5290 |
nn.init.xavier_uniform_(module.condition_modulation_proj.weight)
|
| 5291 |
nn.init.normal_(module.down_proj.weight, mean=0.0, std=0.01)
|
| 5292 |
+
nn.init.zeros_(module.temporal_step_bias)
|
| 5293 |
+
nn.init.zeros_(module.temporal_step_gain_logits)
|
| 5294 |
module.context_norm.weight.data.fill_(1.0)
|
| 5295 |
module.condition_norm.weight.data.fill_(1.0)
|
| 5296 |
|
|
|
|
| 5899 |
)
|
| 5900 |
|
| 5901 |
|
| 5902 |
+
_EXTENDED_CCE_INSTALL = (
|
| 5903 |
+
"cut-cross-entropy @ "
|
| 5904 |
+
"git+https://github.com/Kitsunp/ml-cross-entropy.git@main"
|
| 5905 |
+
)
|
| 5906 |
+
|
| 5907 |
+
|
| 5908 |
+
def _require_extended_cce_options(*option_names: str) -> None:
|
| 5909 |
+
"""Fail clearly only when an explicitly enabled CCE extension is unavailable."""
|
| 5910 |
+
if linear_cross_entropy is None:
|
| 5911 |
+
return
|
| 5912 |
+
parameters = inspect.signature(linear_cross_entropy).parameters
|
| 5913 |
+
missing = [name for name in option_names if name not in parameters]
|
| 5914 |
+
if missing:
|
| 5915 |
+
raise ImportError(
|
| 5916 |
+
"The installed cut-cross-entropy package does not provide the enabled "
|
| 5917 |
+
f"extension options {missing}. Install the extended backend with "
|
| 5918 |
+
f"`pip install --force-reinstall --no-deps \"{_EXTENDED_CCE_INSTALL}\"`, "
|
| 5919 |
+
"or disable the corresponding NeoLLM flags."
|
| 5920 |
+
)
|
| 5921 |
+
|
| 5922 |
+
|
| 5923 |
@torch.compiler.disable
|
| 5924 |
def compute_cce_loss(
|
| 5925 |
hidden_states,
|
|
|
|
| 5928 |
lm_head_bias=None,
|
| 5929 |
pad_token_id=None,
|
| 5930 |
cce_impl="cce_kahan_full_c",
|
| 5931 |
+
use_mile_loss=False,
|
| 5932 |
+
mile_loss_gamma=1.0,
|
| 5933 |
+
use_mu_loss=False,
|
| 5934 |
+
mu_loss_lambda=1e-4,
|
| 5935 |
+
return_loss_metrics=False,
|
| 5936 |
):
|
| 5937 |
"""CCE loss excluded from torch.compile, preserving the configured CCE impl."""
|
| 5938 |
if linear_cross_entropy is None:
|
|
|
|
| 5945 |
processed_labels = _prepare_lm_labels(
|
| 5946 |
labels, device=hidden_states.device, pad_token_id=pad_token_id
|
| 5947 |
)
|
| 5948 |
+
extension_kwargs = {}
|
| 5949 |
+
if use_mile_loss:
|
| 5950 |
+
_require_extended_cce_options("mile_enabled", "mile_gamma")
|
| 5951 |
+
extension_kwargs.update(
|
| 5952 |
+
mile_enabled=True,
|
| 5953 |
+
mile_gamma=float(mile_loss_gamma),
|
| 5954 |
+
)
|
| 5955 |
+
if use_mu_loss:
|
| 5956 |
+
_require_extended_cce_options("mu_loss_enabled", "mu_loss_lambda")
|
| 5957 |
+
extension_kwargs.update(
|
| 5958 |
+
mu_loss_enabled=True,
|
| 5959 |
+
mu_loss_lambda=float(mu_loss_lambda),
|
| 5960 |
+
)
|
| 5961 |
+
if return_loss_metrics:
|
| 5962 |
+
_require_extended_cce_options("return_loss_metrics")
|
| 5963 |
+
extension_kwargs["return_loss_metrics"] = True
|
| 5964 |
return linear_cross_entropy(
|
| 5965 |
hidden_states,
|
| 5966 |
lm_head_weight,
|
|
|
|
| 5969 |
shift=1,
|
| 5970 |
impl=cce_impl,
|
| 5971 |
reduction="mean",
|
| 5972 |
+
**extension_kwargs,
|
| 5973 |
)
|
| 5974 |
|
| 5975 |
|
|
|
|
| 6120 |
h_bar = RMSNorm_h(h_t)
|
| 6121 |
z_bar = RMSNorm_z(stopgrad(P_NITP(h_t)))
|
| 6122 |
u_h = SiLU(W_gate h_bar) * (W_up h_bar)
|
| 6123 |
+
b_tilde_k = b_k - mean_j(b_j)
|
| 6124 |
+
s_{z,k} = tanh(W_condition z_bar + b_tilde_k)
|
| 6125 |
+
g_k = 2 * sigmoid(a_k)
|
| 6126 |
+
delta_{t,k} = g_k * W_down(u_h * s_{z,k})
|
| 6127 |
+
h_hat_{t+1} = h_t + delta_{t,k}
|
| 6128 |
|
| 6129 |
+
The centered signed gate satisfies ``s_{z,k} in (-1, 1)``. Unlike a
|
| 6130 |
positive sigmoid gate, it can attenuate, activate, or reverse an
|
| 6131 |
+
individual contextual feature. A zero-initialized learned vector ``b_k``
|
| 6132 |
+
modulates only the recurrent phase. Before indexing a horizon, the table is
|
| 6133 |
+
reparameterized as
|
| 6134 |
+
|
| 6135 |
+
b_tilde_k = b_k - mean_j(b_j),
|
| 6136 |
+
|
| 6137 |
+
so ``sum_k b_tilde_k = 0``. All horizons still share the same transition
|
| 6138 |
+
weights, but the bias table can encode only relative differences between
|
| 6139 |
+
rollout phases; a single offset shared by every horizon is removed exactly.
|
| 6140 |
+
A second zero-initialized scalar logit ``a_k`` supplies a positive bounded
|
| 6141 |
+
residual gain ``g_k = 2 sigmoid(a_k)`` for each horizon. Thus
|
| 6142 |
+
``b_tilde_k`` controls the relative phase/channel pattern, while ``g_k``
|
| 6143 |
+
controls only its global amplitude. At initialization ``b_k=0`` and
|
| 6144 |
+
``a_k=0`` for every horizon, hence ``b_tilde_k=0``, ``g_k=1``, and the model
|
| 6145 |
+
starts exactly from the previous transition. The step index is
|
| 6146 |
+
deterministic and contains no future-token information.
|
| 6147 |
+
|
| 6148 |
+
At initialization, ``W_condition=0`` implies ``s_{z,k}=0`` and therefore
|
| 6149 |
+
``T_k(h, z)=h``. After training, a non-zero relative phase bias can provide
|
| 6150 |
+
a horizon-specific gate even when the condition projection is weak, but it
|
| 6151 |
+
cannot create the same bias offset at every horizon. The gain can rescale
|
| 6152 |
+
the resulting residual, yet neither phase nor gain creates an additive route
|
| 6153 |
+
through ``down_proj``: every output update remains multiplicatively tied to
|
| 6154 |
+
contextual features proposed by the current causal state.
|
| 6155 |
|
| 6156 |
All projections are bias-free. Therefore the NITP condition has no
|
| 6157 |
additive route to the output and the transition still satisfies:
|
|
|
|
| 6165 |
|
| 6166 |
Parameter count, excluding the already-existing NITP projector:
|
| 6167 |
|
| 6168 |
+
4 * d * m + 2d + W * m + W
|
| 6169 |
|
| 6170 |
+
where ``m = nitp_temporal_intermediate_size``, ``W`` is the temporal
|
| 6171 |
+
horizon, and ``2d`` comes from the two affine RMSNorm scales. With d=512,
|
| 6172 |
+
m=1024, and W=4 this is 2,102,276 trainable parameters: 4,100 more than
|
| 6173 |
+
the shared transition, of which only four are residual-gain parameters.
|
| 6174 |
"""
|
| 6175 |
|
| 6176 |
def __init__(self, config: NeoLLMConfig):
|
| 6177 |
super().__init__()
|
| 6178 |
hidden_size = int(config.hidden_size)
|
| 6179 |
intermediate_size = int(config.nitp_temporal_intermediate_size)
|
| 6180 |
+
horizon = int(config.nitp_temporal_horizon)
|
| 6181 |
+
if horizon < 1:
|
| 6182 |
+
raise ValueError("nitp_temporal_horizon must be at least 1")
|
| 6183 |
|
| 6184 |
# The two inputs have different semantics and are normalized
|
| 6185 |
# independently: a final-layer causal state and a predicted shallow
|
|
|
|
| 6196 |
)
|
| 6197 |
|
| 6198 |
# NITP-condition path: controls contextual features but has no additive
|
| 6199 |
+
# route to the output. The signed tanh gate is centered at zero; the
|
| 6200 |
+
# condition and the zero-mean relative phase bias modulate features
|
| 6201 |
+
# proposed by the current causal state.
|
| 6202 |
self.condition_modulation_proj = nn.Linear(
|
| 6203 |
hidden_size, intermediate_size, bias=False
|
| 6204 |
)
|
| 6205 |
self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
|
| 6206 |
|
| 6207 |
+
# Minimal phase conditioning. Each horizon receives one learned raw
|
| 6208 |
+
# bias in the shared intermediate gate. Forward reparameterizes this
|
| 6209 |
+
# table to zero mean over horizons, so only relative phase differences
|
| 6210 |
+
# are expressible through this branch. Zero initialization preserves
|
| 6211 |
+
# the exact previous transition at step 0 and avoids disturbing warmup.
|
| 6212 |
+
self.temporal_step_bias = nn.Parameter(
|
| 6213 |
+
torch.zeros(horizon, intermediate_size)
|
| 6214 |
+
)
|
| 6215 |
+
|
| 6216 |
+
# Minimal amplitude conditioning. One scalar logit per horizon is
|
| 6217 |
+
# mapped to a positive bounded gain in (0, 2). Zero initialization
|
| 6218 |
+
# gives exactly unit gain: 2 * sigmoid(0) = 1.
|
| 6219 |
+
self.temporal_step_gain_logits = nn.Parameter(torch.zeros(horizon))
|
| 6220 |
+
|
| 6221 |
def forward(
|
| 6222 |
self,
|
| 6223 |
current_states: torch.Tensor,
|
| 6224 |
next_shallow_conditions: torch.Tensor,
|
| 6225 |
+
step_index: int,
|
| 6226 |
) -> torch.Tensor:
|
| 6227 |
context = self.context_norm(current_states)
|
| 6228 |
condition = self.condition_norm(next_shallow_conditions)
|
|
|
|
| 6231 |
F.silu(self.context_gate_proj(context))
|
| 6232 |
* self.context_up_proj(context)
|
| 6233 |
)
|
| 6234 |
+
# Remove the horizon-common bias mode without materializing a full
|
| 6235 |
+
# broadcast tensor. For horizon=1 this term is exactly zero, as there
|
| 6236 |
+
# is no relative phase to represent.
|
| 6237 |
+
relative_step_bias = (
|
| 6238 |
+
self.temporal_step_bias[step_index]
|
| 6239 |
+
- self.temporal_step_bias.mean(dim=0)
|
| 6240 |
+
)
|
| 6241 |
signed_modulation = torch.tanh(
|
| 6242 |
self.condition_modulation_proj(condition)
|
| 6243 |
+
+ relative_step_bias
|
| 6244 |
)
|
| 6245 |
delta = self.down_proj(context_update * signed_modulation)
|
| 6246 |
+
step_gain = 2.0 * torch.sigmoid(
|
| 6247 |
+
self.temporal_step_gain_logits[step_index]
|
| 6248 |
+
)
|
| 6249 |
+
return current_states + step_gain * delta
|
| 6250 |
|
| 6251 |
|
| 6252 |
class NextLatDynamicsModel(nn.Module):
|
|
|
|
| 6642 |
return _masked_mean(selected.mean(dim=-1), window_mask)
|
| 6643 |
|
| 6644 |
|
| 6645 |
+
def _temporal_two_token_readout(
|
| 6646 |
+
student_states: torch.Tensor,
|
| 6647 |
+
teacher_states: torch.Tensor,
|
| 6648 |
+
candidate_labels: torch.LongTensor,
|
| 6649 |
+
candidate_valid: torch.Tensor,
|
| 6650 |
+
target_index: int,
|
| 6651 |
+
base_mask: torch.Tensor,
|
| 6652 |
+
lm_head_weight: torch.Tensor,
|
| 6653 |
+
lm_head_bias: Optional[torch.Tensor],
|
| 6654 |
+
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 6655 |
+
"""
|
| 6656 |
+
Cheap functional anchor over the local temporal candidate set.
|
| 6657 |
+
|
| 6658 |
+
For the real state at horizon ``k`` the candidate set contains only the
|
| 6659 |
+
tokens attached to the W local future horizons. The strongest *different*
|
| 6660 |
+
temporal token under the real state is selected as the competitor. The
|
| 6661 |
+
rollout state then matches the teacher's binary distribution over
|
| 6662 |
+
|
| 6663 |
+
[token at the correct horizon, strongest incorrect temporal token].
|
| 6664 |
+
|
| 6665 |
+
This avoids a [B,T,W,V] or [B,T,V] vocabulary projection. It evaluates W
|
| 6666 |
+
teacher dot-products and two student dot-products, using detached LM-head
|
| 6667 |
+
rows so the auxiliary loss trains the temporal trajectory rather than the
|
| 6668 |
+
vocabulary head. No new temperature, loss weight, or trainable parameter
|
| 6669 |
+
is introduced.
|
| 6670 |
+
"""
|
| 6671 |
+
horizon = int(candidate_labels.shape[-1])
|
| 6672 |
+
zero = student_states.new_zeros((), dtype=torch.float32)
|
| 6673 |
+
if horizon <= 1 or int(student_states.shape[1]) == 0:
|
| 6674 |
+
return zero, zero, zero, zero
|
| 6675 |
+
|
| 6676 |
+
detached_weight = lm_head_weight.detach()
|
| 6677 |
+
detached_bias = lm_head_bias.detach() if lm_head_bias is not None else None
|
| 6678 |
+
teacher = teacher_states.detach()
|
| 6679 |
+
|
| 6680 |
+
teacher_scores_by_candidate = []
|
| 6681 |
+
for candidate_index in range(horizon):
|
| 6682 |
+
token_ids = candidate_labels[..., candidate_index].clamp_min(0)
|
| 6683 |
+
token_rows = F.embedding(token_ids, detached_weight)
|
| 6684 |
+
score = (teacher * token_rows).sum(dim=-1, dtype=torch.float32)
|
| 6685 |
+
if detached_bias is not None:
|
| 6686 |
+
score = score + detached_bias[token_ids].float()
|
| 6687 |
+
teacher_scores_by_candidate.append(score)
|
| 6688 |
+
teacher_scores = torch.stack(teacher_scores_by_candidate, dim=-1)
|
| 6689 |
+
|
| 6690 |
+
target_ids = candidate_labels[..., target_index]
|
| 6691 |
+
safe_target_ids = target_ids.clamp_min(0)
|
| 6692 |
+
target_valid = candidate_valid[..., target_index]
|
| 6693 |
+
target_teacher_score = teacher_scores[..., target_index]
|
| 6694 |
+
|
| 6695 |
+
candidate_indices = torch.arange(
|
| 6696 |
+
horizon,
|
| 6697 |
+
device=candidate_labels.device,
|
| 6698 |
+
).view(1, 1, horizon)
|
| 6699 |
+
competitor_mask = (
|
| 6700 |
+
candidate_valid
|
| 6701 |
+
& candidate_indices.ne(int(target_index))
|
| 6702 |
+
& candidate_labels.ne(target_ids.unsqueeze(-1))
|
| 6703 |
+
)
|
| 6704 |
+
has_competitor = competitor_mask.any(dim=-1)
|
| 6705 |
+
masked_teacher_scores = teacher_scores.masked_fill(
|
| 6706 |
+
~competitor_mask,
|
| 6707 |
+
torch.finfo(teacher_scores.dtype).min,
|
| 6708 |
+
)
|
| 6709 |
+
competitor_index = masked_teacher_scores.argmax(dim=-1)
|
| 6710 |
+
competitor_ids = candidate_labels.gather(
|
| 6711 |
+
dim=-1,
|
| 6712 |
+
index=competitor_index.unsqueeze(-1),
|
| 6713 |
+
).squeeze(-1)
|
| 6714 |
+
safe_competitor_ids = competitor_ids.clamp_min(0)
|
| 6715 |
+
competitor_teacher_score = teacher_scores.gather(
|
| 6716 |
+
dim=-1,
|
| 6717 |
+
index=competitor_index.unsqueeze(-1),
|
| 6718 |
+
).squeeze(-1)
|
| 6719 |
+
|
| 6720 |
+
# Compute the two student logits sequentially so only one gathered
|
| 6721 |
+
# [B,T,H] LM-head block is live at a time.
|
| 6722 |
+
target_rows = F.embedding(safe_target_ids, detached_weight)
|
| 6723 |
+
target_student_score = (
|
| 6724 |
+
student_states * target_rows
|
| 6725 |
+
).sum(dim=-1, dtype=torch.float32)
|
| 6726 |
+
competitor_rows = F.embedding(safe_competitor_ids, detached_weight)
|
| 6727 |
+
competitor_student_score = (
|
| 6728 |
+
student_states * competitor_rows
|
| 6729 |
+
).sum(dim=-1, dtype=torch.float32)
|
| 6730 |
+
if detached_bias is not None:
|
| 6731 |
+
target_student_score = (
|
| 6732 |
+
target_student_score + detached_bias[safe_target_ids].float()
|
| 6733 |
+
)
|
| 6734 |
+
competitor_student_score = (
|
| 6735 |
+
competitor_student_score
|
| 6736 |
+
+ detached_bias[safe_competitor_ids].float()
|
| 6737 |
+
)
|
| 6738 |
+
|
| 6739 |
+
teacher_pair_logits = torch.stack(
|
| 6740 |
+
(target_teacher_score, competitor_teacher_score),
|
| 6741 |
+
dim=-1,
|
| 6742 |
+
)
|
| 6743 |
+
student_pair_logits = torch.stack(
|
| 6744 |
+
(target_student_score, competitor_student_score),
|
| 6745 |
+
dim=-1,
|
| 6746 |
+
)
|
| 6747 |
+
readout_mask = base_mask & target_valid & has_competitor
|
| 6748 |
+
|
| 6749 |
+
teacher_log_probs = F.log_softmax(teacher_pair_logits.detach(), dim=-1)
|
| 6750 |
+
student_log_probs = F.log_softmax(student_pair_logits, dim=-1)
|
| 6751 |
+
per_token_kl = F.kl_div(
|
| 6752 |
+
student_log_probs,
|
| 6753 |
+
teacher_log_probs,
|
| 6754 |
+
log_target=True,
|
| 6755 |
+
reduction="none",
|
| 6756 |
+
).sum(dim=-1)
|
| 6757 |
+
readout_loss = _masked_mean(per_token_kl, readout_mask)
|
| 6758 |
+
|
| 6759 |
+
with torch.no_grad():
|
| 6760 |
+
readout_agreement = _masked_mean(
|
| 6761 |
+
(
|
| 6762 |
+
teacher_pair_logits.argmax(dim=-1)
|
| 6763 |
+
== student_pair_logits.argmax(dim=-1)
|
| 6764 |
+
).float(),
|
| 6765 |
+
readout_mask,
|
| 6766 |
+
)
|
| 6767 |
+
teacher_margin = (
|
| 6768 |
+
target_teacher_score - competitor_teacher_score
|
| 6769 |
+
)
|
| 6770 |
+
student_margin = (
|
| 6771 |
+
target_student_score - competitor_student_score
|
| 6772 |
+
)
|
| 6773 |
+
readout_margin_error = _masked_mean(
|
| 6774 |
+
(student_margin - teacher_margin).abs(),
|
| 6775 |
+
readout_mask,
|
| 6776 |
+
)
|
| 6777 |
+
readout_valid_fraction = readout_mask.float().mean()
|
| 6778 |
+
|
| 6779 |
+
return (
|
| 6780 |
+
readout_loss,
|
| 6781 |
+
readout_agreement,
|
| 6782 |
+
readout_margin_error,
|
| 6783 |
+
readout_valid_fraction,
|
| 6784 |
+
)
|
| 6785 |
+
|
| 6786 |
+
|
| 6787 |
+
NITP_TEMPORAL_STEP_METRIC_NAMES = (
|
| 6788 |
+
# Rows 0..12 are stable for backward-compatible trainer logging.
|
| 6789 |
+
"state_loss",
|
| 6790 |
+
"composite_step_loss",
|
| 6791 |
+
"delta_cosine",
|
| 6792 |
+
"delta_norm_ratio",
|
| 6793 |
+
"rollout_nitp_cosine",
|
| 6794 |
+
"readout_loss",
|
| 6795 |
+
"readout_agreement",
|
| 6796 |
+
"readout_margin_error",
|
| 6797 |
+
"readout_valid_fraction",
|
| 6798 |
+
"cross_example_pred_displacement_cosine",
|
| 6799 |
+
"cross_example_target_displacement_cosine",
|
| 6800 |
+
"predicted_delta_turn_cosine",
|
| 6801 |
+
"target_delta_turn_cosine",
|
| 6802 |
+
# Append-only component diagnostics for the new cheap moment objective.
|
| 6803 |
+
"raw_step_loss",
|
| 6804 |
+
"mean_error_loss",
|
| 6805 |
+
"std_match_loss",
|
| 6806 |
+
)
|
| 6807 |
+
|
| 6808 |
+
|
| 6809 |
def compute_nitp_temporal_objective(
|
| 6810 |
hidden_states: torch.Tensor,
|
| 6811 |
shallow_target_states: torch.Tensor,
|
|
|
|
| 6813 |
attention_mask: Optional[torch.Tensor],
|
| 6814 |
transition_model: NITPTemporalTransition,
|
| 6815 |
nitp_projector: NITPProjector,
|
| 6816 |
+
lm_head_weight: torch.Tensor,
|
| 6817 |
+
lm_head_bias: Optional[torch.Tensor],
|
| 6818 |
horizon: int,
|
| 6819 |
dynamics_weight: float,
|
| 6820 |
identification_weight: float,
|
|
|
|
| 6824 |
eos_token_id: Optional[int] = None,
|
| 6825 |
) -> Tuple[torch.Tensor, ...]:
|
| 6826 |
"""
|
| 6827 |
+
Causal Temporal-NITP with a cheap first-order trajectory objective.
|
| 6828 |
+
|
| 6829 |
+
The autonomous rollout and relational identification are unchanged:
|
| 6830 |
+
|
| 6831 |
+
h_hat_0 = h_0,
|
| 6832 |
+
z_hat_k = P_{sg(theta_P)}(h_hat_{k-1}),
|
| 6833 |
+
h_hat_k = T_k(h_hat_{k-1}, sg(z_hat_k)),
|
| 6834 |
+
|
| 6835 |
+
S = 0.25 A + 0.25 R + 0.5 Z.
|
| 6836 |
+
|
| 6837 |
+
Only the *dynamics objective* changes. The old objective supervised final
|
| 6838 |
+
states alone. The new objective is the fixed arithmetic mean
|
| 6839 |
+
|
| 6840 |
+
L_dyn = (L_position + L_step + L_readout) / 3.
|
| 6841 |
+
|
| 6842 |
+
``L_position`` is the original Smooth-L1 state alignment. ``L_step`` uses
|
| 6843 |
+
target-RMS-normalized local increments and is now
|
| 6844 |
+
|
| 6845 |
+
L_step = L_raw + L_mean_error + 0.5 * L_std.
|
| 6846 |
+
|
| 6847 |
+
``L_raw`` keeps the full per-window correspondence. ``L_mean_error`` applies
|
| 6848 |
+
Smooth-L1 only to the valid-window mean prediction error, directly penalizing
|
| 6849 |
+
a horizon-common direction that is absent from the targets. ``L_std`` matches
|
| 6850 |
+
the per-channel standard deviation around those means, retaining the useful
|
| 6851 |
+
lesson from the removed explicit centered loss: the rollout must preserve
|
| 6852 |
+
context-dependent dispersion instead of shrinking every example toward its
|
| 6853 |
+
batch mean. Means and second moments are reductions to [1,1,H]; no centered
|
| 6854 |
+
[B,S,H] tensors or second full-size Smooth-L1 branch are materialized.
|
| 6855 |
+
``L_readout`` matches a two-token temporal readout selected from the existing
|
| 6856 |
+
W future labels; it protects functionally sensitive LM-head directions
|
| 6857 |
+
without projecting to the full vocabulary.
|
| 6858 |
+
|
| 6859 |
+
The constants 1/3 and 0.5 are not configurable hyperparameters. The first
|
| 6860 |
+
defines an equal mean of the three trajectory views; the second keeps the
|
| 6861 |
+
dispersion match auxiliary to the exact per-window and common-error terms.
|
| 6862 |
+
Existing ``dynamics_weight`` and ``identification_weight`` remain the only
|
| 6863 |
+
outer weights.
|
| 6864 |
+
|
| 6865 |
+
Packed diagnostics are intentionally compact and non-redundant:
|
| 6866 |
+
|
| 6867 |
+
``component_metrics`` [3,4]
|
| 6868 |
+
rows: displacement A, relational R, NITP signature Z.
|
| 6869 |
+
cols: diagonal, off-diagonal, hardest-negative margin,
|
| 6870 |
+
positive-margin fraction. The joint diagonal/off-diagonal are omitted
|
| 6871 |
+
because they are exactly reconstructed as 0.25*A + 0.25*R + 0.5*Z;
|
| 6872 |
+
joint positive-margin fraction is identical to joint top-1.
|
| 6873 |
+
|
| 6874 |
+
``step_metrics`` [16,W]
|
| 6875 |
+
Rows 0..12 preserve the previous order for logger compatibility: state
|
| 6876 |
+
loss, composite normalized step loss, delta cosine, delta norm ratio,
|
| 6877 |
+
rollout-NITP cosine, two-token readout KL, readout rank agreement,
|
| 6878 |
+
readout margin error, readout valid fraction, cross-example predicted
|
| 6879 |
+
displacement cosine, cross-example target displacement cosine,
|
| 6880 |
+
predicted consecutive-delta cosine, target consecutive-delta cosine.
|
| 6881 |
+
Rows 13..15 append the three step-loss components: raw local loss,
|
| 6882 |
+
common mean-error loss, and standard-deviation matching loss. The
|
| 6883 |
+
composite row is exactly raw + mean_error + 0.5*std. Aggregate component
|
| 6884 |
+
means are reconstructible by averaging the appended rows over W.
|
| 6885 |
+
|
| 6886 |
+
``offset_metrics`` [3,W-1]
|
| 6887 |
+
neighbor similarities for A, R, and Z. The joint neighbor profile is
|
| 6888 |
+
omitted because it is exactly reconstructed from these three rows.
|
| 6889 |
+
|
| 6890 |
+
``scalar_metrics`` [5]
|
| 6891 |
+
path-length ratio, predicted and target absolute-state pair cosine,
|
| 6892 |
+
predicted and target centered-displacement pair cosine. Pair gaps are
|
| 6893 |
+
omitted because they are simple differences.
|
| 6894 |
+
|
| 6895 |
+
The previous counterfactual trajectory-specificity rollout is removed. It
|
| 6896 |
+
required an additional W-step transition rollout and is replaced by the
|
| 6897 |
+
much cheaper per-step readout agreement plus cross-example diversity.
|
| 6898 |
"""
|
| 6899 |
horizon = int(horizon)
|
| 6900 |
seq_len = int(hidden_states.shape[1])
|
|
|
|
| 6902 |
zero = hidden_states.new_zeros((), dtype=torch.float32)
|
| 6903 |
if max_horizon == 0:
|
| 6904 |
return (
|
| 6905 |
+
*((zero,) * 9),
|
| 6906 |
+
zero.new_zeros((3, 4)),
|
| 6907 |
+
zero.new_zeros((16, 0)),
|
| 6908 |
+
zero.new_zeros((3, 0)),
|
| 6909 |
+
zero.new_zeros((5,)),
|
| 6910 |
)
|
| 6911 |
|
| 6912 |
device = hidden_states.device
|
|
|
|
| 6919 |
if pad_token_id is not None:
|
| 6920 |
valid_tokens = valid_tokens & (labels_on_device != pad_token_id)
|
| 6921 |
|
| 6922 |
+
# The functional readout needs one token beyond the farthest hidden-state
|
| 6923 |
+
# target because h_{t+k} predicts label_{t+k+1}. Candidate labels are the W
|
| 6924 |
+
# true tokens attached to the local temporal horizons, so selecting the
|
| 6925 |
+
# strongest incorrect one costs O(W*H), not O(V*H).
|
| 6926 |
+
functional_length = max(seq_len - max_horizon - 1, 0)
|
| 6927 |
+
if functional_length > 0:
|
| 6928 |
+
candidate_labels = torch.stack(
|
| 6929 |
+
[
|
| 6930 |
+
labels_on_device[
|
| 6931 |
+
:, offset + 1 : offset + 1 + functional_length
|
| 6932 |
+
]
|
| 6933 |
+
for offset in range(1, max_horizon + 1)
|
| 6934 |
+
],
|
| 6935 |
+
dim=-1,
|
| 6936 |
+
)
|
| 6937 |
+
candidate_valid = torch.stack(
|
| 6938 |
+
[
|
| 6939 |
+
valid_tokens[
|
| 6940 |
+
:, offset + 1 : offset + 1 + functional_length
|
| 6941 |
+
]
|
| 6942 |
+
for offset in range(1, max_horizon + 1)
|
| 6943 |
+
],
|
| 6944 |
+
dim=-1,
|
| 6945 |
+
)
|
| 6946 |
+
functional_window_mask = _valid_temporal_span_mask(
|
| 6947 |
+
valid_tokens=valid_tokens,
|
| 6948 |
+
labels=labels_on_device,
|
| 6949 |
+
span_length=max_horizon + 2,
|
| 6950 |
+
eos_token_id=eos_token_id,
|
| 6951 |
+
)
|
| 6952 |
+
else:
|
| 6953 |
+
candidate_labels = None
|
| 6954 |
+
candidate_valid = None
|
| 6955 |
+
functional_window_mask = None
|
| 6956 |
+
|
| 6957 |
current_states = hidden_states
|
| 6958 |
shifted_targets = hidden_states
|
| 6959 |
predicted_by_step: list[torch.Tensor] = []
|
| 6960 |
condition_by_step: list[torch.Tensor] = []
|
| 6961 |
step_masks: list[torch.Tensor] = []
|
| 6962 |
+
|
| 6963 |
state_loss_by_step: list[torch.Tensor] = []
|
| 6964 |
+
normalized_step_loss_by_step: list[torch.Tensor] = []
|
| 6965 |
+
raw_step_loss_by_step: list[torch.Tensor] = []
|
| 6966 |
+
mean_error_loss_by_step: list[torch.Tensor] = []
|
| 6967 |
+
std_match_loss_by_step: list[torch.Tensor] = []
|
| 6968 |
delta_cosine_by_step: list[torch.Tensor] = []
|
| 6969 |
delta_norm_ratio_by_step: list[torch.Tensor] = []
|
| 6970 |
rollout_nitp_cosine_by_step: list[torch.Tensor] = []
|
| 6971 |
+
readout_loss_by_step: list[torch.Tensor] = []
|
| 6972 |
+
readout_agreement_by_step: list[torch.Tensor] = []
|
| 6973 |
+
readout_margin_error_by_step: list[torch.Tensor] = []
|
| 6974 |
+
readout_valid_fraction_by_step: list[torch.Tensor] = []
|
| 6975 |
predicted_turn_by_step: list[torch.Tensor] = []
|
| 6976 |
target_turn_by_step: list[torch.Tensor] = []
|
| 6977 |
|
| 6978 |
state_loss_total = zero
|
| 6979 |
+
normalized_step_loss_total = zero
|
| 6980 |
+
readout_loss_total = zero
|
| 6981 |
path_predicted_norm_sum = zero
|
| 6982 |
path_target_norm_sum = zero
|
| 6983 |
previous_predicted_delta: Optional[torch.Tensor] = None
|
| 6984 |
previous_real_delta: Optional[torch.Tensor] = None
|
| 6985 |
|
| 6986 |
for step in range(max_horizon):
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6987 |
source_states = current_states[:, :-1, :]
|
| 6988 |
shifted_targets = shifted_targets[:, 1:, :]
|
| 6989 |
next_shallow_signature = _project_nitp_with_frozen_weights(
|
|
|
|
| 6993 |
predicted_states = transition_model(
|
| 6994 |
source_states,
|
| 6995 |
next_shallow_signature.detach(),
|
| 6996 |
+
step_index=step,
|
| 6997 |
)
|
| 6998 |
|
| 6999 |
step_mask = _valid_temporal_span_mask(
|
|
|
|
| 7012 |
state_loss_total = state_loss_total + step_state_loss
|
| 7013 |
state_loss_by_step.append(step_state_loss.detach().float())
|
| 7014 |
|
| 7015 |
+
real_source_states = hidden_states[
|
| 7016 |
+
:, step : step + predicted_states.shape[1], :
|
| 7017 |
+
].detach()
|
| 7018 |
+
predicted_delta = predicted_states - source_states
|
| 7019 |
+
real_delta = shifted_targets.detach() - real_source_states
|
| 7020 |
+
|
| 7021 |
+
# Scale each target delta to unit RMS. This is data-derived and detached,
|
| 7022 |
+
# so there is no new tuned scale and no radial shortcut.
|
| 7023 |
+
target_delta_rms = real_delta.float().pow(2).mean(
|
| 7024 |
+
dim=-1,
|
| 7025 |
+
keepdim=True,
|
| 7026 |
+
).sqrt().clamp_min(1.0e-4)
|
| 7027 |
+
normalized_predicted_delta = predicted_delta.float() / target_delta_rms
|
| 7028 |
+
normalized_real_delta = real_delta.float() / target_delta_rms
|
| 7029 |
+
|
| 7030 |
+
# Absolute view: preserve the legitimate common temporal component as
|
| 7031 |
+
# well as each local direction and magnitude.
|
| 7032 |
+
raw_step_error = F.smooth_l1_loss(
|
| 7033 |
+
normalized_predicted_delta,
|
| 7034 |
+
normalized_real_delta,
|
| 7035 |
+
reduction="none",
|
| 7036 |
+
).mean(dim=-1)
|
| 7037 |
+
raw_step_loss = _masked_mean(raw_step_error, step_mask)
|
| 7038 |
+
|
| 7039 |
+
# Cheap moment supervision over valid windows. Unlike the removed
|
| 7040 |
+
# explicit centered branch, this directly penalizes the common *error*
|
| 7041 |
+
# while preserving the full raw loss. The standard-deviation term keeps
|
| 7042 |
+
# the context-specific spread from collapsing. Only [1,1,H] reductions
|
| 7043 |
+
# survive; no centered [B,S,H] tensors are constructed.
|
| 7044 |
+
step_weights = step_mask.to(
|
| 7045 |
+
device=normalized_predicted_delta.device,
|
| 7046 |
+
dtype=normalized_predicted_delta.dtype,
|
| 7047 |
+
).unsqueeze(-1)
|
| 7048 |
+
valid_step_count = step_weights.sum(
|
| 7049 |
+
dim=(0, 1),
|
| 7050 |
+
keepdim=True,
|
| 7051 |
+
).clamp_min(1.0)
|
| 7052 |
+
|
| 7053 |
+
predicted_step_mean = (
|
| 7054 |
+
normalized_predicted_delta * step_weights
|
| 7055 |
+
).sum(dim=(0, 1), keepdim=True) / valid_step_count
|
| 7056 |
+
target_step_mean = (
|
| 7057 |
+
normalized_real_delta * step_weights
|
| 7058 |
+
).sum(dim=(0, 1), keepdim=True) / valid_step_count
|
| 7059 |
+
|
| 7060 |
+
mean_error_loss = F.smooth_l1_loss(
|
| 7061 |
+
predicted_step_mean,
|
| 7062 |
+
target_step_mean.detach(),
|
| 7063 |
+
reduction="mean",
|
| 7064 |
+
)
|
| 7065 |
+
|
| 7066 |
+
predicted_second_moment = (
|
| 7067 |
+
normalized_predicted_delta.square() * step_weights
|
| 7068 |
+
).sum(dim=(0, 1), keepdim=True) / valid_step_count
|
| 7069 |
+
target_second_moment = (
|
| 7070 |
+
normalized_real_delta.square() * step_weights
|
| 7071 |
+
).sum(dim=(0, 1), keepdim=True) / valid_step_count
|
| 7072 |
+
|
| 7073 |
+
# E[x^2] - E[x]^2 is clamped only for roundoff. The same epsilon on
|
| 7074 |
+
# both paths makes exactly constant prediction/target channels match.
|
| 7075 |
+
predicted_step_std = (
|
| 7076 |
+
predicted_second_moment - predicted_step_mean.square()
|
| 7077 |
+
).clamp_min(0.0).add(1.0e-6).sqrt()
|
| 7078 |
+
target_step_std = (
|
| 7079 |
+
target_second_moment - target_step_mean.square()
|
| 7080 |
+
).clamp_min(0.0).add(1.0e-6).sqrt()
|
| 7081 |
+
std_match_loss = F.smooth_l1_loss(
|
| 7082 |
+
predicted_step_std,
|
| 7083 |
+
target_step_std.detach(),
|
| 7084 |
+
reduction="mean",
|
| 7085 |
+
)
|
| 7086 |
+
|
| 7087 |
+
# Preserve the full local supervision, add direct pressure on the
|
| 7088 |
+
# horizon-common error, and retain a smaller dispersion constraint.
|
| 7089 |
+
step_delta_loss = (
|
| 7090 |
+
raw_step_loss + mean_error_loss + 0.5 * std_match_loss
|
| 7091 |
+
)
|
| 7092 |
+
normalized_step_loss_total = (
|
| 7093 |
+
normalized_step_loss_total + step_delta_loss
|
| 7094 |
+
)
|
| 7095 |
+
normalized_step_loss_by_step.append(step_delta_loss.detach().float())
|
| 7096 |
+
raw_step_loss_by_step.append(raw_step_loss.detach().float())
|
| 7097 |
+
mean_error_loss_by_step.append(mean_error_loss.detach().float())
|
| 7098 |
+
std_match_loss_by_step.append(std_match_loss.detach().float())
|
| 7099 |
+
|
| 7100 |
+
if functional_length > 0:
|
| 7101 |
+
(
|
| 7102 |
+
step_readout_loss,
|
| 7103 |
+
step_readout_agreement,
|
| 7104 |
+
step_readout_margin_error,
|
| 7105 |
+
step_readout_valid_fraction,
|
| 7106 |
+
) = _temporal_two_token_readout(
|
| 7107 |
+
student_states=predicted_states[:, :functional_length, :],
|
| 7108 |
+
teacher_states=shifted_targets[:, :functional_length, :],
|
| 7109 |
+
candidate_labels=candidate_labels,
|
| 7110 |
+
candidate_valid=candidate_valid,
|
| 7111 |
+
target_index=step,
|
| 7112 |
+
base_mask=functional_window_mask,
|
| 7113 |
+
lm_head_weight=lm_head_weight,
|
| 7114 |
+
lm_head_bias=lm_head_bias,
|
| 7115 |
+
)
|
| 7116 |
+
else:
|
| 7117 |
+
step_readout_loss = zero
|
| 7118 |
+
step_readout_agreement = zero
|
| 7119 |
+
step_readout_margin_error = zero
|
| 7120 |
+
step_readout_valid_fraction = zero
|
| 7121 |
+
readout_loss_total = readout_loss_total + step_readout_loss
|
| 7122 |
+
readout_loss_by_step.append(step_readout_loss.detach().float())
|
| 7123 |
+
readout_agreement_by_step.append(
|
| 7124 |
+
step_readout_agreement.detach().float()
|
| 7125 |
+
)
|
| 7126 |
+
readout_margin_error_by_step.append(
|
| 7127 |
+
step_readout_margin_error.detach().float()
|
| 7128 |
+
)
|
| 7129 |
+
readout_valid_fraction_by_step.append(
|
| 7130 |
+
step_readout_valid_fraction.detach().float()
|
| 7131 |
+
)
|
| 7132 |
|
| 7133 |
+
with torch.no_grad():
|
| 7134 |
step_delta_cosine = F.cosine_similarity(
|
| 7135 |
predicted_delta.float(),
|
| 7136 |
real_delta.float(),
|
|
|
|
| 7204 |
|
| 7205 |
inv_horizon = 1.0 / float(max_horizon)
|
| 7206 |
state_loss = state_loss_total * inv_horizon
|
| 7207 |
+
normalized_step_loss = normalized_step_loss_total * inv_horizon
|
| 7208 |
+
readout_loss = readout_loss_total * inv_horizon
|
| 7209 |
+
trajectory_loss = (
|
| 7210 |
+
state_loss + normalized_step_loss + readout_loss
|
| 7211 |
+
) / 3.0
|
| 7212 |
+
|
| 7213 |
state_step_tensor = torch.stack(state_loss_by_step)
|
| 7214 |
+
normalized_step_loss_tensor = torch.stack(
|
| 7215 |
+
normalized_step_loss_by_step
|
| 7216 |
+
)
|
| 7217 |
+
raw_step_loss_tensor = torch.stack(raw_step_loss_by_step)
|
| 7218 |
+
mean_error_loss_tensor = torch.stack(mean_error_loss_by_step)
|
| 7219 |
+
std_match_loss_tensor = torch.stack(std_match_loss_by_step)
|
| 7220 |
delta_step_tensor = torch.stack(delta_cosine_by_step)
|
| 7221 |
delta_norm_ratio_tensor = torch.stack(delta_norm_ratio_by_step)
|
| 7222 |
rollout_nitp_step_tensor = torch.stack(rollout_nitp_cosine_by_step)
|
| 7223 |
+
readout_loss_tensor = torch.stack(readout_loss_by_step)
|
| 7224 |
+
readout_agreement_tensor = torch.stack(readout_agreement_by_step)
|
| 7225 |
+
readout_margin_error_tensor = torch.stack(
|
| 7226 |
+
readout_margin_error_by_step
|
| 7227 |
+
)
|
| 7228 |
+
readout_valid_fraction_tensor = torch.stack(
|
| 7229 |
+
readout_valid_fraction_by_step
|
| 7230 |
+
)
|
| 7231 |
predicted_turn_tensor = torch.stack(predicted_turn_by_step)
|
| 7232 |
target_turn_tensor = torch.stack(target_turn_by_step)
|
|
|
|
|
|
|
|
|
|
| 7233 |
path_length_ratio = (
|
| 7234 |
path_predicted_norm_sum
|
| 7235 |
/ path_target_norm_sum.clamp_min(1.0e-8)
|
|
|
|
| 7241 |
step_metrics = torch.stack(
|
| 7242 |
(
|
| 7243 |
state_step_tensor,
|
| 7244 |
+
normalized_step_loss_tensor,
|
| 7245 |
delta_step_tensor,
|
| 7246 |
delta_norm_ratio_tensor,
|
| 7247 |
rollout_nitp_step_tensor,
|
| 7248 |
+
readout_loss_tensor,
|
| 7249 |
+
readout_agreement_tensor,
|
| 7250 |
+
readout_margin_error_tensor,
|
| 7251 |
+
readout_valid_fraction_tensor,
|
| 7252 |
zero_steps,
|
| 7253 |
zero_steps,
|
| 7254 |
predicted_turn_tensor,
|
| 7255 |
target_turn_tensor,
|
| 7256 |
+
raw_step_loss_tensor,
|
| 7257 |
+
mean_error_loss_tensor,
|
| 7258 |
+
std_match_loss_tensor,
|
| 7259 |
)
|
| 7260 |
)
|
| 7261 |
+
weighted_total = float(dynamics_weight) * trajectory_loss
|
| 7262 |
return (
|
| 7263 |
weighted_total,
|
| 7264 |
state_loss,
|
| 7265 |
+
normalized_step_loss,
|
| 7266 |
+
readout_loss,
|
| 7267 |
zero,
|
| 7268 |
zero,
|
| 7269 |
zero,
|
| 7270 |
zero,
|
| 7271 |
zero,
|
| 7272 |
+
zero.new_zeros((3, 4)),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7273 |
step_metrics,
|
| 7274 |
+
zero.new_zeros((3, max(max_horizon - 1, 0))),
|
| 7275 |
+
torch.stack((path_length_ratio, zero, zero, zero, zero)),
|
| 7276 |
)
|
| 7277 |
|
| 7278 |
(
|
|
|
|
| 7323 |
(row_prediction - expected_offsets).abs().float().mean(dim=-1),
|
| 7324 |
window_mask,
|
| 7325 |
)
|
| 7326 |
+
identification_margin = _temporal_matrix_statistics(
|
| 7327 |
+
similarity.detach(),
|
| 7328 |
+
window_mask,
|
| 7329 |
+
)[2]
|
| 7330 |
|
| 7331 |
+
# A/R/Z component rows only. Joint diagonal/off-diagonal and neighbor
|
| 7332 |
+
# profiles are exact fixed-weight reconstructions and are not logged.
|
|
|
|
| 7333 |
component_matrices = (
|
|
|
|
| 7334 |
displacement_similarity.detach(),
|
| 7335 |
relational_similarity.detach(),
|
| 7336 |
nitp_signature_similarity.detach(),
|
|
|
|
| 7347 |
for component in component_matrices
|
| 7348 |
]
|
| 7349 |
)
|
|
|
|
|
|
|
|
|
|
| 7350 |
|
| 7351 |
with torch.no_grad():
|
| 7352 |
initial_common = hidden_states[:, :common_length, :].detach()
|
|
|
|
| 7435 |
cross_predicted_tensor = torch.stack(cross_predicted_by_step)
|
| 7436 |
cross_target_tensor = torch.stack(cross_target_by_step)
|
| 7437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7438 |
step_metrics = torch.stack(
|
| 7439 |
(
|
| 7440 |
state_step_tensor,
|
| 7441 |
+
normalized_step_loss_tensor,
|
| 7442 |
delta_step_tensor,
|
| 7443 |
delta_norm_ratio_tensor,
|
| 7444 |
rollout_nitp_step_tensor,
|
| 7445 |
+
readout_loss_tensor,
|
| 7446 |
+
readout_agreement_tensor,
|
| 7447 |
+
readout_margin_error_tensor,
|
| 7448 |
+
readout_valid_fraction_tensor,
|
| 7449 |
cross_predicted_tensor,
|
| 7450 |
cross_target_tensor,
|
|
|
|
| 7451 |
predicted_turn_tensor,
|
| 7452 |
target_turn_tensor,
|
| 7453 |
+
raw_step_loss_tensor,
|
| 7454 |
+
mean_error_loss_tensor,
|
| 7455 |
+
std_match_loss_tensor,
|
| 7456 |
)
|
| 7457 |
)
|
| 7458 |
scalar_metrics = torch.stack(
|
| 7459 |
(
|
| 7460 |
path_length_ratio,
|
| 7461 |
+
rollout_pair_cosine,
|
| 7462 |
target_pair_cosine,
|
|
|
|
| 7463 |
rollout_displacement_pair_cosine,
|
| 7464 |
target_displacement_pair_cosine,
|
|
|
|
|
|
|
| 7465 |
)
|
| 7466 |
)
|
| 7467 |
|
| 7468 |
weighted_total = (
|
| 7469 |
+
float(dynamics_weight) * trajectory_loss
|
| 7470 |
+ float(identification_weight) * identification_loss
|
| 7471 |
)
|
| 7472 |
return (
|
| 7473 |
weighted_total,
|
| 7474 |
state_loss,
|
| 7475 |
+
normalized_step_loss,
|
| 7476 |
+
readout_loss,
|
| 7477 |
identification_loss,
|
| 7478 |
temporal_top1_accuracy,
|
| 7479 |
mean_absolute_offset,
|
|
|
|
|
|
|
| 7480 |
identification_margin,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7481 |
valid_window_fraction,
|
|
|
|
| 7482 |
component_metrics,
|
| 7483 |
step_metrics,
|
| 7484 |
offset_metrics,
|
| 7485 |
scalar_metrics,
|
| 7486 |
)
|
| 7487 |
|
|
|
|
| 7488 |
def _categorical_kl_loss(
|
| 7489 |
teacher_logits: torch.Tensor,
|
| 7490 |
student_logits: torch.Tensor,
|
|
|
|
| 7640 |
"`ntp_loss_backend` must be 'cce' or 'liger'. "
|
| 7641 |
f"Got {self.ntp_loss_backend!r}."
|
| 7642 |
)
|
| 7643 |
+
if bool(getattr(config, "use_mile_loss", False)):
|
| 7644 |
+
_require_extended_cce_options("mile_enabled", "mile_gamma")
|
| 7645 |
+
if bool(getattr(config, "use_mu_loss", False)):
|
| 7646 |
+
_require_extended_cce_options("mu_loss_enabled", "mu_loss_lambda")
|
| 7647 |
+
if bool(getattr(config, "use_meap", False)) and meap_mask_inputs is None:
|
| 7648 |
+
raise ImportError(
|
| 7649 |
+
"`use_meap=True` requires the extended cut-cross-entropy package. "
|
| 7650 |
+
f"Install it with `pip install --force-reinstall --no-deps "
|
| 7651 |
+
f"\"{_EXTENDED_CCE_INSTALL}\"`, or set `use_meap=False`."
|
| 7652 |
+
)
|
| 7653 |
+
if bool(getattr(config, "use_meap", False)) and (
|
| 7654 |
+
"return_metrics" not in inspect.signature(meap_mask_inputs).parameters
|
| 7655 |
+
):
|
| 7656 |
+
raise ImportError(
|
| 7657 |
+
"The installed cut-cross-entropy package does not provide kernel-side "
|
| 7658 |
+
"MEAP metrics. Reinstall the extended backend or set `use_meap=False`."
|
| 7659 |
+
)
|
| 7660 |
self._last_ntp_loss = None
|
| 7661 |
+
self._last_ntp_ce_unweighted = None
|
| 7662 |
+
self._last_mile_reweighting_delta = None
|
| 7663 |
+
self._last_mu_loss = None
|
| 7664 |
+
self._last_meap_mask_fraction = None
|
| 7665 |
+
self._last_meap_masked_tokens = None
|
| 7666 |
+
self._last_meap_seed = None
|
| 7667 |
self._last_tweo_loss = None
|
| 7668 |
self._last_nitp_loss = None
|
| 7669 |
self._last_nitp_temporal_loss = None
|
| 7670 |
self._last_nitp_temporal_state_loss = None
|
| 7671 |
+
self._last_nitp_temporal_step_loss = None
|
| 7672 |
+
self._last_nitp_temporal_raw_step_loss = None
|
| 7673 |
+
self._last_nitp_temporal_mean_error_loss = None
|
| 7674 |
+
self._last_nitp_temporal_std_match_loss = None
|
| 7675 |
+
self._last_nitp_temporal_readout_loss = None
|
| 7676 |
self._last_nitp_temporal_identification_loss = None
|
| 7677 |
self._last_nitp_temporal_top1_accuracy = None
|
| 7678 |
self._last_nitp_temporal_mean_absolute_offset = None
|
|
|
|
|
|
|
| 7679 |
self._last_nitp_temporal_identification_margin = None
|
|
|
|
|
|
|
|
|
|
| 7680 |
self._last_nitp_temporal_valid_window_fraction = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7681 |
self._last_nitp_temporal_component_metrics = None
|
| 7682 |
self._last_nitp_temporal_step_metrics = None
|
| 7683 |
self._last_nitp_temporal_offset_metrics = None
|
|
|
|
| 7736 |
position_ids: Optional[torch.LongTensor] = None,
|
| 7737 |
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 7738 |
labels: Optional[torch.LongTensor] = None,
|
| 7739 |
+
meap_seed: Optional[int] = None,
|
| 7740 |
logits_to_keep: Union[int, torch.Tensor] = 0,
|
| 7741 |
output_hidden_states: Optional[bool] = None,
|
| 7742 |
return_dict: Optional[bool] = None,
|
| 7743 |
**kwargs: Unpack[TransformersKwargs],
|
| 7744 |
) -> CausalLMOutputWithPast:
|
| 7745 |
+
self._last_meap_mask_fraction = None
|
| 7746 |
+
self._last_meap_masked_tokens = None
|
| 7747 |
+
self._last_meap_seed = None
|
| 7748 |
+
|
| 7749 |
+
meap_enabled = (
|
| 7750 |
+
bool(getattr(self.config, "use_meap", False))
|
| 7751 |
+
and self.training
|
| 7752 |
+
and labels is not None
|
| 7753 |
+
)
|
| 7754 |
+
if meap_enabled:
|
| 7755 |
+
if input_ids is None or inputs_embeds is not None:
|
| 7756 |
+
raise ValueError(
|
| 7757 |
+
"MEAP requires `input_ids` and does not support precomputed "
|
| 7758 |
+
"`inputs_embeds`."
|
| 7759 |
+
)
|
| 7760 |
+
if meap_mask_inputs is None:
|
| 7761 |
+
raise ImportError(
|
| 7762 |
+
"MEAP is enabled but is unavailable in the installed "
|
| 7763 |
+
"cut-cross-entropy package."
|
| 7764 |
+
)
|
| 7765 |
+
mask_token_id = getattr(self.config, "meap_mask_token_id", None)
|
| 7766 |
+
if mask_token_id is None:
|
| 7767 |
+
raise ValueError("`meap_mask_token_id` is required when MEAP is enabled.")
|
| 7768 |
+
effective_meap_seed = int(
|
| 7769 |
+
getattr(self.config, "meap_seed", 0)
|
| 7770 |
+
if meap_seed is None
|
| 7771 |
+
else meap_seed
|
| 7772 |
+
)
|
| 7773 |
+
eligible_mask = (
|
| 7774 |
+
attention_mask.to(device=input_ids.device, dtype=torch.bool)
|
| 7775 |
+
if attention_mask is not None
|
| 7776 |
+
else None
|
| 7777 |
+
)
|
| 7778 |
+
exclude_last = bool(getattr(self.config, "meap_exclude_last", True))
|
| 7779 |
+
mask_ratio = float(getattr(self.config, "meap_mask_ratio", 0.15))
|
| 7780 |
+
input_ids, meap_metrics = meap_mask_inputs(
|
| 7781 |
+
input_ids,
|
| 7782 |
+
int(mask_token_id),
|
| 7783 |
+
enabled=True,
|
| 7784 |
+
mask_ratio=mask_ratio,
|
| 7785 |
+
eligible_mask=eligible_mask,
|
| 7786 |
+
seed=effective_meap_seed,
|
| 7787 |
+
exclude_last=exclude_last,
|
| 7788 |
+
return_mask=False,
|
| 7789 |
+
return_metrics=True,
|
| 7790 |
+
implementation=str(
|
| 7791 |
+
getattr(self.config, "meap_implementation", "triton")
|
| 7792 |
+
),
|
| 7793 |
+
)
|
| 7794 |
+
eligible_count = meap_metrics[0]
|
| 7795 |
+
masked_count = meap_metrics[1]
|
| 7796 |
+
self._last_meap_mask_fraction = (
|
| 7797 |
+
masked_count.float() / eligible_count.clamp_min(1).float()
|
| 7798 |
+
).detach()
|
| 7799 |
+
self._last_meap_masked_tokens = masked_count.detach()
|
| 7800 |
+
self._last_meap_seed = input_ids.new_tensor(
|
| 7801 |
+
effective_meap_seed, dtype=torch.long
|
| 7802 |
+
)
|
| 7803 |
+
|
| 7804 |
tweo_enabled = (
|
| 7805 |
bool(getattr(self.config, "use_tweo", False))
|
| 7806 |
and labels is not None
|
|
|
|
| 7881 |
nitp_loss = None
|
| 7882 |
nitp_temporal_loss = None
|
| 7883 |
nitp_temporal_state_loss = None
|
| 7884 |
+
nitp_temporal_step_loss = None
|
| 7885 |
+
nitp_temporal_readout_loss = None
|
| 7886 |
nitp_temporal_identification_loss = None
|
| 7887 |
nitp_temporal_top1_accuracy = None
|
| 7888 |
nitp_temporal_mean_absolute_offset = None
|
|
|
|
|
|
|
| 7889 |
nitp_temporal_identification_margin = None
|
|
|
|
|
|
|
|
|
|
| 7890 |
nitp_temporal_valid_window_fraction = None
|
|
|
|
|
|
|
| 7891 |
nitp_temporal_component_metrics = None
|
| 7892 |
nitp_temporal_step_metrics = None
|
| 7893 |
nitp_temporal_offset_metrics = None
|
| 7894 |
nitp_temporal_scalar_metrics = None
|
|
|
|
| 7895 |
nitp_target_hidden_states = None
|
| 7896 |
nextlat_loss = None
|
| 7897 |
nextlat_mse_loss = None
|
| 7898 |
nextlat_kl_loss = None
|
| 7899 |
self._last_ntp_loss = None
|
| 7900 |
+
self._last_ntp_ce_unweighted = None
|
| 7901 |
+
self._last_mile_reweighting_delta = None
|
| 7902 |
+
self._last_mu_loss = None
|
| 7903 |
self._last_tweo_loss = None
|
| 7904 |
self._last_nitp_loss = None
|
| 7905 |
self._last_nitp_temporal_loss = None
|
| 7906 |
self._last_nitp_temporal_state_loss = None
|
| 7907 |
+
self._last_nitp_temporal_step_loss = None
|
| 7908 |
+
self._last_nitp_temporal_raw_step_loss = None
|
| 7909 |
+
self._last_nitp_temporal_mean_error_loss = None
|
| 7910 |
+
self._last_nitp_temporal_std_match_loss = None
|
| 7911 |
+
self._last_nitp_temporal_readout_loss = None
|
| 7912 |
self._last_nitp_temporal_identification_loss = None
|
| 7913 |
self._last_nitp_temporal_top1_accuracy = None
|
| 7914 |
self._last_nitp_temporal_mean_absolute_offset = None
|
|
|
|
|
|
|
| 7915 |
self._last_nitp_temporal_identification_margin = None
|
|
|
|
|
|
|
|
|
|
| 7916 |
self._last_nitp_temporal_valid_window_fraction = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7917 |
self._last_nitp_temporal_component_metrics = None
|
| 7918 |
self._last_nitp_temporal_step_metrics = None
|
| 7919 |
self._last_nitp_temporal_offset_metrics = None
|
|
|
|
| 7933 |
self.liger_ntp_loss,
|
| 7934 |
)
|
| 7935 |
else:
|
| 7936 |
+
return_loss_metrics = bool(
|
| 7937 |
+
getattr(self.config, "use_mile_loss", False)
|
| 7938 |
+
or getattr(self.config, "use_mu_loss", False)
|
| 7939 |
+
or meap_enabled
|
| 7940 |
+
)
|
| 7941 |
+
ntp_result = compute_cce_loss(
|
| 7942 |
hidden_states,
|
| 7943 |
labels,
|
| 7944 |
self.lm_head.weight,
|
| 7945 |
getattr(self.lm_head, "bias", None),
|
| 7946 |
self.config.pad_token_id,
|
| 7947 |
getattr(self.config, "cce_loss_impl", "cce_kahan_full_c"),
|
| 7948 |
+
use_mile_loss=bool(
|
| 7949 |
+
getattr(self.config, "use_mile_loss", False)
|
| 7950 |
+
),
|
| 7951 |
+
mile_loss_gamma=float(
|
| 7952 |
+
getattr(self.config, "mile_loss_gamma", 1.0)
|
| 7953 |
+
),
|
| 7954 |
+
use_mu_loss=bool(getattr(self.config, "use_mu_loss", False)),
|
| 7955 |
+
mu_loss_lambda=float(
|
| 7956 |
+
getattr(self.config, "mu_loss_lambda", 1e-4)
|
| 7957 |
+
),
|
| 7958 |
+
return_loss_metrics=return_loss_metrics,
|
| 7959 |
)
|
| 7960 |
+
if return_loss_metrics:
|
| 7961 |
+
ntp_loss, ntp_metrics = ntp_result
|
| 7962 |
+
self._last_ntp_ce_unweighted = ntp_metrics[
|
| 7963 |
+
"ntp_ce_unweighted"
|
| 7964 |
+
].detach()
|
| 7965 |
+
self._last_mile_reweighting_delta = ntp_metrics[
|
| 7966 |
+
"mile_reweighting_delta"
|
| 7967 |
+
].detach()
|
| 7968 |
+
self._last_mu_loss = ntp_metrics["mu_loss"].detach()
|
| 7969 |
+
else:
|
| 7970 |
+
ntp_loss = ntp_result
|
| 7971 |
loss = ntp_loss
|
| 7972 |
|
| 7973 |
if tweo_enabled:
|
|
|
|
| 8043 |
attention_mask=attention_mask,
|
| 8044 |
transition_model=self.nitp_temporal_transition,
|
| 8045 |
nitp_projector=self.nitp_projector,
|
| 8046 |
+
lm_head_weight=self.lm_head.weight,
|
| 8047 |
+
lm_head_bias=getattr(self.lm_head, "bias", None),
|
| 8048 |
horizon=self.config.nitp_temporal_horizon,
|
| 8049 |
dynamics_weight=self.config.nitp_temporal_dynamics_weight,
|
| 8050 |
identification_weight=(
|
|
|
|
| 8071 |
attention_mask=attention_mask,
|
| 8072 |
transition_model=self.nitp_temporal_transition,
|
| 8073 |
nitp_projector=self.nitp_projector,
|
| 8074 |
+
lm_head_weight=self.lm_head.weight,
|
| 8075 |
+
lm_head_bias=getattr(self.lm_head, "bias", None),
|
| 8076 |
horizon=self.config.nitp_temporal_horizon,
|
| 8077 |
dynamics_weight=(
|
| 8078 |
self.config.nitp_temporal_dynamics_weight
|
|
|
|
| 8093 |
(
|
| 8094 |
nitp_temporal_loss,
|
| 8095 |
nitp_temporal_state_loss,
|
| 8096 |
+
nitp_temporal_step_loss,
|
| 8097 |
+
nitp_temporal_readout_loss,
|
| 8098 |
nitp_temporal_identification_loss,
|
| 8099 |
nitp_temporal_top1_accuracy,
|
| 8100 |
nitp_temporal_mean_absolute_offset,
|
|
|
|
|
|
|
| 8101 |
nitp_temporal_identification_margin,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8102 |
nitp_temporal_valid_window_fraction,
|
|
|
|
| 8103 |
nitp_temporal_component_metrics,
|
| 8104 |
nitp_temporal_step_metrics,
|
| 8105 |
nitp_temporal_offset_metrics,
|
|
|
|
| 8109 |
if temporal_apply_loss:
|
| 8110 |
loss = loss + nitp_temporal_loss
|
| 8111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8112 |
if nextlat_enabled:
|
| 8113 |
if hidden_states_tuple is None or len(hidden_states_tuple) < 2:
|
| 8114 |
raise ValueError(
|
|
|
|
| 8156 |
if nitp_temporal_state_loss is not None
|
| 8157 |
else None
|
| 8158 |
)
|
| 8159 |
+
self._last_nitp_temporal_step_loss = (
|
| 8160 |
+
nitp_temporal_step_loss.detach()
|
| 8161 |
+
if nitp_temporal_step_loss is not None
|
| 8162 |
+
else None
|
| 8163 |
+
)
|
| 8164 |
+
self._last_nitp_temporal_readout_loss = (
|
| 8165 |
+
nitp_temporal_readout_loss.detach()
|
| 8166 |
+
if nitp_temporal_readout_loss is not None
|
| 8167 |
+
else None
|
| 8168 |
+
)
|
| 8169 |
self._last_nitp_temporal_identification_loss = (
|
| 8170 |
nitp_temporal_identification_loss.detach()
|
| 8171 |
if nitp_temporal_identification_loss is not None
|
|
|
|
| 8181 |
if nitp_temporal_mean_absolute_offset is not None
|
| 8182 |
else None
|
| 8183 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8184 |
self._last_nitp_temporal_identification_margin = (
|
| 8185 |
nitp_temporal_identification_margin.detach()
|
| 8186 |
if nitp_temporal_identification_margin is not None
|
| 8187 |
else None
|
| 8188 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8189 |
self._last_nitp_temporal_valid_window_fraction = (
|
| 8190 |
nitp_temporal_valid_window_fraction.detach()
|
| 8191 |
if nitp_temporal_valid_window_fraction is not None
|
| 8192 |
else None
|
| 8193 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8194 |
self._last_nitp_temporal_component_metrics = (
|
| 8195 |
nitp_temporal_component_metrics.detach()
|
| 8196 |
if nitp_temporal_component_metrics is not None
|
|
|
|
| 8201 |
if nitp_temporal_step_metrics is not None
|
| 8202 |
else None
|
| 8203 |
)
|
| 8204 |
+
# Aggregate component metrics are derived from the append-only rows
|
| 8205 |
+
# 13..15. The existing `_last_nitp_temporal_step_loss` remains the
|
| 8206 |
+
# composite raw + mean_error + 0.5*std value for compatibility.
|
| 8207 |
+
if (
|
| 8208 |
+
nitp_temporal_step_metrics is not None
|
| 8209 |
+
and nitp_temporal_step_metrics.shape[0] >= 16
|
| 8210 |
+
and nitp_temporal_step_metrics.shape[1] > 0
|
| 8211 |
+
):
|
| 8212 |
+
detached_step_metrics = nitp_temporal_step_metrics.detach()
|
| 8213 |
+
self._last_nitp_temporal_raw_step_loss = (
|
| 8214 |
+
detached_step_metrics[13].mean()
|
| 8215 |
+
)
|
| 8216 |
+
self._last_nitp_temporal_mean_error_loss = (
|
| 8217 |
+
detached_step_metrics[14].mean()
|
| 8218 |
+
)
|
| 8219 |
+
self._last_nitp_temporal_std_match_loss = (
|
| 8220 |
+
detached_step_metrics[15].mean()
|
| 8221 |
+
)
|
| 8222 |
self._last_nitp_temporal_offset_metrics = (
|
| 8223 |
nitp_temporal_offset_metrics.detach()
|
| 8224 |
if nitp_temporal_offset_metrics is not None
|
|
|
|
| 8229 |
if nitp_temporal_scalar_metrics is not None
|
| 8230 |
else None
|
| 8231 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8232 |
self._last_nextlat_loss = (
|
| 8233 |
nextlat_loss.detach() if nextlat_loss is not None else None
|
| 8234 |
)
|