Strands Decider:为什么不用编码器?
在发布strands-decider之后,Marc Brooker被问及为什么该模型使用解码器而不是编码器。他比较了五种设计,发现对于这个分类任务,解码器表现不俗,在某些条件下还能胜出。
中文
复制
专业水平:已耗尽。
正如我在上一篇文章中承认的,我远算不上专家级模型开发者。以下内容很可能至少有一部分不准确。我尽量做到严谨和量化,以部分弥补专业深度的不足。
上周发布 strands-decider-2B 之后,有几个人问我,为什么它是一个改造过的 LLM,而不是编码器(比如 BERT)。他们的直觉似乎是,双向(即每个 token 的表示由它前后的 token 共同构建)大概率会优于因果(即只使用前面的 token)。编码器被广泛用作分类器,也是同样的道理。
这个问题问得合理,因为稍微换个角度看,我们就是在把解码器当编码器用。
为了验证这个假设,我比较了五种设计:
- v19 是基于 Qwen3.5 的 strands-decider 的最终设计(细节见上一篇文章和 strands-decider README)。
- b1 是编码器-解码器设计(类似最初的 Transformer),基于 T5Gemma 2,编码器 1B 参数、解码器 1B 参数,去掉 LM head,加上我们的 pointer head。
- b2 与 b1 相同,但为 4B+4B。
- e1a 就是 T5Gemma(不是 T5Gemma 2)的编码器部分,2.6B 参数。
- e1b 是 e1a 的延迟优化版本,带 masked state cache,可以并行评估多个问题而互不干扰,state cache 也可以复用 1。
state双向关注整个state,每个问题关注state和自身。
我还测了冻结的 ModernBERT 和 ettin-encoder-1b,但发现它们在同等参数量下不如 T5Gemma,所以没有花时间训练它们。
先看准确率和校准。
b2 在这里表现很好,在 JevBench 准确率和 Brier 上胜过 v19,在 JF100 上以相同准确率取得更好的 Brier。这不错,但别忘了 b2 总参数约 8B,而 v19 只有 2B,所以这不是同等条件的比较。
真正有意思的对比是 v19 和 e1b。在 JevBench 准确率上,e1b 略胜 v19(但落在 v19 的多次运行波动范围内),校准稍差;在 JF100 上校准打平,性能略弱。
到目前为止,编码器模型还谈不上压倒性优势。
接下来看延迟。
纯编码器模型在延迟上赢得干脆,中位数约 35ms,而 v19 是 65ms。编码器-解码器模型最慢。延迟减半、性能相当,看起来 e1b 大获全胜。但深入数据之后,事情就没那么简单了。
可以看到,e1b 在较短 prompt 下优势明显,但随着 prompt 变长,扩展性更差。这与它出色的中位数表现一致。这是否重要取决于工作负载的构成:JF100 和 JevBench 都偏短,对 e1b 有利。这里的扩展性差异归根结底是两个模型的计算成本:e1b 有 26 层完整注意力,带来相应的二次计算成本,而 v19 有 75% 的层是 Gated DeltaNet,计算成本是线性的。这些层的固定成本更高,但渐近成本更好,因此延迟下限更高 2。
最后看一个有意思的支线,回到 e1a(我们未做掩码的 2.6B 纯编码器候选)。在评测集上,它在九个任务中有七个胜过 v19,两个略逊。但在 JevBench 上明显更差(153 对 168),JF100 上也稍差(158 对 162)。这说明编码器的泛化更差,至少在没有 e1b 那种掩码方案的情况下是如此。读取状态时能关注问题,这真的是一种弱点吗?
| 评测集 | v19 | e1a | Δ |
|---|---|---|---|
| 留出的短任务 | 0.647 | 0.695 | +0.048 |
| MuSiQue | 0.882 | 0.948 | +0.066 |
| ContractNLI | 0.873 | 0.864 | −0.009 |
| BoardgameQA | 0.820 | 0.884 | +0.064 |
| HotpotQA(留出) | 0.719 | 0.748 | +0.029 |
| 生成,v16 的 | 0.857 | 0.851 | −0.006 |
| 生成,v18 的 | 0.777 | 0.786 | +0.009 |
| Adequacy,HelpSteer2 | 0.722 | 0.761 | +0.039 |
| Adequacy,生成,均衡 | 0.788 | 0.821 | +0.033 |
那么,编码器与解码器之争,我们到底走到了哪一步?恐怕离真相并没有近多少。这个实验混杂了太多变量——架构、基础模型、指令微调与基础版本,还有其他因素——根本无法理清。但我们确实学到了一些有意思的东西。在这个规模上做这类工作,两者似乎都不是毫无悬念的赢家。
这个实验的代码目前在一个分支里。看起来还不值得并入主线 strands-decider,但经过一些开发之后或许可以。
脚注
- 一些解码器的思路又悄悄回来了。解码器出于同样的原因也用同样的技巧(KV cache 和前缀缓存)。把增量结果缓存起来能提升性能,这肯定不是第一次了。
- 在小数据量下,O(N2) 算法击败 O(N) 算法,这肯定也不是第一次了。
« 返回博客索引
相关文章
- 2026年9月28日 » 小决策:打造一个领先模型
- 2026年7月29日 » Lorenz 与 Little:你的尾部到底有多贵?
- 2026年7月19日 » Aurora DSQL:可扩展的多区域 OLTP
Marc Brooker
本站观点仅代表我个人,不一定代表我雇主的立场。