研究团队用一页代码检查了八个公开模型的因果正确性,发现两款存在缺陷——前向传播未正确遵守自回归约束,影响KV-cache复用和投机解码。
模型发布时会报告参数量、上下文长度、训练 token 数、基准分数。但它们不报告发布的实现是否满足因果正确性——即前向传播是否真正遵守了使自回归建模有意义的基本约束。
所有对模型的实际使用都默默假设了这个约束:Teacher-forced 训练、PPL 评估、增量解码、KV-Cache 复用、投机解码。全部依赖于此。
历史上这种遗漏是可以容忍的。纯解码器的 Transformer 只有一种主要的时间混合机制——自注意力——而它的因果行为由一个显式 mask 控制。所以人们检查 mask 就认为是做了一次审计。
这个假设现在不成立了。现代技术栈在单一模型中混合了异构的混合器:局部注意力、稀疏注意力、线性循环、结构化状态空间模型、状态空间对偶、循环-注意力混合体、卷积替代方案。在这样的系统中,显式注意力 mask 只管辖部分层,而在某些层里根本没有 mask。
传统的审计已经无法覆盖大部分计算图,但没有人来替代它。
因果泄漏不是崩溃。它不会抛出异常。也不会产生明显破坏的输出。
它只会让你的指标看起来更好。
如果未来信息到达了更早的位置,next-token 预测就会变得人为地更容易。训练 loss 下降。验证 PPL 下降。从 teacher-forced 似然计算出的基准分数提高了。仪表盘上的一切都在说这次改动有效。
这种不对称才是问题所在:泄漏提升的恰恰是你用来筛选模型的那些指标,而它只在自由运行生成、部署或下游评估时才会暴露。等有人注意到的时候,基于架构比较来证明设计合理性的工作早已被污染了。
这与 ML 研究中的数据泄漏是同一类问题——学界已经认识到数据泄漏是跨科学领域可复现性失败的主要贡献因素之一。区别在于这种泄漏存在于前向传播内部。
这最初是一个工程工具,而不是研究项目。
在开发一个内部混合序列模型技术栈时,我们遇到了三个独立的因果故障:
一个输出偏移被翻倍了。两个各自正确的对齐操作组合后暴露了一个未来 token。
手写注意力路径中一个错误的因果条件。一个因果邻域被替换成了对称的那个。
一个差分注意力的聚合故障。两个注意力图之间的减法发生在一个已经混合了跨时间信息的序列级聚合之后。
每一个都花费了大量手动调试。每一个都违反了同一个底层属性。没有任何一个在常规训练遥测中显现。
三次定制调试会话处理同一种 bug,这说明你缺少一层抽象。
INPUT model f with layers [1..L]; sequence length T; threshold τ
OUTPUT verdict ∈ {CLEAN, LEAK}; first offending layer ℓ*
1 x₁ ← random token sequence of length T
2 x₂ ← copy of x₁ with position T−1 replaced by a different token
3 attach a forward hook to every layer, capturing its output
4 h₁ ← f(x₁) with caching disabled # forward pass 1
5 h₂ ← f(x₂) with caching disabled # forward pass 2
6 for ℓ = 1..L:
Δℓ ← max |h₁ℓ[0:T−1] − h₂ℓ[0:T−1]| # exclude the differing position
7 ℓ* ← min{ℓ : Δℓ > τ}, or NONE
8 return (LEAK, ℓ*) if ℓ* exists else (CLEAN, −)
这就是全部方法。两次前向传播。不需要训练、梯度、标签,甚至不需要加速器——我们的普查是在 CPU 上跑的。
我们特意完整地展示它。论文的论点是:这个检查足够便宜,理应成为强制性的,而一个放不满一页纸的检查不会成为强制性的。
四个设计选择承载了整个方法的重量:
逐层 hook,而不是输出 logits。 只读取最终的 logits 能告诉你模型是否泄漏。但它无法告诉你泄漏在哪里,因为输出投影已经混合了每一层的贡献。这个测试的交付物是一行代码供工程师查看,所以层索引才是关键。在我们的消融实验中,仅看 logits 的版本检测到了每一个注入的故障,但一个也没有定位到。
排除最后一个位置。 位置 T−1 的差异是合法的——那就是扰动点。对 [0, T−1) 比较精确隔离了必须保持不变的前缀。
测试期间禁用缓存。 增量缓存改变了执行的代码路径。
单个 token 差异就足够了。 它足以暴露任何违规,而且它是构造扰动时最便宜的方式。
八种注入泄漏模式,在三个深度各应用一次(早期层、中间层、晚期层),跨越八个检查点。
Mask 检查什么都没发现,这不是 mask 检查的 bug。这本身就是重点:泄漏不在 mask 里。它们在 scan 和 normalization 里——mask 永远不会触及的代码路径。
除了注入的故障之外,审计还在两个公开发布的混合模型中发现了缺陷。
泄漏恰好在每个模型的分块扫描边界处开始。在 chunk 大小以下,两个模型看起来都是干净的。这不是一个你可以争论的巧合——这是一个指纹,指向了特定的实现路径。
而且我们不是偶然发现这些的。对分块扫描实现的静态分析预测了两个发布混合模型中的因果违规,动态审计确认了这两个预测。
float32 前向传播不是位精确的,所以任何基于 Δ 的测试都需要一个判别器。我们的方法是 ε-sweep:用不同量级进行扰动,观察 Δ 如何响应。
Zamba2 slope 0.63 ± 0.07 ← 真正的泄漏随扰动而缩放
Granite-4.0-h flat ← 数值噪声底
Jamba-tiny flat ← 数值噪声底
真正的泄漏会攀升。数值噪声底会保持平坦。Granite-4.0-h 和 Jamba-tiny 在这个测试下是干净的,而且我们能够有证据地这样说而不是因为没去看,这很重要。
1. 干净的结果在同一个加载的检查点上没有阳性对照就无法解释。
我们从一个失败的审计中学到了这一点。如果你的测试报告 CLEAN,你有两种解释——模型是正确的,或者你的测试没有接好。将一个已知故障注入到那个确切加载的检查点中,并确认测试能捕获它,这是唯一能将两种解释区分开的事情。其他的都是在信任你自己的工具,因为它与你一致。
2. 审计序列长度必须超过架构的 chunk、kernel 或 window 参数。
我们的默认值是 T = 48。在 T = 48 时,Zamba2 看起来是干净的。它的 chunk 大小是 256;相关执行路径从未被进入。一个从未到达 buggy 分支的测试报告的是你想听到的结果。
这个规范不只限于因果性:你的测试必须执行 bug 所在的路径,而架构常量告诉你这些路径从哪里开始。
我们将这个功能构建到 AX-RAY 中——我们的模型诊断系统——因为它解决的现实问题不是学术性的。
当一个组织采用外部模型时,它继承了这个模型的实现。基准分数不能告诉你实现是否满足因果正确性——如上所示,因果缺陷可以让那些基准分数更高。人们用来做决策的那个数字,正是被缺陷虚高的那个数字。
所以有用的门槛不是"这个模型分数好吗"。而是:
因果泄漏的发现不能被好的基准分数覆盖。
这个顺序就是整个产品论点。能力指标和正确性证据是不同类型的声明,一个不能替代另一个。
参数量、上下文长度和基准表随每个模型发布一起交付。因果正确性证书也应该随它们一起交付。
不是因为模型作者不小心——我们发现的两个缺陷来自严肃团队的严肃模型,而且它们正是那种能躲开所有标准检查的 bug。这就是论点的核心。如果一类 bug 对每个人使用的工具都是不可见的,答案就是一个新的、足够便宜的、每个人都会运行的工具。
两次前向传播。不需要梯度。在 CPU 上运行。放得下一页。
没有理由不这样做。
Paper: arXiv:2608.22876 — The Mask Is Not the Model: Auditing Prefix Invariance in Attention, State-Space, and Hybrid Sequence Models Authors: Taebong Kim, Youngsik Hong, Minsik Kim, Sunyoung Choi, Jaewon Jang, Minseo Kim — VIDRAFT AI Research AX-RAY: vidraft.net