信号场注意力(SFA):把 KV Cache 变成 O(1) 的双通道注意力------0.1B/0.3B 受控 A/B 精度反升 15.5% / 24.3%
一句话:把注意力拆成「近场滑窗 softmax + 远场 EMA 信号场」两个通道,解码状态从随长度线性增长变成常数 2.362 MB(2,080 个位置下比标准注意力小 64.9×),而精度不降反升------0.1B 规模受控 A/B 相对困惑度降低 15.51%±0.21pp,0.3B 规模降低 24.34%±0.70pp(均以最差种子判定,预注册 fail-closed)。## 1. 问题:推理的瓶颈不是算力,是 KV Cache自回归解码每一步都要读全部历史的 K/V。标准注意力的 cache 随上下文线性增长:| 上下文长度 | 标准注意力 cache(0.1B 模型,单层) ||---|---|| 512 | 约 37.7 MB || 2,048 | 约 153.4 MB || 8,192 | 约 613 MB |batch 一上来就是 GB 级。社区已有两条应对路线:滑窗/稀疏注意力 (丢远期信息)和线性注意力/RNN 式固定状态(改递推形式)。
TL;DR
- O(1) 解码状态 :解码状态从随长度线性增长变为常数 2.362 MB(@2,080 位置),比标准注意力小 64.9×(153.4 MB)。
- 精度反升 :受控 A/B 下 0.1B 相对困惑度降低 +15.51% 、0.3B 降低 +24.34%,均以最差种子判定(worst-seed)。
- 预注册 fail-closed 协议 :SFA 腿与 Std 腿共享一切、唯一分歧是
use_sfa开关;跑前锁死配方,违反即中止,门禁不橡皮图章。 - 诚实的边界:仅单域语料(TinyStories)、1,000 步未收敛预算、无外部同协议基线------不夸大,全部如实披露。
三条路线在关键维度上的差异如下:
| 维度 | 滑窗/稀疏注意力 | 线性注意力(如 Mamba) | SFA(本文) |
|---|---|---|---|
| 远场信息处理 | 丢弃(窗口外 token 完全不参与) | 递推(固定状态按步递推,历史被压缩进状态) | 压缩(EMA 信号场,按距离指数加权,不丢但压缩) |
| 解码状态复杂度 | 随窗口大小固定,但窗口外信息永久丢失 | O(1) 固定状态(如 Mamba 的 SSM 状态) | O(1) 固定状态(ring + 远场标量态,2.362 MB @2,080 位置) |
| 精度表现 | 窗口外信息丢失,长程依赖受限 | 状态压缩有损,长程检索能力弱(NIAH 常失败) | 受控 A/B 精度反升(0.1B +15.51%、0.3B +24.34%,worst-seed 判定) |
| 实现复杂度 | 低(只需 mask 窗口) | 中(需改写为递推核,如 selective scan) | 中高(ring buffer + EMA 双通道,需两套核 + parity 测试固化等价性) |
本文走第三条:保留精确的 softmax 近场,把远期压成一个 EMA 信号场------远场不是被丢掉,而是被压缩成一个固定大小的向量。
下面是双通道注意力的数据流总览:
#mermaid-svg-h9pPh02TaR5hfZoP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-h9pPh02TaR5hfZoP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-h9pPh02TaR5hfZoP .error-icon{fill:#552222;}#mermaid-svg-h9pPh02TaR5hfZoP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-h9pPh02TaR5hfZoP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-h9pPh02TaR5hfZoP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-h9pPh02TaR5hfZoP .marker.cross{stroke:#333333;}#mermaid-svg-h9pPh02TaR5hfZoP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-h9pPh02TaR5hfZoP p{margin:0;}#mermaid-svg-h9pPh02TaR5hfZoP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-h9pPh02TaR5hfZoP .cluster-label text{fill:#333;}#mermaid-svg-h9pPh02TaR5hfZoP .cluster-label span{color:#333;}#mermaid-svg-h9pPh02TaR5hfZoP .cluster-label span p{background-color:transparent;}#mermaid-svg-h9pPh02TaR5hfZoP .label text,#mermaid-svg-h9pPh02TaR5hfZoP span{fill:#333;color:#333;}#mermaid-svg-h9pPh02TaR5hfZoP .node rect,#mermaid-svg-h9pPh02TaR5hfZoP .node circle,#mermaid-svg-h9pPh02TaR5hfZoP .node ellipse,#mermaid-svg-h9pPh02TaR5hfZoP .node polygon,#mermaid-svg-h9pPh02TaR5hfZoP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-h9pPh02TaR5hfZoP .rough-node .label text,#mermaid-svg-h9pPh02TaR5hfZoP .node .label text,#mermaid-svg-h9pPh02TaR5hfZoP .image-shape .label,#mermaid-svg-h9pPh02TaR5hfZoP .icon-shape .label{text-anchor:middle;}#mermaid-svg-h9pPh02TaR5hfZoP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-h9pPh02TaR5hfZoP .rough-node .label,#mermaid-svg-h9pPh02TaR5hfZoP .node .label,#mermaid-svg-h9pPh02TaR5hfZoP .image-shape .label,#mermaid-svg-h9pPh02TaR5hfZoP .icon-shape .label{text-align:center;}#mermaid-svg-h9pPh02TaR5hfZoP .node.clickable{cursor:pointer;}#mermaid-svg-h9pPh02TaR5hfZoP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-h9pPh02TaR5hfZoP .arrowheadPath{fill:#333333;}#mermaid-svg-h9pPh02TaR5hfZoP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-h9pPh02TaR5hfZoP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-h9pPh02TaR5hfZoP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h9pPh02TaR5hfZoP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-h9pPh02TaR5hfZoP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h9pPh02TaR5hfZoP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-h9pPh02TaR5hfZoP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-h9pPh02TaR5hfZoP .cluster text{fill:#333;}#mermaid-svg-h9pPh02TaR5hfZoP .cluster span{color:#333;}#mermaid-svg-h9pPh02TaR5hfZoP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-h9pPh02TaR5hfZoP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-h9pPh02TaR5hfZoP rect.text{fill:none;stroke-width:0;}#mermaid-svg-h9pPh02TaR5hfZoP .icon-shape,#mermaid-svg-h9pPh02TaR5hfZoP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-h9pPh02TaR5hfZoP .icon-shape p,#mermaid-svg-h9pPh02TaR5hfZoP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-h9pPh02TaR5hfZoP .icon-shape .label rect,#mermaid-svg-h9pPh02TaR5hfZoP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-h9pPh02TaR5hfZoP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-h9pPh02TaR5hfZoP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-h9pPh02TaR5hfZoP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入 token x_t
注意力头内部
近场通道:因果滑窗 softmax
k_w = 32(ring buffer)
远场通道:EMA 信号场
γ = 0.98, α = 0.1
out_near
out_far = α · fieldt
两通道输出相加
o_proj
输出
2. 方法:双通道注意力
每个注意力头内部有两条并行通道:
近场(精确) :对最近 k_w = 32 个 token 做标准因果滑窗 softmax。ring buffer 实现,写入覆盖最旧槽位。
远场(压缩):对全部更早历史维护一个 EMA 信号场:
text
field[t] = γ · field[t-1] + (1-γ) · k̄[t] γ = 0.98
k̄[t] = mean over heads of k[t] (先在 head 维平均,单头广播)
out_far = α · field[t] α = 0.1
两条通道相加后过 o_proj。γ=0.98 对应有效视界 H(γ)=ln(ε)/ln(γ)≈134 个 token 量级,α=0.1 决定远场权重------这两个值是锁死的(见第 6 节)。
为什么远场可以是 EMA:softmax 注意力对远期 token 的权重天然随距离衰减;EMA 是「按距离指数加权」的线性时间实现,与 softmax 的衰减形状同族,但状态是 O(1)。
状态完整性 :枚举「历史→输出」的影响路径,只有两条------(i) 仍在 ring buffer 里的近窗 token,(ii) 远场标量态。(ring, far-state) 是 h_<t 的充分统计量,不存在第三条路径。论文给了形式化论证,并用测试固化了「批量 prefill 物化 ≡ 串行递推」的逐位等价(19 项 parity 用例)。
3. O(1) 解码状态:2.362 MB vs 153.4 MB
| 指标 | 标准注意力 | SFA | 倍数 |
|---|---|---|---|
| 解码状态 @2,080 位置 | 153.4 MB | 2.362 MB | 64.9× 更小 |
| 随长度增长 | 线性 | 常数 | --- |
| 组成 | 全部 K/V | ring(32×head_dim)+ 远场(head_dim) | --- |
状态从 160 到 2,080 token 恒定不变------这就是「O(1)」的实测含义,不是渐近口号。
4. 受控 A/B:唯一变量是注意力
实验设计只有一条纪律:SFA 腿和 Std 腿共享一切 (同骨架、同初始化分布、同语料、同分词、同优化器、同 seed、同 batch 序),唯一分歧是 use_sfa 开关。语料 TinyStories(MIT),GPT-2 BPE 分词,两条腿都从零训练,不使用任何第三方权重。
预注册 fail-closed 配方(跑前锁死,违反即中止):
| 项 | 值 |
|---|---|
| lr / 调度 | 3e-4,cosine + warmup 200 |
| γ / α / k_w | 0.98 / 0.1 / 32 |
| seq / steps | 512 / 1000 |
| seed / 精度 | 42 / bf16 训练、fp32 推理 |
| grad clip | 1.0 |
| batch | 0.1B: 8;0.3B: 4 |
判决规则:以最差种子判定,不用均值------均值会掩盖单条崩掉的种子。地板 0.1B ≥ 0.10、0.3B ≥ 0.18,跑之前定死。
结果(Δ_rel = (PPL_std − PPL_sfa)/PPL_std,正号 = SFA 更优):
| 规模 | 参数量 | Δ_rel(mean ± std, 3 种子) | 最差种子 | 判决 |
|---|---|---|---|---|
| 0.1B | 124,009,728 | +15.51% ± 0.21 pp | +15.37% | PASS(过地板 0.10) |
| 0.3B | 236,686,336 | +24.34% ± 0.70 pp | +23.79% | PASS(过地板 0.18) |
种子间离散度 0.21pp,而实测设备噪声底约 3.8×10⁻⁵------信噪比约 200×,说明种子差异不是设备抖动。
诚实的披露 :0.3B 的 +24.34% 超出了预注册区间上界 0.24。按协议仍判 PASS,但区间外这一点在论文里明确标注,不回避。
5. 速度:解码快 1.97×,但 prefill 慢 1.23×
| 指标 | Std | SFA | 说明 |
|---|---|---|---|
| decode-only 吞吐 | 52.1 tok/s | 102.5 tok/s | 中位数,1.97× |
| 端到端 @2k | 2,291 tok/s | 3,094 tok/s | 1.35×(margin 被 prefill 消耗一部分) |
| prefill @2k | 基准 | 慢 1.23× | ⚠ 不利结果,同表报告 |
decode 快的来源直接:状态小了 64.9×,每步要搬运的字节少。prefill 慢是因为远场矩阵构造有额外代价------这个 1.23× 是如实报告的不利结果,论文 §5.3 里和有利结果放在同一张表。
6. 代码与复现
完整实现 + 判决门禁 + 证据文件,Apache-2.0:
sfalib/attention.py:双通道注意力、ring buffer、EMA 两套核(matmul 参考实现 + O(s) 前缀扫描)sfalib/train.py:训练循环,fail-closed 前置(EMA 核对 fp32 参考 L1≤1e-5 不过就中止;loss/梯度非有限不写 checkpoint)sfalib/gate.py:判决门禁(floor/band/worst-seed/环境审计)tests/:62 项测试,含论文验证矩阵 45 项(prefill≡串行 19 项 parity 等)evidence/:12 份result_1000steps.json+ 门禁判决 + 环境日志,随论文发布
复现论文 headline 数字(M1 16GB 上 0.1B 单腿约 1.5--2h):
bash
pip install -e .
python -m sfalib.train --config 0.1B --use-sfa --batch-size 8 --steps 1000 --seed 42
python -m sfalib.train --config 0.1B --no-sfa --batch-size 8 --steps 1000 --seed 42
python -m sfalib.gate --scale 0.1B \
--sfa-result checkpoints_torch/0.1B/sfa/result_1000steps.json \
--std-result checkpoints_torch/0.1B/std/result_1000steps.json
不想等两小时:evidence/ 里已发布全部原始结果文件,直接对它们复算判决,秒出同样结论。
另外仓库带一个 demo 档(离线合成语料、CPU、约 1 分钟),一条命令跑通「训练→证据→判决」全链路:
bash
python examples/demo_ab.py
7. 诚实的边界(论文 §5.3 全文列出)
不夸大,这条最值钱:
- 单域语料:只有 TinyStories(合成儿童故事),没有跨域验证;
- 未收敛预算:1,000 步,不是训练完成态;
- 两个规模:0.1B / 0.3B,没有 7B 级验证(7B 档只做了形状参数核对,本地 M1 跑不动);
- 单机:全部数字产自一台 Apple Silicon,无 CUDA/集群验证;
- 无外部同协议基线 :Mistral/Qwen/Mamba 等只在 Related Work 里被引用定位,没有在本文协议下跑过对比,不作任何比较声称;
- NIAH 两腿均零命中:针在干草堆测试两腿都没检索到,这是已记录的失败案例,不粉饰。
8. 小结
SFA 的卖点不是「更快」这一个维度,而是同时 拿到了三件事:解码状态 O(1)(64.9×)、精度正向(+15.5%/+24.3%,worst-seed 判定)、以及一套预注册 fail-closed 的可复现协议(门禁不橡皮图章,demo 档上它诚实地判 FAIL)。
对做推理引擎的同学,最实用的部分是 sfalib/attention.py 的 ring buffer + EMA 实现和 19 项 parity 测试------ correctness 的证据比 headline 数字更耐看。
作者:QN1幻化引擎 · 贾大林(石家庄)
代码 Apache-2.0;语料 TinyStories(MIT)、GPT-2 BPE via tiktoken(MIT)、PyTorch(BSD-style)。未使用任何第三方模型权重。