OpenAI 推出的 "Predicted Outputs" 特性的原理是什么?

2024-11-19 阅读 7
更新于 2026年01月03日
就是speculative edits,cursor发明的玩意
原理很简单。llm正常的解码,一个token一个token蹦,很慢。
想要加速就得想办法并行,正常思路就是speculative decoding,即用一个小模型先想几个token的draft,然后把这几个token一次全都跑一个概率出来。
如果draft不错,就留下。如果大模型和小模型意见不同,就扔掉。
那对于改代码这种常见的应用场景,最好的draft是什么呢?
不是小模型的prediction,而是被改的代码本身
举个例子。假如我们的file有5个function,其中我们想要改第三个。
4o会先生成前两个function,才开始干正事,这就一分钟过去了。
sonnet则会只生成第三个function,可这就需要用户自己复制粘贴。
那么speculative edits就会把整个file全部给大模型,去算每个token位置上用这个token的概率
大模型因为不准备动前两个function,就会都output 100%,直到第三个function,发现哦不对了,开始改,这会儿进入正常解码模式。
这样,处理前两个function的速度基本能做到跟prefilling的速度一样
高赞回答已经提到了 Predicted Outputs 背后大概率是 Prompt-lookup Decoding 这类推测解码技术。那我们来聊聊这类技术的优势和局限。
首先回顾下推测解码。GPU 在 decoding 过程中大量时间花费在访存读取权重,矩阵运算的时间占比较低。基于这个发现,我们可以推算出 decoding 阶段输入一个 token 和 \gamma\gamma 个 token 的时间开销基本一样,因为绝大多数时间还是花费在读取权重上。
因此,如果我们能在 decoding 之前花很少的时间猜出 \gamma\gamma 个 draft token 作为输入(通常称作 drafting 过程),执行一次 decoding(通常称作 scoring 过程),最后再通过一个算法快速决定这 \gamma\gamma 个 token 中哪些是正确的(通常称作 verification 过程),推理的速度将会有明显的提升。
传统的推测解码需要一个小模型来完成 drafting 的工作,小模型的输出和大模型越相似,推理速度越快。但小模型不可能在所有场景下都做的和大模型一样好,因此有些时候,传统推测解码反而是负优化。
现在说回 Prompt-lookup Decoding。顾名思义,这个算法是通过匹配 prompt 中相似的 token 序列,生成 draft token 的算法。这个算法的优势在于不需要小模型做 drafting,并且 drafting 的计算很简单,完全可以放在 CPU 上完成。而劣势也显而易见,如果接下来要生成的 token 不在 prompt 中,drafting 带来的时间开销反而会让推理变慢。
根据 Spec-Bench 的评测,Prompt-lookup Decoding 在总结类任务上表现非常出色(因为 prompt 中的 token 大概率出现在输出中),但在翻译类任务上翻大车(因为 prompt 中的 token 几乎不可能出现在输出中)。
Spec-Bench 对各种推测解码技术的评测但在 OpenAI 的 Predicted Outputs 特性中,draft token 是通过匹配用户传入的 text 生成的,也就是说,用户要保证传入的 text 和输出有大量重叠的部分,这个前提条件确保了 Prompt-lookup Decoding 能够总是有性能收益。
Predicted Outputs 这个特性在很多开源推理引擎(如 vLLM)中也早已支持了,只不过 API 层面并没有允许用户传入 prediction text,而是直接用 prompt。相信开源社区也会快速跟进 OpenAI 的这个新特性 :D
这条路线算是 Speculative Decoding 中比较小众的一条,但在特定场景下的加速比同样很可观。
这条路线主要针对的是模型输出和已有语料重合度很高的情况。在这种情况下,已有语料可以提供质量很高的 draft token。
这条路线上两个比较有名的工作是 REST 和 PLD。REST 使用的是自己构建的语料库,而 PLD 直接使用了 prompt。PLD 没有发表为文章,只有一个 github repo:
而 REST 已经发表于 NAACL 2024,以下是我写的 paper reading,里面也有文章的链接:
OpenAI 这套解决方案就更有意思了。他们很鸡贼地避开了选择什么语料来提供 draft 的问题,选择让使用者自己提供语料。这在实际使用中当然是非常合理的,毕竟针对不同场景可能有不同的语料库选择:改错和 summary 使用原文就很好,翻译问题或许可以用粗糙的逐词翻译作为 draft …… 这只是两个很简单的例子,实际使用中可能可以有一些更大的脑洞。
关于 Speculative Decoding,如果想了解更多的内容,可以考虑看看我的 paper reading 合集:
最逆天的是,用了 pld 的投机采样之后花的钱更多了,详见这篇文章:
周博洋:投机采样的显性化——OpenAI新feature:Predicted Outputs
从成本的角度看,原如果用 PD 分离或者 chunked prefill,原本 forward 一次可以处理多个 token 的 decode (PD 分离)或者多个 prefill + 少量 decode(chunked prefill);而采用投机采样,验证失败的 token 就成为了 overhead, forward 一次的吞吐下降了。
之前做投机采样的同学都在思考:虽然提升了单用户体验,但是降低了吞吐成本上升了怎么办?OpenAI 的答案是:转嫁给用户。
非常巧合的是最近一段时间恰好在做基于检索的投机解码,也看到了大家提到的最相关的两个工作PLD和REST, 和各自的一些缺陷.
这里我也来分享一下我们最近的工作,希望可以是Predicted Outputs的一种可行的开源实现方案
技术上,我们通过后缀自动机进行文本匹配的方式实现草稿的检索,相比于PLD和REST,我们可以同时从上下文和文本库中在均摊O(1)的时间复杂度内找到模型以生成内容的最长后缀匹配,并类似PLD的方式将匹配位置的后续token作为草稿. 同时该方法也可以和基于模型的投机方法共同使用,我们可以根据匹配长度动态的选择使用检索模型或者使用草稿模型。也因此我们的方法可以看作上下文检索、文本库检索和基于模型这三类投机采样方法的集成方法.
实验上,我们可以和目前sota的eagle2方法进行了结合,在保留eagle2各个任务加速比的情况下,进一步针对summarization等任务进行加速。
相对详细的内容见
GitHub: