Upload final NeoLLM checkpoint and inference configuration
Browse files- config.json +1 -1
- configuration_neollm.py +33 -15
- generation_config.json +1 -1
- model.safetensors +2 -2
- modeling_neollm.py +771 -271
config.json
CHANGED
|
@@ -93,7 +93,7 @@
|
|
| 93 |
"stack_memory_cache_size": 2048,
|
| 94 |
"stack_slots": 16,
|
| 95 |
"tie_word_embeddings": false,
|
| 96 |
-
"transformers_version": "5.
|
| 97 |
"tweo_eps": 1e-06,
|
| 98 |
"tweo_loss_weight": 0.01,
|
| 99 |
"tweo_power": 4.0,
|
|
|
|
| 93 |
"stack_memory_cache_size": 2048,
|
| 94 |
"stack_slots": 16,
|
| 95 |
"tie_word_embeddings": false,
|
| 96 |
+
"transformers_version": "5.14.1",
|
| 97 |
"tweo_eps": 1e-06,
|
| 98 |
"tweo_loss_weight": 0.01,
|
| 99 |
"tweo_power": 4.0,
|
configuration_neollm.py
CHANGED
|
@@ -575,35 +575,52 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 575 |
Numerical stability epsilon added to the TWEO denominator.
|
| 576 |
|
| 577 |
use_nitp_temporal (:obj:`bool`, *optional*, defaults to ``False``):
|
| 578 |
-
Instantiate the NITP temporal-transition extension. The
|
| 579 |
-
a separate bias-free
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
nitp_temporal_apply_loss (:obj:`bool`, *optional*, defaults to ``True``):
|
| 587 |
When ``True``, add the weighted temporal state and identification
|
| 588 |
losses to the model loss. When ``False``, keep the transition
|
| 589 |
parameters instantiated and compute all temporal metrics under
|
| 590 |
``torch.no_grad()``, allowing a monitoring-only NTP+NITP baseline.
|
| 591 |
nitp_temporal_horizon (:obj:`int`, *optional*, defaults to ``4``):
|
| 592 |
-
Number :math:`W` of
|
| 593 |
nitp_temporal_dynamics_weight (:obj:`float`, *optional*, defaults to ``1.0``):
|
| 594 |
Weight applied to the average Smooth-L1 alignment between each
|
| 595 |
predicted final state and the stop-gradient real final state at
|
| 596 |
the same temporal offset.
|
| 597 |
nitp_temporal_identification_weight (:obj:`float`, *optional*, defaults to ``0.1``):
|
| 598 |
Weight applied to the symmetric listwise temporal-identification
|
| 599 |
-
objective over
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
nitp_temporal_intermediate_size (:obj:`int`, *optional*):
|
| 601 |
-
Intermediate width of the context proposal and
|
| 602 |
paths. ``None`` resolves to ``2 * hidden_size``. At
|
| 603 |
``hidden_size=512`` this branch adds ``2,098,176`` parameters, in
|
| 604 |
addition to the NITP projector.
|
| 605 |
nitp_temporal_similarity_temperature (:obj:`float`, *optional*, defaults to ``0.1``):
|
| 606 |
-
Temperature applied to
|
| 607 |
listwise temporal-identification softmax.
|
| 608 |
nitp_temporal_target_temperature (:obj:`float`, *optional*, defaults to ``0.5``):
|
| 609 |
Temperature controlling temporal label smoothing. Smaller values
|
|
@@ -827,9 +844,10 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 827 |
nitp_projector_intermediate_size=None,
|
| 828 |
# ── NITP temporal transition / identification extension ──────────
|
| 829 |
# This is deliberately a NITP-side module, not the existing NextLat
|
| 830 |
-
# implementation. It learns
|
| 831 |
-
#
|
| 832 |
-
#
|
|
|
|
| 833 |
# `nitp_temporal_apply_loss=False` keeps the module instantiated and
|
| 834 |
# computes every diagnostic metric, but does not add its objective to
|
| 835 |
# the model loss. This is the requested monitoring-only ablation.
|
|
|
|
| 575 |
Numerical stability epsilon added to the TWEO denominator.
|
| 576 |
|
| 577 |
use_nitp_temporal (:obj:`bool`, *optional*, defaults to ``False``):
|
| 578 |
+
Instantiate the causal NITP temporal-transition extension. The
|
| 579 |
+
module is a separate bias-free multiplicative residual updater and
|
| 580 |
+
does not reuse ``NextLatDynamicsModel``. At every rollout step it
|
| 581 |
+
conditions on the detached NITP prediction of the next shallow
|
| 582 |
+
state, :math:`\operatorname{sg}(P_{\mathrm{NITP}}(\hat h_t))`,
|
| 583 |
+
never on the real future token embedding. The condition uses the
|
| 584 |
+
centered signed gate :math:`\tanh(W_z\bar z)`, which can
|
| 585 |
+
attenuate, activate, or reverse contextual update features. With
|
| 586 |
+
``W_z=0`` the update vanishes, so the transition cannot learn a
|
| 587 |
+
non-trivial condition-independent path. It also preserves
|
| 588 |
+
``F(0, z)=0``. The branch predicts
|
| 589 |
+
:math:`\hat h_{t+1}^L`, may be composed for
|
| 590 |
+
``nitp_temporal_horizon`` causal rollout steps, and never
|
| 591 |
+
materializes vocabulary logits.
|
| 592 |
nitp_temporal_apply_loss (:obj:`bool`, *optional*, defaults to ``True``):
|
| 593 |
When ``True``, add the weighted temporal state and identification
|
| 594 |
losses to the model loss. When ``False``, keep the transition
|
| 595 |
parameters instantiated and compute all temporal metrics under
|
| 596 |
``torch.no_grad()``, allowing a monitoring-only NTP+NITP baseline.
|
| 597 |
nitp_temporal_horizon (:obj:`int`, *optional*, defaults to ``4``):
|
| 598 |
+
Number :math:`W` of autonomous NITP-conditioned latent rollout steps.
|
| 599 |
nitp_temporal_dynamics_weight (:obj:`float`, *optional*, defaults to ``1.0``):
|
| 600 |
Weight applied to the average Smooth-L1 alignment between each
|
| 601 |
predicted final state and the stop-gradient real final state at
|
| 602 |
the same temporal offset.
|
| 603 |
nitp_temporal_identification_weight (:obj:`float`, *optional*, defaults to ``0.1``):
|
| 604 |
Weight applied to the symmetric listwise temporal-identification
|
| 605 |
+
objective over a local :math:`W\times W` joint-signature matrix.
|
| 606 |
+
The score keeps two conceptual halves, geometry and frozen-weight
|
| 607 |
+
NITP content. Geometry is an equal-norm concatenation of direct
|
| 608 |
+
accumulated-displacement cosine :math:`A` and a relational angular
|
| 609 |
+
profile cosine :math:`R` computed against every real future in the
|
| 610 |
+
local window. The resulting fixed score is
|
| 611 |
+
:math:`S=\tfrac14 A+\tfrac14 R+\tfrac12 Z`. Thus a rollout that
|
| 612 |
+
makes every step parallel is penalized only when the target
|
| 613 |
+
trajectory itself has distinguishable angular structure. No
|
| 614 |
+
direct diversity penalty, extra module, batch negative, vocabulary
|
| 615 |
+
projection, permutation in the trainable loss, or tunable mixing
|
| 616 |
+
coefficient is introduced.
|
| 617 |
nitp_temporal_intermediate_size (:obj:`int`, *optional*):
|
| 618 |
+
Intermediate width of the context proposal and detached NITP-condition
|
| 619 |
paths. ``None`` resolves to ``2 * hidden_size``. At
|
| 620 |
``hidden_size=512`` this branch adds ``2,098,176`` parameters, in
|
| 621 |
addition to the NITP projector.
|
| 622 |
nitp_temporal_similarity_temperature (:obj:`float`, *optional*, defaults to ``0.1``):
|
| 623 |
+
Temperature applied to joint-signature similarities before the
|
| 624 |
listwise temporal-identification softmax.
|
| 625 |
nitp_temporal_target_temperature (:obj:`float`, *optional*, defaults to ``0.5``):
|
| 626 |
Temperature controlling temporal label smoothing. Smaller values
|
|
|
|
| 844 |
nitp_projector_intermediate_size=None,
|
| 845 |
# ── NITP temporal transition / identification extension ──────────
|
| 846 |
# This is deliberately a NITP-side module, not the existing NextLat
|
| 847 |
+
# implementation. It learns the causal latent update
|
| 848 |
+
# z_{t+1} = stopgrad(P_NITP(h_t^L))
|
| 849 |
+
# (h_t^L, z_{t+1}) -> h_{t+1}^L
|
| 850 |
+
# and recursively recomputes z from every predicted state.
|
| 851 |
# `nitp_temporal_apply_loss=False` keeps the module instantiated and
|
| 852 |
# computes every diagnostic metric, but does not add its objective to
|
| 853 |
# the model loss. This is the requested monitoring-only ablation.
|
generation_config.json
CHANGED
|
@@ -7,5 +7,5 @@
|
|
| 7 |
"output_attentions": false,
|
| 8 |
"output_hidden_states": false,
|
| 9 |
"pad_token_id": 0,
|
| 10 |
-
"transformers_version": "5.
|
| 11 |
}
|
|
|
|
| 7 |
"output_attentions": false,
|
| 8 |
"output_hidden_states": false,
|
| 9 |
"pad_token_id": 0,
|
| 10 |
+
"transformers_version": "5.14.1"
|
| 11 |
}
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e2d79a82ec12f9a950502bacacb5343dc6a3f16209e741fa6213d3195d9a0c81
|
| 3 |
+
size 244921048
|
modeling_neollm.py
CHANGED
|
@@ -5230,6 +5230,15 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 5230 |
- W_res: normal(0, initializer_range)
|
| 5231 |
- router: parent handles (normal init)
|
| 5232 |
- scaler: ones (identity at init)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5233 |
NeoLLMAttention (Affine-Scaled Attention):
|
| 5234 |
- alpha_proj: normal(0, 0.02) — near-zero so linear_clipping(≈0) ≈ 0.5
|
| 5235 |
at init, giving a mild ~0.5× scaling of softmax weights
|
|
@@ -5258,6 +5267,19 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 5258 |
def _init_weights(self, module):
|
| 5259 |
super()._init_weights(module)
|
| 5260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5261 |
if isinstance(module, NeoLLMAttention):
|
| 5262 |
if getattr(module, "use_fan_residual", False):
|
| 5263 |
if hasattr(module, "lambda_1") and module.lambda_1 is not None:
|
|
@@ -6032,30 +6054,34 @@ def compute_nitp_loss(
|
|
| 6032 |
|
| 6033 |
class NITPTemporalTransition(nn.Module):
|
| 6034 |
"""
|
| 6035 |
-
|
| 6036 |
|
| 6037 |
-
This module
|
| 6038 |
-
|
| 6039 |
-
|
| 6040 |
-
proposal:
|
| 6041 |
|
| 6042 |
h_bar = RMSNorm_h(h_t)
|
| 6043 |
-
|
| 6044 |
u_h = SiLU(W_gate h_bar) * (W_up h_bar)
|
| 6045 |
-
|
| 6046 |
-
delta_t = W_down(u_h *
|
| 6047 |
h_hat_{t+1} = h_t + delta_t
|
| 6048 |
|
| 6049 |
-
|
| 6050 |
-
|
|
|
|
|
|
|
|
|
|
| 6051 |
|
| 6052 |
-
|
| 6053 |
-
|
| 6054 |
|
| 6055 |
-
|
| 6056 |
-
|
| 6057 |
-
|
| 6058 |
-
|
|
|
|
|
|
|
| 6059 |
|
| 6060 |
Parameter count, excluding the already-existing NITP projector:
|
| 6061 |
|
|
@@ -6071,12 +6097,13 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6071 |
hidden_size = int(config.hidden_size)
|
| 6072 |
intermediate_size = int(config.nitp_temporal_intermediate_size)
|
| 6073 |
|
| 6074 |
-
#
|
| 6075 |
-
#
|
|
|
|
| 6076 |
self.context_norm = nn.RMSNorm(hidden_size, eps=config.rms_norm_eps)
|
| 6077 |
-
self.
|
| 6078 |
|
| 6079 |
-
# Context path: proposes the
|
| 6080 |
self.context_gate_proj = nn.Linear(
|
| 6081 |
hidden_size, intermediate_size, bias=False
|
| 6082 |
)
|
|
@@ -6084,10 +6111,10 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6084 |
hidden_size, intermediate_size, bias=False
|
| 6085 |
)
|
| 6086 |
|
| 6087 |
-
#
|
| 6088 |
-
# route to the output
|
| 6089 |
-
#
|
| 6090 |
-
self.
|
| 6091 |
hidden_size, intermediate_size, bias=False
|
| 6092 |
)
|
| 6093 |
self.down_proj = nn.Linear(intermediate_size, hidden_size, bias=False)
|
|
@@ -6095,17 +6122,19 @@ class NITPTemporalTransition(nn.Module):
|
|
| 6095 |
def forward(
|
| 6096 |
self,
|
| 6097 |
current_states: torch.Tensor,
|
| 6098 |
-
|
| 6099 |
) -> torch.Tensor:
|
| 6100 |
context = self.context_norm(current_states)
|
| 6101 |
-
|
| 6102 |
|
| 6103 |
context_update = (
|
| 6104 |
F.silu(self.context_gate_proj(context))
|
| 6105 |
* self.context_up_proj(context)
|
| 6106 |
)
|
| 6107 |
-
|
| 6108 |
-
|
|
|
|
|
|
|
| 6109 |
return current_states + delta
|
| 6110 |
|
| 6111 |
|
|
@@ -6172,10 +6201,10 @@ def _valid_temporal_span_mask(
|
|
| 6172 |
"""
|
| 6173 |
Return a mask for contiguous temporal spans that stay inside one document.
|
| 6174 |
|
| 6175 |
-
A span includes the source state and every
|
| 6176 |
-
the rollout.
|
| 6177 |
-
permitted only at the final position, so no transition is
|
| 6178 |
-
packed-document boundary.
|
| 6179 |
"""
|
| 6180 |
token_windows = valid_tokens.unfold(dimension=1, size=span_length, step=1)
|
| 6181 |
span_mask = token_windows.all(dim=-1)
|
|
@@ -6187,45 +6216,324 @@ def _valid_temporal_span_mask(
|
|
| 6187 |
return span_mask
|
| 6188 |
|
| 6189 |
|
| 6190 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6191 |
predicted_by_step: list[torch.Tensor],
|
|
|
|
| 6192 |
target_hidden_states: torch.Tensor,
|
|
|
|
|
|
|
| 6193 |
common_length: int,
|
| 6194 |
-
) ->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6195 |
"""
|
| 6196 |
-
Build the local ``W x W``
|
| 6197 |
-
|
| 6198 |
-
|
| 6199 |
-
|
| 6200 |
-
|
| 6201 |
-
|
| 6202 |
-
|
| 6203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6204 |
"""
|
| 6205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6206 |
for predicted_states in predicted_by_step:
|
| 6207 |
-
|
|
|
|
|
|
|
| 6208 |
row = []
|
| 6209 |
-
for offset in range(1,
|
| 6210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6211 |
:, offset : offset + common_length, :
|
| 6212 |
].detach()
|
| 6213 |
row.append(
|
| 6214 |
F.cosine_similarity(
|
| 6215 |
-
|
| 6216 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6217 |
dim=-1,
|
| 6218 |
-
eps=
|
| 6219 |
)
|
| 6220 |
)
|
| 6221 |
-
|
| 6222 |
-
return torch.stack(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6223 |
|
| 6224 |
|
| 6225 |
def compute_nitp_temporal_objective(
|
| 6226 |
hidden_states: torch.Tensor,
|
| 6227 |
shallow_target_states: torch.Tensor,
|
| 6228 |
-
token_embeds: torch.Tensor,
|
| 6229 |
labels: torch.LongTensor,
|
| 6230 |
attention_mask: Optional[torch.Tensor],
|
| 6231 |
transition_model: NITPTemporalTransition,
|
|
@@ -6237,79 +6545,63 @@ def compute_nitp_temporal_objective(
|
|
| 6237 |
target_temperature: float,
|
| 6238 |
pad_token_id: Optional[int] = None,
|
| 6239 |
eos_token_id: Optional[int] = None,
|
| 6240 |
-
) -> Tuple[
|
| 6241 |
-
torch.Tensor,
|
| 6242 |
-
torch.Tensor,
|
| 6243 |
-
torch.Tensor,
|
| 6244 |
-
torch.Tensor,
|
| 6245 |
-
torch.Tensor,
|
| 6246 |
-
torch.Tensor,
|
| 6247 |
-
torch.Tensor,
|
| 6248 |
-
torch.Tensor,
|
| 6249 |
-
torch.Tensor,
|
| 6250 |
-
torch.Tensor,
|
| 6251 |
-
torch.Tensor,
|
| 6252 |
-
torch.Tensor,
|
| 6253 |
-
torch.Tensor,
|
| 6254 |
-
]:
|
| 6255 |
"""
|
| 6256 |
-
NITP temporal
|
| 6257 |
|
| 6258 |
-
|
| 6259 |
|
| 6260 |
h_hat_{t,0} = h_t
|
| 6261 |
-
|
| 6262 |
-
|
| 6263 |
-
|
| 6264 |
-
|
| 6265 |
-
|
| 6266 |
-
|
| 6267 |
-
|
| 6268 |
-
|
| 6269 |
-
|
| 6270 |
-
|
| 6271 |
-
|
| 6272 |
-
|
| 6273 |
-
|
| 6274 |
-
|
| 6275 |
-
|
| 6276 |
-
|
| 6277 |
-
|
| 6278 |
-
|
| 6279 |
-
|
| 6280 |
-
|
| 6281 |
-
|
| 6282 |
-
|
| 6283 |
-
|
| 6284 |
-
|
| 6285 |
-
|
| 6286 |
-
|
| 6287 |
-
|
| 6288 |
-
|
| 6289 |
-
|
| 6290 |
-
|
| 6291 |
-
|
| 6292 |
-
|
| 6293 |
-
|
| 6294 |
-
|
| 6295 |
-
|
| 6296 |
-
|
| 6297 |
-
|
| 6298 |
-
RNG, graph recompilation, and cross-rank communication.
|
| 6299 |
-
|
| 6300 |
-
Returned scalars, in order:
|
| 6301 |
-
weighted_total, state_loss, identification_loss,
|
| 6302 |
-
temporal_top1_accuracy, mean_absolute_offset,
|
| 6303 |
-
diagonal_cosine, off_diagonal_cosine, identification_margin,
|
| 6304 |
-
last_step_state_loss, rollout_nitp_cosine,
|
| 6305 |
-
rollout_pair_cosine, valid_window_fraction, context_specificity.
|
| 6306 |
"""
|
| 6307 |
horizon = int(horizon)
|
| 6308 |
seq_len = int(hidden_states.shape[1])
|
| 6309 |
max_horizon = max(min(horizon, seq_len - 1), 0)
|
| 6310 |
zero = hidden_states.new_zeros((), dtype=torch.float32)
|
| 6311 |
if max_horizon == 0:
|
| 6312 |
-
return (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6313 |
|
| 6314 |
device = hidden_states.device
|
| 6315 |
labels_on_device = labels.to(device=device)
|
|
@@ -6322,69 +6614,167 @@ def compute_nitp_temporal_objective(
|
|
| 6322 |
valid_tokens = valid_tokens & (labels_on_device != pad_token_id)
|
| 6323 |
|
| 6324 |
current_states = hidden_states
|
| 6325 |
-
shifted_token_embeds = token_embeds
|
| 6326 |
shifted_targets = hidden_states
|
| 6327 |
-
predicted_by_step = []
|
| 6328 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6329 |
state_loss_total = zero
|
| 6330 |
-
|
| 6331 |
-
|
|
|
|
|
|
|
| 6332 |
|
| 6333 |
for step in range(max_horizon):
|
| 6334 |
-
#
|
| 6335 |
-
#
|
| 6336 |
-
#
|
| 6337 |
-
#
|
| 6338 |
source_states = current_states[:, :-1, :]
|
| 6339 |
-
shifted_token_embeds = shifted_token_embeds[:, 1:, :]
|
| 6340 |
shifted_targets = shifted_targets[:, 1:, :]
|
| 6341 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6342 |
|
| 6343 |
-
step_span = step + 2 # source + (step + 1) consumed future tokens
|
| 6344 |
step_mask = _valid_temporal_span_mask(
|
| 6345 |
valid_tokens=valid_tokens,
|
| 6346 |
labels=labels_on_device,
|
| 6347 |
-
span_length=
|
| 6348 |
eos_token_id=eos_token_id,
|
| 6349 |
)
|
| 6350 |
step_masks.append(step_mask)
|
|
|
|
| 6351 |
step_state_loss = _masked_smooth_l1(
|
| 6352 |
predicted=predicted_states,
|
| 6353 |
target=shifted_targets,
|
| 6354 |
mask=step_mask,
|
| 6355 |
)
|
| 6356 |
state_loss_total = state_loss_total + step_state_loss
|
| 6357 |
-
|
| 6358 |
|
| 6359 |
-
# NITP interaction metric only. It does not contribute gradients or
|
| 6360 |
-
# alter the objective. For k=1 this reproduces the ordinary NITP
|
| 6361 |
-
# alignment; later k measure whether recursively predicted states still
|
| 6362 |
-
# point toward the correct shallow implicit token.
|
| 6363 |
with torch.no_grad():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6364 |
shallow_target = shallow_target_states[:, step + 1 :, :]
|
| 6365 |
-
|
| 6366 |
-
|
| 6367 |
-
projected_shallow.float(),
|
| 6368 |
shallow_target.float(),
|
| 6369 |
dim=-1,
|
| 6370 |
-
eps=
|
| 6371 |
)
|
| 6372 |
-
|
| 6373 |
-
|
| 6374 |
-
step_mask,
|
| 6375 |
)
|
| 6376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6377 |
predicted_by_step.append(predicted_states)
|
|
|
|
| 6378 |
current_states = predicted_states
|
| 6379 |
|
| 6380 |
inv_horizon = 1.0 / float(max_horizon)
|
| 6381 |
state_loss = state_loss_total * inv_horizon
|
| 6382 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6383 |
|
| 6384 |
-
# All W rollout steps must share the same source positions to form the
|
| 6385 |
-
# local W x W identification matrix. The common number of starts is T-W.
|
| 6386 |
common_length = seq_len - max_horizon
|
| 6387 |
if common_length <= 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6388 |
weighted_total = float(dynamics_weight) * state_loss
|
| 6389 |
return (
|
| 6390 |
weighted_total,
|
|
@@ -6396,21 +6786,30 @@ def compute_nitp_temporal_objective(
|
|
| 6396 |
zero,
|
| 6397 |
zero,
|
| 6398 |
last_step_state_loss,
|
|
|
|
| 6399 |
rollout_nitp_cosine,
|
| 6400 |
zero,
|
| 6401 |
zero,
|
| 6402 |
zero,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6403 |
)
|
| 6404 |
|
| 6405 |
-
|
| 6406 |
-
|
| 6407 |
-
|
| 6408 |
-
|
| 6409 |
-
|
|
|
|
| 6410 |
predicted_by_step=predicted_by_step,
|
|
|
|
| 6411 |
target_hidden_states=hidden_states,
|
|
|
|
|
|
|
| 6412 |
common_length=common_length,
|
| 6413 |
-
)
|
| 6414 |
|
| 6415 |
window_mask = _valid_temporal_span_mask(
|
| 6416 |
valid_tokens=valid_tokens,
|
|
@@ -6438,137 +6837,191 @@ def compute_nitp_temporal_objective(
|
|
| 6438 |
|
| 6439 |
row_prediction = similarity.argmax(dim=-1)
|
| 6440 |
expected_offsets = offsets.view(1, 1, -1)
|
| 6441 |
-
|
| 6442 |
-
|
|
|
|
|
|
|
| 6443 |
mean_absolute_offset = _masked_mean(
|
| 6444 |
(row_prediction - expected_offsets).abs().float().mean(dim=-1),
|
| 6445 |
window_mask,
|
| 6446 |
)
|
| 6447 |
|
| 6448 |
-
|
| 6449 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6450 |
|
| 6451 |
-
|
| 6452 |
-
|
| 6453 |
-
|
| 6454 |
-
|
| 6455 |
-
|
| 6456 |
-
|
| 6457 |
-
|
| 6458 |
-
|
| 6459 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6460 |
)
|
| 6461 |
-
|
| 6462 |
-
|
| 6463 |
window_mask,
|
| 6464 |
)
|
| 6465 |
-
|
| 6466 |
-
|
| 6467 |
-
|
| 6468 |
-
|
| 6469 |
-
|
| 6470 |
-
identification_margin = _masked_mean(
|
| 6471 |
-
(diagonal - hard_negative).mean(dim=-1),
|
| 6472 |
window_mask,
|
| 6473 |
)
|
| 6474 |
-
|
| 6475 |
-
|
| 6476 |
-
|
| 6477 |
-
|
| 6478 |
-
|
| 6479 |
-
for predicted_right in predicted_by_step:
|
| 6480 |
-
predicted_right = predicted_right[:, :common_length, :]
|
| 6481 |
-
pair_row.append(
|
| 6482 |
-
F.cosine_similarity(
|
| 6483 |
-
predicted_left.float(),
|
| 6484 |
-
predicted_right.float(),
|
| 6485 |
-
dim=-1,
|
| 6486 |
-
eps=1e-8,
|
| 6487 |
-
)
|
| 6488 |
-
)
|
| 6489 |
-
predicted_pair_rows.append(torch.stack(pair_row, dim=-1))
|
| 6490 |
-
predicted_pair_similarity = torch.stack(predicted_pair_rows, dim=-2)
|
| 6491 |
-
rollout_off_diagonal = predicted_pair_similarity.masked_select(
|
| 6492 |
-
~identity.view(1, 1, max_horizon, max_horizon)
|
| 6493 |
-
).view(
|
| 6494 |
-
similarity.shape[0],
|
| 6495 |
-
similarity.shape[1],
|
| 6496 |
-
max_horizon * (max_horizon - 1),
|
| 6497 |
-
)
|
| 6498 |
-
rollout_pair_cosine = _masked_mean(
|
| 6499 |
-
rollout_off_diagonal.mean(dim=-1),
|
| 6500 |
window_mask,
|
| 6501 |
)
|
| 6502 |
-
else:
|
| 6503 |
-
off_diagonal_cosine = zero
|
| 6504 |
-
identification_margin = zero
|
| 6505 |
-
rollout_pair_cosine = zero
|
| 6506 |
-
|
| 6507 |
-
# ------------------------------------------------------------------
|
| 6508 |
-
# Context-specificity diagnostic (monitoring only, no gradients).
|
| 6509 |
-
# ------------------------------------------------------------------
|
| 6510 |
-
# The multiplicative transition already guarantees F(0, e) = 0, so a
|
| 6511 |
-
# zero-context/token-only rollout is now true by construction and no longer
|
| 6512 |
-
# diagnoses learned behavior. Instead, use an on-manifold but incorrect
|
| 6513 |
-
# context from the next example in the local batch while retaining each
|
| 6514 |
-
# example's exact teacher-forced future tokens:
|
| 6515 |
-
#
|
| 6516 |
-
# pi(i) = (i + 1) mod B
|
| 6517 |
-
# h_tilde_{i,t,0} = stopgrad(h^L_{pi(i),t})
|
| 6518 |
-
# h_tilde_{i,t,k} = F_psi(h_tilde_{i,t,k-1}, E[x_{i,t+k}]).
|
| 6519 |
-
#
|
| 6520 |
-
# With L_full = state_loss and L_wrong the counterfactual Smooth-L1 loss,
|
| 6521 |
-
# report the bounded, scale-normalized score
|
| 6522 |
-
#
|
| 6523 |
-
# C_ctx = (L_wrong - L_full) / (L_wrong + L_full + eps).
|
| 6524 |
-
#
|
| 6525 |
-
# C_ctx ~= 0: any plausible context works almost equally well.
|
| 6526 |
-
# C_ctx > 0: the exact context improves the transition.
|
| 6527 |
-
# C_ctx < 0: the wrong context unexpectedly performs better.
|
| 6528 |
-
#
|
| 6529 |
-
# This replaces the three old token-only metrics at lower cost: it reuses
|
| 6530 |
-
# one no-grad rollout but does not build a second W x W similarity matrix.
|
| 6531 |
-
with torch.no_grad():
|
| 6532 |
-
if int(hidden_states.shape[0]) > 1:
|
| 6533 |
-
wrong_context_current = torch.roll(
|
| 6534 |
-
hidden_states.detach(), shifts=1, dims=0
|
| 6535 |
-
)
|
| 6536 |
-
wrong_context_shifted_embeds = token_embeds.detach()
|
| 6537 |
-
wrong_context_targets = hidden_states.detach()
|
| 6538 |
-
wrong_context_state_loss_total = zero
|
| 6539 |
|
|
|
|
|
|
|
|
|
|
| 6540 |
for step in range(max_horizon):
|
| 6541 |
-
|
| 6542 |
-
|
| 6543 |
-
|
|
|
|
|
|
|
| 6544 |
)
|
| 6545 |
-
|
| 6546 |
-
|
| 6547 |
-
|
| 6548 |
-
wrong_context_shifted_embeds,
|
| 6549 |
)
|
| 6550 |
-
|
| 6551 |
-
|
| 6552 |
-
|
| 6553 |
-
|
| 6554 |
-
|
| 6555 |
-
|
| 6556 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6557 |
)
|
| 6558 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6559 |
|
| 6560 |
-
|
| 6561 |
-
|
| 6562 |
-
|
| 6563 |
-
|
| 6564 |
-
|
| 6565 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6566 |
(wrong_state_loss - full_state_loss)
|
| 6567 |
/ (wrong_state_loss + full_state_loss + 1.0e-8)
|
| 6568 |
).clamp(min=-1.0, max=1.0)
|
| 6569 |
else:
|
| 6570 |
-
|
| 6571 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6572 |
|
| 6573 |
weighted_total = (
|
| 6574 |
float(dynamics_weight) * state_loss
|
|
@@ -6584,10 +7037,15 @@ def compute_nitp_temporal_objective(
|
|
| 6584 |
off_diagonal_cosine,
|
| 6585 |
identification_margin,
|
| 6586 |
last_step_state_loss,
|
|
|
|
| 6587 |
rollout_nitp_cosine,
|
| 6588 |
rollout_pair_cosine,
|
| 6589 |
valid_window_fraction,
|
| 6590 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6591 |
)
|
| 6592 |
|
| 6593 |
|
|
@@ -6761,9 +7219,14 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 6761 |
self._last_nitp_temporal_rollout_nitp_cosine = None
|
| 6762 |
self._last_nitp_temporal_rollout_pair_cosine = None
|
| 6763 |
self._last_nitp_temporal_valid_window_fraction = None
|
| 6764 |
-
self.
|
|
|
|
| 6765 |
self._last_nitp_temporal_to_nitp_ratio = None
|
| 6766 |
self._last_nitp_temporal_loss_applied = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6767 |
self._last_nextlat_loss = None
|
| 6768 |
self._last_nextlat_mse_loss = None
|
| 6769 |
self._last_nextlat_kl_loss = None
|
|
@@ -6913,7 +7376,12 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 6913 |
nitp_temporal_rollout_nitp_cosine = None
|
| 6914 |
nitp_temporal_rollout_pair_cosine = None
|
| 6915 |
nitp_temporal_valid_window_fraction = None
|
| 6916 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6917 |
nitp_temporal_to_nitp_ratio = None
|
| 6918 |
nitp_target_hidden_states = None
|
| 6919 |
nextlat_loss = None
|
|
@@ -6934,9 +7402,14 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 6934 |
self._last_nitp_temporal_rollout_nitp_cosine = None
|
| 6935 |
self._last_nitp_temporal_rollout_pair_cosine = None
|
| 6936 |
self._last_nitp_temporal_valid_window_fraction = None
|
| 6937 |
-
self.
|
|
|
|
| 6938 |
self._last_nitp_temporal_to_nitp_ratio = None
|
| 6939 |
self._last_nitp_temporal_loss_applied = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6940 |
self._last_nextlat_loss = None
|
| 6941 |
self._last_nextlat_mse_loss = None
|
| 6942 |
self._last_nextlat_kl_loss = None
|
|
@@ -7018,7 +7491,6 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7018 |
)
|
| 7019 |
nitp_target_hidden_states = hidden_states_tuple[target_layer]
|
| 7020 |
|
| 7021 |
-
token_embeds = hidden_states_tuple[0]
|
| 7022 |
temporal_apply_loss = bool(
|
| 7023 |
getattr(self.config, "nitp_temporal_apply_loss", True)
|
| 7024 |
)
|
|
@@ -7032,7 +7504,6 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7032 |
temporal_results = compute_nitp_temporal_objective(
|
| 7033 |
hidden_states=hidden_states,
|
| 7034 |
shallow_target_states=nitp_target_hidden_states,
|
| 7035 |
-
token_embeds=token_embeds,
|
| 7036 |
labels=labels,
|
| 7037 |
attention_mask=attention_mask,
|
| 7038 |
transition_model=self.nitp_temporal_transition,
|
|
@@ -7059,7 +7530,6 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7059 |
temporal_results = compute_nitp_temporal_objective(
|
| 7060 |
hidden_states=hidden_states,
|
| 7061 |
shallow_target_states=nitp_target_hidden_states,
|
| 7062 |
-
token_embeds=token_embeds,
|
| 7063 |
labels=labels,
|
| 7064 |
attention_mask=attention_mask,
|
| 7065 |
transition_model=self.nitp_temporal_transition,
|
|
@@ -7091,10 +7561,15 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7091 |
nitp_temporal_off_diagonal_cosine,
|
| 7092 |
nitp_temporal_identification_margin,
|
| 7093 |
nitp_temporal_last_step_state_loss,
|
|
|
|
| 7094 |
nitp_temporal_rollout_nitp_cosine,
|
| 7095 |
nitp_temporal_rollout_pair_cosine,
|
| 7096 |
nitp_temporal_valid_window_fraction,
|
| 7097 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7098 |
) = temporal_results
|
| 7099 |
|
| 7100 |
if temporal_apply_loss:
|
|
@@ -7113,10 +7588,10 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7113 |
"NeoLLMForCausalLM.forward enables them automatically "
|
| 7114 |
"while labels are present."
|
| 7115 |
)
|
|
|
|
|
|
|
|
|
|
| 7116 |
token_embeds = hidden_states_tuple[0]
|
| 7117 |
-
# NextLat uses final hidden states h_t and input embeddings
|
| 7118 |
-
# x_{t+1}; p_psi is training-only and inference remains the
|
| 7119 |
-
# standard autoregressive LM path.
|
| 7120 |
nextlat_loss, nextlat_mse_loss, nextlat_kl_loss = compute_nextlat_loss(
|
| 7121 |
hidden_states=hidden_states,
|
| 7122 |
token_embeds=token_embeds,
|
|
@@ -7203,9 +7678,34 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 7203 |
if nitp_temporal_valid_window_fraction is not None
|
| 7204 |
else None
|
| 7205 |
)
|
| 7206 |
-
self.
|
| 7207 |
-
|
| 7208 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7209 |
else None
|
| 7210 |
)
|
| 7211 |
self._last_nitp_temporal_to_nitp_ratio = (
|
|
|
|
| 5230 |
- W_res: normal(0, initializer_range)
|
| 5231 |
- router: parent handles (normal init)
|
| 5232 |
- scaler: ones (identity at init)
|
| 5233 |
+
NITPTemporalTransition:
|
| 5234 |
+
- context_gate_proj/context_up_proj/condition_modulation_proj:
|
| 5235 |
+
Xavier-uniform so both the contextual proposal and the
|
| 5236 |
+
detached NITP condition have non-degenerate variance at
|
| 5237 |
+
step 0.
|
| 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
|
| 5244 |
at init, giving a mild ~0.5× scaling of softmax weights
|
|
|
|
| 5267 |
def _init_weights(self, module):
|
| 5268 |
super()._init_weights(module)
|
| 5269 |
|
| 5270 |
+
if isinstance(module, NITPTemporalTransition):
|
| 5271 |
+
# A centered tanh gate has no constant 0.5 path. Xavier
|
| 5272 |
+
# initialization gives the detached NITP condition measurable
|
| 5273 |
+
# variation from step 0, while a small non-zero down projection
|
| 5274 |
+
# keeps the full residual transition close to identity without
|
| 5275 |
+
# suppressing gradients into the condition path.
|
| 5276 |
+
nn.init.xavier_uniform_(module.context_gate_proj.weight)
|
| 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 |
+
|
| 5283 |
if isinstance(module, NeoLLMAttention):
|
| 5284 |
if getattr(module, "use_fan_residual", False):
|
| 5285 |
if hasattr(module, "lambda_1") and module.lambda_1 is not None:
|
|
|
|
| 6054 |
|
| 6055 |
class NITPTemporalTransition(nn.Module):
|
| 6056 |
"""
|
| 6057 |
+
Causal NITP-conditioned multiplicative transition.
|
| 6058 |
|
| 6059 |
+
This module remains independent from ``NextLatDynamicsModel``. The current
|
| 6060 |
+
final hidden state proposes a latent update, while the detached NITP
|
| 6061 |
+
prediction of the next shallow state modulates that proposal:
|
|
|
|
| 6062 |
|
| 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 |
+
s_z = tanh(W_condition z_bar)
|
| 6067 |
+
delta_t = W_down(u_h * s_z)
|
| 6068 |
h_hat_{t+1} = h_t + delta_t
|
| 6069 |
|
| 6070 |
+
The centered signed gate satisfies ``s_z in (-1, 1)``. Unlike a
|
| 6071 |
+
positive sigmoid gate, it can attenuate, activate, or reverse an
|
| 6072 |
+
individual contextual feature. More importantly, ``W_condition=0``
|
| 6073 |
+
now implies ``s_z=0`` and therefore ``T(h, z)=h``: the transition can
|
| 6074 |
+
no longer learn a non-trivial update while ignoring the NITP condition.
|
| 6075 |
|
| 6076 |
+
All projections are bias-free. Therefore the NITP condition has no
|
| 6077 |
+
additive route to the output and the transition still satisfies:
|
| 6078 |
|
| 6079 |
+
F(0, z) = 0
|
| 6080 |
+
dF(0, z) / dz = 0
|
| 6081 |
+
|
| 6082 |
+
The condition cannot construct a deep state by itself; it only controls
|
| 6083 |
+
features proposed by the current causal state. The module never
|
| 6084 |
+
materializes vocabulary logits.
|
| 6085 |
|
| 6086 |
Parameter count, excluding the already-existing NITP projector:
|
| 6087 |
|
|
|
|
| 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
|
| 6102 |
+
# next-state condition produced by the NITP projector.
|
| 6103 |
self.context_norm = nn.RMSNorm(hidden_size, eps=config.rms_norm_eps)
|
| 6104 |
+
self.condition_norm = nn.RMSNorm(hidden_size, eps=config.rms_norm_eps)
|
| 6105 |
|
| 6106 |
+
# Context path: proposes the features of the deep-state update.
|
| 6107 |
self.context_gate_proj = nn.Linear(
|
| 6108 |
hidden_size, intermediate_size, bias=False
|
| 6109 |
)
|
|
|
|
| 6111 |
hidden_size, intermediate_size, bias=False
|
| 6112 |
)
|
| 6113 |
|
| 6114 |
+
# NITP-condition path: controls contextual features but has no additive
|
| 6115 |
+
# route to the output. The centered tanh gate forces every non-zero
|
| 6116 |
+
# update to depend on the detached NITP condition.
|
| 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)
|
|
|
|
| 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)
|
| 6129 |
|
| 6130 |
context_update = (
|
| 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 |
return current_states + delta
|
| 6139 |
|
| 6140 |
|
|
|
|
| 6201 |
"""
|
| 6202 |
Return a mask for contiguous temporal spans that stay inside one document.
|
| 6203 |
|
| 6204 |
+
A span includes the source state and every real future target used to
|
| 6205 |
+
evaluate the causal rollout. Padding / ignored labels invalidate the full
|
| 6206 |
+
span. EOS is permitted only at the final position, so no transition is
|
| 6207 |
+
trained across a packed-document boundary.
|
| 6208 |
"""
|
| 6209 |
token_windows = valid_tokens.unfold(dimension=1, size=span_length, step=1)
|
| 6210 |
span_mask = token_windows.all(dim=-1)
|
|
|
|
| 6216 |
return span_mask
|
| 6217 |
|
| 6218 |
|
| 6219 |
+
def _project_nitp_with_frozen_weights(
|
| 6220 |
+
hidden_states: torch.Tensor,
|
| 6221 |
+
projector: NITPProjector,
|
| 6222 |
+
) -> torch.Tensor:
|
| 6223 |
+
"""
|
| 6224 |
+
Evaluate the current NITP projector while freezing only its parameters.
|
| 6225 |
+
|
| 6226 |
+
``torch.no_grad()`` would also remove the derivative with respect to
|
| 6227 |
+
``hidden_states``. The temporal identification objective instead needs:
|
| 6228 |
+
|
| 6229 |
+
d P_{sg(theta_P)}(h) / d h != 0
|
| 6230 |
+
d P_{sg(theta_P)}(h) / d theta_P = 0.
|
| 6231 |
+
|
| 6232 |
+
The explicit bias-free SwiGLU computation below therefore uses detached
|
| 6233 |
+
projector weights. Temporal gradients can move a rollout state into a
|
| 6234 |
+
region where the already-defined NITP representation remains valid, but
|
| 6235 |
+
they cannot turn the projector into a private code for the transition.
|
| 6236 |
+
"""
|
| 6237 |
+
gate = F.linear(
|
| 6238 |
+
hidden_states,
|
| 6239 |
+
projector.gate_proj.weight.detach(),
|
| 6240 |
+
bias=None,
|
| 6241 |
+
)
|
| 6242 |
+
up = F.linear(
|
| 6243 |
+
hidden_states,
|
| 6244 |
+
projector.up_proj.weight.detach(),
|
| 6245 |
+
bias=None,
|
| 6246 |
+
)
|
| 6247 |
+
return F.linear(
|
| 6248 |
+
F.silu(gate) * up,
|
| 6249 |
+
projector.down_proj.weight.detach(),
|
| 6250 |
+
bias=None,
|
| 6251 |
+
)
|
| 6252 |
+
|
| 6253 |
+
|
| 6254 |
+
def _build_relational_temporal_similarity(
|
| 6255 |
predicted_by_step: list[torch.Tensor],
|
| 6256 |
+
condition_by_step: list[torch.Tensor],
|
| 6257 |
target_hidden_states: torch.Tensor,
|
| 6258 |
+
shallow_target_states: torch.Tensor,
|
| 6259 |
+
initial_hidden_states: torch.Tensor,
|
| 6260 |
common_length: int,
|
| 6261 |
+
) -> Tuple[
|
| 6262 |
+
torch.Tensor,
|
| 6263 |
+
torch.Tensor,
|
| 6264 |
+
torch.Tensor,
|
| 6265 |
+
torch.Tensor,
|
| 6266 |
+
]:
|
| 6267 |
"""
|
| 6268 |
+
Build the local ``W x W`` temporal-identification matrices.
|
| 6269 |
+
|
| 6270 |
+
The trainable identification score keeps two conceptual halves:
|
| 6271 |
+
|
| 6272 |
+
S_{k,j} = 0.5 * [Gamma_{k,j} + Z_{k,j}],
|
| 6273 |
+
|
| 6274 |
+
where the geometric half is itself an equal-norm concatenation:
|
| 6275 |
+
|
| 6276 |
+
Gamma_{k,j} = 0.5 * [A_{k,j} + R_{k,j}].
|
| 6277 |
+
|
| 6278 |
+
The expanded score is therefore
|
| 6279 |
+
|
| 6280 |
+
S_{k,j} = 0.25 A_{k,j} + 0.25 R_{k,j} + 0.5 Z_{k,j}.
|
| 6281 |
+
|
| 6282 |
+
``A`` is the direct accumulated-displacement cosine:
|
| 6283 |
+
|
| 6284 |
+
u_hat_k = normalize(h_hat_k - h_0)
|
| 6285 |
+
u_j^* = normalize(stopgrad(h_j^* - h_0))
|
| 6286 |
+
A_{k,j} = u_hat_k^T u_j^*.
|
| 6287 |
+
|
| 6288 |
+
``R`` compares relational angular profiles instead of forcing the rollout
|
| 6289 |
+
to copy the teacher's local tangent. First compute
|
| 6290 |
+
|
| 6291 |
+
G^*_{j,r} = (u_j^*)^T u_r^*,
|
| 6292 |
+
rho_hat_k = normalize(A_{k,:}),
|
| 6293 |
+
rho_j^* = normalize(G^*_{j,:}),
|
| 6294 |
+
R_{k,j} = rho_hat_k^T rho_j^*.
|
| 6295 |
+
|
| 6296 |
+
If all rollout displacements collapse to one direction while the target
|
| 6297 |
+
trajectory has distinct directions, the rows ``A_{k,:}`` become nearly
|
| 6298 |
+
identical and cannot match the distinct target profiles ``G^*_{j,:}``.
|
| 6299 |
+
Conversely, if the target trajectory is genuinely parallel, its profiles
|
| 6300 |
+
are also similar, so this term does not invent artificial diversity.
|
| 6301 |
+
|
| 6302 |
+
``Z`` is the frozen-weight NITP shallow-signature cosine. Projector
|
| 6303 |
+
parameters remain stop-gradient while gradients through the rollout state
|
| 6304 |
+
are preserved by ``_project_nitp_with_frozen_weights``.
|
| 6305 |
+
|
| 6306 |
+
No tunable mixing coefficient is introduced: 1/2 and 1/4 follow exactly
|
| 6307 |
+
from concatenating independently normalized blocks. The implementation
|
| 6308 |
+
deliberately evaluates the W-by-W cosines row-by-row instead of creating
|
| 6309 |
+
a ``[B,T,W,D]`` FP32 tensor, keeping peak memory small for W=4.
|
| 6310 |
"""
|
| 6311 |
+
horizon = len(predicted_by_step)
|
| 6312 |
+
initial_common = initial_hidden_states[:, :common_length, :]
|
| 6313 |
+
detached_initial = initial_common.detach()
|
| 6314 |
+
|
| 6315 |
+
displacement_rows = []
|
| 6316 |
for predicted_states in predicted_by_step:
|
| 6317 |
+
predicted_displacement = (
|
| 6318 |
+
predicted_states[:, :common_length, :] - initial_common
|
| 6319 |
+
)
|
| 6320 |
row = []
|
| 6321 |
+
for offset in range(1, horizon + 1):
|
| 6322 |
+
target_displacement = (
|
| 6323 |
+
target_hidden_states[
|
| 6324 |
+
:, offset : offset + common_length, :
|
| 6325 |
+
].detach()
|
| 6326 |
+
- detached_initial
|
| 6327 |
+
)
|
| 6328 |
+
row.append(
|
| 6329 |
+
F.cosine_similarity(
|
| 6330 |
+
predicted_displacement.float(),
|
| 6331 |
+
target_displacement.float(),
|
| 6332 |
+
dim=-1,
|
| 6333 |
+
eps=1.0e-8,
|
| 6334 |
+
)
|
| 6335 |
+
)
|
| 6336 |
+
displacement_rows.append(torch.stack(row, dim=-1))
|
| 6337 |
+
displacement_similarity = torch.stack(displacement_rows, dim=-2)
|
| 6338 |
+
|
| 6339 |
+
target_gram_rows = []
|
| 6340 |
+
for left_offset in range(1, horizon + 1):
|
| 6341 |
+
left_displacement = (
|
| 6342 |
+
target_hidden_states[
|
| 6343 |
+
:, left_offset : left_offset + common_length, :
|
| 6344 |
+
].detach()
|
| 6345 |
+
- detached_initial
|
| 6346 |
+
)
|
| 6347 |
+
row = []
|
| 6348 |
+
for right_offset in range(1, horizon + 1):
|
| 6349 |
+
right_displacement = (
|
| 6350 |
+
target_hidden_states[
|
| 6351 |
+
:, right_offset : right_offset + common_length, :
|
| 6352 |
+
].detach()
|
| 6353 |
+
- detached_initial
|
| 6354 |
+
)
|
| 6355 |
+
row.append(
|
| 6356 |
+
F.cosine_similarity(
|
| 6357 |
+
left_displacement.float(),
|
| 6358 |
+
right_displacement.float(),
|
| 6359 |
+
dim=-1,
|
| 6360 |
+
eps=1.0e-8,
|
| 6361 |
+
)
|
| 6362 |
+
)
|
| 6363 |
+
target_gram_rows.append(torch.stack(row, dim=-1))
|
| 6364 |
+
target_gram = torch.stack(target_gram_rows, dim=-2)
|
| 6365 |
+
|
| 6366 |
+
predicted_profiles = F.normalize(
|
| 6367 |
+
displacement_similarity,
|
| 6368 |
+
p=2.0,
|
| 6369 |
+
dim=-1,
|
| 6370 |
+
eps=1.0e-8,
|
| 6371 |
+
)
|
| 6372 |
+
target_profiles = F.normalize(
|
| 6373 |
+
target_gram,
|
| 6374 |
+
p=2.0,
|
| 6375 |
+
dim=-1,
|
| 6376 |
+
eps=1.0e-8,
|
| 6377 |
+
)
|
| 6378 |
+
relational_similarity = torch.einsum(
|
| 6379 |
+
"btkr,btjr->btkj",
|
| 6380 |
+
predicted_profiles,
|
| 6381 |
+
target_profiles,
|
| 6382 |
+
)
|
| 6383 |
+
|
| 6384 |
+
nitp_rows = []
|
| 6385 |
+
for predicted_condition in condition_by_step:
|
| 6386 |
+
predicted_condition = predicted_condition[:, :common_length, :]
|
| 6387 |
+
row = []
|
| 6388 |
+
for offset in range(1, horizon + 1):
|
| 6389 |
+
target_condition = shallow_target_states[
|
| 6390 |
:, offset : offset + common_length, :
|
| 6391 |
].detach()
|
| 6392 |
row.append(
|
| 6393 |
F.cosine_similarity(
|
| 6394 |
+
predicted_condition.float(),
|
| 6395 |
+
target_condition.float(),
|
| 6396 |
+
dim=-1,
|
| 6397 |
+
eps=1.0e-8,
|
| 6398 |
+
)
|
| 6399 |
+
)
|
| 6400 |
+
nitp_rows.append(torch.stack(row, dim=-1))
|
| 6401 |
+
nitp_signature_similarity = torch.stack(nitp_rows, dim=-2)
|
| 6402 |
+
|
| 6403 |
+
geometric_similarity = 0.5 * (
|
| 6404 |
+
displacement_similarity + relational_similarity
|
| 6405 |
+
)
|
| 6406 |
+
joint_similarity = 0.5 * (
|
| 6407 |
+
geometric_similarity + nitp_signature_similarity
|
| 6408 |
+
)
|
| 6409 |
+
return (
|
| 6410 |
+
joint_similarity,
|
| 6411 |
+
displacement_similarity,
|
| 6412 |
+
relational_similarity,
|
| 6413 |
+
nitp_signature_similarity,
|
| 6414 |
+
)
|
| 6415 |
+
|
| 6416 |
+
|
| 6417 |
+
def _temporal_matrix_statistics(
|
| 6418 |
+
matrix: torch.Tensor,
|
| 6419 |
+
window_mask: torch.Tensor,
|
| 6420 |
+
) -> torch.Tensor:
|
| 6421 |
+
"""
|
| 6422 |
+
Return ``[diagonal, off_diagonal, margin, positive_margin_fraction]``.
|
| 6423 |
+
|
| 6424 |
+
The margin is the diagonal score minus the hardest incorrect candidate in
|
| 6425 |
+
each row. ``positive_margin_fraction`` prevents a positive mean margin
|
| 6426 |
+
from hiding a large fraction of individually misidentified rows.
|
| 6427 |
+
"""
|
| 6428 |
+
horizon = int(matrix.shape[-1])
|
| 6429 |
+
zero = matrix.new_zeros((), dtype=torch.float32)
|
| 6430 |
+
diagonal = matrix.diagonal(dim1=-2, dim2=-1)
|
| 6431 |
+
diagonal_mean = _masked_mean(diagonal.mean(dim=-1), window_mask)
|
| 6432 |
+
if horizon <= 1:
|
| 6433 |
+
return torch.stack((diagonal_mean, zero, zero, zero))
|
| 6434 |
+
|
| 6435 |
+
identity = torch.eye(horizon, dtype=torch.bool, device=matrix.device)
|
| 6436 |
+
identity = identity.view(1, 1, horizon, horizon)
|
| 6437 |
+
off_diagonal = matrix.masked_select(~identity).view(
|
| 6438 |
+
matrix.shape[0],
|
| 6439 |
+
matrix.shape[1],
|
| 6440 |
+
horizon * (horizon - 1),
|
| 6441 |
+
)
|
| 6442 |
+
off_diagonal_mean = _masked_mean(
|
| 6443 |
+
off_diagonal.mean(dim=-1),
|
| 6444 |
+
window_mask,
|
| 6445 |
+
)
|
| 6446 |
+
hard_negative = matrix.masked_fill(
|
| 6447 |
+
identity,
|
| 6448 |
+
torch.finfo(matrix.dtype).min,
|
| 6449 |
+
).max(dim=-1).values
|
| 6450 |
+
row_margin = diagonal - hard_negative
|
| 6451 |
+
margin = _masked_mean(row_margin.mean(dim=-1), window_mask)
|
| 6452 |
+
positive_fraction = _masked_mean(
|
| 6453 |
+
(row_margin > 0.0).float().mean(dim=-1),
|
| 6454 |
+
window_mask,
|
| 6455 |
+
)
|
| 6456 |
+
return torch.stack(
|
| 6457 |
+
(diagonal_mean, off_diagonal_mean, margin, positive_fraction)
|
| 6458 |
+
)
|
| 6459 |
+
|
| 6460 |
+
|
| 6461 |
+
def _temporal_neighbor_cosines(
|
| 6462 |
+
matrix: torch.Tensor,
|
| 6463 |
+
window_mask: torch.Tensor,
|
| 6464 |
+
) -> torch.Tensor:
|
| 6465 |
+
"""Average matrix entries grouped by temporal distance ``|k-j|``."""
|
| 6466 |
+
horizon = int(matrix.shape[-1])
|
| 6467 |
+
if horizon <= 1:
|
| 6468 |
+
return matrix.new_zeros((0,), dtype=torch.float32)
|
| 6469 |
+
|
| 6470 |
+
indices = torch.arange(horizon, device=matrix.device)
|
| 6471 |
+
temporal_distance = (indices[:, None] - indices[None, :]).abs()
|
| 6472 |
+
values = []
|
| 6473 |
+
for offset in range(1, horizon):
|
| 6474 |
+
offset_mask = temporal_distance.eq(offset).view(
|
| 6475 |
+
1, 1, horizon, horizon
|
| 6476 |
+
)
|
| 6477 |
+
selected = matrix.masked_select(offset_mask).view(
|
| 6478 |
+
matrix.shape[0],
|
| 6479 |
+
matrix.shape[1],
|
| 6480 |
+
-1,
|
| 6481 |
+
)
|
| 6482 |
+
values.append(_masked_mean(selected.mean(dim=-1), window_mask))
|
| 6483 |
+
return torch.stack(values)
|
| 6484 |
+
|
| 6485 |
+
|
| 6486 |
+
def _pairwise_cosine_matrix(states: torch.Tensor) -> torch.Tensor:
|
| 6487 |
+
"""Return the within-trajectory cosine Gram matrix for ``[B,T,W,D]``."""
|
| 6488 |
+
unit = F.normalize(states.float(), p=2.0, dim=-1, eps=1.0e-8)
|
| 6489 |
+
return torch.einsum("btkd,btjd->btkj", unit, unit)
|
| 6490 |
+
|
| 6491 |
+
|
| 6492 |
+
def _pairwise_cosine_from_steps(
|
| 6493 |
+
states_by_step: list[torch.Tensor],
|
| 6494 |
+
origin: Optional[torch.Tensor] = None,
|
| 6495 |
+
) -> torch.Tensor:
|
| 6496 |
+
"""Low-peak-memory pair matrix from W tensors shaped ``[B,T,D]``."""
|
| 6497 |
+
rows = []
|
| 6498 |
+
for left in states_by_step:
|
| 6499 |
+
left_value = left if origin is None else left - origin
|
| 6500 |
+
row = []
|
| 6501 |
+
for right in states_by_step:
|
| 6502 |
+
right_value = right if origin is None else right - origin
|
| 6503 |
+
row.append(
|
| 6504 |
+
F.cosine_similarity(
|
| 6505 |
+
left_value.float(),
|
| 6506 |
+
right_value.float(),
|
| 6507 |
dim=-1,
|
| 6508 |
+
eps=1.0e-8,
|
| 6509 |
)
|
| 6510 |
)
|
| 6511 |
+
rows.append(torch.stack(row, dim=-1))
|
| 6512 |
+
return torch.stack(rows, dim=-2)
|
| 6513 |
+
|
| 6514 |
+
|
| 6515 |
+
def _off_diagonal_pair_mean(
|
| 6516 |
+
matrix: torch.Tensor,
|
| 6517 |
+
window_mask: torch.Tensor,
|
| 6518 |
+
) -> torch.Tensor:
|
| 6519 |
+
horizon = int(matrix.shape[-1])
|
| 6520 |
+
zero = matrix.new_zeros((), dtype=torch.float32)
|
| 6521 |
+
if horizon <= 1:
|
| 6522 |
+
return zero
|
| 6523 |
+
identity = torch.eye(horizon, dtype=torch.bool, device=matrix.device)
|
| 6524 |
+
selected = matrix.masked_select(
|
| 6525 |
+
~identity.view(1, 1, horizon, horizon)
|
| 6526 |
+
).view(
|
| 6527 |
+
matrix.shape[0],
|
| 6528 |
+
matrix.shape[1],
|
| 6529 |
+
horizon * (horizon - 1),
|
| 6530 |
+
)
|
| 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,
|
|
|
|
| 6537 |
labels: torch.LongTensor,
|
| 6538 |
attention_mask: Optional[torch.Tensor],
|
| 6539 |
transition_model: NITPTemporalTransition,
|
|
|
|
| 6545 |
target_temperature: float,
|
| 6546 |
pad_token_id: Optional[int] = None,
|
| 6547 |
eos_token_id: Optional[int] = None,
|
| 6548 |
+
) -> Tuple[torch.Tensor, ...]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6549 |
"""
|
| 6550 |
+
Causal NITP temporal rollout with relational joint identification.
|
| 6551 |
|
| 6552 |
+
Autonomous rollout:
|
| 6553 |
|
| 6554 |
h_hat_{t,0} = h_t
|
| 6555 |
+
z_hat_{t,k} = P_{stopgrad(theta_P)}(h_hat_{t,k-1})
|
| 6556 |
+
h_hat_{t,k} = T_psi(h_hat_{t,k-1}, stopgrad(z_hat_{t,k})).
|
| 6557 |
+
|
| 6558 |
+
The state objective remains the average Smooth-L1 alignment with real final
|
| 6559 |
+
states. The identification objective now uses
|
| 6560 |
+
|
| 6561 |
+
S = 0.25 A + 0.25 R + 0.5 Z,
|
| 6562 |
+
|
| 6563 |
+
where ``A`` is accumulated-displacement alignment, ``R`` is the relational
|
| 6564 |
+
angular-profile alignment across the full local future window, and ``Z``
|
| 6565 |
+
is frozen-weight NITP shallow-content alignment. This discourages an
|
| 6566 |
+
artificially parallel rollout only when the target trajectory itself has
|
| 6567 |
+
non-parallel angular structure. It does not add a direct diversity
|
| 6568 |
+
penalty, a new parameter, a new rollout, vocabulary logits, batch negatives
|
| 6569 |
+
or a tunable mixing coefficient.
|
| 6570 |
+
|
| 6571 |
+
Packed monitoring outputs are appended after the original fourteen scalar
|
| 6572 |
+
returns so old dashboards can remain intact:
|
| 6573 |
+
|
| 6574 |
+
``component_metrics`` [4,4]
|
| 6575 |
+
rows: joint, displacement A, relational R, NITP signature Z
|
| 6576 |
+
cols: diagonal, off-diagonal, margin, positive-margin fraction.
|
| 6577 |
+
|
| 6578 |
+
``step_metrics`` [11,W]
|
| 6579 |
+
rows: state loss, delta cosine, delta norm ratio, rollout-NITP cosine,
|
| 6580 |
+
trajectory specificity, cross-example predicted displacement cosine,
|
| 6581 |
+
cross-example target displacement cosine, their gap, predicted
|
| 6582 |
+
consecutive-delta cosine, target consecutive-delta cosine, their gap.
|
| 6583 |
+
|
| 6584 |
+
``offset_metrics`` [4,W-1]
|
| 6585 |
+
rows use the same component order and columns group incorrect pairs by
|
| 6586 |
+
temporal distance 1..W-1.
|
| 6587 |
+
|
| 6588 |
+
``scalar_metrics`` [6]
|
| 6589 |
+
path-length ratio, target absolute-state pair cosine, absolute pair gap,
|
| 6590 |
+
predicted centered-displacement pair cosine, target centered-
|
| 6591 |
+
displacement pair cosine, centered pair gap.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6592 |
"""
|
| 6593 |
horizon = int(horizon)
|
| 6594 |
seq_len = int(hidden_states.shape[1])
|
| 6595 |
max_horizon = max(min(horizon, seq_len - 1), 0)
|
| 6596 |
zero = hidden_states.new_zeros((), dtype=torch.float32)
|
| 6597 |
if max_horizon == 0:
|
| 6598 |
+
return (
|
| 6599 |
+
*((zero,) * 14),
|
| 6600 |
+
zero.new_zeros((4, 4)),
|
| 6601 |
+
zero.new_zeros((11, 0)),
|
| 6602 |
+
zero.new_zeros((4, 0)),
|
| 6603 |
+
zero.new_zeros((6,)),
|
| 6604 |
+
)
|
| 6605 |
|
| 6606 |
device = hidden_states.device
|
| 6607 |
labels_on_device = labels.to(device=device)
|
|
|
|
| 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(
|
| 6642 |
+
source_states,
|
| 6643 |
+
nitp_projector,
|
| 6644 |
+
)
|
| 6645 |
+
predicted_states = transition_model(
|
| 6646 |
+
source_states,
|
| 6647 |
+
next_shallow_signature.detach(),
|
| 6648 |
+
)
|
| 6649 |
|
|
|
|
| 6650 |
step_mask = _valid_temporal_span_mask(
|
| 6651 |
valid_tokens=valid_tokens,
|
| 6652 |
labels=labels_on_device,
|
| 6653 |
+
span_length=step + 2,
|
| 6654 |
eos_token_id=eos_token_id,
|
| 6655 |
)
|
| 6656 |
step_masks.append(step_mask)
|
| 6657 |
+
|
| 6658 |
step_state_loss = _masked_smooth_l1(
|
| 6659 |
predicted=predicted_states,
|
| 6660 |
target=shifted_targets,
|
| 6661 |
mask=step_mask,
|
| 6662 |
)
|
| 6663 |
state_loss_total = state_loss_total + step_state_loss
|
| 6664 |
+
state_loss_by_step.append(step_state_loss.detach().float())
|
| 6665 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6666 |
with torch.no_grad():
|
| 6667 |
+
real_source_states = hidden_states[
|
| 6668 |
+
:, step : step + predicted_states.shape[1], :
|
| 6669 |
+
]
|
| 6670 |
+
predicted_delta = predicted_states - source_states
|
| 6671 |
+
real_delta = shifted_targets - real_source_states
|
| 6672 |
+
|
| 6673 |
+
step_delta_cosine = F.cosine_similarity(
|
| 6674 |
+
predicted_delta.float(),
|
| 6675 |
+
real_delta.float(),
|
| 6676 |
+
dim=-1,
|
| 6677 |
+
eps=1.0e-8,
|
| 6678 |
+
)
|
| 6679 |
+
delta_cosine_by_step.append(
|
| 6680 |
+
_masked_mean(step_delta_cosine, step_mask)
|
| 6681 |
+
)
|
| 6682 |
+
|
| 6683 |
+
predicted_norm = predicted_delta.float().norm(dim=-1)
|
| 6684 |
+
real_norm = real_delta.float().norm(dim=-1)
|
| 6685 |
+
predicted_norm_mean = _masked_mean(predicted_norm, step_mask)
|
| 6686 |
+
real_norm_mean = _masked_mean(real_norm, step_mask)
|
| 6687 |
+
delta_norm_ratio_by_step.append(
|
| 6688 |
+
predicted_norm_mean / real_norm_mean.clamp_min(1.0e-8)
|
| 6689 |
+
)
|
| 6690 |
+
step_weights = step_mask.to(dtype=torch.float32)
|
| 6691 |
+
path_predicted_norm_sum = path_predicted_norm_sum + (
|
| 6692 |
+
predicted_norm * step_weights
|
| 6693 |
+
).sum()
|
| 6694 |
+
path_target_norm_sum = path_target_norm_sum + (
|
| 6695 |
+
real_norm * step_weights
|
| 6696 |
+
).sum()
|
| 6697 |
+
|
| 6698 |
shallow_target = shallow_target_states[:, step + 1 :, :]
|
| 6699 |
+
step_nitp_cosine = F.cosine_similarity(
|
| 6700 |
+
next_shallow_signature.detach().float(),
|
|
|
|
| 6701 |
shallow_target.float(),
|
| 6702 |
dim=-1,
|
| 6703 |
+
eps=1.0e-8,
|
| 6704 |
)
|
| 6705 |
+
rollout_nitp_cosine_by_step.append(
|
| 6706 |
+
_masked_mean(step_nitp_cosine, step_mask)
|
|
|
|
| 6707 |
)
|
| 6708 |
|
| 6709 |
+
if previous_predicted_delta is None:
|
| 6710 |
+
predicted_turn_by_step.append(zero)
|
| 6711 |
+
target_turn_by_step.append(zero)
|
| 6712 |
+
else:
|
| 6713 |
+
previous_predicted_aligned = previous_predicted_delta[
|
| 6714 |
+
:, : predicted_delta.shape[1], :
|
| 6715 |
+
]
|
| 6716 |
+
previous_real_aligned = previous_real_delta[
|
| 6717 |
+
:, : real_delta.shape[1], :
|
| 6718 |
+
]
|
| 6719 |
+
predicted_turn = F.cosine_similarity(
|
| 6720 |
+
previous_predicted_aligned.float(),
|
| 6721 |
+
predicted_delta.float(),
|
| 6722 |
+
dim=-1,
|
| 6723 |
+
eps=1.0e-8,
|
| 6724 |
+
)
|
| 6725 |
+
target_turn = F.cosine_similarity(
|
| 6726 |
+
previous_real_aligned.float(),
|
| 6727 |
+
real_delta.float(),
|
| 6728 |
+
dim=-1,
|
| 6729 |
+
eps=1.0e-8,
|
| 6730 |
+
)
|
| 6731 |
+
predicted_turn_by_step.append(
|
| 6732 |
+
_masked_mean(predicted_turn, step_mask)
|
| 6733 |
+
)
|
| 6734 |
+
target_turn_by_step.append(
|
| 6735 |
+
_masked_mean(target_turn, step_mask)
|
| 6736 |
+
)
|
| 6737 |
+
previous_predicted_delta = predicted_delta.detach()
|
| 6738 |
+
previous_real_delta = real_delta.detach()
|
| 6739 |
+
|
| 6740 |
predicted_by_step.append(predicted_states)
|
| 6741 |
+
condition_by_step.append(next_shallow_signature)
|
| 6742 |
current_states = predicted_states
|
| 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)
|
| 6758 |
+
)
|
| 6759 |
|
|
|
|
|
|
|
| 6760 |
common_length = seq_len - max_horizon
|
| 6761 |
if common_length <= 0:
|
| 6762 |
+
zero_steps = zero.new_zeros((max_horizon,))
|
| 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 |
+
zero_steps,
|
| 6770 |
+
zero_steps,
|
| 6771 |
+
zero_steps,
|
| 6772 |
+
zero_steps,
|
| 6773 |
+
predicted_turn_tensor,
|
| 6774 |
+
target_turn_tensor,
|
| 6775 |
+
predicted_turn_tensor - target_turn_tensor,
|
| 6776 |
+
)
|
| 6777 |
+
)
|
| 6778 |
weighted_total = float(dynamics_weight) * state_loss
|
| 6779 |
return (
|
| 6780 |
weighted_total,
|
|
|
|
| 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((4, max(max_horizon - 1, 0))),
|
| 6797 |
+
torch.stack((path_length_ratio, zero, zero, zero, zero, zero)),
|
| 6798 |
)
|
| 6799 |
|
| 6800 |
+
(
|
| 6801 |
+
similarity,
|
| 6802 |
+
displacement_similarity,
|
| 6803 |
+
relational_similarity,
|
| 6804 |
+
nitp_signature_similarity,
|
| 6805 |
+
) = _build_relational_temporal_similarity(
|
| 6806 |
predicted_by_step=predicted_by_step,
|
| 6807 |
+
condition_by_step=condition_by_step,
|
| 6808 |
target_hidden_states=hidden_states,
|
| 6809 |
+
shallow_target_states=shallow_target_states,
|
| 6810 |
+
initial_hidden_states=hidden_states,
|
| 6811 |
common_length=common_length,
|
| 6812 |
+
)
|
| 6813 |
|
| 6814 |
window_mask = _valid_temporal_span_mask(
|
| 6815 |
valid_tokens=valid_tokens,
|
|
|
|
| 6837 |
|
| 6838 |
row_prediction = similarity.argmax(dim=-1)
|
| 6839 |
expected_offsets = offsets.view(1, 1, -1)
|
| 6840 |
+
temporal_top1_accuracy = _masked_mean(
|
| 6841 |
+
(row_prediction == expected_offsets).float().mean(dim=-1),
|
| 6842 |
+
window_mask,
|
| 6843 |
+
)
|
| 6844 |
mean_absolute_offset = _masked_mean(
|
| 6845 |
(row_prediction - expected_offsets).abs().float().mean(dim=-1),
|
| 6846 |
window_mask,
|
| 6847 |
)
|
| 6848 |
|
| 6849 |
+
# All decomposed diagnostics use detached matrices so they cannot retain
|
| 6850 |
+
# additional backward graphs. Their values still describe the exact
|
| 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(),
|
| 6857 |
+
)
|
| 6858 |
+
component_metrics = torch.stack(
|
| 6859 |
+
[
|
| 6860 |
+
_temporal_matrix_statistics(component, window_mask)
|
| 6861 |
+
for component in component_matrices
|
| 6862 |
+
]
|
| 6863 |
+
)
|
| 6864 |
+
offset_metrics = torch.stack(
|
| 6865 |
+
[
|
| 6866 |
+
_temporal_neighbor_cosines(component, window_mask)
|
| 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()
|
| 6876 |
+
predicted_state_steps = [
|
| 6877 |
+
state[:, :common_length, :].detach()
|
| 6878 |
+
for state in predicted_by_step
|
| 6879 |
+
]
|
| 6880 |
+
target_state_steps = [
|
| 6881 |
+
hidden_states[
|
| 6882 |
+
:, offset : offset + common_length, :
|
| 6883 |
+
].detach()
|
| 6884 |
+
for offset in range(1, max_horizon + 1)
|
| 6885 |
+
]
|
| 6886 |
+
rollout_pair_cosine = _off_diagonal_pair_mean(
|
| 6887 |
+
_pairwise_cosine_from_steps(predicted_state_steps),
|
| 6888 |
+
window_mask,
|
| 6889 |
)
|
| 6890 |
+
target_pair_cosine = _off_diagonal_pair_mean(
|
| 6891 |
+
_pairwise_cosine_from_steps(target_state_steps),
|
| 6892 |
window_mask,
|
| 6893 |
)
|
| 6894 |
+
rollout_displacement_pair_cosine = _off_diagonal_pair_mean(
|
| 6895 |
+
_pairwise_cosine_from_steps(
|
| 6896 |
+
predicted_state_steps,
|
| 6897 |
+
origin=initial_common,
|
| 6898 |
+
),
|
|
|
|
|
|
|
| 6899 |
window_mask,
|
| 6900 |
)
|
| 6901 |
+
target_displacement_pair_cosine = _off_diagonal_pair_mean(
|
| 6902 |
+
_pairwise_cosine_from_steps(
|
| 6903 |
+
target_state_steps,
|
| 6904 |
+
origin=initial_common,
|
| 6905 |
+
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6906 |
window_mask,
|
| 6907 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6908 |
|
| 6909 |
+
cross_predicted_by_step = []
|
| 6910 |
+
cross_target_by_step = []
|
| 6911 |
+
if int(hidden_states.shape[0]) > 1:
|
| 6912 |
for step in range(max_horizon):
|
| 6913 |
+
step_mask_common = step_masks[step][:, :common_length]
|
| 6914 |
+
paired_mask = step_mask_common & torch.roll(
|
| 6915 |
+
step_mask_common,
|
| 6916 |
+
shifts=1,
|
| 6917 |
+
dims=0,
|
| 6918 |
)
|
| 6919 |
+
predicted_displacement = (
|
| 6920 |
+
predicted_by_step[step][:, :common_length, :].detach()
|
| 6921 |
+
- initial_common
|
|
|
|
| 6922 |
)
|
| 6923 |
+
target_displacement = (
|
| 6924 |
+
hidden_states[
|
| 6925 |
+
:, step + 1 : step + 1 + common_length, :
|
| 6926 |
+
].detach()
|
| 6927 |
+
- initial_common
|
| 6928 |
+
)
|
| 6929 |
+
cross_predicted = F.cosine_similarity(
|
| 6930 |
+
predicted_displacement.float(),
|
| 6931 |
+
torch.roll(
|
| 6932 |
+
predicted_displacement.float(),
|
| 6933 |
+
shifts=1,
|
| 6934 |
+
dims=0,
|
| 6935 |
+
),
|
| 6936 |
+
dim=-1,
|
| 6937 |
+
eps=1.0e-8,
|
| 6938 |
+
)
|
| 6939 |
+
cross_target = F.cosine_similarity(
|
| 6940 |
+
target_displacement.float(),
|
| 6941 |
+
torch.roll(
|
| 6942 |
+
target_displacement.float(),
|
| 6943 |
+
shifts=1,
|
| 6944 |
+
dims=0,
|
| 6945 |
+
),
|
| 6946 |
+
dim=-1,
|
| 6947 |
+
eps=1.0e-8,
|
| 6948 |
)
|
| 6949 |
+
cross_predicted_by_step.append(
|
| 6950 |
+
_masked_mean(cross_predicted, paired_mask)
|
| 6951 |
+
)
|
| 6952 |
+
cross_target_by_step.append(
|
| 6953 |
+
_masked_mean(cross_target, paired_mask)
|
| 6954 |
+
)
|
| 6955 |
+
else:
|
| 6956 |
+
cross_predicted_by_step = [zero] * max_horizon
|
| 6957 |
+
cross_target_by_step = [zero] * max_horizon
|
| 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 |
+
trajectory_specificity_by_step,
|
| 7006 |
+
cross_predicted_tensor,
|
| 7007 |
+
cross_target_tensor,
|
| 7008 |
+
cross_predicted_tensor - cross_target_tensor,
|
| 7009 |
+
predicted_turn_tensor,
|
| 7010 |
+
target_turn_tensor,
|
| 7011 |
+
predicted_turn_tensor - target_turn_tensor,
|
| 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) * state_loss
|
|
|
|
| 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 |
|
|
|
|
| 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
|
| 7229 |
+
self._last_nitp_temporal_scalar_metrics = None
|
| 7230 |
self._last_nextlat_loss = None
|
| 7231 |
self._last_nextlat_mse_loss = None
|
| 7232 |
self._last_nextlat_kl_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
|
|
|
|
| 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
|
| 7412 |
+
self._last_nitp_temporal_scalar_metrics = None
|
| 7413 |
self._last_nextlat_loss = None
|
| 7414 |
self._last_nextlat_mse_loss = None
|
| 7415 |
self._last_nextlat_kl_loss = None
|
|
|
|
| 7491 |
)
|
| 7492 |
nitp_target_hidden_states = hidden_states_tuple[target_layer]
|
| 7493 |
|
|
|
|
| 7494 |
temporal_apply_loss = bool(
|
| 7495 |
getattr(self.config, "nitp_temporal_apply_loss", True)
|
| 7496 |
)
|
|
|
|
| 7504 |
temporal_results = compute_nitp_temporal_objective(
|
| 7505 |
hidden_states=hidden_states,
|
| 7506 |
shallow_target_states=nitp_target_hidden_states,
|
|
|
|
| 7507 |
labels=labels,
|
| 7508 |
attention_mask=attention_mask,
|
| 7509 |
transition_model=self.nitp_temporal_transition,
|
|
|
|
| 7530 |
temporal_results = compute_nitp_temporal_objective(
|
| 7531 |
hidden_states=hidden_states,
|
| 7532 |
shallow_target_states=nitp_target_hidden_states,
|
|
|
|
| 7533 |
labels=labels,
|
| 7534 |
attention_mask=attention_mask,
|
| 7535 |
transition_model=self.nitp_temporal_transition,
|
|
|
|
| 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,
|
| 7572 |
+
nitp_temporal_scalar_metrics,
|
| 7573 |
) = temporal_results
|
| 7574 |
|
| 7575 |
if temporal_apply_loss:
|
|
|
|
| 7588 |
"NeoLLMForCausalLM.forward enables them automatically "
|
| 7589 |
"while labels are present."
|
| 7590 |
)
|
| 7591 |
+
# NextLat keeps its original teacher-forced token-embedding
|
| 7592 |
+
# path. This assignment is local to NextLat; causal Temporal
|
| 7593 |
+
# NITP no longer reads ``hidden_states_tuple[0]``.
|
| 7594 |
token_embeds = hidden_states_tuple[0]
|
|
|
|
|
|
|
|
|
|
| 7595 |
nextlat_loss, nextlat_mse_loss, nextlat_kl_loss = compute_nextlat_loss(
|
| 7596 |
hidden_states=hidden_states,
|
| 7597 |
token_embeds=token_embeds,
|
|
|
|
| 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
|
| 7694 |
+
else None
|
| 7695 |
+
)
|
| 7696 |
+
self._last_nitp_temporal_step_metrics = (
|
| 7697 |
+
nitp_temporal_step_metrics.detach()
|
| 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
|
| 7704 |
+
else None
|
| 7705 |
+
)
|
| 7706 |
+
self._last_nitp_temporal_scalar_metrics = (
|
| 7707 |
+
nitp_temporal_scalar_metrics.detach()
|
| 7708 |
+
if nitp_temporal_scalar_metrics is not None
|
| 7709 |
else None
|
| 7710 |
)
|
| 7711 |
self._last_nitp_temporal_to_nitp_ratio = (
|