perf(model): batched causal-mask native_train_step (~10.75x), gradient-checked#669
Merged
Merged
Conversation
…t-checked The transformer trainer (native_train_step, model extension — the iLambdaAi 24-hour training kernel) re-ran a FULL forward+backward over the growing prefix for every target position in each window: ~31 nested passes over prefixes of length 1..31 per 32-token window. Since the attention is causal (model_infer.c masks j>i), each position's activations are independent of how long the prefix is, so all 31 passes recompute identical work. Replaced with one causal-masked forward over the whole window + a cheap per-position loss/seed loop + one backward. Same backward/forward kernels, called once instead of seq times. Gradient-identical: every position already trains against the same start-of-step weights, so the masked batch computes the identical summed gradient. Measured (d=32/L=4, EIGS_TRAIN_PROFILE): 179 -> 16.65 ms/window = 10.75x, turning a ~24h run into ~2.2h. Profiler confirmed 97% of the old cost was the redundant forward+backward compute (3% alloc), so the win is realized, not eaten by overhead. Verified against the per-position path as its own gradient-check oracle: identical loss sequences to float precision from a common checkpoint (a real gradient error compounds exponentially and would diverge within a few steps; instead the sequences stay float-identical and non-diverging). Locked in by test_native_train_gradcheck.sh (suite [47c], model build): a tiny model, six steps each path, max loss diff must stay < 1e-3. Dispatch: batched is the default; EIGS_TRAIN_PERPOS=1 restores the oracle. Gated profiler (EIGS_TRAIN_PROFILE) kept as the A/B measurement instrument, zero-cost when off. Full http+model suite 3164/3164. Default (non-model) build unaffected — model_train.c is not compiled there.
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.
The transformer trainer
native_train_step— the model-extension kernel iLambdaAi's ~24-hour training runs on — re-ran a full forward+backward over the growing prefix for every target position in each window: ~31 nested passes over prefixes of length 1…31 per 32-token window.The attention is causal (
model_infer.cmasksj > i), so each position's activations are independent of prefix length — all 31 passes recompute identical work. Standard transformer training does all positions in one causal-masked pass.Fix
One causal-masked forward over the whole window + a cheap per-position loss/seed loop + one backward. Same forward/backward kernels, called once instead of
seqtimes. Gradient-identical, because every position already trains against the same start-of-step weights, so the masked batch computes the identical summed gradient.Measured
EIGS_TRAIN_PROFILE, d=32/L=4 model:The profiler showed 97% of the old cost was the redundant forward+backward compute (3% alloc/update), so the win is realized, not eaten by overhead.
Verified against its own oracle
The per-position path is the gradient-check oracle. From a common checkpoint, both paths produce float-identical, non-diverging loss sequences — and that's the decisive test, because a real gradient error compounds exponentially and would visibly diverge within a few steps. It doesn't.
EIGS_TRAIN_PERPOS=1restores the oracle path.test_native_train_gradcheck.sh(suite [47c], model build): tiny model, six steps each path, asserts max loss diff < 1e-3 — pins the two paths together so the equivalence can't silently regress.Gates
model_train.cisn't compiled there, so the standard suite and ASan legs are untouchedEIGS_TRAIN_PROFILE) kept as the A/B instrument, zero-cost offNote: this makes the search for a working iLambdaAi model ~10× cheaper per experiment — the point is A/B iteration speed, not a faster working model (there isn't one yet).
🤖 Generated with Claude Code