Text Generation
Transformers
Safetensors
PyTorch
English
neollm
causal-lm
research
bf16
attention
normalization
conversational
custom_code
Instructions to use KitsuVp/NeoLLM with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use KitsuVp/NeoLLM with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="KitsuVp/NeoLLM", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("KitsuVp/NeoLLM", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use KitsuVp/NeoLLM with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "KitsuVp/NeoLLM" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "KitsuVp/NeoLLM", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/KitsuVp/NeoLLM
- SGLang
How to use KitsuVp/NeoLLM with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "KitsuVp/NeoLLM" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "KitsuVp/NeoLLM", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "KitsuVp/NeoLLM" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "KitsuVp/NeoLLM", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use KitsuVp/NeoLLM with Docker Model Runner:
docker model run hf.co/KitsuVp/NeoLLM
Model save
Browse files- README.md +72 -526
- config.json +15 -2
- configuration_neollm.py +55 -11
- generation_config.json +1 -1
- model.safetensors +2 -2
- modeling_neollm.py +733 -119
- optimizer_precision.json +5 -5
- training_args.bin +1 -1
README.md
CHANGED
|
@@ -1,532 +1,78 @@
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
license: apache-2.0
|
| 4 |
tags:
|
| 5 |
-
-
|
| 6 |
-
-
|
| 7 |
-
-
|
| 8 |
-
|
| 9 |
-
- normalization
|
| 10 |
-
- neollm
|
| 11 |
-
datasets:
|
| 12 |
-
- HuggingFaceFW/fineweb-edu
|
| 13 |
---
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
NeoLLM is a **85.09 M parameter** decoder-only language model trained from scratch on
|
| 18 |
-
[FineWeb-Edu](https://huggingface.co/datasets/HuggingFaceFW/fineweb-edu) with
|
| 19 |
-
**BF16** compute, completing training in approximately
|
| 20 |
-
**~0h 47m** on **NVIDIA RTX PRO 6000 Blackwell Server Edition**.
|
| 21 |
-
It integrates a collection of recently published attention and normalization techniques
|
| 22 |
-
into a single architecture, with the goal of studying how they interact during
|
| 23 |
-
pretraining. The model is actively being developed and the current checkpoint represents
|
| 24 |
-
an intermediate training state.
|
| 25 |
-
|
| 26 |
-
> **Author / contact:** [@Kyokopom](https://x.com/Kyokopom) on X
|
| 27 |
-
> **Repository:** [KitsuVp/NeoLLM](https://huggingface.co/KitsuVp/NeoLLM)
|
| 28 |
-
|
| 29 |
-
---
|
| 30 |
-
|
| 31 |
-
## Architecture
|
| 32 |
-
|
| 33 |
-
NeoLLM is a decoder-only transformer with the following configuration:
|
| 34 |
-
|
| 35 |
-
| Parameter | Value |
|
| 36 |
-
|---|---|
|
| 37 |
-
| Hidden size | 512 |
|
| 38 |
-
| Layers | 12 |
|
| 39 |
-
| Attention heads | 8 |
|
| 40 |
-
| KV heads (GQA) | 4 |
|
| 41 |
-
| Head dim | 64 |
|
| 42 |
-
| Intermediate size | 1536 |
|
| 43 |
-
| Vocabulary | LiquidAI/LFM2.5-1.2B-Thinking tokenizer (64,402 tokens) |
|
| 44 |
-
| Context length | 512 tokens |
|
| 45 |
-
| Leviathan | enabled=True; d_seed=128, modes=8, knots=16 |
|
| 46 |
-
| JTok / JTok-M | enabled=False / False; Torch continuous surfaces, experts=5, top_k=2 |
|
| 47 |
-
| DAGFormer | enabled=False; {'predictor_dim': 256, 'predictor_layers': 2, 'predictor_heads': 4, 'local_dim': 128, 'input_source': 'tokens'} |
|
| 48 |
-
| Virtual Head Attention | enabled=False; query/KV heads follow the configured geometry |
|
| 49 |
-
| Copy-Paste LM | enabled=True; causal vocabulary/pointer mixture |
|
| 50 |
-
|
| 51 |
-
### Parameter breakdown
|
| 52 |
-
|
| 53 |
-
| Parameter bucket | Count |
|
| 54 |
-
|---|---|
|
| 55 |
-
| **Total parameters** | 85.09M (85,093,304) |
|
| 56 |
-
| **Embedding parameters** (tied) | 32.97M (32,973,824) |
|
| 57 |
-
| **Non-embedding parameters** | 52.12M (52,119,480) |
|
| 58 |
-
| **Effective trainable parameters** | 85.09M (85,093,304) |
|
| 59 |
-
|
| 60 |
-
> Weight tying is **enabled**: the input embedding matrix and the language-model head
|
| 61 |
-
> share the same parameters, so the effective trainable budget is
|
| 62 |
-
> `total − embed = 52.12M`.
|
| 63 |
-
|
| 64 |
-
### Integrated techniques
|
| 65 |
-
|
| 66 |
-
NeoLLM combines architecture modules, optional auxiliary objectives, and
|
| 67 |
-
training-time optimizer/stability components from the following papers.
|
| 68 |
-
|
| 69 |
-
**Embedding and token representation**
|
| 70 |
-
|
| 71 |
-
- **Learnable Multipliers** ([arXiv:2601.04890](https://arxiv.org/abs/2601.04890)) — Adds
|
| 72 |
-
per-row and per-column learnable scalar parameters to selected matrix layers and, when
|
| 73 |
-
enabled, embeddings.
|
| 74 |
-
- **Leviathan** ([arXiv:2601.22040](https://arxiv.org/abs/2601.22040)) — Optional
|
| 75 |
-
continuous token embedding generator that can replace the discrete input lookup table.
|
| 76 |
-
- **Leviathan-JTok / JTok-M** ([arXiv:2602.00800](https://arxiv.org/abs/2602.00800)) —
|
| 77 |
-
Optional continuous adaptation of JTok over the shared Leviathan coordinate. JTok
|
| 78 |
-
applies one normalized surface as a multiplicative MLP gate; JTok-M routes a
|
| 79 |
-
Sigmoid+TopK mixture of continuous surfaces and adds the paper's depth-scaled
|
| 80 |
-
residual. Runtime ``jtok_kernel_backend`` selects the PyTorch reference or the
|
| 81 |
-
CCE Triton adapter; the JTok surfaces remain outside MXFP8 conversion.
|
| 82 |
-
- **KHRONOS** ([arXiv:2505.13315](https://arxiv.org/abs/2505.13315)) — Kernel/basis
|
| 83 |
-
reference used by the Leviathan continuous token generator implementation.
|
| 84 |
-
- **Spelling Bee Embeddings** ([arXiv:2601.18030](https://arxiv.org/abs/2601.18030)) —
|
| 85 |
-
Augments token embeddings with character-level spelling information.
|
| 86 |
-
- **Token Embedding Manifold analysis** ([arXiv:2504.01002](https://arxiv.org/abs/2504.01002)) —
|
| 87 |
-
Reference motivation for treating token embeddings as structured objects rather than
|
| 88 |
-
unconstrained lookup rows.
|
| 89 |
-
|
| 90 |
-
**Attention, positions, and output projection**
|
| 91 |
-
|
| 92 |
-
- **Virtual Head Attention** ([arXiv:2610.17959](https://arxiv.org/abs/2610.17959)) — Optional
|
| 93 |
-
group-specific query premix and low-rank head postmix. NeoLLM shares its gated query
|
| 94 |
-
projection across corresponding head slots in KV groups and applies postmix after the gate; inference weights are
|
| 95 |
-
not automatically folded into standard GQA projections.
|
| 96 |
-
- **Copy-Paste LM** ([arXiv:2610.19247](https://arxiv.org/abs/2610.19247)) — Optional
|
| 97 |
-
causal pointer and sink mixed with the vocabulary distribution. CUDA training
|
| 98 |
-
uses CCE's sparse Copy-Paste kernels; inference returns dense mixed logits.
|
| 99 |
-
- **FAN** ([arXiv:2502.21309](https://arxiv.org/abs/2502.21309)) — Fourier Analysis Networks.
|
| 100 |
-
A portion of the projection channels are dedicated to periodic cosine/sine features.
|
| 101 |
-
- **MEA** ([arXiv:2601.19611](https://arxiv.org/abs/2601.19611)) — Explicit Multi-head
|
| 102 |
-
Attention. Adds small learnable interaction matrices between attention heads for K and V.
|
| 103 |
-
- **LUCID** ([arXiv:2602.10410](https://arxiv.org/abs/2602.10410)) — Applies a learned
|
| 104 |
-
lower-triangular preconditioner to V before attention, decorrelating value representations
|
| 105 |
-
across positions.
|
| 106 |
-
- **Affine-Scaled Attention** ([arXiv:2602.23057](https://arxiv.org/abs/2602.23057)) — Adds
|
| 107 |
-
two learnable per-head scalars (α and β) to the softmax weights:
|
| 108 |
-
`[α·softmax(QKᵀ) + β]·V`.
|
| 109 |
-
- **XSA** ([arXiv:2603.09078](https://arxiv.org/abs/2603.09078)) — Exclusive Self Attention.
|
| 110 |
-
After computing attention, removes the component of the output aligned with the token's
|
| 111 |
-
own value vector.
|
| 112 |
-
- **Directional Routing** ([arXiv:2603.14923](https://arxiv.org/abs/2603.14923)) — Each head
|
| 113 |
-
learns K=4 directions in the output space; a learned router suppresses the attention output
|
| 114 |
-
along each direction per input.
|
| 115 |
-
- **Gated Attention** ([arXiv:2505.06708](https://arxiv.org/abs/2505.06708)) — A sigmoid gate
|
| 116 |
-
is applied to the attention output before the output projection, introducing non-linearity
|
| 117 |
-
and preventing attention sinks.
|
| 118 |
-
- **Momentum Attention** ([arXiv:2411.03884](https://arxiv.org/abs/2411.03884)) — Modifies Q
|
| 119 |
-
and K by subtracting a fraction of the previous position's Q and K values (causal
|
| 120 |
-
first-difference).
|
| 121 |
-
- **Interleaved Head Attention / IHA** ([arXiv:2602.21371](https://arxiv.org/abs/2602.21371)) —
|
| 122 |
-
Builds pseudo-heads from learned cross-head mixtures to create multiple attention patterns
|
| 123 |
-
per original head.
|
| 124 |
-
- **REPO** ([arXiv:2512.14391](https://arxiv.org/abs/2512.14391)) — Context re-positioning
|
| 125 |
-
module that learns contextual position coordinates above a configurable start layer.
|
| 126 |
-
- **GRAPE** ([arXiv:2512.07805](https://arxiv.org/abs/2512.07805)) — Group representational
|
| 127 |
-
position encoding used by the REPO-GRAPE positional path.
|
| 128 |
-
- **GOAT priors** ([arXiv:2601.15380](https://arxiv.org/abs/2601.15380)) — Optional
|
| 129 |
-
factorized attention log-prior channels inspired by trainable attention priors.
|
| 130 |
-
- **Hadamard output projection** ([arXiv:2603.08343](https://arxiv.org/abs/2603.08343)) —
|
| 131 |
-
Replaces dense attention output projection with a structured Hadamard transform plus
|
| 132 |
-
lightweight scaling.
|
| 133 |
-
|
| 134 |
-
**Normalization, residual flow, and MLP**
|
| 135 |
-
|
| 136 |
-
- **SeeDNorm** ([arXiv:2510.22777](https://arxiv.org/abs/2510.22777)) — Applied to Q and K
|
| 137 |
-
projections. Dynamically rescales normalization from the input's own statistics.
|
| 138 |
-
- **LayerNorm Scaling / LNS** ([arXiv:2502.05795](https://arxiv.org/abs/2502.05795)) — Each
|
| 139 |
-
layer's output is scaled by 1/√ℓ where ℓ is the layer index.
|
| 140 |
-
- **GPAS** ([arXiv:2506.22049](https://arxiv.org/abs/2506.22049)) — Gradient-Preserving
|
| 141 |
-
Activation Scaling for residual junctions.
|
| 142 |
-
- **PolyNorm** ([arXiv:2602.04902](https://arxiv.org/abs/2602.04902)) — Replaces the standard
|
| 143 |
-
MLP activation with normalized linear, quadratic, and cubic branches.
|
| 144 |
-
- **SimpleGPT** ([arXiv:2602.01212](https://arxiv.org/abs/2602.01212)) — Second-order
|
| 145 |
-
geometry-inspired normalization strategy applied inside MLP projections.
|
| 146 |
-
- **StackMemory / STACKTRANS** ([NeurIPS 2025](https://openreview.net/forum?id=2bbDg587uh)) —
|
| 147 |
-
Optional differentiable hidden-state stack between decoder layers.
|
| 148 |
-
- **Attention Residuals / AttnRes** ([arXiv:2603.15031](https://arxiv.org/abs/2603.15031)) —
|
| 149 |
-
Optional learned depth-wise aggregation over previous layer outputs or block summaries.
|
| 150 |
-
- **LAUREL** ([arXiv:2411.07501](https://arxiv.org/abs/2411.07501)) — Optional learned
|
| 151 |
-
augmented residual layer with residual-weight and low-rank variants.
|
| 152 |
-
|
| 153 |
-
**Training objectives and training-time regularizers**
|
| 154 |
-
|
| 155 |
-
- **Cut Cross Entropy** ([Apple repository](https://github.com/apple/ml-cross-entropy)) —
|
| 156 |
-
Memory-efficient next-token loss that avoids materializing the full token-by-vocabulary
|
| 157 |
-
logits tensor. NeoLLM remains compatible with the upstream package when the extensions
|
| 158 |
-
below are disabled.
|
| 159 |
-
- **MiLe Loss** ([arXiv:2310.19531](https://arxiv.org/abs/2310.19531)) — Optional detached,
|
| 160 |
-
mean-normalized predictive-entropy weighting of token losses, implemented inside the
|
| 161 |
-
extended CCE path.
|
| 162 |
-
- **Output Embedding Centering / mu-loss**
|
| 163 |
-
([arXiv:2601.02031](https://arxiv.org/abs/2601.02031)) — Optional
|
| 164 |
-
`lambda * ||mean(output_embeddings)||^2` regularizer for output-logit stability.
|
| 165 |
-
- **MEAP** ([arXiv:2502.07490](https://arxiv.org/abs/2502.07490)) — Optional training-only
|
| 166 |
-
input corruption that masks a fixed fraction of eligible tokens while preserving clean
|
| 167 |
-
next-token labels, causal attention, and the inference path.
|
| 168 |
-
- **TWEO** ([arXiv:2511.23225](https://arxiv.org/abs/2511.23225)) — Optional
|
| 169 |
-
Transformers Without Extreme Outliers activation regularizer for FP8/low-bit-friendly
|
| 170 |
-
training.
|
| 171 |
-
- **NITP** ([arXiv:2605.24956](https://arxiv.org/abs/2605.24956)) — Optional Next Implicit
|
| 172 |
-
Token Prediction auxiliary objective using shallow-layer implicit token targets and a
|
| 173 |
-
cosine loss.
|
| 174 |
-
- **NextLat** ([arXiv:2511.05963](https://arxiv.org/abs/2511.05963)) — Optional next-latent
|
| 175 |
-
prediction objective using latent dynamics, Smooth L1 supervision, and frozen-head KL.
|
| 176 |
-
|
| 177 |
-
### Optional extended-CCE configuration
|
| 178 |
-
|
| 179 |
-
| Feature | Enabled | Value |
|
| 180 |
-
|---|---:|---:|
|
| 181 |
-
| MiLe Loss | True | gamma=1.0 |
|
| 182 |
-
| mu-loss | True | lambda=0.0001 |
|
| 183 |
-
| MEAP | True | ratio=0.15 |
|
| 184 |
-
|
| 185 |
-
Copy-Paste uses CCE sparse mixture statistics for CUDA training and computes mu-loss in Torch. MEAP and patch training also use the extended cut-cross-entropy package.
|
| 186 |
-
[`Kitsunp/ml-cross-entropy`](https://github.com/Kitsunp/ml-cross-entropy) supplies the extended kernels.
|
| 187 |
-
Copy-Paste exposes three compact
|
| 188 |
-
scalars: unweighted NTP cross entropy, the MiLe reweighting delta, and the mu-loss penalty.
|
| 189 |
-
Their sum reconstructs `ntp_loss` exactly. MEAP reports its eligible and selected counts from
|
| 190 |
-
the masking kernel; the trainer logs the selected count and exact fraction. Copy-Paste diagnostics use sparse source-token candidates and CCE vocabulary reductions.
|
| 191 |
-
|
| 192 |
-
**Optimizer and training stability**
|
| 193 |
-
|
| 194 |
-
- **Adam-family optimizer mode** — Active variant: **AdEMAMix**.
|
| 195 |
-
**AdEMAMix** ([arXiv:2409.03137](https://arxiv.org/abs/2409.03137)) contributes the optional
|
| 196 |
-
beta3 slow-memory branch when `ADEMAMIX=True`. **DeltaMomentum**
|
| 197 |
-
([arXiv:2608.19491](https://arxiv.org/abs/2608.19491)) optionally replaces only the fast beta1
|
| 198 |
-
first-moment update on hidden Linear weights when `DELTA=True`; beta2 remains Adam's
|
| 199 |
-
ordinary squared-gradient EMA in every mode.
|
| 200 |
-
- **BF16 stochastic rounding** ([arXiv:2502.20566](https://arxiv.org/abs/2502.20566)) —
|
| 201 |
-
Optional master-free BF16 model update with stochastic rather than nearest rounding; the same
|
| 202 |
-
write-back path is shared by AdamW, DeltaAdamW, AdEMAMix, and DeltaAdEMAMix.
|
| 203 |
-
- **Cautious Weight Decay** ([arXiv:2510.12402](https://arxiv.org/abs/2510.12402)) —
|
| 204 |
-
Sign-selective weight decay variant used by the custom optimizer logic.
|
| 205 |
-
- **Correction of Decoupled Weight Decay** ([arXiv:2512.08217](https://arxiv.org/abs/2512.08217)) —
|
| 206 |
-
Adapts decoupled weight decay during learning-rate decay.
|
| 207 |
-
- **AdamHD** ([arXiv:2511.14721](https://arxiv.org/abs/2511.14721)) —
|
| 208 |
-
Decoupled Huber decay regularization reference used by the optimizer.
|
| 209 |
-
- **Gradient conditioning** — CAST active; history-adaptive spectral/norm policies by optimizer group; 15625 committed updates.
|
| 210 |
-
References: [CAST](https://arxiv.org/abs/2610.19761),
|
| 211 |
-
[GradientStabilizer](https://arxiv.org/abs/2502.17055).
|
| 212 |
-
---
|
| 213 |
-
|
| 214 |
-
## Training
|
| 215 |
-
|
| 216 |
-
| Setting | Value |
|
| 217 |
-
|---|---|
|
| 218 |
-
| Dataset | FineWeb-Edu (sample-10BT) |
|
| 219 |
-
| Tokens seen | ~0.51B (15,625 steps × batch 64 × length 512) |
|
| 220 |
-
| Precision | BF16 model state (bfloat16: 85,091,128 elements, float32: 2,176 elements) + AdEMAMix FP32 master active; stochastic rounding disabled |
|
| 221 |
-
| Optimizer | AdEMAMix |
|
| 222 |
-
| Gradient transform | CAST active; history-adaptive spectral/norm policies by optimizer group; 15625 committed updates |
|
| 223 |
-
| Learning rate | 1e-03 with 4,000-step linear warmup |
|
| 224 |
-
| Weight decay | coefficients [0.005, 0.01, 0.1]; WD 5/5 groups; CWD 2; Huber 0; Correction 0 |
|
| 225 |
-
| Training time | ~0h 47m |
|
| 226 |
-
| Hardware | NVIDIA RTX PRO 6000 Blackwell Server Edition |
|
| 227 |
-
|
| 228 |
|
| 229 |
-
#
|
| 230 |
-
|
| 231 |
-
Total includes MiLe when enabled, plus all active auxiliary objectives and regularizers. Without MiLe means model total minus its MiLe delta on the same forward; this is not a separate training run without MiLe.
|
| 232 |
-
|
| 233 |
-
| Step | Train total | Val total | Train without MiLe | Val without MiLe |
|
| 234 |
-
|---|---|---|---|---|
|
| 235 |
-
| 1 | 12.2845 | — | 12.2845 | — |
|
| 236 |
-
| 250 | 7.51328 | — | 7.50593 | — |
|
| 237 |
-
| 500 | 7.37632 | — | 7.36168 | — |
|
| 238 |
-
| 750 | 7.33534 | — | 7.31743 | — |
|
| 239 |
-
| 1,000 | 7.2956 | — | 7.27509 | — |
|
| 240 |
-
| 1,250 | 7.25757 | — | 7.2354 | — |
|
| 241 |
-
| 1,500 | 7.22776 | — | 7.20332 | — |
|
| 242 |
-
| 1,750 | 7.18971 | — | 7.16376 | — |
|
| 243 |
-
| 2,000 | 7.16679 | — | 7.13879 | — |
|
| 244 |
-
| 2,250 | 7.15075 | — | 7.12142 | — |
|
| 245 |
-
| 2,500 | 7.1182 | — | 7.08786 | — |
|
| 246 |
-
| 2,750 | 7.09542 | — | 7.064 | — |
|
| 247 |
-
| 3,000 | 7.07595 | — | 7.0437 | — |
|
| 248 |
-
| 3,250 | 7.05828 | — | 7.02471 | — |
|
| 249 |
-
| 3,500 | 7.04374 | — | 7.00896 | — |
|
| 250 |
-
| 3,750 | 7.03011 | — | 6.99452 | — |
|
| 251 |
-
| 4,000 | 7.01765 | — | 6.98176 | — |
|
| 252 |
-
| 4,250 | 7.00604 | — | 6.96907 | — |
|
| 253 |
-
| 4,500 | 6.99175 | — | 6.95386 | — |
|
| 254 |
-
| 4,750 | 6.97323 | — | 6.93439 | — |
|
| 255 |
-
| 5,000 | 6.95435 | 7.03772 | 6.91428 | 6.97998 |
|
| 256 |
-
| 5,250 | 6.94098 | — | 6.90037 | — |
|
| 257 |
-
| 5,500 | 6.9301 | — | 6.88864 | — |
|
| 258 |
-
| 5,750 | 6.91726 | — | 6.87426 | — |
|
| 259 |
-
| 6,000 | 6.905 | — | 6.86125 | — |
|
| 260 |
-
| 6,250 | 6.89508 | — | 6.85136 | — |
|
| 261 |
-
| 6,500 | 6.8811 | — | 6.8378 | — |
|
| 262 |
-
| 6,750 | 6.87753 | — | 6.8327 | — |
|
| 263 |
-
| 7,000 | 6.86382 | — | 6.81881 | — |
|
| 264 |
-
| 7,250 | 6.85904 | — | 6.81314 | — |
|
| 265 |
-
| 7,500 | 6.85565 | — | 6.8089 | — |
|
| 266 |
-
| 7,750 | 6.84594 | — | 6.79925 | — |
|
| 267 |
-
| 8,000 | 6.8399 | — | 6.79186 | — |
|
| 268 |
-
| 8,250 | 6.8271 | — | 6.77829 | — |
|
| 269 |
-
| 8,500 | 6.82443 | — | 6.77634 | — |
|
| 270 |
-
| 8,750 | 6.8251 | — | 6.77586 | — |
|
| 271 |
-
| 9,000 | 6.81961 | — | 6.77061 | — |
|
| 272 |
-
| 9,250 | 6.80826 | — | 6.75788 | — |
|
| 273 |
-
| 9,500 | 6.80517 | — | 6.75465 | — |
|
| 274 |
-
| 9,750 | 6.805 | — | 6.7549 | — |
|
| 275 |
-
| 10,000 | 6.79291 | 6.90652 | 6.74131 | 6.83695 |
|
| 276 |
-
| 10,250 | 6.79435 | — | 6.74302 | — |
|
| 277 |
-
| 10,500 | 6.57804 | — | 6.46818 | — |
|
| 278 |
-
| 10,750 | 5.64887 | — | 5.30678 | — |
|
| 279 |
-
| 11,000 | 5.50961 | — | 5.1322 | — |
|
| 280 |
-
| 11,250 | 5.44243 | — | 5.04573 | — |
|
| 281 |
-
| 11,500 | 5.39135 | — | 4.97991 | — |
|
| 282 |
-
| 11,750 | 5.3537 | — | 4.93408 | — |
|
| 283 |
-
| 12,000 | 5.32865 | — | 4.90204 | — |
|
| 284 |
-
| 12,250 | 5.29837 | — | 4.86656 | — |
|
| 285 |
-
| 12,500 | 5.26806 | — | 4.83252 | — |
|
| 286 |
-
| 12,750 | 5.25518 | — | 4.81263 | — |
|
| 287 |
-
| 13,000 | 5.22838 | — | 4.78307 | — |
|
| 288 |
-
| 13,250 | 5.2163 | — | 4.7663 | — |
|
| 289 |
-
| 13,500 | 5.1947 | — | 4.74032 | — |
|
| 290 |
-
| 13,750 | 5.19089 | — | 4.73445 | — |
|
| 291 |
-
| 14,000 | 5.16889 | — | 4.71043 | — |
|
| 292 |
-
| 14,250 | 5.1559 | — | 4.69624 | — |
|
| 293 |
-
| 14,500 | 5.14548 | — | 4.68216 | — |
|
| 294 |
-
| 14,750 | 5.13203 | — | 4.66433 | — |
|
| 295 |
-
| 15,000 | 5.13145 | 4.7568 | 4.66355 | 4.18981 |
|
| 296 |
-
| 15,250 | 5.11204 | — | 4.64183 | — |
|
| 297 |
-
| 15,500 | 5.10473 | — | 4.63283 | — |
|
| 298 |
-
| 15,625 | 5.09438 | 4.7291 | 4.62103 | 4.15709 |
|
| 299 |
-
|
| 300 |
-
### Cross-entropy with and without MiLe
|
| 301 |
-
|
| 302 |
-
CE without MiLe is unweighted CE; CE with MiLe adds the reweighting delta. Both exclude mu and auxiliary terms. `ntp_loss` includes mu when enabled.
|
| 303 |
-
|
| 304 |
-
| Step | Train CE without MiLe | Val CE without MiLe | Train CE with MiLe | Val CE with MiLe |
|
| 305 |
-
|---|---|---|---|---|
|
| 306 |
-
| 1 | 11.2377 | — | 11.2377 | — |
|
| 307 |
-
| 250 | 7.33083 | — | 7.33818 | — |
|
| 308 |
-
| 500 | 7.01992 | — | 7.03457 | — |
|
| 309 |
-
| 750 | 6.9117 | — | 6.92962 | — |
|
| 310 |
-
| 1,000 | 6.84122 | — | 6.86173 | — |
|
| 311 |
-
| 1,250 | 6.78967 | — | 6.81184 | — |
|
| 312 |
-
| 1,500 | 6.75051 | — | 6.77496 | — |
|
| 313 |
-
| 1,750 | 6.71397 | — | 6.73992 | — |
|
| 314 |
-
| 2,000 | 6.68534 | — | 6.71334 | — |
|
| 315 |
-
| 2,250 | 6.66963 | — | 6.69896 | — |
|
| 316 |
-
| 2,500 | 6.64192 | — | 6.67227 | — |
|
| 317 |
-
| 2,750 | 6.621 | — | 6.65242 | — |
|
| 318 |
-
| 3,000 | 6.60442 | — | 6.63668 | — |
|
| 319 |
-
| 3,250 | 6.59009 | — | 6.62366 | — |
|
| 320 |
-
| 3,500 | 6.5758 | — | 6.61058 | — |
|
| 321 |
-
| 3,750 | 6.55762 | — | 6.59321 | — |
|
| 322 |
-
| 4,000 | 6.54081 | — | 6.5767 | — |
|
| 323 |
-
| 4,250 | 6.52894 | — | 6.56591 | — |
|
| 324 |
-
| 4,500 | 6.51391 | — | 6.5518 | — |
|
| 325 |
-
| 4,750 | 6.49645 | — | 6.53529 | — |
|
| 326 |
-
| 5,000 | 6.4769 | 6.35905 | 6.51696 | 6.41679 |
|
| 327 |
-
| 5,250 | 6.46543 | — | 6.50604 | — |
|
| 328 |
-
| 5,500 | 6.45592 | — | 6.49738 | — |
|
| 329 |
-
| 5,750 | 6.441 | — | 6.484 | — |
|
| 330 |
-
| 6,000 | 6.43025 | — | 6.474 | — |
|
| 331 |
-
| 6,250 | 6.42147 | — | 6.4652 | — |
|
| 332 |
-
| 6,500 | 6.40953 | — | 6.45284 | — |
|
| 333 |
-
| 6,750 | 6.40453 | — | 6.44936 | — |
|
| 334 |
-
| 7,000 | 6.39054 | — | 6.43555 | — |
|
| 335 |
-
| 7,250 | 6.38482 | — | 6.43072 | — |
|
| 336 |
-
| 7,500 | 6.3804 | — | 6.42715 | — |
|
| 337 |
-
| 7,750 | 6.36999 | — | 6.41668 | — |
|
| 338 |
-
| 8,000 | 6.36302 | — | 6.41106 | — |
|
| 339 |
-
| 8,250 | 6.35259 | — | 6.4014 | — |
|
| 340 |
-
| 8,500 | 6.35024 | — | 6.39833 | — |
|
| 341 |
-
| 8,750 | 6.34786 | — | 6.3971 | — |
|
| 342 |
-
| 9,000 | 6.34222 | — | 6.39122 | — |
|
| 343 |
-
| 9,250 | 6.32834 | — | 6.37873 | — |
|
| 344 |
-
| 9,500 | 6.32368 | — | 6.37419 | — |
|
| 345 |
-
| 9,750 | 6.32497 | — | 6.37507 | — |
|
| 346 |
-
| 10,000 | 6.31065 | 6.20464 | 6.36225 | 6.27421 |
|
| 347 |
-
| 10,250 | 6.31157 | — | 6.3629 | — |
|
| 348 |
-
| 10,500 | 6.01485 | — | 6.12471 | — |
|
| 349 |
-
| 10,750 | 4.89594 | — | 5.23804 | — |
|
| 350 |
-
| 11,000 | 4.72479 | — | 5.1022 | — |
|
| 351 |
-
| 11,250 | 4.63385 | — | 5.03055 | — |
|
| 352 |
-
| 11,500 | 4.56533 | — | 4.97677 | — |
|
| 353 |
-
| 11,750 | 4.5158 | — | 4.93542 | — |
|
| 354 |
-
| 12,000 | 4.48125 | — | 4.90787 | — |
|
| 355 |
-
| 12,250 | 4.44365 | — | 4.87546 | — |
|
| 356 |
-
| 12,500 | 4.40877 | — | 4.84431 | — |
|
| 357 |
-
| 12,750 | 4.38846 | — | 4.83101 | — |
|
| 358 |
-
| 13,000 | 4.35794 | — | 4.80324 | — |
|
| 359 |
-
| 13,250 | 4.33989 | — | 4.78989 | — |
|
| 360 |
-
| 13,500 | 4.31309 | — | 4.76746 | — |
|
| 361 |
-
| 13,750 | 4.30621 | — | 4.76265 | — |
|
| 362 |
-
| 14,000 | 4.28204 | — | 4.7405 | — |
|
| 363 |
-
| 14,250 | 4.26676 | — | 4.72641 | — |
|
| 364 |
-
| 14,500 | 4.2524 | — | 4.71572 | — |
|
| 365 |
-
| 14,750 | 4.23404 | — | 4.70174 | — |
|
| 366 |
-
| 15,000 | 4.23243 | 3.78875 | 4.70032 | 4.35574 |
|
| 367 |
-
| 15,250 | 4.21065 | — | 4.68087 | — |
|
| 368 |
-
| 15,500 | 4.20151 | — | 4.67341 | — |
|
| 369 |
-
| 15,625 | 4.18959 | 3.75747 | 4.66293 | 4.32948 |
|
| 370 |
-
|
| 371 |
-
### Observed loss components — weighted contributions
|
| 372 |
-
|
| 373 |
-
Only contributions actually added to the objective are shown; raw values and subcomponents remain in training metrics. `regularization_loss` is the subtotal of mu, weighted TWeo, JTok-M and StackMemory entropy, excluding NITP/NextLat; do not add it again to those components. JTok-M auxiliary loss is training-only.
|
| 374 |
-
|
| 375 |
-
| Step | Phase | mu | TWeo | NITP | Reg. subtotal |
|
| 376 |
-
|---|---|---|---|---|---|
|
| 377 |
-
| 1 | train | 3.16275e-10 | 8.85299e-07 | 1.0468 | 8.85615e-07 |
|
| 378 |
-
| 250 | train | 4.01168e-06 | 0.00101028 | 0.174095 | 0.00101429 |
|
| 379 |
-
| 500 | train | 8.93938e-06 | 0.000425533 | 0.341321 | 0.000434472 |
|
| 380 |
-
| 750 | train | 1.49341e-05 | 0.000574217 | 0.405132 | 0.000589151 |
|
| 381 |
-
| 1,000 | train | 2.21405e-05 | 0.000717058 | 0.433133 | 0.000739198 |
|
| 382 |
-
| 1,250 | train | 3.00225e-05 | 0.000947325 | 0.444758 | 0.000977348 |
|
| 383 |
-
| 1,500 | train | 3.7833e-05 | 0.00116823 | 0.451597 | 0.00120607 |
|
| 384 |
-
| 1,750 | train | 4.49507e-05 | 0.00147651 | 0.448272 | 0.00152146 |
|
| 385 |
-
| 2,000 | train | 5.20222e-05 | 0.00178034 | 0.451619 | 0.00183236 |
|
| 386 |
-
| 2,250 | train | 5.97428e-05 | 0.00206258 | 0.449671 | 0.00212232 |
|
| 387 |
-
| 2,500 | train | 6.78635e-05 | 0.00220622 | 0.443663 | 0.00227409 |
|
| 388 |
-
| 2,750 | train | 7.61504e-05 | 0.00231168 | 0.440618 | 0.00238783 |
|
| 389 |
-
| 3,000 | train | 8.58517e-05 | 0.00233333 | 0.436857 | 0.00241919 |
|
| 390 |
-
| 3,250 | train | 9.77149e-05 | 0.00236563 | 0.432168 | 0.00246334 |
|
| 391 |
-
| 3,500 | train | 0.000110827 | 0.00231476 | 0.430735 | 0.00242559 |
|
| 392 |
-
| 3,750 | train | 0.000126875 | 0.00226564 | 0.434512 | 0.00239251 |
|
| 393 |
-
| 4,000 | train | 0.000145417 | 0.00211525 | 0.438694 | 0.00226067 |
|
| 394 |
-
| 4,250 | train | 0.000167628 | 0.00196029 | 0.437996 | 0.00212792 |
|
| 395 |
-
| 4,500 | train | 0.000194782 | 0.00182893 | 0.437925 | 0.00202371 |
|
| 396 |
-
| 4,750 | train | 0.000227027 | 0.00170113 | 0.436016 | 0.00192816 |
|
| 397 |
-
| 5,000 | train | 0.000263738 | 0.00154546 | 0.435576 | 0.00180919 |
|
| 398 |
-
| 5,000 | validation | 0.000283719 | 0.0060813 | 0.614562 | 0.00636502 |
|
| 399 |
-
| 5,250 | train | 0.000303911 | 0.00140913 | 0.433229 | 0.00171304 |
|
| 400 |
-
| 5,500 | train | 0.000345929 | 0.00130875 | 0.431072 | 0.00165468 |
|
| 401 |
-
| 5,750 | train | 0.000391956 | 0.00119768 | 0.431669 | 0.00158963 |
|
| 402 |
-
| 6,000 | train | 0.000435046 | 0.00113317 | 0.429428 | 0.00156821 |
|
| 403 |
-
| 6,250 | train | 0.000476276 | 0.00107261 | 0.428334 | 0.00154889 |
|
| 404 |
-
| 6,500 | train | 0.000520947 | 0.000988251 | 0.426753 | 0.0015092 |
|
| 405 |
-
| 6,750 | train | 0.000561467 | 0.000925999 | 0.426688 | 0.00148747 |
|
| 406 |
-
| 7,000 | train | 0.000600642 | 0.000889937 | 0.426782 | 0.00149058 |
|
| 407 |
-
| 7,250 | train | 0.000640212 | 0.000860261 | 0.426819 | 0.00150047 |
|
| 408 |
-
| 7,500 | train | 0.000679096 | 0.000852769 | 0.426972 | 0.00153187 |
|
| 409 |
-
| 7,750 | train | 0.000715778 | 0.000802992 | 0.427743 | 0.00151877 |
|
| 410 |
-
| 8,000 | train | 0.000753992 | 0.00078903 | 0.4273 | 0.00154302 |
|
| 411 |
-
| 8,250 | train | 0.000795478 | 0.000771698 | 0.424126 | 0.00156718 |
|
| 412 |
-
| 8,500 | train | 0.000837118 | 0.000758088 | 0.424502 | 0.00159521 |
|
| 413 |
-
| 8,750 | train | 0.000873988 | 0.00075022 | 0.426376 | 0.00162421 |
|
| 414 |
-
| 9,000 | train | 0.000910428 | 0.000754263 | 0.426734 | 0.00166469 |
|
| 415 |
-
| 9,250 | train | 0.000944036 | 0.000730808 | 0.427862 | 0.00167484 |
|
| 416 |
-
| 9,500 | train | 0.000975691 | 0.00071411 | 0.429285 | 0.0016898 |
|
| 417 |
-
| 9,750 | train | 0.00100823 | 0.000682743 | 0.428235 | 0.00169098 |
|
| 418 |
-
| 10,000 | train | 0.00104292 | 0.000664123 | 0.428943 | 0.00170704 |
|
| 419 |
-
| 10,000 | validation | 0.00106212 | 0.0022162 | 0.629043 | 0.00327832 |
|
| 420 |
-
| 10,250 | train | 0.00108166 | 0.000681578 | 0.429688 | 0.00176324 |
|
| 421 |
-
| 10,500 | train | 0.0011197 | 0.00105885 | 0.451152 | 0.00217854 |
|
| 422 |
-
| 10,750 | train | 0.00114721 | 0.000800759 | 0.408884 | 0.00194796 |
|
| 423 |
-
| 11,000 | train | 0.00114271 | 0.000609513 | 0.405662 | 0.00175222 |
|
| 424 |
-
| 11,250 | train | 0.00112443 | 0.000589441 | 0.410163 | 0.00171387 |
|
| 425 |
-
| 11,500 | train | 0.00110764 | 0.000626262 | 0.412851 | 0.0017339 |
|
| 426 |
-
| 11,750 | train | 0.0011031 | 0.0007034 | 0.416477 | 0.0018065 |
|
| 427 |
-
| 12,000 | train | 0.00110705 | 0.000701879 | 0.418976 | 0.00180893 |
|
| 428 |
-
| 12,250 | train | 0.00111366 | 0.000731281 | 0.42106 | 0.00184494 |
|
| 429 |
-
| 12,500 | train | 0.00112138 | 0.000758367 | 0.421869 | 0.00187974 |
|
| 430 |
-
| 12,750 | train | 0.00113102 | 0.000750959 | 0.422287 | 0.00188198 |
|
| 431 |
-
| 13,000 | train | 0.00114004 | 0.000732814 | 0.423269 | 0.00187286 |
|
| 432 |
-
| 13,250 | train | 0.0011468 | 0.000694571 | 0.424568 | 0.00184138 |
|
| 433 |
-
| 13,500 | train | 0.00115065 | 0.000657363 | 0.425431 | 0.00180801 |
|
| 434 |
-
| 13,750 | train | 0.00115104 | 0.000615922 | 0.426476 | 0.00176697 |
|
| 435 |
-
| 14,000 | train | 0.00115097 | 0.000595539 | 0.42664 | 0.00174651 |
|
| 436 |
-
| 14,250 | train | 0.00115072 | 0.000557399 | 0.427775 | 0.00170812 |
|
| 437 |
-
| 14,500 | train | 0.00114966 | 0.000522873 | 0.428093 | 0.00167254 |
|
| 438 |
-
| 14,750 | train | 0.00115023 | 0.000500229 | 0.428635 | 0.00165046 |
|
| 439 |
-
| 15,000 | train | 0.00115158 | 0.000471158 | 0.429507 | 0.00162274 |
|
| 440 |
-
| 15,000 | validation | 0.00115209 | 0.000515729 | 0.399388 | 0.00166782 |
|
| 441 |
-
| 15,250 | train | 0.00115244 | 0.000452634 | 0.429571 | 0.00160508 |
|
| 442 |
-
| 15,500 | train | 0.00115244 | 0.000431864 | 0.429741 | 0.00158431 |
|
| 443 |
-
| 15,625 | train | 0.00115257 | 0.000415416 | 0.429879 | 0.00156799 |
|
| 444 |
-
| 15,625 | validation | 0.00115263 | 0.000468992 | 0.397996 | 0.00162163 |
|
| 445 |
-
|
| 446 |
-
Tables use exact logged steps; missing values are — without carrying values forward. Repeated evaluations at one step use the latest logged value. Components average batch scalars weighted by examples; CE/PPL token metrics retain their valid-target weighting. Weight decay/CWD act in the optimizer, outside these forward losses.
|
| 447 |
-
|
| 448 |
-
---
|
| 449 |
-
|
| 450 |
-
## Limitations
|
| 451 |
-
|
| 452 |
-
- **Token budget** — ~1.5 B tokens seen; below estimated optimum. Knowledge-intensive tasks
|
| 453 |
-
will improve with more training.
|
| 454 |
-
- **Gradient spike at step 40k** — Reorganized the attention pattern in layer 9 that
|
| 455 |
-
previously captured long-range token correlations. A checkpoint from ~step 38k is expected
|
| 456 |
-
to have better aggregate benchmark scores.
|
| 457 |
-
- **PolyNorm exclusivity** — The quadratic branch has become partially redundant with the
|
| 458 |
-
linear branch. Will be corrected in the next training run.
|
| 459 |
-
- **Base model only** — Not instruction-tuned or aligned; purely a next-token-prediction
|
| 460 |
-
base model.
|
| 461 |
-
|
| 462 |
-
---
|
| 463 |
-
|
| 464 |
-
## References
|
| 465 |
-
|
| 466 |
-
All papers whose techniques are integrated into NeoLLM's architecture,
|
| 467 |
-
training objective, or training stack:
|
| 468 |
-
|
| 469 |
-
| Area | Technique | Paper title | Reference |
|
| 470 |
-
|---|---|---|---|
|
| 471 |
-
| Embeddings | Learnable Multipliers | Freeing the Scale of Language Model Matrix Layers | [arXiv:2601.04890](https://arxiv.org/abs/2601.04890) |
|
| 472 |
-
| Embeddings | Leviathan | A Separable Architecture for Continuous Token Representation in Language Models | [arXiv:2601.22040](https://arxiv.org/abs/2601.22040) |
|
| 473 |
-
| Embeddings / residual modulation | JTok / JTok-M | JTok: On Token Embedding as another Axis of Scaling Law via Joint Token Self-modulation | [arXiv:2602.00800](https://arxiv.org/abs/2602.00800) |
|
| 474 |
-
| Embeddings | KHRONOS | KHRONOS: a Kernel-Based Neural Architecture for Rapid, Resource-Efficient Scientific Computation | [arXiv:2505.13315](https://arxiv.org/abs/2505.13315) |
|
| 475 |
-
| Embeddings | Spelling Bee | Spelling Bee Embeddings for Language Modeling | [arXiv:2601.18030](https://arxiv.org/abs/2601.18030) |
|
| 476 |
-
| Embeddings | Token embedding analysis | Token Embeddings Violate the Manifold Hypothesis | [arXiv:2504.01002](https://arxiv.org/abs/2504.01002) |
|
| 477 |
-
| Attention / positions | FAN | Fourier Analysis Networks | [arXiv:2502.21309](https://arxiv.org/abs/2502.21309) |
|
| 478 |
-
| Attention / positions | MEA | Explicit Multi-head Attention for Inter-head Interaction in Large Language Models | [arXiv:2601.19611](https://arxiv.org/abs/2601.19611) |
|
| 479 |
-
| Attention / positions | LUCID | Attention with Preconditioned Representations | [arXiv:2602.10410](https://arxiv.org/abs/2602.10410) |
|
| 480 |
-
| Attention / positions | Affine-Scaled Attention | Affine-Scaled Attention: Towards Flexible and Stable Transformer Attention | [arXiv:2602.23057](https://arxiv.org/abs/2602.23057) |
|
| 481 |
-
| Attention / positions | XSA | Exclusive Self Attention | [arXiv:2603.09078](https://arxiv.org/abs/2603.09078) |
|
| 482 |
-
| Attention / positions | Directional Routing | Directional Routing in Transformers | [arXiv:2603.14923](https://arxiv.org/abs/2603.14923) |
|
| 483 |
-
| Attention / positions | Gated Attention | Gated Attention for Large Language Models: Non-linearity, Sparsity, and Attention-Sink-Free | [arXiv:2505.06708](https://arxiv.org/abs/2505.06708) |
|
| 484 |
-
| Attention / positions | Momentum Attention | Momentum Attention | [arXiv:2411.03884](https://arxiv.org/abs/2411.03884) |
|
| 485 |
-
| Attention / positions | IHA | Interleaved Head Attention | [arXiv:2602.21371](https://arxiv.org/abs/2602.21371) |
|
| 486 |
-
| Attention / positions | REPO | Language Models with Context Re-Positioning | [arXiv:2512.14391](https://arxiv.org/abs/2512.14391) |
|
| 487 |
-
| Attention / positions | GRAPE | Group Representational Position Encoding | [arXiv:2512.07805](https://arxiv.org/abs/2512.07805) |
|
| 488 |
-
| Attention / positions | GOAT priors | You Need Better Attention Priors | [arXiv:2601.15380](https://arxiv.org/abs/2601.15380) |
|
| 489 |
-
| Attention / positions | Hadamard o_proj | Rethinking Attention Output Projection: Structured Hadamard Transforms for Efficient Transformers | [arXiv:2603.08343](https://arxiv.org/abs/2603.08343) |
|
| 490 |
-
| Residual / normalization | SeeDNorm | Self-Rescaled Dynamic Normalization | [arXiv:2510.22777](https://arxiv.org/abs/2510.22777) |
|
| 491 |
-
| Residual / normalization | LNS | The Curse of Depth in LLMs | [arXiv:2502.05795](https://arxiv.org/abs/2502.05795) |
|
| 492 |
-
| Residual / normalization | GPAS | Gradient-Preserving Activation Scaling | [arXiv:2506.22049](https://arxiv.org/abs/2506.22049) |
|
| 493 |
-
| Residual / normalization | PolyNorm | PolyNorm / PolyCom | [arXiv:2602.04902](https://arxiv.org/abs/2602.04902) |
|
| 494 |
-
| Residual / normalization | SimpleGPT | SimpleGPT | [arXiv:2602.01212](https://arxiv.org/abs/2602.01212) |
|
| 495 |
-
| Residual / normalization | StackMemory / STACKTRANS | Recursive Transformer: Boosting Reasoning Ability with State Stack | [NeurIPS 2025](https://openreview.net/forum?id=2bbDg587uh) |
|
| 496 |
-
| Residual / normalization | Attention Residuals | Attention Residuals | [arXiv:2603.15031](https://arxiv.org/abs/2603.15031) |
|
| 497 |
-
| Residual / normalization | LAUREL | LAUREL: Learned Augmented Residual Layer | [arXiv:2411.07501](https://arxiv.org/abs/2411.07501) |
|
| 498 |
-
| Objectives | TWEO | Transformers Without Extreme Outliers Enables FP8 Training And Quantization For Dummies | [arXiv:2511.23225](https://arxiv.org/abs/2511.23225) |
|
| 499 |
-
| Objectives | NITP | Next Implicit Token Prediction for LLM Pre-training | [arXiv:2605.24956](https://arxiv.org/abs/2605.24956) |
|
| 500 |
-
| Objectives | NextLat | Next-Latent Prediction Transformers Learn Compact World Models | [arXiv:2511.05963](https://arxiv.org/abs/2511.05963) |
|
| 501 |
-
| Optimizer / training | AdEMAMix | The AdEMAMix Optimizer: Better, Faster, Older | [arXiv:2409.03137](https://arxiv.org/abs/2409.03137) |
|
| 502 |
-
| Optimizer / training | DeltaMomentum | DeltaMomentum: A Key-Value based Anisotropic Momentum Update via Delta Rule | [arXiv:2608.19491](https://arxiv.org/abs/2608.19491) |
|
| 503 |
-
| Optimizer / training | BF16 + SR | Stochastic Rounding for LLM Training: Theory and Practice | [arXiv:2502.20566](https://arxiv.org/abs/2502.20566) |
|
| 504 |
-
| Optimizer / training | CWD | Cautious Weight Decay | [arXiv:2510.12402](https://arxiv.org/abs/2510.12402) |
|
| 505 |
-
| Optimizer / training | WD correction | Correction of Decoupled Weight Decay | [arXiv:2512.08217](https://arxiv.org/abs/2512.08217) |
|
| 506 |
-
| Optimizer / training | AdamHD | AdamHD: Decoupled Huber Decay Regularization for Language Model Pre-Training | [arXiv:2511.14721](https://arxiv.org/abs/2511.14721) |
|
| 507 |
-
| Optimizer / training | GradientStabilizer | GradientStabilizer | [arXiv:2502.17055](https://arxiv.org/abs/2502.17055) |
|
| 508 |
-
|
| 509 |
-
---
|
| 510 |
-
|
| 511 |
-
## Citation
|
| 512 |
-
|
| 513 |
-
```bibtex
|
| 514 |
-
@misc{neollm2026,
|
| 515 |
-
title = {NeoLLM: A Research Language Model Integrating Recent Attention and Normalization Techniques},
|
| 516 |
-
author = {KitsuVp},
|
| 517 |
-
year = {2026},
|
| 518 |
-
url = {https://huggingface.co/KitsuVp/NeoLLM}
|
| 519 |
-
}
|
| 520 |
-
```
|
| 521 |
-
|
| 522 |
-
---
|
| 523 |
-
|
| 524 |
-
## Author
|
| 525 |
-
|
| 526 |
-
[@Kyokopom](https://x.com/Kyokopom) on X
|
| 527 |
-
|
| 528 |
-
---
|
| 529 |
-
|
| 530 |
-
## License
|
| 531 |
|
| 532 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
library_name: transformers
|
|
|
|
| 3 |
tags:
|
| 4 |
+
- generated_from_trainer
|
| 5 |
+
model-index:
|
| 6 |
+
- name: NeoLLM
|
| 7 |
+
results: []
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
+
<!-- This model card has been generated automatically according to the information the Trainer had access to. You
|
| 11 |
+
should probably proofread and complete it, then remove this comment. -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
+
# NeoLLM
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
This model is a fine-tuned version of [](https://huggingface.co/) on an unknown dataset.
|
| 16 |
+
It achieves the following results on the evaluation set:
|
| 17 |
+
- Loss: 4.9291
|
| 18 |
+
- Ce: 3.9075
|
| 19 |
+
- Valid Targets: 2083162.0
|
| 20 |
+
- Ppl: 49.7745
|
| 21 |
+
- Mile Loss: 4.5021
|
| 22 |
+
- Mile Ppl: 90.2041
|
| 23 |
+
- Top1 Accuracy: 0.3108
|
| 24 |
+
- Top3 Accuracy: 0.4650
|
| 25 |
+
- Topk Valid Targets: 2083162.0
|
| 26 |
+
- Ntp Loss: 4.5034
|
| 27 |
+
- Ntp Ce Unweighted: 3.9080
|
| 28 |
+
- Mile Reweighting Delta: 0.5945
|
| 29 |
+
- Mu Loss: 0.0010
|
| 30 |
+
- Tweo Loss: 0.0668
|
| 31 |
+
- Nitp Loss: 0.4250
|
| 32 |
+
- Total Model Loss: 4.9291
|
| 33 |
+
- Tweo Weighted Loss: 0.0007
|
| 34 |
+
- Nitp Weighted Loss: 0.4250
|
| 35 |
+
- Auxiliary Loss: 0.4257
|
| 36 |
+
- Regularization Loss: 0.0016
|
| 37 |
+
|
| 38 |
+
## Model description
|
| 39 |
+
|
| 40 |
+
More information needed
|
| 41 |
+
|
| 42 |
+
## Intended uses & limitations
|
| 43 |
+
|
| 44 |
+
More information needed
|
| 45 |
+
|
| 46 |
+
## Training and evaluation data
|
| 47 |
+
|
| 48 |
+
More information needed
|
| 49 |
+
|
| 50 |
+
## Training procedure
|
| 51 |
+
|
| 52 |
+
### Training hyperparameters
|
| 53 |
+
|
| 54 |
+
The following hyperparameters were used during training:
|
| 55 |
+
- learning_rate: 0.001
|
| 56 |
+
- train_batch_size: 64
|
| 57 |
+
- eval_batch_size: 64
|
| 58 |
+
- seed: 42
|
| 59 |
+
- optimizer: Use OptimizerNames.ADAMW_TORCH_FUSED with betas=(0.9,0.999) and epsilon=1e-08 and optimizer_args=No additional optimizer arguments
|
| 60 |
+
- lr_scheduler_type: linear
|
| 61 |
+
- num_epochs: 1
|
| 62 |
+
|
| 63 |
+
### Training results
|
| 64 |
+
|
| 65 |
+
| Training Loss | Epoch | Step | Validation Loss | Ce | Valid Targets | Ppl | Mile Loss | Mile Ppl | Top1 Accuracy | Top3 Accuracy | Topk Valid Targets | Ntp Loss | Ntp Ce Unweighted | Mile Reweighting Delta | Mu Loss | Tweo Loss | Nitp Loss | Total Model Loss | Tweo Weighted Loss | Nitp Weighted Loss | Auxiliary Loss | Regularization Loss |
|
| 66 |
+
|:-------------:|:-----:|:-----:|:---------------:|:------:|:-------------:|:--------:|:---------:|:--------:|:-------------:|:-------------:|:------------------:|:--------:|:-----------------:|:----------------------:|:-------:|:---------:|:---------:|:----------------:|:------------------:|:------------------:|:--------------:|:-------------------:|
|
| 67 |
+
| 7.2623 | 0.32 | 5000 | 7.4209 | 6.6778 | 2083162.0 | 794.6030 | 6.7310 | 837.9544 | 0.0784 | 0.1546 | 2083162.0 | 6.7312 | 6.6778 | 0.0531 | 0.0003 | 0.8364 | 0.6813 | 7.4209 | 0.0084 | 0.6813 | 0.6897 | 0.0087 |
|
| 68 |
+
| 6.9846 | 0.64 | 10000 | 7.1389 | 6.3917 | 2083162.0 | 596.8784 | 6.4607 | 639.4872 | 0.0952 | 0.1738 | 2083162.0 | 6.4614 | 6.3917 | 0.0690 | 0.0008 | 0.1872 | 0.6756 | 7.1389 | 0.0019 | 0.6756 | 0.6775 | 0.0027 |
|
| 69 |
+
| 5.3718 | 0.96 | 15000 | 4.9829 | 3.9751 | 2083162.0 | 53.2555 | 4.5515 | 94.7726 | 0.3041 | 0.4569 | 2083162.0 | 4.5528 | 3.9756 | 0.5763 | 0.0009 | 0.0772 | 0.4294 | 4.9829 | 0.0008 | 0.4294 | 0.4301 | 0.0017 |
|
| 70 |
+
| 5.3163 | 1.0 | 15625 | 4.9291 | 3.9075 | 2083162.0 | 49.7745 | 4.5021 | 90.2041 | 0.3108 | 0.4650 | 2083162.0 | 4.5034 | 3.9080 | 0.5945 | 0.0010 | 0.0668 | 0.4250 | 4.9291 | 0.0007 | 0.4250 | 0.4257 | 0.0016 |
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
### Framework versions
|
| 74 |
+
|
| 75 |
+
- Transformers 5.22.1
|
| 76 |
+
- Pytorch 2.14.1+cu130
|
| 77 |
+
- Datasets 4.8.5
|
| 78 |
+
- Tokenizers 0.23.3
|
config.json
CHANGED
|
@@ -13,6 +13,7 @@
|
|
| 13 |
},
|
| 14 |
"bos_token_id": 1,
|
| 15 |
"cce_loss_impl": "cce_kahan_full_c",
|
|
|
|
| 16 |
"dagformer": {
|
| 17 |
"input_source": "tokens",
|
| 18 |
"local_dim": 128,
|
|
@@ -56,19 +57,29 @@
|
|
| 56 |
"jtok_num_modes": 4,
|
| 57 |
"jtok_top_k": 2,
|
| 58 |
"laurel_lr_rank": 32,
|
|
|
|
|
|
|
|
|
|
| 59 |
"liger_loss_accum_dtype": "float32",
|
| 60 |
"lucid_attention_eps": 1e-06,
|
| 61 |
"max_position_embeddings": 512,
|
| 62 |
"mea_component_key_value_heads": 4,
|
| 63 |
"mea_groupnorm_eps": 1e-06,
|
| 64 |
"meap_exclude_last": true,
|
|
|
|
| 65 |
"meap_implementation": "triton",
|
| 66 |
"meap_mask_ratio": 0.15,
|
| 67 |
"meap_mask_token_id": 16,
|
|
|
|
| 68 |
"meap_seed": 42,
|
| 69 |
"mile_loss_gamma": 1.0,
|
| 70 |
"model_type": "neollm",
|
| 71 |
"momentum_gamma": 0.1,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
"mu_loss_lambda": 0.0001,
|
| 73 |
"nextlat_dynamics_proj_factor": 1.0,
|
| 74 |
"nextlat_horizon": 1,
|
|
@@ -113,7 +124,7 @@
|
|
| 113 |
"stack_memory_cache_size": 2048,
|
| 114 |
"stack_slots": 16,
|
| 115 |
"tie_word_embeddings": false,
|
| 116 |
-
"transformers_version": "5.
|
| 117 |
"tweo_eps": 1e-06,
|
| 118 |
"tweo_loss_weight": 0.01,
|
| 119 |
"tweo_power": 4.0,
|
|
@@ -121,7 +132,7 @@
|
|
| 121 |
"use_affine_scaled_attention": false,
|
| 122 |
"use_attn_res": false,
|
| 123 |
"use_cache": false,
|
| 124 |
-
"use_copy_paste":
|
| 125 |
"use_dagformer": false,
|
| 126 |
"use_directional_routing": false,
|
| 127 |
"use_embedding_input_norm": true,
|
|
@@ -136,6 +147,7 @@
|
|
| 136 |
"use_laurel": false,
|
| 137 |
"use_laurel_lr": false,
|
| 138 |
"use_laurel_rw": false,
|
|
|
|
| 139 |
"use_learnable_multipliers": true,
|
| 140 |
"use_liger_kernel": false,
|
| 141 |
"use_lns": true,
|
|
@@ -144,6 +156,7 @@
|
|
| 144 |
"use_meap": true,
|
| 145 |
"use_mile_loss": true,
|
| 146 |
"use_momentum_attention": true,
|
|
|
|
| 147 |
"use_mu_loss": true,
|
| 148 |
"use_nextlat": false,
|
| 149 |
"use_nitp": true,
|
|
|
|
| 13 |
},
|
| 14 |
"bos_token_id": 1,
|
| 15 |
"cce_loss_impl": "cce_kahan_full_c",
|
| 16 |
+
"copy_paste_lexical_keys": false,
|
| 17 |
"dagformer": {
|
| 18 |
"input_source": "tokens",
|
| 19 |
"local_dim": 128,
|
|
|
|
| 57 |
"jtok_num_modes": 4,
|
| 58 |
"jtok_top_k": 2,
|
| 59 |
"laurel_lr_rank": 32,
|
| 60 |
+
"ldm_groups": 8,
|
| 61 |
+
"ldm_hidden_dim": 32,
|
| 62 |
+
"ldm_key_dim": 8,
|
| 63 |
"liger_loss_accum_dtype": "float32",
|
| 64 |
"lucid_attention_eps": 1e-06,
|
| 65 |
"max_position_embeddings": 512,
|
| 66 |
"mea_component_key_value_heads": 4,
|
| 67 |
"mea_groupnorm_eps": 1e-06,
|
| 68 |
"meap_exclude_last": true,
|
| 69 |
+
"meap_exclude_mask_from_copy": false,
|
| 70 |
"meap_implementation": "triton",
|
| 71 |
"meap_mask_ratio": 0.15,
|
| 72 |
"meap_mask_token_id": 16,
|
| 73 |
+
"meap_protect_structural_tokens": false,
|
| 74 |
"meap_seed": 42,
|
| 75 |
"mile_loss_gamma": 1.0,
|
| 76 |
"model_type": "neollm",
|
| 77 |
"momentum_gamma": 0.1,
|
| 78 |
+
"msar_backend": "auto",
|
| 79 |
+
"msar_block_branches": 4,
|
| 80 |
+
"msar_kernel_sizes": [
|
| 81 |
+
4
|
| 82 |
+
],
|
| 83 |
"mu_loss_lambda": 0.0001,
|
| 84 |
"nextlat_dynamics_proj_factor": 1.0,
|
| 85 |
"nextlat_horizon": 1,
|
|
|
|
| 124 |
"stack_memory_cache_size": 2048,
|
| 125 |
"stack_slots": 16,
|
| 126 |
"tie_word_embeddings": false,
|
| 127 |
+
"transformers_version": "5.22.1",
|
| 128 |
"tweo_eps": 1e-06,
|
| 129 |
"tweo_loss_weight": 0.01,
|
| 130 |
"tweo_power": 4.0,
|
|
|
|
| 132 |
"use_affine_scaled_attention": false,
|
| 133 |
"use_attn_res": false,
|
| 134 |
"use_cache": false,
|
| 135 |
+
"use_copy_paste": false,
|
| 136 |
"use_dagformer": false,
|
| 137 |
"use_directional_routing": false,
|
| 138 |
"use_embedding_input_norm": true,
|
|
|
|
| 147 |
"use_laurel": false,
|
| 148 |
"use_laurel_lr": false,
|
| 149 |
"use_laurel_rw": false,
|
| 150 |
+
"use_ldm": false,
|
| 151 |
"use_learnable_multipliers": true,
|
| 152 |
"use_liger_kernel": false,
|
| 153 |
"use_lns": true,
|
|
|
|
| 156 |
"use_meap": true,
|
| 157 |
"use_mile_loss": true,
|
| 158 |
"use_momentum_attention": true,
|
| 159 |
+
"use_msar": false,
|
| 160 |
"use_mu_loss": true,
|
| 161 |
"use_nextlat": false,
|
| 162 |
"use_nitp": true,
|
configuration_neollm.py
CHANGED
|
@@ -224,12 +224,26 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 224 |
``use_xsa=False``.
|
| 225 |
use_msar (:obj:`bool`, *optional*, defaults to ``False``):
|
| 226 |
Enable Block Multi-Stream Attention Residuals (arXiv:2610.13630).
|
| 227 |
-
It
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
causal views and independent depth reads are reconstructed per branch.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
msar_block_branches (:obj:`int` or ``None``, optional):
|
| 231 |
Number of attention/MLP branches per block. ``None`` derives a
|
| 232 |
-
size from
|
|
|
|
|
|
|
| 233 |
msar_kernel_sizes (:obj:`tuple`, optional):
|
| 234 |
Causal depthwise widths; the paper uses ``(4, 8, 12)``.
|
| 235 |
msar_backend (:obj:`str`, optional):
|
|
@@ -771,8 +785,9 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 771 |
# ── Attention Residuals (Kimi Team, 2026) ─────────────────────────
|
| 772 |
use_attn_res=False,
|
| 773 |
attn_res_num_blocks=4,
|
| 774 |
-
# MSAR
|
| 775 |
use_msar=False,
|
|
|
|
| 776 |
msar_block_branches=None, # auto: approximately eight depth blocks
|
| 777 |
msar_kernel_sizes=(4, 8, 12),
|
| 778 |
msar_backend="auto", # Triton on CUDA, Torch on CPU; "torch" is a reference
|
|
@@ -1104,14 +1119,15 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 1104 |
|
| 1105 |
# ── Residual-flow mechanism mutex ─────────────────────────────────
|
| 1106 |
# AttnRes and LAuReL compete directly with residual topology.
|
| 1107 |
-
# StackMemory may be paired with SiameseNorm
|
| 1108 |
-
#
|
| 1109 |
_residual_flow_flags = {
|
| 1110 |
"use_laurel": bool(use_laurel),
|
| 1111 |
"use_attn_res": bool(use_attn_res),
|
| 1112 |
"use_stack_memory": bool(use_stack_memory),
|
| 1113 |
"use_siamesenorm": bool(use_siamesenorm),
|
| 1114 |
"use_msar": bool(use_msar),
|
|
|
|
| 1115 |
}
|
| 1116 |
_active_residual_flow = [
|
| 1117 |
name for name, enabled in _residual_flow_flags.items() if enabled
|
|
@@ -1122,13 +1138,25 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 1122 |
and not bool(use_laurel)
|
| 1123 |
and not bool(use_attn_res)
|
| 1124 |
and not bool(use_msar)
|
|
|
|
| 1125 |
)
|
| 1126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1127 |
raise ValueError(
|
| 1128 |
"Enable at most one residual-flow mechanism among "
|
| 1129 |
"`use_laurel`, `use_attn_res`, `use_stack_memory`, "
|
| 1130 |
-
"`use_siamesenorm`, and `
|
| 1131 |
-
"`use_stack_memory` + `use_siamesenorm`
|
|
|
|
| 1132 |
f"Active flags: {_active_residual_flow}."
|
| 1133 |
)
|
| 1134 |
|
|
@@ -1138,9 +1166,15 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 1138 |
"`use_msar=True` cannot be combined with `use_gpas`, "
|
| 1139 |
"`use_fan_residual`, or `use_dagformer`."
|
| 1140 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1141 |
if msar_block_branches is None:
|
| 1142 |
-
#
|
| 1143 |
-
|
|
|
|
| 1144 |
if isinstance(msar_block_branches, bool) or not isinstance(msar_block_branches, int) or msar_block_branches < 1:
|
| 1145 |
raise ValueError("`msar_block_branches` must be a positive integer.")
|
| 1146 |
if (not isinstance(msar_kernel_sizes, (tuple, list)) or not msar_kernel_sizes
|
|
@@ -1382,6 +1416,16 @@ class NeoLLMConfig(PretrainedConfig):
|
|
| 1382 |
# Memory cost: O(num_blocks × batch × seq × hidden) instead of
|
| 1383 |
# O(num_layers × batch × seq × hidden).
|
| 1384 |
self.use_msar = bool(use_msar)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1385 |
self.msar_block_branches = msar_block_branches
|
| 1386 |
self.msar_kernel_sizes = tuple(msar_kernel_sizes)
|
| 1387 |
self.msar_backend = msar_backend
|
|
|
|
| 224 |
``use_xsa=False``.
|
| 225 |
use_msar (:obj:`bool`, *optional*, defaults to ``False``):
|
| 226 |
Enable Block Multi-Stream Attention Residuals (arXiv:2610.13630).
|
| 227 |
+
It may be combined with SiameseNorm; the hybrid adds an MSAR read
|
| 228 |
+
of the shared unscaled branch history to the normalized X/Y sum,
|
| 229 |
+
before its existing optional shared input norm. No extra
|
| 230 |
+
normalization or user parameter is introduced by the combination.
|
| 231 |
+
This is an architectural adaptation, not a configuration tested in
|
| 232 |
+
the MSAR paper. Other residual topologies, GPAS, FAN residual and
|
| 233 |
+
DAGFormer remain exclusive. Single-stream summaries are retained;
|
| 234 |
causal views and independent depth reads are reconstructed per branch.
|
| 235 |
+
use_ldm (:obj:`bool`, *optional*, defaults to ``False``):
|
| 236 |
+
Enable Linear Depth Memory (RLS per token and feature group). Group
|
| 237 |
+
count follows the attention head geometry automatically, and the
|
| 238 |
+
key and controller dimensions follow the paper's small-width recipe.
|
| 239 |
+
SiameseNorm can be combined with LDM through a shared history of
|
| 240 |
+
unscaled branch outputs; this hybrid is an architectural adaptation.
|
| 241 |
+
Other alternative residual flows remain mutually exclusive.
|
| 242 |
msar_block_branches (:obj:`int` or ``None``, optional):
|
| 243 |
Number of attention/MLP branches per block. ``None`` derives a
|
| 244 |
+
size from the total number of attention/MLP branches, aiming for
|
| 245 |
+
roughly eight contiguous blocks; block boundaries may fall between
|
| 246 |
+
attention and MLP. An explicit value is preserved as supplied.
|
| 247 |
msar_kernel_sizes (:obj:`tuple`, optional):
|
| 248 |
Causal depthwise widths; the paper uses ``(4, 8, 12)``.
|
| 249 |
msar_backend (:obj:`str`, optional):
|
|
|
|
| 785 |
# ── Attention Residuals (Kimi Team, 2026) ─────────────────────────
|
| 786 |
use_attn_res=False,
|
| 787 |
attn_res_num_blocks=4,
|
| 788 |
+
# MSAR may also be paired with the existing SiameseNorm residual flow.
|
| 789 |
use_msar=False,
|
| 790 |
+
use_ldm=False,
|
| 791 |
msar_block_branches=None, # auto: approximately eight depth blocks
|
| 792 |
msar_kernel_sizes=(4, 8, 12),
|
| 793 |
msar_backend="auto", # Triton on CUDA, Torch on CPU; "torch" is a reference
|
|
|
|
| 1119 |
|
| 1120 |
# ── Residual-flow mechanism mutex ─────────────────────────────────
|
| 1121 |
# AttnRes and LAuReL compete directly with residual topology.
|
| 1122 |
+
# StackMemory and MSAR may separately be paired with SiameseNorm. The
|
| 1123 |
+
# hybrid keeps the X/Y updates and reads MSAR's shared branch history.
|
| 1124 |
_residual_flow_flags = {
|
| 1125 |
"use_laurel": bool(use_laurel),
|
| 1126 |
"use_attn_res": bool(use_attn_res),
|
| 1127 |
"use_stack_memory": bool(use_stack_memory),
|
| 1128 |
"use_siamesenorm": bool(use_siamesenorm),
|
| 1129 |
"use_msar": bool(use_msar),
|
| 1130 |
+
"use_ldm": bool(use_ldm),
|
| 1131 |
}
|
| 1132 |
_active_residual_flow = [
|
| 1133 |
name for name, enabled in _residual_flow_flags.items() if enabled
|
|
|
|
| 1138 |
and not bool(use_laurel)
|
| 1139 |
and not bool(use_attn_res)
|
| 1140 |
and not bool(use_msar)
|
| 1141 |
+
and not bool(use_ldm)
|
| 1142 |
)
|
| 1143 |
+
allow_msar_siamese = (
|
| 1144 |
+
bool(use_msar) and bool(use_siamesenorm)
|
| 1145 |
+
and not bool(use_stack_memory) and not bool(use_laurel)
|
| 1146 |
+
and not bool(use_attn_res)
|
| 1147 |
+
and not bool(use_ldm)
|
| 1148 |
+
)
|
| 1149 |
+
allow_ldm_siamese = (
|
| 1150 |
+
bool(use_ldm) and bool(use_siamesenorm)
|
| 1151 |
+
and not any((use_stack_memory, use_laurel, use_attn_res, use_msar))
|
| 1152 |
+
)
|
| 1153 |
+
if len(_active_residual_flow) > 1 and not (allow_stack_siamese or allow_msar_siamese or allow_ldm_siamese):
|
| 1154 |
raise ValueError(
|
| 1155 |
"Enable at most one residual-flow mechanism among "
|
| 1156 |
"`use_laurel`, `use_attn_res`, `use_stack_memory`, "
|
| 1157 |
+
"`use_siamesenorm`, `use_msar`, and `use_ldm`, except the explicit "
|
| 1158 |
+
"`use_stack_memory` + `use_siamesenorm` and "
|
| 1159 |
+
"`use_msar` + `use_siamesenorm` and `use_ldm` + `use_siamesenorm` pairs. "
|
| 1160 |
f"Active flags: {_active_residual_flow}."
|
| 1161 |
)
|
| 1162 |
|
|
|
|
| 1166 |
"`use_msar=True` cannot be combined with `use_gpas`, "
|
| 1167 |
"`use_fan_residual`, or `use_dagformer`."
|
| 1168 |
)
|
| 1169 |
+
if use_ldm and (use_gpas or use_fan_residual or use_dagformer):
|
| 1170 |
+
raise ValueError(
|
| 1171 |
+
"`use_ldm=True` cannot be combined with `use_gpas`, "
|
| 1172 |
+
"`use_fan_residual`, or `use_dagformer`."
|
| 1173 |
+
)
|
| 1174 |
if msar_block_branches is None:
|
| 1175 |
+
# Branch granularity counts attention and MLP independently. Do not
|
| 1176 |
+
# round to whole decoder layers: e.g. 24 branches / 8 = 3.
|
| 1177 |
+
msar_block_branches = max(1, math.ceil(2 * num_hidden_layers / 8))
|
| 1178 |
if isinstance(msar_block_branches, bool) or not isinstance(msar_block_branches, int) or msar_block_branches < 1:
|
| 1179 |
raise ValueError("`msar_block_branches` must be a positive integer.")
|
| 1180 |
if (not isinstance(msar_kernel_sizes, (tuple, list)) or not msar_kernel_sizes
|
|
|
|
| 1416 |
# Memory cost: O(num_blocks × batch × seq × hidden) instead of
|
| 1417 |
# O(num_layers × batch × seq × hidden).
|
| 1418 |
self.use_msar = bool(use_msar)
|
| 1419 |
+
self.use_ldm = bool(use_ldm)
|
| 1420 |
+
# Follow the paper's value width = attention head width, even when
|
| 1421 |
+
# num_attention_heads * head_dim differs from hidden_size. For an
|
| 1422 |
+
# incompatible width choose the closest divisor without padding values.
|
| 1423 |
+
divisors = (g for g in range(1, hidden_size + 1) if hidden_size % g == 0)
|
| 1424 |
+
self.ldm_groups = min(divisors,
|
| 1425 |
+
key=lambda g: (abs(hidden_size // g - head_dim),
|
| 1426 |
+
abs(g - num_attention_heads)))
|
| 1427 |
+
self.ldm_key_dim = min(8, hidden_size // self.ldm_groups)
|
| 1428 |
+
self.ldm_hidden_dim = min(32, hidden_size)
|
| 1429 |
self.msar_block_branches = msar_block_branches
|
| 1430 |
self.msar_kernel_sizes = tuple(msar_kernel_sizes)
|
| 1431 |
self.msar_backend = msar_backend
|
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.22.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:30daee49b68ae04dcd13eaf707ee60e1ae2daaf2acb5ff9cf4f0f93975e6fff7
|
| 3 |
+
size 169184776
|
modeling_neollm.py
CHANGED
|
@@ -76,6 +76,8 @@ References:
|
|
| 76 |
arXiv:2601.15380.
|
| 77 |
StackMemory / STACKTRANS: Zhang et al. (2025). "Recursive Transformer:
|
| 78 |
Boosting Reasoning Ability with State Stack." NeurIPS 2025.
|
|
|
|
|
|
|
| 79 |
HOLA: Cui (2026). "A Hippocampus for Linear Attention: An Exact Memory
|
| 80 |
for What the Recurrent State Forgets." arXiv:2607.02303.
|
| 81 |
TWEO: Liang et al. (2026). "Transformers Without Extreme Outliers Enables
|
|
@@ -6718,11 +6720,12 @@ def _msar_reference_read(sources, banks, query, valid, position, widths, eps):
|
|
| 6718 |
|
| 6719 |
if triton is not None:
|
| 6720 |
@triton.jit
|
| 6721 |
-
def _msar_read_kernel(SOURCES, BANKS, QUERY, VALID, POSITION, OUT, LSE,
|
| 6722 |
T: tl.constexpr, D: tl.constexpr, NS: tl.constexpr,
|
| 6723 |
M: tl.constexpr,
|
| 6724 |
-
WIDTHS: tl.constexpr, EPS: tl.constexpr, BD: tl.constexpr
|
| 6725 |
-
|
|
|
|
| 6726 |
row = tl.program_id(0)
|
| 6727 |
stream = tl.program_id(1)
|
| 6728 |
batch = row // T
|
|
@@ -6734,7 +6737,11 @@ if triton is not None:
|
|
| 6734 |
q = tl.load(QUERY + stream * D + c, mask_c, other=0).to(tl.float32)
|
| 6735 |
running_max = tl.full((), -float('inf'), tl.float32)
|
| 6736 |
denom = tl.full((), 0., tl.float32)
|
| 6737 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6738 |
for i in tl.static_range(NS):
|
| 6739 |
value = tl.full((BD,), 0., tl.float32)
|
| 6740 |
if stream == 0:
|
|
@@ -6743,7 +6750,7 @@ if triton is not None:
|
|
| 6743 |
offset = 0
|
| 6744 |
for r in tl.static_range(len(WIDTHS)):
|
| 6745 |
if stream == r + 1:
|
| 6746 |
-
for delta in tl.static_range(WIDTHS[r]):
|
| 6747 |
past = row - delta
|
| 6748 |
in_seq = token >= delta
|
| 6749 |
past_valid = tl.load(VALID + past, in_seq, other=0).to(tl.int1)
|
|
@@ -6760,91 +6767,141 @@ if triton is not None:
|
|
| 6760 |
new_max = tl.maximum(running_max, score)
|
| 6761 |
old_weight = tl.exp(running_max - new_max)
|
| 6762 |
new_weight = tl.exp(score - new_max)
|
| 6763 |
-
|
|
|
|
|
|
|
|
|
|
| 6764 |
denom = denom * old_weight + new_weight
|
| 6765 |
running_max = new_max
|
| 6766 |
-
|
| 6767 |
-
|
|
|
|
|
|
|
|
|
|
| 6768 |
|
| 6769 |
|
| 6770 |
@triton.jit
|
| 6771 |
-
def _msar_vjp_value(SOURCE, BANK, QUERY, VALID, POSITION, LSE,
|
| 6772 |
ROWS: tl.constexpr, T: tl.constexpr, D: tl.constexpr,
|
| 6773 |
M: tl.constexpr,
|
| 6774 |
WIDTHS: tl.constexpr, EPS: tl.constexpr, R: tl.constexpr,
|
| 6775 |
-
BD: tl.constexpr, GROUPS: tl.constexpr):
|
| 6776 |
-
"""
|
| 6777 |
group = tl.program_id(0)
|
| 6778 |
-
|
|
|
|
| 6779 |
row = group * R + tl.arange(0, R)
|
| 6780 |
c = tl.arange(0, BD)
|
| 6781 |
row_ok = row < ROWS
|
| 6782 |
-
tok = row % T
|
| 6783 |
-
valid = tl.load(VALID + row, row_ok, other=0).to(tl.int1)
|
| 6784 |
-
pos = tl.load(POSITION + row, row_ok, other=0)
|
| 6785 |
-
q = tl.load(QUERY + stream*D+c, c < D, other=0).to(tl.float32)
|
| 6786 |
-
v = tl.full((R, BD), 0., tl.float32)
|
| 6787 |
-
if stream == 0:
|
| 6788 |
-
v = tl.load(SOURCE + row[:,None]*D+c[None,:],
|
| 6789 |
-
row_ok[:,None] & valid[:,None] & (c[None,:] < D), other=0).to(tl.float32)
|
| 6790 |
-
offset = 0
|
| 6791 |
-
for r in tl.static_range(len(WIDTHS)):
|
| 6792 |
-
if stream == r+1:
|
| 6793 |
-
for delta in tl.static_range(WIDTHS[r]):
|
| 6794 |
-
past = row - delta
|
| 6795 |
-
in_seq = row_ok & (tok >= delta)
|
| 6796 |
-
pv = tl.load(VALID + past, in_seq, other=0).to(tl.int1)
|
| 6797 |
-
pp = tl.load(POSITION + past, in_seq, other=0)
|
| 6798 |
-
allowed = in_seq & valid & pv & ((pos-pp) == delta)
|
| 6799 |
-
x = tl.load(SOURCE + past[:,None]*D+c[None,:],
|
| 6800 |
-
allowed[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6801 |
-
w = tl.load(BANK+(offset+delta)*D+c,
|
| 6802 |
-
c<D, other=0).to(tl.float32)
|
| 6803 |
-
v += x*w[None,:]
|
| 6804 |
-
offset += WIDTHS[r]
|
| 6805 |
-
inv = tl.rsqrt(tl.sum(v*v, 1)/D + EPS)
|
| 6806 |
-
qv = tl.sum(v*q[None,:], 1)
|
| 6807 |
lse = tl.load(LSE+row*M+stream, row_ok, other=0)
|
| 6808 |
-
p = tl.exp(qv*inv-lse)
|
| 6809 |
-
z = tl.load(Z+row[:,None]*M*D+stream*D+c[None,:],
|
| 6810 |
-
row_ok[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6811 |
g = tl.load(G+row[:,None]*M*D+stream*D+c[None,:],
|
| 6812 |
row_ok[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6813 |
-
|
| 6814 |
-
|
| 6815 |
-
|
| 6816 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6817 |
row_ok[:,None] & (c[None,:]<D))
|
| 6818 |
-
|
| 6819 |
-
|
|
|
|
|
|
|
| 6820 |
|
| 6821 |
|
| 6822 |
@triton.jit
|
| 6823 |
-
def _msar_vjp_source(
|
| 6824 |
-
|
| 6825 |
-
|
| 6826 |
-
|
| 6827 |
-
|
| 6828 |
-
|
| 6829 |
-
|
| 6830 |
-
|
| 6831 |
-
|
| 6832 |
-
|
| 6833 |
-
|
| 6834 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6835 |
offset = 0
|
| 6836 |
for r in tl.static_range(len(WIDTHS)):
|
| 6837 |
-
for delta in tl.static_range(WIDTHS[r]):
|
| 6838 |
future = row+delta
|
| 6839 |
in_seq = ok & ((token+delta)<T)
|
| 6840 |
fv = tl.load(VALID+future, in_seq, other=0).to(tl.int1)
|
| 6841 |
fp = tl.load(POSITION+future, in_seq, other=0)
|
| 6842 |
allowed = in_seq & valid & fv & ((fp-pos)==delta)
|
| 6843 |
-
|
| 6844 |
-
|
| 6845 |
-
|
|
|
|
| 6846 |
offset += WIDTHS[r]
|
| 6847 |
-
tl.store(DX+
|
| 6848 |
|
| 6849 |
|
| 6850 |
@triton.jit
|
|
@@ -6861,21 +6918,78 @@ if triton is not None:
|
|
| 6861 |
pos = tl.load(POSITION+row, ok, other=0)
|
| 6862 |
offset = 0
|
| 6863 |
for r in tl.static_range(len(WIDTHS)):
|
| 6864 |
-
grad = tl.load(DV+
|
| 6865 |
ok[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6866 |
for delta in tl.static_range(WIDTHS[r]):
|
| 6867 |
-
|
| 6868 |
-
|
| 6869 |
-
|
| 6870 |
-
|
| 6871 |
-
|
| 6872 |
-
|
| 6873 |
-
|
| 6874 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6875 |
tl.store(WPART+(offset+delta)*GROUPS*D+group*D+c, part, c<D)
|
| 6876 |
offset += WIDTHS[r]
|
| 6877 |
|
| 6878 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6879 |
@torch.library.custom_op("neollm_msar::read", mutates_args=())
|
| 6880 |
def _msar_read_op(sources: list[torch.Tensor], banks: list[torch.Tensor],
|
| 6881 |
query: torch.Tensor, valid: torch.Tensor, position: torch.Tensor,
|
|
@@ -6888,9 +7002,10 @@ def _msar_read_op(sources: list[torch.Tensor], banks: list[torch.Tensor],
|
|
| 6888 |
position = position.contiguous()
|
| 6889 |
result = sources[0].new_empty((b, t, len(widths)+1, d))
|
| 6890 |
lse = torch.empty((b,t,len(widths)+1),device=result.device,dtype=torch.float32)
|
| 6891 |
-
|
| 6892 |
-
|
| 6893 |
-
|
|
|
|
| 6894 |
return result, lse
|
| 6895 |
|
| 6896 |
|
|
@@ -6906,38 +7021,66 @@ def _msar_backward_op(sources: list[torch.Tensor], banks: list[torch.Tensor],
|
|
| 6906 |
query: torch.Tensor, valid: torch.Tensor, position: torch.Tensor,
|
| 6907 |
widths: list[int], eps: float,
|
| 6908 |
grad: torch.Tensor, lse: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tensor], torch.Tensor]:
|
| 6909 |
-
"""Fused VJP with
|
| 6910 |
b, t, d = sources[0].shape
|
| 6911 |
n, m, ksum = b*t, len(widths)+1, sum(widths)
|
|
|
|
|
|
|
|
|
|
| 6912 |
sources = [x.contiguous() for x in sources]
|
| 6913 |
banks, query = [x.contiguous() for x in banks], query.contiguous()
|
| 6914 |
valid, position, grad = valid.contiguous(), position.contiguous(), grad.contiguous()
|
| 6915 |
-
|
| 6916 |
-
|
| 6917 |
-
|
| 6918 |
-
|
| 6919 |
-
|
| 6920 |
-
|
| 6921 |
-
|
| 6922 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6923 |
qrows = max(1, min(8, 8192 // triton.next_power_of_2(d)))
|
| 6924 |
-
|
| 6925 |
-
|
| 6926 |
-
|
| 6927 |
-
|
|
|
|
|
|
|
|
|
|
| 6928 |
dq = torch.zeros_like(query, dtype=torch.float32)
|
| 6929 |
dws = []
|
| 6930 |
dxs = []
|
| 6931 |
for source, bank in zip(sources, banks):
|
| 6932 |
-
_msar_vjp_value[(qgroups,m)](source,bank,query,valid,position,lse,z,grad,dv,qpart,
|
| 6933 |
-
n,t,d,m,tuple(widths),eps,qrows,triton.next_power_of_2(d),qgroups,num_warps=4)
|
| 6934 |
dx = torch.empty_like(source)
|
| 6935 |
-
|
| 6936 |
-
|
| 6937 |
-
|
| 6938 |
-
|
| 6939 |
-
|
| 6940 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6941 |
dxs.append(dx)
|
| 6942 |
return dxs, dws, dq.to(query.dtype).contiguous()
|
| 6943 |
|
|
@@ -7032,6 +7175,335 @@ def _msar_start_branch(sources, partial, branch, block_size):
|
|
| 7032 |
return sources, partial
|
| 7033 |
|
| 7034 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7035 |
class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
| 7036 |
"""
|
| 7037 |
Decoder layer with standard residual connections.
|
|
@@ -7205,6 +7677,11 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7205 |
self.msar_block_branches = config.msar_block_branches
|
| 7206 |
self.msar_attn_read = MSARRead(config) if self.use_msar else None
|
| 7207 |
self.msar_mlp_read = MSARRead(config) if self.use_msar else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7208 |
self.use_attn_res = getattr(config, "use_attn_res", False)
|
| 7209 |
if self.use_attn_res:
|
| 7210 |
self.attn_res_query_attn = nn.Parameter(torch.zeros(config.hidden_size))
|
|
@@ -7500,19 +7977,43 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7500 |
dag_sources_y=None,
|
| 7501 |
dag_plan=None,
|
| 7502 |
dynamics_valid_mask: Optional[torch.Tensor] = None,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7503 |
**kwargs: Unpack[FlashAttentionKwargs],
|
| 7504 |
) -> Tuple:
|
| 7505 |
-
"""Update
|
| 7506 |
-
|
| 7507 |
-
|
| 7508 |
-
|
| 7509 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7510 |
"""
|
| 7511 |
# SiameseNorm keeps two coupled streams with shared Attention/MLP
|
| 7512 |
# parameters. All Siamese normalization modules are RMSNorm by
|
| 7513 |
# construction; no dynamic-normalization branch remains.
|
| 7514 |
# ── Attention shared block ────────────────────────────────────────
|
| 7515 |
norm_backend = getattr(self, "siamesenorm_kernel_backend", "reference")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7516 |
if norm_backend == "reference":
|
| 7517 |
x_attn_norm = self.siamese_attn_x_norm(x_states)
|
| 7518 |
y_attn_norm = self.siamese_attn_y_norm(y_states)
|
|
@@ -7520,17 +8021,23 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7520 |
dtype=x_attn_norm.dtype, device=x_attn_norm.device
|
| 7521 |
)
|
| 7522 |
h_attn = x_scale * x_attn_norm + y_attn_norm
|
| 7523 |
-
if self.siamese_attn_input_norm is not None:
|
| 7524 |
-
h_attn = self.siamese_attn_input_norm(h_attn)
|
| 7525 |
else:
|
| 7526 |
from cut_cross_entropy.siamesenorm import siamesenorm
|
| 7527 |
h_attn = siamesenorm(
|
| 7528 |
x_states, y_states,
|
| 7529 |
self.siamese_attn_x_norm.weight, self.siamese_attn_y_norm.weight,
|
| 7530 |
-
self.siamese_attn_input_norm.weight
|
|
|
|
| 7531 |
self.siamese_attn_x_scale.to(dtype=x_states.dtype, device=x_states.device),
|
| 7532 |
eps=self.siamese_attn_x_norm.eps, backend=norm_backend,
|
| 7533 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7534 |
|
| 7535 |
stack_metrics = None
|
| 7536 |
if self.use_stack_memory:
|
|
@@ -7566,36 +8073,56 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7566 |
y_states = y_states + dag_ry
|
| 7567 |
x_after_attn = x_states + stream_scale * attn_out
|
| 7568 |
y_after_attn = y_states + attn_out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7569 |
|
| 7570 |
if self.use_gpas:
|
| 7571 |
x_after_attn = self.gpas_attn(x_after_attn)
|
| 7572 |
|
| 7573 |
# ── MLP shared block ──────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7574 |
if norm_backend == "reference":
|
| 7575 |
x_mlp_norm = self.siamese_mlp_x_norm(x_after_attn)
|
| 7576 |
y_mlp_norm = self.siamese_mlp_y_norm(y_after_attn)
|
| 7577 |
h_mlp = x_mlp_norm + y_mlp_norm
|
| 7578 |
-
if self.siamese_mlp_input_norm is not None:
|
| 7579 |
-
h_mlp = self.siamese_mlp_input_norm(h_mlp)
|
| 7580 |
else:
|
| 7581 |
h_mlp = siamesenorm(
|
| 7582 |
x_after_attn, y_after_attn,
|
| 7583 |
self.siamese_mlp_x_norm.weight, self.siamese_mlp_y_norm.weight,
|
| 7584 |
-
self.siamese_mlp_input_norm.weight
|
|
|
|
| 7585 |
eps=self.siamese_mlp_x_norm.eps, backend=norm_backend,
|
| 7586 |
post_scale=(
|
| 7587 |
self.lns_mlp.scale.to(device=x_after_attn.device, dtype=x_after_attn.dtype)
|
| 7588 |
-
if self.use_lns else None
|
| 7589 |
),
|
| 7590 |
out_dtype=(
|
| 7591 |
torch.get_autocast_dtype("cuda")
|
| 7592 |
-
if torch.is_autocast_enabled("cuda") else None
|
| 7593 |
),
|
| 7594 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7595 |
|
| 7596 |
# Only this consumer starts directly with an autocast Linear. Attention
|
| 7597 |
# also exposes native states to positional, router and memory consumers.
|
| 7598 |
-
h_lns2 = self.lns_mlp(h_mlp) if self.use_lns and norm_backend == "reference" else h_mlp
|
| 7599 |
delta_m = self.mlp(h_lns2)
|
| 7600 |
|
| 7601 |
jtok_aux_stats = None
|
|
@@ -7616,11 +8143,21 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7616 |
|
| 7617 |
x_next = x_after_attn + stream_scale * shared_update
|
| 7618 |
y_next = y_after_attn + shared_update
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7619 |
|
| 7620 |
if self.use_gpas:
|
| 7621 |
x_next = self.gpas_mlp(x_next)
|
| 7622 |
|
| 7623 |
outputs = (x_next, y_next)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7624 |
if self.use_stack_memory:
|
| 7625 |
outputs += (stack_memory, stack_memory_mask, stack_metrics)
|
| 7626 |
if jtok_aux_stats is not None:
|
|
@@ -7642,6 +8179,8 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7642 |
msar_banks=None,
|
| 7643 |
msar_valid=None,
|
| 7644 |
msar_position=None,
|
|
|
|
|
|
|
| 7645 |
output_attentions: Optional[bool] = False,
|
| 7646 |
repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
|
| 7647 |
position_ids: Optional[torch.LongTensor] = None,
|
|
@@ -7690,6 +8229,10 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7690 |
h_attn = hidden_states
|
| 7691 |
residual_attn = hidden_states
|
| 7692 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7693 |
# ── Attention block ───────────────────────────────────────────────
|
| 7694 |
|
| 7695 |
# Optional embedding input normalisation:
|
|
@@ -7740,6 +8283,9 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7740 |
attn_aug = residual_attn + hidden_states
|
| 7741 |
|
| 7742 |
h_tilde = self.gpas_attn(attn_aug) if self.use_gpas else attn_aug
|
|
|
|
|
|
|
|
|
|
| 7743 |
|
| 7744 |
# ── Attention Residuals: compute pre-MLP input ────────────────────
|
| 7745 |
# After attention, the partial sum is updated with h_tilde.
|
|
@@ -7764,6 +8310,10 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7764 |
h_mlp = h_tilde
|
| 7765 |
residual_mlp = h_tilde
|
| 7766 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7767 |
# ── MLP block ─────────────────────────────────────────────────────
|
| 7768 |
h_normed2 = _apply_norm(self.post_attention_layernorm, h_mlp)
|
| 7769 |
h_lns2 = self.lns_mlp(h_normed2) if self.use_lns else h_normed2
|
|
@@ -7802,8 +8352,13 @@ class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
|
| 7802 |
mlp_aug = residual_mlp + delta_m
|
| 7803 |
|
| 7804 |
hidden_states = self.gpas_mlp(mlp_aug) if self.use_gpas else mlp_aug
|
|
|
|
|
|
|
|
|
|
| 7805 |
|
| 7806 |
outputs = (hidden_states,)
|
|
|
|
|
|
|
| 7807 |
if self.use_msar:
|
| 7808 |
outputs += (msar_sources, msar_partial)
|
| 7809 |
if jtok_aux_stats is not None:
|
|
@@ -8147,6 +8702,9 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 8147 |
_supports_flash_attn_2 = True
|
| 8148 |
_supports_sdpa = True
|
| 8149 |
_is_stateful = True
|
|
|
|
|
|
|
|
|
|
| 8150 |
|
| 8151 |
@classmethod
|
| 8152 |
def from_pretrained(cls, *args, **kwargs):
|
|
@@ -8250,9 +8808,9 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 8250 |
return model
|
| 8251 |
|
| 8252 |
def _init_weights(self, module):
|
| 8253 |
-
"""Apply HF initialization, then
|
| 8254 |
super()._init_weights(module)
|
| 8255 |
-
if getattr(module, "_dag_zero_init", False):
|
| 8256 |
nn.init.zeros_(module.weight)
|
| 8257 |
nn.init.zeros_(module.bias)
|
| 8258 |
return
|
|
@@ -8520,6 +9078,8 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 8520 |
sum(config.msar_kernel_sizes), config.hidden_size))
|
| 8521 |
if config.use_msar else None
|
| 8522 |
)
|
|
|
|
|
|
|
| 8523 |
self.dagformer = (DAGFormerTopology(config, self.layers)
|
| 8524 |
if bool(getattr(config, "use_dagformer", False)) else None)
|
| 8525 |
self.use_siamesenorm = bool(getattr(config, "use_siamesenorm", False))
|
|
@@ -8862,6 +9422,26 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 8862 |
hidden_states = inputs_embeds
|
| 8863 |
use_siamesenorm = bool(getattr(self.config, "use_siamesenorm", False))
|
| 8864 |
siamese_y_states = inputs_embeds if use_siamesenorm else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8865 |
# The same validated dense/right-padding training contract applies to
|
| 8866 |
# the causal planner: valid queries cannot see future padded keys.
|
| 8867 |
dag_plans = (self.dagformer(input_ids, inputs_embeds, position_ids,
|
|
@@ -9021,18 +9601,28 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 9021 |
dag_sources=dag_sources,
|
| 9022 |
dag_plan=dag_plans[layer_idx] if dag_plans is not None else None,
|
| 9023 |
dynamics_valid_mask=attention_mask,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9024 |
**kwargs,
|
| 9025 |
)
|
| 9026 |
hidden_states = layer_outputs[0]
|
| 9027 |
siamese_y_states = layer_outputs[1]
|
| 9028 |
-
if
|
| 9029 |
-
|
| 9030 |
-
|
| 9031 |
-
|
| 9032 |
-
|
| 9033 |
-
extras_start =
|
| 9034 |
else:
|
| 9035 |
extras_start = 2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9036 |
else:
|
| 9037 |
layer_outputs = decoder_layer(
|
| 9038 |
hidden_states,
|
|
@@ -9044,6 +9634,7 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 9044 |
msar_sources=msar_sources, msar_partial=msar_partial,
|
| 9045 |
msar_banks=self.msar_banks, msar_valid=msar_valid,
|
| 9046 |
msar_position=msar_position,
|
|
|
|
| 9047 |
output_attentions=output_attentions,
|
| 9048 |
repo_rope_args=repo_rope_args,
|
| 9049 |
position_ids=position_ids,
|
|
@@ -9061,6 +9652,9 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 9061 |
extras_start = 3
|
| 9062 |
# The last branch's h_mlp + delta_m is the terminal
|
| 9063 |
# residual merge. No new source expansion is applied.
|
|
|
|
|
|
|
|
|
|
| 9064 |
else:
|
| 9065 |
extras_start = 1
|
| 9066 |
|
|
@@ -9106,7 +9700,11 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 9106 |
|
| 9107 |
if use_siamesenorm:
|
| 9108 |
norm_backend = getattr(self, "siamesenorm_kernel_backend", "reference")
|
| 9109 |
-
if
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9110 |
hidden_states = self.siamese_final_norm(
|
| 9111 |
self.siamese_x_final_norm(hidden_states)
|
| 9112 |
+ self.siamese_y_final_norm(siamese_y_states)
|
|
@@ -9120,6 +9718,9 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 9120 |
eps=self.siamese_x_final_norm.eps, backend=norm_backend,
|
| 9121 |
)
|
| 9122 |
else:
|
|
|
|
|
|
|
|
|
|
| 9123 |
hidden_states = self.norm(hidden_states)
|
| 9124 |
|
| 9125 |
if output_hidden_states:
|
|
@@ -11431,6 +12032,17 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 11431 |
for name, parameter in module.named_parameters():
|
| 11432 |
if parameter.requires_grad:
|
| 11433 |
groups[f"{kind}/layer_{module.layer_idx}/{name}"] = (parameter,)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11434 |
families = {
|
| 11435 |
"dag": ("dagformer_local",),
|
| 11436 |
"attnres": ("attn_res_query_attn", "attn_res_query_mlp", "attn_res_norm"),
|
|
@@ -11453,6 +12065,8 @@ class NeoLLMForCausalLM(NeoLLMPreTrainedModel, GenerationMixin):
|
|
| 11453 |
groups[f"fan/layer_{layer.layer_idx}"] = (layer.self_attn.lambda_1, layer.self_attn.lambda_2)
|
| 11454 |
if self.model.dagformer is not None:
|
| 11455 |
groups["dag/global_topology"] = tuple(p for p in self.model.dagformer.parameters() if p.requires_grad)
|
|
|
|
|
|
|
| 11456 |
return groups
|
| 11457 |
|
| 11458 |
def set_input_embeddings(self, value):
|
|
|
|
| 76 |
arXiv:2601.15380.
|
| 77 |
StackMemory / STACKTRANS: Zhang et al. (2025). "Recursive Transformer:
|
| 78 |
Boosting Reasoning Ability with State Stack." NeurIPS 2025.
|
| 79 |
+
Linear Depth Memory: González-Martínez et al. (2026). "Depth Memory."
|
| 80 |
+
arXiv:2610.18809; flexible Triton backend adapted under the MIT license.
|
| 81 |
HOLA: Cui (2026). "A Hippocampus for Linear Attention: An Exact Memory
|
| 82 |
for What the Recurrent State Forgets." arXiv:2607.02303.
|
| 83 |
TWEO: Liang et al. (2026). "Transformers Without Extreme Outliers Enables
|
|
|
|
| 6720 |
|
| 6721 |
if triton is not None:
|
| 6722 |
@triton.jit
|
| 6723 |
+
def _msar_read_kernel(SOURCES, BANKS, QUERY, VALID, POSITION, OUT, LSE, GRAD,
|
| 6724 |
T: tl.constexpr, D: tl.constexpr, NS: tl.constexpr,
|
| 6725 |
M: tl.constexpr,
|
| 6726 |
+
WIDTHS: tl.constexpr, EPS: tl.constexpr, BD: tl.constexpr,
|
| 6727 |
+
DOT_ONLY: tl.constexpr):
|
| 6728 |
+
"""Read depth streams, or recompute only the backward scalar <g,z>."""
|
| 6729 |
row = tl.program_id(0)
|
| 6730 |
stream = tl.program_id(1)
|
| 6731 |
batch = row // T
|
|
|
|
| 6737 |
q = tl.load(QUERY + stream * D + c, mask_c, other=0).to(tl.float32)
|
| 6738 |
running_max = tl.full((), -float('inf'), tl.float32)
|
| 6739 |
denom = tl.full((), 0., tl.float32)
|
| 6740 |
+
if DOT_ONLY:
|
| 6741 |
+
g = tl.load(GRAD + row * M * D + stream * D + c, mask_c, other=0).to(tl.float32)
|
| 6742 |
+
dot = tl.full((), 0., tl.float32)
|
| 6743 |
+
else:
|
| 6744 |
+
accum = tl.full((BD,), 0., tl.float32)
|
| 6745 |
for i in tl.static_range(NS):
|
| 6746 |
value = tl.full((BD,), 0., tl.float32)
|
| 6747 |
if stream == 0:
|
|
|
|
| 6750 |
offset = 0
|
| 6751 |
for r in tl.static_range(len(WIDTHS)):
|
| 6752 |
if stream == r + 1:
|
| 6753 |
+
for delta in tl.static_range(min(WIDTHS[r], T)):
|
| 6754 |
past = row - delta
|
| 6755 |
in_seq = token >= delta
|
| 6756 |
past_valid = tl.load(VALID + past, in_seq, other=0).to(tl.int1)
|
|
|
|
| 6767 |
new_max = tl.maximum(running_max, score)
|
| 6768 |
old_weight = tl.exp(running_max - new_max)
|
| 6769 |
new_weight = tl.exp(score - new_max)
|
| 6770 |
+
if DOT_ONLY:
|
| 6771 |
+
dot = dot * old_weight + tl.sum(g * value, 0) * new_weight
|
| 6772 |
+
else:
|
| 6773 |
+
accum = accum * old_weight + value * new_weight
|
| 6774 |
denom = denom * old_weight + new_weight
|
| 6775 |
running_max = new_max
|
| 6776 |
+
if DOT_ONLY:
|
| 6777 |
+
tl.store(OUT + row * M + stream, dot / denom)
|
| 6778 |
+
else:
|
| 6779 |
+
tl.store(OUT + row * M * D + stream * D + c, accum / denom, mask_c)
|
| 6780 |
+
tl.store(LSE + row * M + stream, running_max + tl.log(denom))
|
| 6781 |
|
| 6782 |
|
| 6783 |
@triton.jit
|
| 6784 |
+
def _msar_vjp_value(SOURCE, BANK, QUERY, VALID, POSITION, LSE, GDOT, G, DV, QPART,
|
| 6785 |
ROWS: tl.constexpr, T: tl.constexpr, D: tl.constexpr,
|
| 6786 |
M: tl.constexpr,
|
| 6787 |
WIDTHS: tl.constexpr, EPS: tl.constexpr, R: tl.constexpr,
|
| 6788 |
+
BD: tl.constexpr, GROUPS: tl.constexpr, SINGLE_SOURCE: tl.constexpr):
|
| 6789 |
+
"""Materialize convolution-view VJPs and their query partials."""
|
| 6790 |
group = tl.program_id(0)
|
| 6791 |
+
# Identity is handled by _msar_vjp_source: avoid its full DV buffer.
|
| 6792 |
+
stream = tl.program_id(1) + 1
|
| 6793 |
row = group * R + tl.arange(0, R)
|
| 6794 |
c = tl.arange(0, BD)
|
| 6795 |
row_ok = row < ROWS
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6796 |
lse = tl.load(LSE+row*M+stream, row_ok, other=0)
|
|
|
|
|
|
|
|
|
|
| 6797 |
g = tl.load(G+row[:,None]*M*D+stream*D+c[None,:],
|
| 6798 |
row_ok[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6799 |
+
if SINGLE_SOURCE:
|
| 6800 |
+
# A finite one-entry softmax is constant: dv=g and dq=0. The
|
| 6801 |
+
# saved LSE and upstream gradient detect nonfinite inputs without
|
| 6802 |
+
# reconstructing any convolution or forming score derivatives.
|
| 6803 |
+
bad_g = tl.sum(((tl.abs(g) >= float('inf')) | (g != g)).to(tl.int32), 1) > 0
|
| 6804 |
+
finite = (tl.abs(lse) < float('inf')) & ~bad_g
|
| 6805 |
+
dv = tl.where(finite[:,None], g, float('nan'))
|
| 6806 |
+
bad_rows = tl.sum((~finite & row_ok).to(tl.int32), 0) > 0
|
| 6807 |
+
# The query VJP is identically zero for a finite one-source
|
| 6808 |
+
# softmax. All D components have the same zero/NaN status, so
|
| 6809 |
+
# store one scalar per row group rather than D identical values.
|
| 6810 |
+
qp = tl.where(bad_rows, float('nan'), 0.)
|
| 6811 |
+
else:
|
| 6812 |
+
tok = row % T
|
| 6813 |
+
valid = tl.load(VALID + row, row_ok, other=0).to(tl.int1)
|
| 6814 |
+
pos = tl.load(POSITION + row, row_ok, other=0)
|
| 6815 |
+
q = tl.load(QUERY + stream*D+c, c < D, other=0).to(tl.float32)
|
| 6816 |
+
v = tl.full((R, BD), 0., tl.float32)
|
| 6817 |
+
offset = 0
|
| 6818 |
+
for r in tl.static_range(len(WIDTHS)):
|
| 6819 |
+
if stream == r+1:
|
| 6820 |
+
for delta in tl.static_range(min(WIDTHS[r], T)):
|
| 6821 |
+
past = row - delta
|
| 6822 |
+
in_seq = row_ok & (tok >= delta)
|
| 6823 |
+
pv = tl.load(VALID + past, in_seq, other=0).to(tl.int1)
|
| 6824 |
+
pp = tl.load(POSITION + past, in_seq, other=0)
|
| 6825 |
+
allowed = in_seq & valid & pv & ((pos-pp) == delta)
|
| 6826 |
+
x = tl.load(SOURCE + past[:,None]*D+c[None,:],
|
| 6827 |
+
allowed[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6828 |
+
w = tl.load(BANK+(offset+delta)*D+c,
|
| 6829 |
+
c<D, other=0).to(tl.float32)
|
| 6830 |
+
v += x*w[None,:]
|
| 6831 |
+
offset += WIDTHS[r]
|
| 6832 |
+
inv = tl.rsqrt(tl.sum(v*v, 1)/D + EPS)
|
| 6833 |
+
qv = tl.sum(v*q[None,:], 1)
|
| 6834 |
+
p = tl.exp(qv*inv-lse)
|
| 6835 |
+
gv = tl.sum(g*v, 1)
|
| 6836 |
+
gdot = tl.load(GDOT+row*M+stream, row_ok, other=0)
|
| 6837 |
+
ds = p*(gv-gdot)
|
| 6838 |
+
dv = p[:,None]*g + ds[:,None]*(q[None,:]*inv[:,None] -
|
| 6839 |
+
v*(qv*inv*inv*inv/D)[:,None])
|
| 6840 |
+
qp = tl.sum(ds[:,None]*v*inv[:,None], 0)
|
| 6841 |
+
tl.store(DV+(stream-1)*ROWS*D+row[:,None]*D+c[None,:], dv,
|
| 6842 |
row_ok[:,None] & (c[None,:]<D))
|
| 6843 |
+
if SINGLE_SOURCE:
|
| 6844 |
+
tl.store(QPART+stream*GROUPS+group, qp)
|
| 6845 |
+
else:
|
| 6846 |
+
tl.store(QPART+stream*GROUPS*D+group*D+c, qp, c<D)
|
| 6847 |
|
| 6848 |
|
| 6849 |
@triton.jit
|
| 6850 |
+
def _msar_vjp_source(SOURCE, BANK, QUERY, VALID, POSITION, LSE, GDOT, G, DV, QPART, DX,
|
| 6851 |
+
ROWS: tl.constexpr, T: tl.constexpr, D: tl.constexpr, M: tl.constexpr,
|
| 6852 |
+
WIDTHS: tl.constexpr, EPS: tl.constexpr, R: tl.constexpr,
|
| 6853 |
+
BD: tl.constexpr, GROUPS: tl.constexpr, SINGLE_SOURCE: tl.constexpr):
|
| 6854 |
+
"""Fuse the identity-view VJP into the convolution input transpose.
|
| 6855 |
+
|
| 6856 |
+
The identity query partial is still reduced in FP32. For a finite
|
| 6857 |
+
one-source softmax its query VJP is exactly zero; nonfinite rows keep
|
| 6858 |
+
the same NaN propagation as the materialized implementation.
|
| 6859 |
+
"""
|
| 6860 |
+
group = tl.program_id(0)
|
| 6861 |
+
row = group * R + tl.arange(0, R)
|
| 6862 |
+
c = tl.arange(0, BD)
|
| 6863 |
+
ok = row < ROWS
|
| 6864 |
+
token = row % T
|
| 6865 |
+
valid = tl.load(VALID + row, ok, other=0).to(tl.int1)
|
| 6866 |
+
pos = tl.load(POSITION + row, ok, other=0)
|
| 6867 |
+
lse = tl.load(LSE + row * M, ok, other=0)
|
| 6868 |
+
g = tl.load(G + row[:,None] * M * D + c[None,:],
|
| 6869 |
+
ok[:,None] & (c[None,:] < D), other=0).to(tl.float32)
|
| 6870 |
+
if SINGLE_SOURCE:
|
| 6871 |
+
bad_g = tl.sum(((tl.abs(g) >= float('inf')) | (g != g)).to(tl.int32), 1) > 0
|
| 6872 |
+
finite = (tl.abs(lse) < float('inf')) & ~bad_g
|
| 6873 |
+
identity_vjp = tl.where(finite[:,None], g, float('nan'))
|
| 6874 |
+
bad_rows = tl.sum((~finite & ok).to(tl.int32), 0) > 0
|
| 6875 |
+
tl.store(QPART + group, tl.where(bad_rows, float('nan'), 0.))
|
| 6876 |
+
else:
|
| 6877 |
+
q = tl.load(QUERY + c, c < D, other=0).to(tl.float32)
|
| 6878 |
+
v = tl.load(SOURCE + row[:,None] * D + c[None,:],
|
| 6879 |
+
ok[:,None] & valid[:,None] & (c[None,:] < D), other=0).to(tl.float32)
|
| 6880 |
+
inv = tl.rsqrt(tl.sum(v*v, 1) / D + EPS)
|
| 6881 |
+
qv = tl.sum(v*q[None,:], 1)
|
| 6882 |
+
p = tl.exp(qv*inv-lse)
|
| 6883 |
+
gv = tl.sum(g*v, 1)
|
| 6884 |
+
gdot = tl.load(GDOT + row*M, ok, other=0)
|
| 6885 |
+
ds = p*(gv-gdot)
|
| 6886 |
+
identity_vjp = p[:,None]*g + ds[:,None]*(q[None,:]*inv[:,None] -
|
| 6887 |
+
v*(qv*inv*inv*inv/D)[:,None])
|
| 6888 |
+
qp = tl.sum(ds[:,None]*v*inv[:,None], 0)
|
| 6889 |
+
tl.store(QPART + group*D + c, qp, c < D)
|
| 6890 |
+
dx = tl.where(valid[:,None], identity_vjp, 0.)
|
| 6891 |
offset = 0
|
| 6892 |
for r in tl.static_range(len(WIDTHS)):
|
| 6893 |
+
for delta in tl.static_range(min(WIDTHS[r], T)):
|
| 6894 |
future = row+delta
|
| 6895 |
in_seq = ok & ((token+delta)<T)
|
| 6896 |
fv = tl.load(VALID+future, in_seq, other=0).to(tl.int1)
|
| 6897 |
fp = tl.load(POSITION+future, in_seq, other=0)
|
| 6898 |
allowed = in_seq & valid & fv & ((fp-pos)==delta)
|
| 6899 |
+
dv = tl.load(DV+r*ROWS*D+future[:,None]*D+c[None,:],
|
| 6900 |
+
allowed[:,None] & (c[None,:]<D), other=0)
|
| 6901 |
+
w = tl.load(BANK+(offset+delta)*D+c, c<D, other=0).to(tl.float32)
|
| 6902 |
+
dx += dv*w[None,:]
|
| 6903 |
offset += WIDTHS[r]
|
| 6904 |
+
tl.store(DX+row[:,None]*D+c[None,:], dx, ok[:,None] & (c[None,:]<D))
|
| 6905 |
|
| 6906 |
|
| 6907 |
@triton.jit
|
|
|
|
| 6918 |
pos = tl.load(POSITION+row, ok, other=0)
|
| 6919 |
offset = 0
|
| 6920 |
for r in tl.static_range(len(WIDTHS)):
|
| 6921 |
+
grad = tl.load(DV+r*ROWS*D+row[:,None]*D+c[None,:],
|
| 6922 |
ok[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6923 |
for delta in tl.static_range(WIDTHS[r]):
|
| 6924 |
+
if delta < T:
|
| 6925 |
+
past = row-delta
|
| 6926 |
+
in_seq = ok & (tok>=delta)
|
| 6927 |
+
pv = tl.load(VALID+past, in_seq, other=0).to(tl.int1)
|
| 6928 |
+
pp = tl.load(POSITION+past, in_seq, other=0)
|
| 6929 |
+
allowed = in_seq & valid & pv & ((pos-pp)==delta)
|
| 6930 |
+
x = tl.load(SOURCE+past[:,None]*D+c[None,:],
|
| 6931 |
+
allowed[:,None] & (c[None,:]<D), other=0).to(tl.float32)
|
| 6932 |
+
part = tl.sum(grad*x, 0)
|
| 6933 |
+
else:
|
| 6934 |
+
# These convolution taps cannot be reached by any token.
|
| 6935 |
+
# The partial buffer is uninitialized, so write exact zero.
|
| 6936 |
+
part = tl.full((C,), 0., tl.float32)
|
| 6937 |
tl.store(WPART+(offset+delta)*GROUPS*D+group*D+c, part, c<D)
|
| 6938 |
offset += WIDTHS[r]
|
| 6939 |
|
| 6940 |
|
| 6941 |
+
@triton.jit
|
| 6942 |
+
def _msar_reduce_query_bank(QPART, WPART, DQ, DW, D: tl.constexpr,
|
| 6943 |
+
M: tl.constexpr, KSUM: tl.constexpr,
|
| 6944 |
+
QGROUPS: tl.constexpr, WGROUPS: tl.constexpr,
|
| 6945 |
+
C: tl.constexpr, REDUCE_ROWS: tl.constexpr,
|
| 6946 |
+
FIRST_TILE: tl.constexpr, SINGLE_SOURCE: tl.constexpr):
|
| 6947 |
+
"""Accumulate query and bank partials in FP32 in one launch.
|
| 6948 |
+
|
| 6949 |
+
A source tile contributes to ``DQ`` across all sources and tiles;
|
| 6950 |
+
``DW`` belongs to one source and is initialized by its first tile.
|
| 6951 |
+
The single-source query partial is one zero/NaN scalar per row group.
|
| 6952 |
+
Chunked reductions accumulate in FP32, but their order need not be
|
| 6953 |
+
bit-identical to the framework's separate reductions.
|
| 6954 |
+
"""
|
| 6955 |
+
pid = tl.program_id(0)
|
| 6956 |
+
column_blocks = tl.cdiv(D, C)
|
| 6957 |
+
if pid < M * column_blocks:
|
| 6958 |
+
q_stream = pid // column_blocks
|
| 6959 |
+
q_col = (pid % column_blocks)*C + tl.arange(0, C)
|
| 6960 |
+
q_offsets = tl.arange(0, REDUCE_ROWS)
|
| 6961 |
+
if SINGLE_SOURCE:
|
| 6962 |
+
q_sum = tl.full((), 0., tl.float32)
|
| 6963 |
+
for q_start in range(tl.cdiv(QGROUPS, REDUCE_ROWS)):
|
| 6964 |
+
q_row = q_start*REDUCE_ROWS + q_offsets
|
| 6965 |
+
q_value = tl.load(QPART + q_stream*QGROUPS + q_row,
|
| 6966 |
+
q_row < QGROUPS, other=0)
|
| 6967 |
+
q_sum += tl.sum(q_value, 0)
|
| 6968 |
+
else:
|
| 6969 |
+
q_sum = tl.full((C,), 0., tl.float32)
|
| 6970 |
+
for q_start in range(tl.cdiv(QGROUPS, REDUCE_ROWS)):
|
| 6971 |
+
q_row = q_start*REDUCE_ROWS + q_offsets
|
| 6972 |
+
q_value = tl.load(QPART + q_stream*QGROUPS*D + q_row[:,None]*D + q_col[None,:],
|
| 6973 |
+
(q_row[:,None] < QGROUPS) & (q_col[None,:] < D), other=0)
|
| 6974 |
+
q_sum += tl.sum(q_value, 0)
|
| 6975 |
+
previous_q = tl.load(DQ + q_stream*D + q_col, q_col < D, other=0)
|
| 6976 |
+
tl.store(DQ + q_stream*D + q_col, previous_q + q_sum, q_col < D)
|
| 6977 |
+
else:
|
| 6978 |
+
bank_pid = pid - M * column_blocks
|
| 6979 |
+
bank_tap = bank_pid // column_blocks
|
| 6980 |
+
bank_col = (bank_pid % column_blocks)*C + tl.arange(0, C)
|
| 6981 |
+
bank_offsets = tl.arange(0, REDUCE_ROWS)
|
| 6982 |
+
bank_sum = tl.full((C,), 0., tl.float32)
|
| 6983 |
+
for bank_start in range(tl.cdiv(WGROUPS, REDUCE_ROWS)):
|
| 6984 |
+
bank_row = bank_start*REDUCE_ROWS + bank_offsets
|
| 6985 |
+
bank_value = tl.load(WPART + bank_tap*WGROUPS*D + bank_row[:,None]*D + bank_col[None,:],
|
| 6986 |
+
(bank_row[:,None] < WGROUPS) & (bank_col[None,:] < D), other=0)
|
| 6987 |
+
bank_sum += tl.sum(bank_value, 0)
|
| 6988 |
+
if not FIRST_TILE:
|
| 6989 |
+
bank_sum += tl.load(DW + bank_tap*D + bank_col, bank_col < D, other=0)
|
| 6990 |
+
tl.store(DW + bank_tap*D + bank_col, bank_sum, bank_col < D)
|
| 6991 |
+
|
| 6992 |
+
|
| 6993 |
@torch.library.custom_op("neollm_msar::read", mutates_args=())
|
| 6994 |
def _msar_read_op(sources: list[torch.Tensor], banks: list[torch.Tensor],
|
| 6995 |
query: torch.Tensor, valid: torch.Tensor, position: torch.Tensor,
|
|
|
|
| 7002 |
position = position.contiguous()
|
| 7003 |
result = sources[0].new_empty((b, t, len(widths)+1, d))
|
| 7004 |
lse = torch.empty((b,t,len(widths)+1),device=result.device,dtype=torch.float32)
|
| 7005 |
+
if b*t:
|
| 7006 |
+
_msar_read_kernel[(b*t, len(widths)+1)](tuple(sources), tuple(banks), query, valid, position,
|
| 7007 |
+
result, lse, None, t, d, len(sources), len(widths)+1,
|
| 7008 |
+
tuple(widths), eps, triton.next_power_of_2(d), False, num_warps=4)
|
| 7009 |
return result, lse
|
| 7010 |
|
| 7011 |
|
|
|
|
| 7021 |
query: torch.Tensor, valid: torch.Tensor, position: torch.Tensor,
|
| 7022 |
widths: list[int], eps: float,
|
| 7023 |
grad: torch.Tensor, lse: torch.Tensor) -> tuple[list[torch.Tensor], list[torch.Tensor], torch.Tensor]:
|
| 7024 |
+
"""Fused VJP with FP32 scalar recomputation and one-source workspace."""
|
| 7025 |
b, t, d = sources[0].shape
|
| 7026 |
n, m, ksum = b*t, len(widths)+1, sum(widths)
|
| 7027 |
+
if not n:
|
| 7028 |
+
return ([torch.empty_like(source) for source in sources],
|
| 7029 |
+
[torch.zeros_like(bank) for bank in banks], torch.zeros_like(query))
|
| 7030 |
sources = [x.contiguous() for x in sources]
|
| 7031 |
banks, query = [x.contiguous() for x in banks], query.contiguous()
|
| 7032 |
valid, position, grad = valid.contiguous(), position.contiguous(), grad.contiguous()
|
| 7033 |
+
single = len(sources) == 1
|
| 7034 |
+
# ds_i = p_i * (<g,v_i> - <g,z>); recompute the scalar <g,z>
|
| 7035 |
+
# directly rather than materializing all FP32 stream vectors z. A single
|
| 7036 |
+
# finite source has ds=0, so that specialization skips recomputation.
|
| 7037 |
+
gdot = lse
|
| 7038 |
+
if not single:
|
| 7039 |
+
gdot = torch.empty((b,t,m),device=grad.device,dtype=torch.float32)
|
| 7040 |
+
_msar_read_kernel[(n,m)](tuple(sources), tuple(banks), query, valid, position, gdot, lse, grad,
|
| 7041 |
+
t,d,len(sources),m,tuple(widths),eps,
|
| 7042 |
+
triton.next_power_of_2(d),True,num_warps=4)
|
| 7043 |
+
# Process complete sequences together so convolution never crosses a tile.
|
| 7044 |
+
# Bound temporary storage automatically by both geometry and device memory;
|
| 7045 |
+
# at least one sequence fits even when a single sequence exceeds the budget.
|
| 7046 |
+
scratch_limit = min(128 * 1024**2, torch.cuda.get_device_properties(grad.device).total_memory // 64)
|
| 7047 |
+
bytes_per_sequence = max(1, t * m * d * 4)
|
| 7048 |
+
batch_tile = max(1, min(b, scratch_limit // bytes_per_sequence))
|
| 7049 |
+
max_rows = batch_tile * t
|
| 7050 |
+
# One source at a time, and only its convolution views: the identity VJP
|
| 7051 |
+
# is computed in the input-transpose kernel instead of stored in FP32.
|
| 7052 |
+
dv = torch.empty(((m-1)*max_rows*d,),device=grad.device,dtype=torch.float32)
|
| 7053 |
qrows = max(1, min(8, 8192 // triton.next_power_of_2(d)))
|
| 7054 |
+
max_qgroups = triton.cdiv(max_rows,qrows)
|
| 7055 |
+
# A single source has the same zero/NaN query partial in every dimension;
|
| 7056 |
+
# the general multi-source path still needs one partial per dimension.
|
| 7057 |
+
qpart_width = 1 if single else d
|
| 7058 |
+
qpart = torch.empty((m*max_qgroups*qpart_width,),device=grad.device,dtype=torch.float32)
|
| 7059 |
+
max_wgroups = triton.cdiv(max_rows,64)
|
| 7060 |
+
wpart = torch.empty((ksum*max_wgroups*d,),device=grad.device,dtype=torch.float32)
|
| 7061 |
dq = torch.zeros_like(query, dtype=torch.float32)
|
| 7062 |
dws = []
|
| 7063 |
dxs = []
|
| 7064 |
for source, bank in zip(sources, banks):
|
|
|
|
|
|
|
| 7065 |
dx = torch.empty_like(source)
|
| 7066 |
+
dw = torch.empty_like(bank, dtype=torch.float32)
|
| 7067 |
+
for start in range(0,b,batch_tile):
|
| 7068 |
+
end = min(start+batch_tile,b)
|
| 7069 |
+
rows = (end-start)*t
|
| 7070 |
+
qgroups = triton.cdiv(rows,qrows)
|
| 7071 |
+
wgroups = triton.cdiv(rows,64)
|
| 7072 |
+
_msar_vjp_value[(qgroups,m-1)](source[start:end],bank,query,valid[start:end],
|
| 7073 |
+
position[start:end],lse[start:end],gdot[start:end],grad[start:end],dv,qpart,
|
| 7074 |
+
rows,t,d,m,tuple(widths),eps,qrows,triton.next_power_of_2(d),qgroups,single,num_warps=4)
|
| 7075 |
+
_msar_vjp_source[(qgroups,)](source[start:end],bank,query,valid[start:end],
|
| 7076 |
+
position[start:end],lse[start:end],gdot[start:end],grad[start:end],dv,qpart,dx[start:end],
|
| 7077 |
+
rows,t,d,m,tuple(widths),eps,qrows,triton.next_power_of_2(d),qgroups,single,num_warps=4)
|
| 7078 |
+
_msar_vjp_bank[(wgroups,triton.cdiv(d,32))](source[start:end],dv,valid[start:end],
|
| 7079 |
+
position[start:end],wpart,rows,t,d,tuple(widths),64,32,wgroups,num_warps=4)
|
| 7080 |
+
_msar_reduce_query_bank[((m+ksum)*triton.cdiv(d,32),)](
|
| 7081 |
+
qpart,wpart,dq,dw,d,m,ksum,qgroups,wgroups,32,128,
|
| 7082 |
+
start == 0,single,num_warps=4)
|
| 7083 |
+
dws.append(dw.to(bank.dtype))
|
| 7084 |
dxs.append(dx)
|
| 7085 |
return dxs, dws, dq.to(query.dtype).contiguous()
|
| 7086 |
|
|
|
|
| 7175 |
return sources, partial
|
| 7176 |
|
| 7177 |
|
| 7178 |
+
# Linear Depth Memory (RLS), adapted from the authors' flexible backend,
|
| 7179 |
+
# github.com/davidgonmar/depth-memory, commit 9a6865feeb43a153a4501cc9a6457e047ffef3c3.
|
| 7180 |
+
# The live memory is unwound in backward, so BF16 restoration is approximate.
|
| 7181 |
+
# The symmetric covariance tape stores only its upper triangle as in paper Appendix F.
|
| 7182 |
+
# MIT License
|
| 7183 |
+
# Copyright (c) 2026 David Gonzalez Martinez
|
| 7184 |
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 7185 |
+
# of this software and associated documentation files (the "Software"), to deal
|
| 7186 |
+
# in the Software without restriction, including without limitation the rights
|
| 7187 |
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 7188 |
+
# copies of the Software, and to permit persons to whom the Software is
|
| 7189 |
+
# furnished to do so, subject to the following conditions:
|
| 7190 |
+
# The above copyright notice and this permission notice shall be included in all
|
| 7191 |
+
# copies or substantial portions of the Software.
|
| 7192 |
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 7193 |
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 7194 |
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 7195 |
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 7196 |
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 7197 |
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 7198 |
+
# SOFTWARE.
|
| 7199 |
+
|
| 7200 |
+
|
| 7201 |
+
if triton is not None:
|
| 7202 |
+
@triton.jit
|
| 7203 |
+
def _ldm_forward(M, P, COV, KEY, VALUE, QUERY, LAM, OUT, ERROR, GAIN, DEN,
|
| 7204 |
+
N: tl.constexpr, K: tl.constexpr, D: tl.constexpr,
|
| 7205 |
+
BK: tl.constexpr, BD: tl.constexpr, BN: tl.constexpr):
|
| 7206 |
+
"""Write/read RLS and save the symmetric covariance as a triangle."""
|
| 7207 |
+
row = tl.program_id(0)*BN + tl.arange(0, BN)
|
| 7208 |
+
kk = tl.arange(0, BK)
|
| 7209 |
+
dd = tl.arange(0, BD)
|
| 7210 |
+
row_ok = row < N
|
| 7211 |
+
km = row_ok[:, None] & (kk[None, :] < K)
|
| 7212 |
+
vm = row_ok[:, None] & (dd[None, :] < D)
|
| 7213 |
+
key = tl.load(KEY + row[:, None]*K + kk[None, :], km, 0).to(tl.float32)
|
| 7214 |
+
value = tl.load(VALUE + row[:, None]*D + dd[None, :], vm, 0).to(tl.float32)
|
| 7215 |
+
lam = tl.load(LAM + row, row_ok, 1.).to(tl.float32)
|
| 7216 |
+
u = tl.zeros((BN, BK), tl.float32)
|
| 7217 |
+
den = lam
|
| 7218 |
+
for i in tl.static_range(K):
|
| 7219 |
+
p_off = row[:, None]*K*K + i*K + kk[None, :]
|
| 7220 |
+
p_row = tl.load(P + p_off, km, 0).to(tl.float32)
|
| 7221 |
+
# The live covariance starts at I and the RLS update preserves exact
|
| 7222 |
+
# symmetry. Store its upper triangle only; backward mirrors indices.
|
| 7223 |
+
packed = row[:, None] * (K*(K+1)//2) + i*(2*K-i+1)//2 + kk[None, :] - i
|
| 7224 |
+
tl.store(COV + packed, p_row, km & (kk[None, :] >= i))
|
| 7225 |
+
ui = tl.sum(p_row*key, 1)
|
| 7226 |
+
ki = tl.load(KEY + row*K + i, row_ok, 0).to(tl.float32)
|
| 7227 |
+
den += ki*ui
|
| 7228 |
+
u = tl.where(kk[None, :] == i, ui[:, None], u)
|
| 7229 |
+
# The tape is produced by the full CTA; synchronize before reading it.
|
| 7230 |
+
tl.debug_barrier()
|
| 7231 |
+
for i in tl.static_range(K):
|
| 7232 |
+
p_off = row[:, None]*K*K + i*K + kk[None, :]
|
| 7233 |
+
packed = row[:, None] * (K*(K+1)//2) + i*(2*K-i+1)//2 + kk[None, :] - i
|
| 7234 |
+
upper = km & (kk[None, :] >= i)
|
| 7235 |
+
p_row = tl.load(COV + packed, upper, 0).to(tl.float32)
|
| 7236 |
+
ui = tl.sum(tl.where(kk[None, :] == i, u, 0.), 1)
|
| 7237 |
+
p_new = (p_row - ui[:, None]*u/den[:, None])/lam[:, None]
|
| 7238 |
+
tl.store(P + p_off, p_new, upper)
|
| 7239 |
+
transpose_off = row[:, None]*K*K + kk[None, :]*K + i
|
| 7240 |
+
tl.store(P + transpose_off, p_new, km & (kk[None, :] > i))
|
| 7241 |
+
error = value
|
| 7242 |
+
for i in tl.static_range(K):
|
| 7243 |
+
m_off = row[:, None]*K*D + i*D + dd[None, :]
|
| 7244 |
+
mr = tl.load(M + m_off, vm, 0).to(tl.float32)
|
| 7245 |
+
ki = tl.load(KEY + row*K + i, row_ok, 0).to(tl.float32)
|
| 7246 |
+
error -= ki[:, None]*mr
|
| 7247 |
+
output = tl.zeros((BN, BD), tl.float32)
|
| 7248 |
+
for i in tl.static_range(K):
|
| 7249 |
+
m_off = row[:, None]*K*D + i*D + dd[None, :]
|
| 7250 |
+
old = tl.load(M + m_off, vm, 0).to(tl.float32)
|
| 7251 |
+
ui = tl.sum(tl.where(kk[None, :] == i, u, 0.), 1)
|
| 7252 |
+
gain = ui/den
|
| 7253 |
+
after = (old + gain[:, None]*error).to(M.dtype.element_ty)
|
| 7254 |
+
tl.store(M + m_off, after, vm)
|
| 7255 |
+
qi = tl.load(QUERY + row*K + i, row_ok, 0).to(tl.float32)
|
| 7256 |
+
output += after.to(tl.float32)*qi[:, None]
|
| 7257 |
+
tl.store(GAIN + row*K + i, gain, row_ok)
|
| 7258 |
+
tl.store(OUT + row[:, None]*D + dd[None, :], output.to(OUT.dtype.element_ty), vm)
|
| 7259 |
+
tl.store(ERROR + row[:, None]*D + dd[None, :], error.to(ERROR.dtype.element_ty), vm)
|
| 7260 |
+
tl.store(DEN + row, den, row_ok)
|
| 7261 |
+
|
| 7262 |
+
|
| 7263 |
+
@triton.jit
|
| 7264 |
+
def _ldm_backward(M, P, COV, GM_IN, GP_IN, GM_OUT, GP_OUT, KEY, QUERY, LAM, ERROR, GAIN, DEN, DY,
|
| 7265 |
+
DK, DV, DQ, DL, N: tl.constexpr, K: tl.constexpr, D: tl.constexpr,
|
| 7266 |
+
BK: tl.constexpr, BD: tl.constexpr, BN: tl.constexpr, FIRST: tl.constexpr,
|
| 7267 |
+
HAS_GM: tl.constexpr, HAS_GP: tl.constexpr):
|
| 7268 |
+
"""Reverse RLS without mutating or pre-copying incoming cotangents."""
|
| 7269 |
+
row = tl.program_id(0)*BN + tl.arange(0, BN)
|
| 7270 |
+
ii = tl.arange(0, BK)
|
| 7271 |
+
jj = tl.arange(0, BD)
|
| 7272 |
+
row_ok = row < N
|
| 7273 |
+
km = row_ok[:, None] & (ii[None, :] < K)
|
| 7274 |
+
vm = row_ok[:, None] & (jj[None, :] < D)
|
| 7275 |
+
mm = row_ok[:, None, None] & (ii[None, :, None] < K) & (jj[None, None, :] < D)
|
| 7276 |
+
pm = row_ok[:, None, None] & (ii[None, :, None] < K) & (ii[None, None, :] < K)
|
| 7277 |
+
mo = row[:, None, None]*K*D + ii[None, :, None]*D + jj[None, None, :]
|
| 7278 |
+
po = row[:, None, None]*K*K + ii[None, :, None]*K + ii[None, None, :]
|
| 7279 |
+
ko = row[:, None]*K + ii[None, :]
|
| 7280 |
+
vo = row[:, None]*D + jj[None, :]
|
| 7281 |
+
after = tl.load(M + mo, mm, 0).to(tl.float32)
|
| 7282 |
+
p_after = tl.load(P + po, pm, 0).to(tl.float32)
|
| 7283 |
+
lo = tl.minimum(ii[:, None], ii[None, :])
|
| 7284 |
+
hi = tl.maximum(ii[:, None], ii[None, :])
|
| 7285 |
+
packed = row[:, None, None]*(K*(K+1)//2) + lo[None, :, :]*(2*K-lo[None, :, :]+1)//2 + hi[None, :, :]-lo[None, :, :]
|
| 7286 |
+
p_before = tl.load(COV + packed, pm, 0).to(tl.float32)
|
| 7287 |
+
key = tl.load(KEY + ko, km, 0).to(tl.float32)
|
| 7288 |
+
query = tl.load(QUERY + ko, km, 0).to(tl.float32)
|
| 7289 |
+
error = tl.load(ERROR + vo, vm, 0).to(tl.float32)
|
| 7290 |
+
gain = tl.load(GAIN + ko, km, 0).to(tl.float32)
|
| 7291 |
+
lam = tl.load(LAM + row, row_ok, 1.).to(tl.float32)
|
| 7292 |
+
den = tl.load(DEN + row, row_ok, 1.).to(tl.float32)
|
| 7293 |
+
dy = tl.load(DY + vo, vm, 0).to(tl.float32)
|
| 7294 |
+
before = (after - gain[:, :, None]*error[:, None, :]).to(M.dtype.element_ty).to(tl.float32)
|
| 7295 |
+
if FIRST:
|
| 7296 |
+
before = tl.zeros((BN, BK, BD), tl.float32)
|
| 7297 |
+
after = (gain[:, :, None]*error[:, None, :]).to(M.dtype.element_ty).to(tl.float32)
|
| 7298 |
+
read_grad = (query[:, :, None]*dy[:, None, :]).to(M.dtype.element_ty).to(tl.float32)
|
| 7299 |
+
if HAS_GM:
|
| 7300 |
+
gm_in = tl.load(GM_IN + mo, mm, 0).to(tl.float32)
|
| 7301 |
+
else:
|
| 7302 |
+
gm_in = tl.zeros((BN, BK, BD), tl.float32)
|
| 7303 |
+
h = (gm_in + read_grad).to(M.dtype.element_ty).to(tl.float32)
|
| 7304 |
+
dq = tl.sum(after*dy[:, None, :], 2)
|
| 7305 |
+
dv = tl.sum(h*gain[:, :, None], 1)
|
| 7306 |
+
dg = tl.sum(h*error[:, None, :], 2)
|
| 7307 |
+
if HAS_GP:
|
| 7308 |
+
jp = tl.load(GP_IN + po, pm, 0).to(tl.float32)
|
| 7309 |
+
else:
|
| 7310 |
+
jp = tl.zeros((BN, BK, BK), tl.float32)
|
| 7311 |
+
u = gain*den[:, None]
|
| 7312 |
+
ju = tl.sum(jp*u[:, None, :], 2)
|
| 7313 |
+
jtu = tl.sum(jp*u[:, :, None], 1)
|
| 7314 |
+
du = dg/den[:, None] - (ju+jtu)/(lam*den)[:, None]
|
| 7315 |
+
dden = -tl.sum(dg*gain, 1)/den + tl.sum(u*ju, 1)/(lam*den*den)
|
| 7316 |
+
du += dden[:, None]*key
|
| 7317 |
+
dk = -tl.sum(before*dv[:, None, :], 2) + dden[:, None]*u + tl.sum(p_before*du[:, :, None], 1)
|
| 7318 |
+
gp = jp/lam[:, None, None] + du[:, :, None]*key[:, None, :]
|
| 7319 |
+
dl = dden - tl.sum(tl.sum(jp*p_after, 2), 1)/lam
|
| 7320 |
+
gm = h - key[:, :, None]*dv[:, None, :]
|
| 7321 |
+
tl.store(GM_OUT + mo, gm.to(GM_OUT.dtype.element_ty), mm)
|
| 7322 |
+
tl.store(GP_OUT + po, gp, pm)
|
| 7323 |
+
tl.store(DK + ko, dk.to(DK.dtype.element_ty), km)
|
| 7324 |
+
tl.store(DQ + ko, dq.to(DQ.dtype.element_ty), km)
|
| 7325 |
+
tl.store(DV + vo, dv.to(DV.dtype.element_ty), vm)
|
| 7326 |
+
tl.store(DL + row, dl, row_ok)
|
| 7327 |
+
tl.store(M + mo, before.to(M.dtype.element_ty), mm)
|
| 7328 |
+
tl.store(P + po, p_before, pm)
|
| 7329 |
+
|
| 7330 |
+
|
| 7331 |
+
|
| 7332 |
+
def _ldm_kernel_shape(memory):
|
| 7333 |
+
k, d = memory.shape[-2:]
|
| 7334 |
+
return memory.numel()//(k*d), k, d, max(2, triton.next_power_of_2(k)), max(2, triton.next_power_of_2(d))
|
| 7335 |
+
|
| 7336 |
+
|
| 7337 |
+
def _ldm_row_tile(bk, bd, budget, maximum):
|
| 7338 |
+
rows = max(1, min(maximum, budget//(bk*bd)))
|
| 7339 |
+
return 1 << (rows.bit_length()-1)
|
| 7340 |
+
|
| 7341 |
+
|
| 7342 |
+
@torch.library.custom_op("neollm_ldm::forward", mutates_args=("memory", "covariance"))
|
| 7343 |
+
def _ldm_forward_op(memory: torch.Tensor, covariance: torch.Tensor, key: torch.Tensor, value: torch.Tensor,
|
| 7344 |
+
query: torch.Tensor, forgetting: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 7345 |
+
out, error = torch.empty_like(value), torch.empty_like(value)
|
| 7346 |
+
gain = torch.empty_like(key, dtype=torch.float32)
|
| 7347 |
+
den = torch.empty_like(forgetting, dtype=torch.float32)
|
| 7348 |
+
k = memory.shape[-2]
|
| 7349 |
+
before_cov = torch.empty((*covariance.shape[:-2], k*(k+1)//2), dtype=covariance.dtype, device=covariance.device)
|
| 7350 |
+
n, k, d, bk, bd = _ldm_kernel_shape(memory)
|
| 7351 |
+
if n:
|
| 7352 |
+
bn = _ldm_row_tile(bk, bd, 8192, 16)
|
| 7353 |
+
_ldm_forward[(triton.cdiv(n, bn),)](memory, covariance, before_cov, key, value, query, forgetting,
|
| 7354 |
+
out, error, gain, den, n, k, d, bk, bd, bn, num_warps=4)
|
| 7355 |
+
return out, error, gain, den, before_cov
|
| 7356 |
+
|
| 7357 |
+
|
| 7358 |
+
@_ldm_forward_op.register_fake
|
| 7359 |
+
def _ldm_forward_fake(memory, covariance, key, value, query, forgetting):
|
| 7360 |
+
k = memory.shape[-2]
|
| 7361 |
+
return (torch.empty_like(value), torch.empty_like(value), torch.empty_like(key, dtype=torch.float32),
|
| 7362 |
+
torch.empty_like(forgetting, dtype=torch.float32),
|
| 7363 |
+
torch.empty((*covariance.shape[:-2], k*(k+1)//2), dtype=covariance.dtype, device=covariance.device))
|
| 7364 |
+
|
| 7365 |
+
|
| 7366 |
+
@torch.library.custom_op("neollm_ldm::backward", mutates_args=("memory", "covariance"))
|
| 7367 |
+
def _ldm_backward_op(memory: torch.Tensor, covariance: torch.Tensor, before_cov: torch.Tensor,
|
| 7368 |
+
grad_memory: torch.Tensor | None, grad_covariance: torch.Tensor | None, key: torch.Tensor,
|
| 7369 |
+
query: torch.Tensor, forgetting: torch.Tensor, error: torch.Tensor,
|
| 7370 |
+
gain: torch.Tensor, den: torch.Tensor, grad_out: torch.Tensor,
|
| 7371 |
+
first: bool) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
|
| 7372 |
+
dk, dv, dq, dl = (torch.empty_like(item) for item in (key, error, query, forgetting))
|
| 7373 |
+
gm, gp = torch.empty_like(memory), torch.empty_like(covariance)
|
| 7374 |
+
gm_in = grad_memory.contiguous() if grad_memory is not None else memory
|
| 7375 |
+
gp_in = grad_covariance.contiguous() if grad_covariance is not None else covariance
|
| 7376 |
+
n, k, d, bk, bd = _ldm_kernel_shape(memory)
|
| 7377 |
+
if n:
|
| 7378 |
+
bn = _ldm_row_tile(bk, bd, 2048, 8)
|
| 7379 |
+
_ldm_backward[(triton.cdiv(n, bn),)](memory, covariance, before_cov, gm_in, gp_in, gm, gp,
|
| 7380 |
+
key, query, forgetting, error, gain, den, grad_out, dk, dv, dq, dl,
|
| 7381 |
+
n, k, d, bk, bd, bn, first, grad_memory is not None, grad_covariance is not None, num_warps=4)
|
| 7382 |
+
return gm, gp, dk, dv, dq, dl
|
| 7383 |
+
|
| 7384 |
+
|
| 7385 |
+
@_ldm_backward_op.register_fake
|
| 7386 |
+
def _ldm_backward_fake(memory, covariance, before_cov, grad_memory, grad_covariance, key, query,
|
| 7387 |
+
forgetting, error, gain, den, grad_out, first):
|
| 7388 |
+
return tuple(torch.empty_like(item) for item in (memory, covariance, key, error, query, forgetting))
|
| 7389 |
+
|
| 7390 |
+
|
| 7391 |
+
class _LDMReversibleStep(torch.autograd.Function):
|
| 7392 |
+
"""First-order reverse-mode update with an explicitly owned mutable state."""
|
| 7393 |
+
|
| 7394 |
+
@staticmethod
|
| 7395 |
+
def forward(ctx, memory, covariance, key, value, query, forgetting, first):
|
| 7396 |
+
out, error, gain, den, before_cov = _ldm_forward_op(
|
| 7397 |
+
memory, covariance, key.contiguous(), value.contiguous(), query.contiguous(), forgetting.contiguous())
|
| 7398 |
+
ctx.mark_dirty(memory, covariance)
|
| 7399 |
+
ctx.set_materialize_grads(False)
|
| 7400 |
+
ctx.memory, ctx.covariance = memory.detach(), covariance.detach()
|
| 7401 |
+
ctx.first, ctx.used = first, False
|
| 7402 |
+
ctx.save_for_backward(before_cov, key, query, forgetting, error, gain, den)
|
| 7403 |
+
return memory, covariance, out
|
| 7404 |
+
|
| 7405 |
+
@staticmethod
|
| 7406 |
+
def backward(ctx, grad_memory, grad_covariance, grad_out):
|
| 7407 |
+
if ctx.used:
|
| 7408 |
+
raise RuntimeError("LDM reversible state supports one backward per forward")
|
| 7409 |
+
ctx.used = True
|
| 7410 |
+
before_cov, key, query, forgetting, error, gain, den = ctx.saved_tensors
|
| 7411 |
+
dy = torch.zeros_like(error) if grad_out is None else grad_out.contiguous()
|
| 7412 |
+
gm, gp, dk, dv, dq, dl = _ldm_backward_op(ctx.memory, ctx.covariance, before_cov,
|
| 7413 |
+
grad_memory, grad_covariance, key.contiguous(),
|
| 7414 |
+
query.contiguous(), forgetting.contiguous(),
|
| 7415 |
+
error, gain, den, dy, ctx.first)
|
| 7416 |
+
return gm, gp, dk, dv, dq, dl, None
|
| 7417 |
+
|
| 7418 |
+
|
| 7419 |
+
def _ldm_step(memory, covariance, key, value, query, forgetting, first):
|
| 7420 |
+
return _LDMReversibleStep.apply(memory, covariance, key, value, query, forgetting, first)
|
| 7421 |
+
|
| 7422 |
+
|
| 7423 |
+
def _ldm_reference_step(memory, covariance, key, value, query, forgetting):
|
| 7424 |
+
"""Non-mutating RLS reference, also used where Triton is unavailable."""
|
| 7425 |
+
k, v, q = key.float(), value.float(), query.float()
|
| 7426 |
+
u = torch.einsum("...ij,...j->...i", covariance, k)
|
| 7427 |
+
den = forgetting + (k * u).sum(-1)
|
| 7428 |
+
gain = u / den.unsqueeze(-1)
|
| 7429 |
+
error = v - torch.einsum("...kd,...k->...d", memory.float(), k)
|
| 7430 |
+
updated = (memory.float() + gain.unsqueeze(-1) * error.unsqueeze(-2)).to(memory.dtype)
|
| 7431 |
+
covariance_new = (covariance - u.unsqueeze(-1) * u.unsqueeze(-2)
|
| 7432 |
+
/ den[..., None, None]) / forgetting[..., None, None]
|
| 7433 |
+
read = torch.einsum("...kd,...k->...d", updated.float(), q).to(value.dtype)
|
| 7434 |
+
return updated, covariance_new, read
|
| 7435 |
+
|
| 7436 |
+
|
| 7437 |
+
class LDMAddress(nn.Module):
|
| 7438 |
+
"""Small input-dependent address and identity-initialized group gate."""
|
| 7439 |
+
|
| 7440 |
+
def __init__(self, config):
|
| 7441 |
+
super().__init__()
|
| 7442 |
+
self.groups = config.ldm_groups
|
| 7443 |
+
self.key_dim = config.ldm_key_dim
|
| 7444 |
+
self.context_norm = nn.RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 7445 |
+
self.w1 = nn.Linear(config.hidden_size, config.ldm_hidden_dim, bias=True)
|
| 7446 |
+
self.w2 = nn.Linear(config.ldm_hidden_dim, self.groups * self.key_dim, bias=True)
|
| 7447 |
+
self.gate = nn.Linear(config.ldm_hidden_dim, self.groups, bias=True)
|
| 7448 |
+
# NeoLLM's HF post_init visits child Linear modules independently.
|
| 7449 |
+
self.gate._ldm_gate_zero_init = True
|
| 7450 |
+
nn.init.zeros_(self.gate.weight)
|
| 7451 |
+
nn.init.zeros_(self.gate.bias)
|
| 7452 |
+
|
| 7453 |
+
def forward(self, source):
|
| 7454 |
+
normalized = F.rms_norm(source.float(), self.context_norm.normalized_shape,
|
| 7455 |
+
self.context_norm.weight.float(), self.context_norm.eps)
|
| 7456 |
+
features = F.silu(self.w1(normalized.to(source.dtype)))
|
| 7457 |
+
address = self.w2(features).float().reshape(*source.shape[:-1], self.groups, self.key_dim)
|
| 7458 |
+
address = F.normalize(address, p=2, dim=-1, eps=1e-6)
|
| 7459 |
+
gate = 2.0 * torch.sigmoid(self.gate(features).float())
|
| 7460 |
+
return address, gate
|
| 7461 |
+
|
| 7462 |
+
|
| 7463 |
+
class LDMWrite(nn.Module):
|
| 7464 |
+
"""Generate a weighted write from a residual context and branch output."""
|
| 7465 |
+
|
| 7466 |
+
def __init__(self, config):
|
| 7467 |
+
super().__init__()
|
| 7468 |
+
self.address = LDMAddress(config)
|
| 7469 |
+
self.groups = config.ldm_groups
|
| 7470 |
+
self.value_dim = config.hidden_size // self.groups
|
| 7471 |
+
self.forgetting_logit = nn.Parameter(torch.full((self.groups,), math.log(.99 / .01)))
|
| 7472 |
+
|
| 7473 |
+
def forward(self, context, value, valid, dtype):
|
| 7474 |
+
key, weight = self.address(context)
|
| 7475 |
+
# Mask after sqrt: sqrt(0) in an autograd path can produce NaN gradients.
|
| 7476 |
+
# Match the authors' numerical floors for an extreme negative gate
|
| 7477 |
+
# or forgetting logit, avoiding sqrt(0) and division by zero.
|
| 7478 |
+
scale = weight.clamp_min(1e-6).sqrt() * valid.unsqueeze(-1).to(weight.dtype)
|
| 7479 |
+
key = (key * scale.unsqueeze(-1)).to(dtype).contiguous()
|
| 7480 |
+
value = (value.float().reshape(*value.shape[:-1], self.groups, self.value_dim)
|
| 7481 |
+
* scale.unsqueeze(-1)).to(dtype).contiguous()
|
| 7482 |
+
forgetting = torch.sigmoid(self.forgetting_logit.float()).clamp_min(1e-6).expand_as(weight)
|
| 7483 |
+
forgetting = torch.where(valid.unsqueeze(-1), forgetting, torch.ones_like(forgetting)).contiguous()
|
| 7484 |
+
return key, value, forgetting
|
| 7485 |
+
|
| 7486 |
+
|
| 7487 |
+
class LDMRead(nn.Module):
|
| 7488 |
+
"""Read the latest pending write with a normalized gated query."""
|
| 7489 |
+
|
| 7490 |
+
def __init__(self, config):
|
| 7491 |
+
super().__init__()
|
| 7492 |
+
self.address = LDMAddress(config)
|
| 7493 |
+
self.read_gain = nn.Parameter(torch.ones(config.ldm_groups))
|
| 7494 |
+
|
| 7495 |
+
def forward(self, context, state, valid):
|
| 7496 |
+
memory, covariance, key, value, forgetting, first = state
|
| 7497 |
+
query, gate = self.address(context)
|
| 7498 |
+
query = (query * (gate * self.read_gain.float()).unsqueeze(-1)
|
| 7499 |
+
* valid[..., None, None].to(query.dtype)).to(memory.dtype).contiguous()
|
| 7500 |
+
if memory.is_cuda and triton is not None:
|
| 7501 |
+
memory, covariance, read = _ldm_step(memory, covariance, key, value, query, forgetting, first)
|
| 7502 |
+
else:
|
| 7503 |
+
memory, covariance, read = _ldm_reference_step(memory, covariance, key, value, query, forgetting)
|
| 7504 |
+
return memory, covariance, read.reshape_as(context).to(context.dtype)
|
| 7505 |
+
|
| 7506 |
+
|
| 7507 |
class NeoLLMDecoderLayer(GradientCheckpointingLayer):
|
| 7508 |
"""
|
| 7509 |
Decoder layer with standard residual connections.
|
|
|
|
| 7677 |
self.msar_block_branches = config.msar_block_branches
|
| 7678 |
self.msar_attn_read = MSARRead(config) if self.use_msar else None
|
| 7679 |
self.msar_mlp_read = MSARRead(config) if self.use_msar else None
|
| 7680 |
+
self.use_ldm = bool(getattr(config, "use_ldm", False))
|
| 7681 |
+
self.ldm_attn_read = LDMRead(config) if self.use_ldm else None
|
| 7682 |
+
self.ldm_attn_write = LDMWrite(config) if self.use_ldm else None
|
| 7683 |
+
self.ldm_mlp_read = LDMRead(config) if self.use_ldm else None
|
| 7684 |
+
self.ldm_mlp_write = LDMWrite(config) if self.use_ldm else None
|
| 7685 |
self.use_attn_res = getattr(config, "use_attn_res", False)
|
| 7686 |
if self.use_attn_res:
|
| 7687 |
self.attn_res_query_attn = nn.Parameter(torch.zeros(config.hidden_size))
|
|
|
|
| 7977 |
dag_sources_y=None,
|
| 7978 |
dag_plan=None,
|
| 7979 |
dynamics_valid_mask: Optional[torch.Tensor] = None,
|
| 7980 |
+
msar_sources=None,
|
| 7981 |
+
msar_partial=None,
|
| 7982 |
+
msar_banks=None,
|
| 7983 |
+
msar_valid=None,
|
| 7984 |
+
msar_position=None,
|
| 7985 |
+
ldm_state=None,
|
| 7986 |
+
ldm_valid=None,
|
| 7987 |
**kwargs: Unpack[FlashAttentionKwargs],
|
| 7988 |
) -> Tuple:
|
| 7989 |
+
"""Update X/Y streams with the selected optional depth mechanism.
|
| 7990 |
+
|
| 7991 |
+
In the hybrid, MSAR stores one history of unscaled shared branch outputs.
|
| 7992 |
+
Its causal depth read is added after separate X/Y normalization, before
|
| 7993 |
+
their optional shared input norm. This uses the existing SiameseNorm
|
| 7994 |
+
input norm and does not introduce an additional normalization. The X/Y
|
| 7995 |
+
update equations and final merge are unchanged, while branch values can
|
| 7996 |
+
change.
|
| 7997 |
+
This hybrid is an adaptation, not the single-stream paper architecture.
|
| 7998 |
+
|
| 7999 |
+
LDM likewise stores one shared history of unscaled branch outputs. It
|
| 8000 |
+
adds its read to the separate X/Y normalization result before the
|
| 8001 |
+
existing shared input norm; write keys use the mean of the updated X/Y
|
| 8002 |
+
streams. Its kernel is independent of the SiameseNorm kernel.
|
| 8003 |
"""
|
| 8004 |
# SiameseNorm keeps two coupled streams with shared Attention/MLP
|
| 8005 |
# parameters. All Siamese normalization modules are RMSNorm by
|
| 8006 |
# construction; no dynamic-normalization branch remains.
|
| 8007 |
# ── Attention shared block ────────────────────────────────────────
|
| 8008 |
norm_backend = getattr(self, "siamesenorm_kernel_backend", "reference")
|
| 8009 |
+
if self.use_msar:
|
| 8010 |
+
branch = 2 * self.layer_idx
|
| 8011 |
+
msar_sources, msar_partial = _msar_start_branch(
|
| 8012 |
+
msar_sources, msar_partial, branch, self.msar_block_branches)
|
| 8013 |
+
msar_attn = self.msar_attn_read(msar_sources, msar_partial, msar_banks,
|
| 8014 |
+
branch, self.msar_block_branches, msar_valid, msar_position)
|
| 8015 |
+
else:
|
| 8016 |
+
msar_attn = None
|
| 8017 |
if norm_backend == "reference":
|
| 8018 |
x_attn_norm = self.siamese_attn_x_norm(x_states)
|
| 8019 |
y_attn_norm = self.siamese_attn_y_norm(y_states)
|
|
|
|
| 8021 |
dtype=x_attn_norm.dtype, device=x_attn_norm.device
|
| 8022 |
)
|
| 8023 |
h_attn = x_scale * x_attn_norm + y_attn_norm
|
|
|
|
|
|
|
| 8024 |
else:
|
| 8025 |
from cut_cross_entropy.siamesenorm import siamesenorm
|
| 8026 |
h_attn = siamesenorm(
|
| 8027 |
x_states, y_states,
|
| 8028 |
self.siamese_attn_x_norm.weight, self.siamese_attn_y_norm.weight,
|
| 8029 |
+
self.siamese_attn_input_norm.weight
|
| 8030 |
+
if not (self.use_msar or self.use_ldm) and self.siamese_attn_input_norm is not None else None,
|
| 8031 |
self.siamese_attn_x_scale.to(dtype=x_states.dtype, device=x_states.device),
|
| 8032 |
eps=self.siamese_attn_x_norm.eps, backend=norm_backend,
|
| 8033 |
)
|
| 8034 |
+
if self.use_msar:
|
| 8035 |
+
h_attn = h_attn + msar_attn
|
| 8036 |
+
if self.use_ldm:
|
| 8037 |
+
ldm_memory, ldm_covariance, ldm_attn = self.ldm_attn_read(h_attn, ldm_state, ldm_valid)
|
| 8038 |
+
h_attn = h_attn + ldm_attn
|
| 8039 |
+
if self.siamese_attn_input_norm is not None and (norm_backend == "reference" or self.use_msar or self.use_ldm):
|
| 8040 |
+
h_attn = self.siamese_attn_input_norm(h_attn)
|
| 8041 |
|
| 8042 |
stack_metrics = None
|
| 8043 |
if self.use_stack_memory:
|
|
|
|
| 8073 |
y_states = y_states + dag_ry
|
| 8074 |
x_after_attn = x_states + stream_scale * attn_out
|
| 8075 |
y_after_attn = y_states + attn_out
|
| 8076 |
+
if self.use_ldm:
|
| 8077 |
+
ldm_state = (ldm_memory, ldm_covariance,
|
| 8078 |
+
*self.ldm_attn_write((x_after_attn + y_after_attn) * .5,
|
| 8079 |
+
attn_out, ldm_valid, ldm_memory.dtype), False)
|
| 8080 |
+
if self.use_msar:
|
| 8081 |
+
msar_partial = attn_out if msar_partial is None else msar_partial + attn_out
|
| 8082 |
|
| 8083 |
if self.use_gpas:
|
| 8084 |
x_after_attn = self.gpas_attn(x_after_attn)
|
| 8085 |
|
| 8086 |
# ── MLP shared block ──────────────────────────────────────────────
|
| 8087 |
+
if self.use_msar:
|
| 8088 |
+
branch = 2 * self.layer_idx + 1
|
| 8089 |
+
msar_sources, msar_partial = _msar_start_branch(
|
| 8090 |
+
msar_sources, msar_partial, branch, self.msar_block_branches)
|
| 8091 |
+
msar_mlp = self.msar_mlp_read(msar_sources, msar_partial, msar_banks,
|
| 8092 |
+
branch, self.msar_block_branches, msar_valid, msar_position)
|
| 8093 |
+
else:
|
| 8094 |
+
msar_mlp = None
|
| 8095 |
if norm_backend == "reference":
|
| 8096 |
x_mlp_norm = self.siamese_mlp_x_norm(x_after_attn)
|
| 8097 |
y_mlp_norm = self.siamese_mlp_y_norm(y_after_attn)
|
| 8098 |
h_mlp = x_mlp_norm + y_mlp_norm
|
|
|
|
|
|
|
| 8099 |
else:
|
| 8100 |
h_mlp = siamesenorm(
|
| 8101 |
x_after_attn, y_after_attn,
|
| 8102 |
self.siamese_mlp_x_norm.weight, self.siamese_mlp_y_norm.weight,
|
| 8103 |
+
self.siamese_mlp_input_norm.weight
|
| 8104 |
+
if not (self.use_msar or self.use_ldm) and self.siamese_mlp_input_norm is not None else None,
|
| 8105 |
eps=self.siamese_mlp_x_norm.eps, backend=norm_backend,
|
| 8106 |
post_scale=(
|
| 8107 |
self.lns_mlp.scale.to(device=x_after_attn.device, dtype=x_after_attn.dtype)
|
| 8108 |
+
if self.use_lns and not (self.use_msar or self.use_ldm) else None
|
| 8109 |
),
|
| 8110 |
out_dtype=(
|
| 8111 |
torch.get_autocast_dtype("cuda")
|
| 8112 |
+
if not (self.use_msar or self.use_ldm) and torch.is_autocast_enabled("cuda") else None
|
| 8113 |
),
|
| 8114 |
)
|
| 8115 |
+
if self.use_msar:
|
| 8116 |
+
h_mlp = h_mlp + msar_mlp
|
| 8117 |
+
if self.use_ldm:
|
| 8118 |
+
ldm_memory, ldm_covariance, ldm_mlp = self.ldm_mlp_read(h_mlp, ldm_state, ldm_valid)
|
| 8119 |
+
h_mlp = h_mlp + ldm_mlp
|
| 8120 |
+
if self.siamese_mlp_input_norm is not None and (norm_backend == "reference" or self.use_msar or self.use_ldm):
|
| 8121 |
+
h_mlp = self.siamese_mlp_input_norm(h_mlp)
|
| 8122 |
|
| 8123 |
# Only this consumer starts directly with an autocast Linear. Attention
|
| 8124 |
# also exposes native states to positional, router and memory consumers.
|
| 8125 |
+
h_lns2 = self.lns_mlp(h_mlp) if self.use_lns and (norm_backend == "reference" or self.use_msar or self.use_ldm) else h_mlp
|
| 8126 |
delta_m = self.mlp(h_lns2)
|
| 8127 |
|
| 8128 |
jtok_aux_stats = None
|
|
|
|
| 8143 |
|
| 8144 |
x_next = x_after_attn + stream_scale * shared_update
|
| 8145 |
y_next = y_after_attn + shared_update
|
| 8146 |
+
if self.use_ldm:
|
| 8147 |
+
ldm_state = (ldm_memory, ldm_covariance,
|
| 8148 |
+
*self.ldm_mlp_write((x_next + y_next) * .5,
|
| 8149 |
+
shared_update, ldm_valid, ldm_memory.dtype), False)
|
| 8150 |
+
if self.use_msar:
|
| 8151 |
+
msar_partial = shared_update if msar_partial is None else msar_partial + shared_update
|
| 8152 |
|
| 8153 |
if self.use_gpas:
|
| 8154 |
x_next = self.gpas_mlp(x_next)
|
| 8155 |
|
| 8156 |
outputs = (x_next, y_next)
|
| 8157 |
+
if self.use_ldm:
|
| 8158 |
+
outputs += (ldm_state,)
|
| 8159 |
+
if self.use_msar:
|
| 8160 |
+
outputs += (msar_sources, msar_partial)
|
| 8161 |
if self.use_stack_memory:
|
| 8162 |
outputs += (stack_memory, stack_memory_mask, stack_metrics)
|
| 8163 |
if jtok_aux_stats is not None:
|
|
|
|
| 8179 |
msar_banks=None,
|
| 8180 |
msar_valid=None,
|
| 8181 |
msar_position=None,
|
| 8182 |
+
ldm_state=None,
|
| 8183 |
+
ldm_valid=None,
|
| 8184 |
output_attentions: Optional[bool] = False,
|
| 8185 |
repo_rope_args: Optional[Tuple[torch.Tensor, float]] = None,
|
| 8186 |
position_ids: Optional[torch.LongTensor] = None,
|
|
|
|
| 8229 |
h_attn = hidden_states
|
| 8230 |
residual_attn = hidden_states
|
| 8231 |
|
| 8232 |
+
if self.use_ldm:
|
| 8233 |
+
ldm_memory, ldm_covariance, ldm_attn = self.ldm_attn_read(h_attn, ldm_state, ldm_valid)
|
| 8234 |
+
h_attn = h_attn + ldm_attn
|
| 8235 |
+
|
| 8236 |
# ── Attention block ───────────────────────────────────────────────
|
| 8237 |
|
| 8238 |
# Optional embedding input normalisation:
|
|
|
|
| 8283 |
attn_aug = residual_attn + hidden_states
|
| 8284 |
|
| 8285 |
h_tilde = self.gpas_attn(attn_aug) if self.use_gpas else attn_aug
|
| 8286 |
+
if self.use_ldm:
|
| 8287 |
+
ldm_state = (ldm_memory, ldm_covariance,
|
| 8288 |
+
*self.ldm_attn_write(h_tilde, hidden_states, ldm_valid, ldm_memory.dtype), False)
|
| 8289 |
|
| 8290 |
# ── Attention Residuals: compute pre-MLP input ────────────────────
|
| 8291 |
# After attention, the partial sum is updated with h_tilde.
|
|
|
|
| 8310 |
h_mlp = h_tilde
|
| 8311 |
residual_mlp = h_tilde
|
| 8312 |
|
| 8313 |
+
if self.use_ldm:
|
| 8314 |
+
ldm_memory, ldm_covariance, ldm_mlp = self.ldm_mlp_read(h_mlp, ldm_state, ldm_valid)
|
| 8315 |
+
h_mlp = h_mlp + ldm_mlp
|
| 8316 |
+
|
| 8317 |
# ── MLP block ─────────────────────────────────────────────────────
|
| 8318 |
h_normed2 = _apply_norm(self.post_attention_layernorm, h_mlp)
|
| 8319 |
h_lns2 = self.lns_mlp(h_normed2) if self.use_lns else h_normed2
|
|
|
|
| 8352 |
mlp_aug = residual_mlp + delta_m
|
| 8353 |
|
| 8354 |
hidden_states = self.gpas_mlp(mlp_aug) if self.use_gpas else mlp_aug
|
| 8355 |
+
if self.use_ldm:
|
| 8356 |
+
ldm_state = (ldm_memory, ldm_covariance,
|
| 8357 |
+
*self.ldm_mlp_write(hidden_states, delta_m, ldm_valid, ldm_memory.dtype), False)
|
| 8358 |
|
| 8359 |
outputs = (hidden_states,)
|
| 8360 |
+
if self.use_ldm:
|
| 8361 |
+
outputs += (ldm_state,)
|
| 8362 |
if self.use_msar:
|
| 8363 |
outputs += (msar_sources, msar_partial)
|
| 8364 |
if jtok_aux_stats is not None:
|
|
|
|
| 8702 |
_supports_flash_attn_2 = True
|
| 8703 |
_supports_sdpa = True
|
| 8704 |
_is_stateful = True
|
| 8705 |
+
# Preserve the paper's FP32 LDM controls while loading a BF16 checkpoint.
|
| 8706 |
+
# Transformers applies this before copying tensors, avoiding lossy casts.
|
| 8707 |
+
_keep_in_fp32_modules_strict = {"ldm_*.read_gain", "ldm_*.forgetting_logit"}
|
| 8708 |
|
| 8709 |
@classmethod
|
| 8710 |
def from_pretrained(cls, *args, **kwargs):
|
|
|
|
| 8808 |
return model
|
| 8809 |
|
| 8810 |
def _init_weights(self, module):
|
| 8811 |
+
"""Apply HF initialization, then preserve identity-centered gates."""
|
| 8812 |
super()._init_weights(module)
|
| 8813 |
+
if getattr(module, "_dag_zero_init", False) or getattr(module, "_ldm_gate_zero_init", False):
|
| 8814 |
nn.init.zeros_(module.weight)
|
| 8815 |
nn.init.zeros_(module.bias)
|
| 8816 |
return
|
|
|
|
| 9078 |
sum(config.msar_kernel_sizes), config.hidden_size))
|
| 9079 |
if config.use_msar else None
|
| 9080 |
)
|
| 9081 |
+
self.ldm_embedding_write = LDMWrite(config) if config.use_ldm else None
|
| 9082 |
+
self.ldm_final_read = LDMRead(config) if config.use_ldm else None
|
| 9083 |
self.dagformer = (DAGFormerTopology(config, self.layers)
|
| 9084 |
if bool(getattr(config, "use_dagformer", False)) else None)
|
| 9085 |
self.use_siamesenorm = bool(getattr(config, "use_siamesenorm", False))
|
|
|
|
| 9422 |
hidden_states = inputs_embeds
|
| 9423 |
use_siamesenorm = bool(getattr(self.config, "use_siamesenorm", False))
|
| 9424 |
siamese_y_states = inputs_embeds if use_siamesenorm else None
|
| 9425 |
+
use_ldm = bool(getattr(self.config, "use_ldm", False))
|
| 9426 |
+
if use_ldm:
|
| 9427 |
+
if self.gradient_checkpointing and self.training:
|
| 9428 |
+
raise ValueError("LDM reversible state is incompatible with whole-layer gradient checkpointing.")
|
| 9429 |
+
if attention_mask is not None and (attention_mask.ndim != 2 or attention_mask.shape != hidden_states.shape[:2]):
|
| 9430 |
+
raise ValueError("LDM requires a token-domain 2-D attention mask.")
|
| 9431 |
+
ldm_valid = (attention_mask.to(dtype=torch.bool).contiguous() if attention_mask is not None
|
| 9432 |
+
else torch.ones(hidden_states.shape[:2], dtype=torch.bool, device=hidden_states.device))
|
| 9433 |
+
state_dtype = (torch.get_autocast_dtype("cuda") if hidden_states.is_cuda and
|
| 9434 |
+
torch.is_autocast_enabled("cuda") else hidden_states.dtype)
|
| 9435 |
+
groups, key_dim = self.config.ldm_groups, self.config.ldm_key_dim
|
| 9436 |
+
value_dim = self.config.hidden_size // groups
|
| 9437 |
+
ldm_memory = torch.zeros((*hidden_states.shape[:2], groups, key_dim, value_dim),
|
| 9438 |
+
device=hidden_states.device, dtype=state_dtype)
|
| 9439 |
+
ldm_covariance = torch.eye(key_dim, device=hidden_states.device, dtype=torch.float32).expand(
|
| 9440 |
+
*hidden_states.shape[:2], groups, key_dim, key_dim).clone()
|
| 9441 |
+
ldm_state = (ldm_memory, ldm_covariance,
|
| 9442 |
+
*self.ldm_embedding_write(hidden_states, hidden_states, ldm_valid, state_dtype), True)
|
| 9443 |
+
else:
|
| 9444 |
+
ldm_state = ldm_valid = None
|
| 9445 |
# The same validated dense/right-padding training contract applies to
|
| 9446 |
# the causal planner: valid queries cannot see future padded keys.
|
| 9447 |
dag_plans = (self.dagformer(input_ids, inputs_embeds, position_ids,
|
|
|
|
| 9601 |
dag_sources=dag_sources,
|
| 9602 |
dag_plan=dag_plans[layer_idx] if dag_plans is not None else None,
|
| 9603 |
dynamics_valid_mask=attention_mask,
|
| 9604 |
+
msar_sources=msar_sources, msar_partial=msar_partial,
|
| 9605 |
+
msar_banks=self.msar_banks, msar_valid=msar_valid,
|
| 9606 |
+
msar_position=msar_position,
|
| 9607 |
+
ldm_state=ldm_state, ldm_valid=ldm_valid,
|
| 9608 |
**kwargs,
|
| 9609 |
)
|
| 9610 |
hidden_states = layer_outputs[0]
|
| 9611 |
siamese_y_states = layer_outputs[1]
|
| 9612 |
+
if use_msar:
|
| 9613 |
+
msar_sources, msar_partial = layer_outputs[2:4]
|
| 9614 |
+
extras_start = 4
|
| 9615 |
+
elif use_ldm:
|
| 9616 |
+
ldm_state = layer_outputs[2]
|
| 9617 |
+
extras_start = 3
|
| 9618 |
else:
|
| 9619 |
extras_start = 2
|
| 9620 |
+
if use_stack_memory:
|
| 9621 |
+
stack_memory = layer_outputs[extras_start]
|
| 9622 |
+
stack_memory_mask = layer_outputs[extras_start + 1]
|
| 9623 |
+
stack_layer_metrics = layer_outputs[extras_start + 2]
|
| 9624 |
+
all_stack_metrics = all_stack_metrics + (stack_layer_metrics,)
|
| 9625 |
+
extras_start += 3
|
| 9626 |
else:
|
| 9627 |
layer_outputs = decoder_layer(
|
| 9628 |
hidden_states,
|
|
|
|
| 9634 |
msar_sources=msar_sources, msar_partial=msar_partial,
|
| 9635 |
msar_banks=self.msar_banks, msar_valid=msar_valid,
|
| 9636 |
msar_position=msar_position,
|
| 9637 |
+
ldm_state=ldm_state, ldm_valid=ldm_valid,
|
| 9638 |
output_attentions=output_attentions,
|
| 9639 |
repo_rope_args=repo_rope_args,
|
| 9640 |
position_ids=position_ids,
|
|
|
|
| 9652 |
extras_start = 3
|
| 9653 |
# The last branch's h_mlp + delta_m is the terminal
|
| 9654 |
# residual merge. No new source expansion is applied.
|
| 9655 |
+
elif use_ldm:
|
| 9656 |
+
ldm_state = layer_outputs[1]
|
| 9657 |
+
extras_start = 2
|
| 9658 |
else:
|
| 9659 |
extras_start = 1
|
| 9660 |
|
|
|
|
| 9700 |
|
| 9701 |
if use_siamesenorm:
|
| 9702 |
norm_backend = getattr(self, "siamesenorm_kernel_backend", "reference")
|
| 9703 |
+
if use_ldm:
|
| 9704 |
+
merged = self.siamese_x_final_norm(hidden_states) + self.siamese_y_final_norm(siamese_y_states)
|
| 9705 |
+
_, _, ldm_final = self.ldm_final_read(merged, ldm_state, ldm_valid)
|
| 9706 |
+
hidden_states = self.siamese_final_norm(merged + ldm_final)
|
| 9707 |
+
elif norm_backend == "reference":
|
| 9708 |
hidden_states = self.siamese_final_norm(
|
| 9709 |
self.siamese_x_final_norm(hidden_states)
|
| 9710 |
+ self.siamese_y_final_norm(siamese_y_states)
|
|
|
|
| 9718 |
eps=self.siamese_x_final_norm.eps, backend=norm_backend,
|
| 9719 |
)
|
| 9720 |
else:
|
| 9721 |
+
if use_ldm:
|
| 9722 |
+
_, _, ldm_final = self.ldm_final_read(hidden_states, ldm_state, ldm_valid)
|
| 9723 |
+
hidden_states = hidden_states + ldm_final
|
| 9724 |
hidden_states = self.norm(hidden_states)
|
| 9725 |
|
| 9726 |
if output_hidden_states:
|
|
|
|
| 12032 |
for name, parameter in module.named_parameters():
|
| 12033 |
if parameter.requires_grad:
|
| 12034 |
groups[f"{kind}/layer_{module.layer_idx}/{name}"] = (parameter,)
|
| 12035 |
+
for slot in ("attn", "mlp"):
|
| 12036 |
+
read = getattr(layer, f"msar_{slot}_read", None)
|
| 12037 |
+
if read is not None:
|
| 12038 |
+
prefix = f"msar/layer_{layer.layer_idx}/{slot}"
|
| 12039 |
+
if read.query.requires_grad:
|
| 12040 |
+
groups[f"{prefix}/query"] = (read.query,)
|
| 12041 |
+
mixer = tuple(parameter for parameter in
|
| 12042 |
+
(read.mixer_weight, read.mixer_bias, read.mixer_scale)
|
| 12043 |
+
if parameter.requires_grad)
|
| 12044 |
+
if mixer:
|
| 12045 |
+
groups[f"{prefix}/mixer"] = mixer
|
| 12046 |
families = {
|
| 12047 |
"dag": ("dagformer_local",),
|
| 12048 |
"attnres": ("attn_res_query_attn", "attn_res_query_mlp", "attn_res_norm"),
|
|
|
|
| 12065 |
groups[f"fan/layer_{layer.layer_idx}"] = (layer.self_attn.lambda_1, layer.self_attn.lambda_2)
|
| 12066 |
if self.model.dagformer is not None:
|
| 12067 |
groups["dag/global_topology"] = tuple(p for p in self.model.dagformer.parameters() if p.requires_grad)
|
| 12068 |
+
if self.model.msar_banks is not None and self.model.msar_banks.requires_grad:
|
| 12069 |
+
groups["msar/banks"] = (self.model.msar_banks,)
|
| 12070 |
return groups
|
| 12071 |
|
| 12072 |
def set_input_embeddings(self, value):
|
optimizer_precision.json
CHANGED
|
@@ -8,9 +8,9 @@
|
|
| 8 |
"delta_enabled": false,
|
| 9 |
"delta_eta": 0.37,
|
| 10 |
"fp32_master_active": true,
|
| 11 |
-
"fp32_master_elements":
|
| 12 |
"fp32_master_groups": 6,
|
| 13 |
-
"fp32_master_tensors":
|
| 14 |
"fp32_passthrough_elements": 0,
|
| 15 |
"mode": "fp32_master",
|
| 16 |
"mxfp8_active": false,
|
|
@@ -19,12 +19,12 @@
|
|
| 19 |
"mxfp8_recipe": null,
|
| 20 |
"native_precision_elements": 0,
|
| 21 |
"optimizer_variant": "AdEMAMix",
|
| 22 |
-
"ordinary_linear_layers":
|
| 23 |
"parameter_elements_by_dtype": {
|
| 24 |
-
"bfloat16":
|
| 25 |
"float32": 2176
|
| 26 |
},
|
| 27 |
-
"parameter_storage_bytes":
|
| 28 |
"runtime_precision_mode": "BF16_FP32_MASTER",
|
| 29 |
"stochastic_round_seed": 0
|
| 30 |
}
|
|
|
|
| 8 |
"delta_enabled": false,
|
| 9 |
"delta_eta": 0.37,
|
| 10 |
"fp32_master_active": true,
|
| 11 |
+
"fp32_master_elements": 84567992,
|
| 12 |
"fp32_master_groups": 6,
|
| 13 |
+
"fp32_master_tensors": 374,
|
| 14 |
"fp32_passthrough_elements": 0,
|
| 15 |
"mode": "fp32_master",
|
| 16 |
"mxfp8_active": false,
|
|
|
|
| 19 |
"mxfp8_recipe": null,
|
| 20 |
"native_precision_elements": 0,
|
| 21 |
"optimizer_variant": "AdEMAMix",
|
| 22 |
+
"ordinary_linear_layers": 124,
|
| 23 |
"parameter_elements_by_dtype": {
|
| 24 |
+
"bfloat16": 84565816,
|
| 25 |
"float32": 2176
|
| 26 |
},
|
| 27 |
+
"parameter_storage_bytes": 169140336,
|
| 28 |
"runtime_precision_mode": "BF16_FP32_MASTER",
|
| 29 |
"stochastic_round_seed": 0
|
| 30 |
}
|
training_args.bin
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 5329
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f25ab9f8e336f20fbb462d246d9a32edde7efc0113368fb5f2ca06f3cfe35459
|
| 3 |
size 5329
|