| 模型 | 核心做法 | N-gram | 地址映射 | 注入位置 | Context-aware Gate | 参数,比例 |
|---|---|---|---|---|---|---|
| Over-Tokenized Transformer (OE) | Hierarchical N-gram → Feature Hashing → sliced low-dim embeddings → projection → 输入 embedding | 1…N-gram | f(ngram) mod m + 多 sliced tables | 模型输入 | - | - |
| Gemma 4 E2B/E4B | Per-Layer Embedding:每层独立 token embedding + context projection | - | Token-ID lookup | 每层 | - | - |
| Engram-27B | Tokenizer compression → N-gram → 多头 Hash → memory lookup → context-aware fusion → short causal Conv → 多 residual stream | 2/3-gram | compressed IDs + 8 hash heads/order | 第 2、15 层 | ✓ | 5.7B,21.30% |
| LongCat-2.0 | Scale OE | 2–5 gram | Hash/mod + 4 splits/order | 模型输入 | - | 135B,8.4% |
| DeepSeek-V4.1-Flash | Scale Engram;删除 short Conv; Sinkhorn balancing | 2/3/4-gram | compressed IDs + 8 hash heads/order | 第 2、15 层 | ✓ | 196B,26.2% |
| Qwen3.8-Flash-Next | Scale Engram;去掉 tokenizer compression,直接 hash raw token IDs | 2/3-gram | raw token IDs + 8 hash heads/order | 第 2 层 | ✓ | 51B,29.0% |
一、Over Encoding
Input Vocabulary 与 Output Vocabulary
在之前的 paper 中,就有发现:大 tokenizer 往往有利于大模型,却可能伤害小模型。
但是,tokenizer,或者说词表,其实有两个作用:input vocabulary 和 output vocabulary。
于是我们可以进一步解耦这个问题:到底是“大 input vocabulary”伤害小模型,还是“大 output vocabulary”伤害小模型?

Over Encoding(OE)发现,实际上是 大 output vocabulary 导致的。
这里有一个很直觉的解释:input vocabulary 增大,本质是在增强上下文到 representation 的映射能力;而 output vocabulary 增大,则是在把预测问题变成更细粒度、更困难的分类任务。大模型有能力利用这种 supervision,小模型则容易 underfit。
从这个角度来讲,input vocabulary 和 output vocabulary 不应该被绑定在一起 scaling。
Hierarchical N-gram 与 Feature Hashing
做法上,论文保留原来的 BPE token 序列不变,但把每个位置的输入 embedding 从“只查当前 token”,改成同时查当前 token 及其历史 n-gram。
例如,当前位置为 c,前两个 token 是 a,b,则构造:
- 1-gram:c;
- 2-gram:(b,c);
- 3-gram:(a,b,c)。
先用下面的函数,把每个固定长度的 n-gram 唯一编码成一个巨大整数:
其中 V 是基础词表大小。由于理论上有 V^n 种组合,不可能真的建 V^n 行 embedding,作者使用 feature hashing,直接计算 f(\cdot)\bmod m,只查一个 m 行的表 E[f(\cdot)\bmod m],允许不同 n-gram 碰撞到同一行。
所谓 hierarchical n-gram,就是不是只用 3-gram,而是在同一个位置同时加入 1+2+\cdots+n-gram embedding。例如:
从而同时保留单 token、短局部组合和更长局部组合的信息。
Sliced Low-Dimensional Embeddings
进一步,对于每一种 n-gram,作者不是只建一个宽的 m\times d 表,而是使用 sliced low-dimensional embeddings:把同样的参数预算拆成 k 个较窄的 m_i\times(d/k) 表,每次 lookup 出低维向量后,用 W_i\in\mathbb{R}^{(d/k)\times d_{\mathrm{model}}} 投影回模型维度,再相加:
关键是这些 slice 的 m_i 故意设得略有不同,如 m,m+2,m+4。于是,同一个 n-gram 会得到 x\bmod m、x\bmod(m+2),\ldots 多组不同的 hash 地址:即使它在一个表里和别的 n-gram 撞车,也很难在所有表里同时撞车。
最终就是 BPE embedding + 多层级 n-gram × 多个不同 hash view 的低维 embedding,全部相加后送进原封不动的 Transformer。因此,增加的是大量稀疏 lookup 参数,而几乎不增加 Transformer 主干 FLOPs。
从上述流程也可以看出,OE 的 hash 地址和稀疏查表只依赖 token ID,不需要等待 contextual hidden state,特别适合放到 CPU,甚至提前计算。查表后的 Linear 投影仍有矩阵运算,但 OE 参数虽然很大,每个 token 只访问极少几行。换个视角来说,这也是一种对 input embedding 的稀疏化。
2-gram (b,c) -> hash_i -> Emb_i -> Linear_i -> sum_i --+
3-gram (a,b,c) -> hash_i -> Emb_i -> Linear_i -> sum_i --+-> SUM
1-gram c -> Token Embedding ------------------------+ |
v
Transformer -> LM Head
每条 n-gram 分支里的 i=1,\ldots,k 对应多个 slice;先在分支内求和,再与基础 token embedding 相加。
二、Per-Layer Embeddings(PLE)
Gemma 3n、Gemma 4 E2B / E4B 都使用了 Per-Layer Embeddings。
Motivation 为:减少 backbone 做“静态记忆”的负担,用 memory scaling 换 compute scaling,不同深度可以学不同的 token prior。前者也是后续 Engram 的 motivation。
做法上,除了普通 token embedding 之外,再给每个 token 在每一层都准备一份独立的低维 embedding,例如:
模型运行到第 m 层时,会取出这个 token 对应的第 m 层 PLE,用当前 contextual hidden state 乘 gate 矩阵,再过 GELU 产生一个 gate,选择性读取其中的信息,然后投影回 hidden dimension,加到 residual stream。
它的本质可以理解为一种 layer-specific token memory:让深层网络不必完全依赖前面几十层去保存原始 token 信息,而是每层都能直接访问一份针对该层专门学习的静态记忆。
这样可以用大量、稀疏访问的 embedding 参数提升模型容量,同时只增加较少的实际计算。
三、Engram
Motivation:Conditional Memory
Engram 比较难得,是一篇在技术上和写作上都很棒的 paper,并且在吸取了 OE 与 PLE 的设计经验后进一步创新。我们来细读一下。
首先是 motivation 上,将大模型的计算分为:
1、 动态、组合性的计算:逻辑推理、数学推导、代码、长距离关系等,需要真正的深层 block 计算。
2、 静态、局部、重复的模式:人名、地名、固定短语、习语、常见局部组合等,本质上更类似“看到 key,取出 value”,并不需要很深的计算来获取这类 factual knowledge。
在此之外,作者还有另外更大的野心:希望找到第二个 sparsity 轴,即 Conditional Memory;以及在 dense compute 和 MoE experts 之外,找到 LLM 的第三种容量 scaling 方式:增加静态、稀疏访问的 memory。
从 N-gram Lookup 到 Residual Injection

因为大模型 tokenizer 中,许多文本形式近似等价的 token 却拥有完全不同的 ID,例如大小写差异、是否带前导空格等,Engram 首先对 token 做 canonicalization,将这些变体映射到更统一的表示空间。
随后,在当前位置构造 2-gram、3-gram 等局部短语,并通过多个独立 hash 函数映射到超大的 embedding table 中进行查表:
查出的 memory e_t 经过共享的 Value projection W_V,得到:
在 mHC 中,同一层的多个 residual stream 共享这份 memory 和 W_V,但每个 branch m 拥有独立的 W_K^{(m)}。模型利用当前 branch 的 hidden state h_t^{(m)} 与 memory key 计算 context-aware gate:
从而得到该 branch 实际读取的 memory:
最后,原文中声称是为了进一步扩大局部感受野并增强非线性,在 gated memory 序列 \tilde V 上加入一个轻量的 short depthwise causal convolution:
(这玩意儿我很存疑。)
最终 Y 再写回对应的 residual stream。整体上就是:canonicalization → N-gram hash lookup → context-aware gated retrieval → local causal convolution refinement → residual injection。
Infra:Host Memory 与 Prefetch
与 OE 同理,由于 hash 地址只依赖 token ID,memory 可以提前在 CPU / Host DRAM 查表并异步搬到 GPU,与前层计算重叠。因此,可以把参数规模扩得很大,而每个 token 的 lookup 数量保持不变;投影、gate 与卷积仍有少量计算开销。

有趣的实验问题与结论
实验结果就无需多言。接着,我们看看文章里有哪些有趣的实验问题与结论。
1、 固定预算下,MoE 和 Engram 的参数怎么分?
固定总参数和激活参数,只改变 sparse budget 在 MoE 与 Engram 之间的分配。结果呈明显 U 型:纯 MoE 不是最优,大约 75%-80% 给 MoE、20%-25% 给 Engram 效果最好。
2、 Engram 可以 scale 吗?
可以。固定 backbone,只不断扩大 Engram table,validation loss 持续下降,并呈较稳定的 scaling 趋势。更 nice 的是:memory table 可以变得很大,但每个 token 只查固定数量的 row,因此参数规模增长并不会同比增加 FLOPs。所以,memory size 可以成为独立于模型计算量之外的新 scaling axis。
3、 N-gram memory 能改善 reasoning 吗?
可以!虽然 Engram 本身不是在“做推理”,但有了它,也许前几层不必花计算重新组合静态实体和短语,因此能更早进入高层语义处理。LogitLens 和 CKA 显示,Engram 模型在更浅层就能形成接近 baseline 更深层的表示,因此作者称其提升了 effective depth:把更多真正的 Transformer 深度留给组合推理、数学和代码。
4、 Engram 能改善长上下文吗?
可以!普通 Attention 不仅要处理长程依赖,还要承担大量局部 pattern 建模;Engram 把一部分 local dependency 直接交给 memory lookup。这样,Attention capacity 可以更多用于 global dependency。(写到这里,不禁再次让我想到 Zeyuan 的语言模型物理学。)
5、 Engram 应该放在哪一层?哪些组件真正有用?
这也是一个需要 trade-off 的事情。直觉来想,太早时 hidden state 缺少 context,可能 gate 不准;太晚又已经浪费了前层计算。文章实验发现,在第二层放置最好,把预算拆成多个 Engram、分布在不同深度,还能进一步提升。
消融上,context-aware gate、tokenizer compression、mHC branch-specific fusion 最关键;Short Causal Conv 只有小幅增益(于是 DS4.1 干脆删了)。
6、 Engram 到底学了什么?
关闭 Engram 后,事实知识类任务性能大幅下降,而阅读理解保留得更多。这说明模型自然形成了功能分工:Engram 更偏向存储实体、事实、固定短语等静态 parametric knowledge;Transformer backbone 更偏向上下文处理、组合与推理。
当然,以上结论都是在小 size 模型上做的。在现在的发版模型中,具体 Engram 的配置也有了一些变化。
四、Qwen3.8 Flash Next 的消融
在这里,我简单提下 Qwen3.8 Flash Next 中的消融结论。

1、 N-gram 层数放置。 浅层总体较强,但中层、深层也有竞争力;把固定参数预算拆成两层并没有稳定收益。因此,最终选择只放 Layer 2。放在 Layer 2,可以在计算 Layer 1 时,从 host memory 提前 prefetch N-gram embedding。
2、 固定总参数预算。 约 25% 参数给 N-gram 时,training loss 最好,但 downstream 评估上并没有对应的 25% 最优点。
3、 固定 backbone,额外增加 N-gram 参数。 从 loss 上来看,N-gram 可以持续 scale。但是,“loss 越低 ≠ downstream 越好”:reasoning benchmark 到一定规模之后会持平,甚至下降。
4、 中文 benchmark。 N-gram 对中文 benchmark(如 C-Eval 和 CMMLU)的 scaling 特别稳定。

此外,LongCat-2.0 的选择也略有不同,在这里我不再赘述,感兴趣的可以去看他们的技术报告。
作者:Yuwei Niu
https://github.com/Purshow/Purshow_Notes/blob/main/Ngram_Embedding/CN/Ngram_Embedding_CN.md