Repository navigation
fix(ricursive): mask from actual cache positions, keep labeled loss - #3551
Merged
Qubitium merged 1 commit intoNov 6, 2026
Merged
Conversation
StaticCache returns its full preallocated capacity from update(), so using k.shape[2] as the occupied length gave a 6-token prompt in a 16-slot cache query positions 10-15; changing a later token then changed earlier outputs. Trim the unwritten tail and build the verify mask from the layer's actual get_seq_length() and cache_position, aligning an oversized incoming mask. logits_to_keep=1 with labels trimmed both logits and labels to one position, leaving the causal shift empty and the loss NaN. Keep the full sequence when labels are present so the loss is defined, and trim only the returned logits.
Collaborator
Author
|
Full-model verification of this branch: Ripple-65B-Preview GPTQ W4A16 (Marlin), single RTX 4090, bf16, 40.2 GiB peak, using the native
The block-path error (0.25) is ~1.4x the no-mask control (0.156) and ~130x smaller than the pre-fix 32.31, i.e. the verify mask is correct and the residual is bf16 kernel shape noise. The DFlash token mismatch is a genuine tie at bf16 precision, not a masking error. Re-ran the same suite with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3545 and #3549 (both merged). Two defects found in review of the mirrored HF patch.
1. Preallocated caches broke causal attention
StaticCachelayers return their full preallocated capacity fromupdate(), sok.shape[2]is capacity, not occupied context. A 6-token prefill into a 16-slot cache was therefore treated as a 10-token prefix: the end-anchored verify mask gave query positions 10-15, letting each query attend slots of a different absolute position. Changing token 6 changed token 1's output (measured max diff 0.4830), which is impossible under causal attention.Fix: read the layer's real length via
Cache.get_seq_length(layer_idx), trim the unwritten tail ofk/v, build the mask fromcache_positionand the absolute key positions (trailing window for evicting caches), and align an incoming mask that is longer than the keys actually present.2.
labels+logits_to_keep=1returned NaN lossThe patch trimmed hidden states and labels to one position, then the causal shift produced empty tensors and
cross_entropyreturned NaN.Fix: when
labelsare present, keep the full sequence so the shifted loss is defined, and trim only the returned logits. Unlabeled calls still slice the LM-head input, so the[batch, seq, vocab]projection is never materialised during generation.Validation
tests/test_ricursive_support.pygainstest_static_cache_uses_actual_positions_not_capacityandtest_labels_with_logits_to_keep_keeps_finite_loss; 7 focused tests pass on CPU.labels+logits_to_keep=1loss 5.562519 (full 5.562519, finite),logits_to_keep=1shape(1,1,256)and max diff 8.9e-08, cached == uncached generation, bf16 causality 0.0, peak test allocation 9.4 MiB.