跳到主要内容
被拒绝的草稿不是废稿——画开 ReTrace

被拒绝的草稿不是废稿——画开 ReTrace

画唠
画唠

· 阅读约 3 分钟

给 ReTrace 这名字绕了不少弯。第一眼看标题——Rejected-Trajectory Conditioning for Speculative Decoding——我直觉把它理解成:上一轮被拒的后缀,拿来当下一轮的条件输入。脑子里立刻出现画面:学生重写错题的时候,把错的那一页垫在下面照抄。

这想法,说好听叫朴素,说难听点就是蠢。后来读到真正的实现细节才知道根本不是这么回事。

先把问题摆出来。推测解码的流程你我都熟:草稿模型噼里啪啦写一段,目标模型一口气验证,验证到第 k 位,不行,卡住。按标准做法,第 k 位之前采纳,第 k 位重新从目标分布采样,第 k 位之后那一整条后缀——直接丢,下一轮从新位置白纸起稿。

我之前一直觉得这事挺浪费的,但说不上来浪费在哪。草稿嘛,本来就是要被删的东西,删了又有什么可惜。

ReTrace 说:可惜。被拒的后缀不是废,是草稿模型用一次前向换来的路标。它上面写了这条路走到哪断的、断面长什么样,你却把它连根拔了,让模型下一轮从头再猜一遍。

标准做法:
  draft: A B C✗ D E F
                │
         C 被拒,D E F 丢进回收站
         下一轮从 C' 开始,D E F 不再参与任何计算

ReTrace:
  同上,但 D E F 没丢
  ——被保留下来,作为下一轮草稿块的条件输入

第一版我画的就是上面这张图,画完有点得意,觉得这么简单一件事也能写篇论文。结果往细里读,发现自己漏了关键一格。

ReTrace 不是把被拒后缀当普通文本拼回去。它保留的是那串被拒后缀的隐藏表示——模型在生成它的时候,中间层留下的向量。草稿模型在算 D E F 的时候并不是瞎猜的:D E F 虽然被目标模型拒了,但里面带着"我当时认为下一步大概会长什么样"的全部结构信息。它把这个隐藏表示跟下一个草稿块做对齐,再拿同一轮验证过程中目标模型给的校正信号精炼一遍,最后通过一个门控残差融合,注入草稿模型的输入嵌入。

看到这里我愣了一下。这几个词放在一块,"对齐"、"校正信号"、"门控残差融合",乍一看像堆术语,其实翻译过来就是:把旧轨迹在被拒绝的那一瞬间长什么样,经过目标模型验证时暴露出来的偏差修正之后,悄悄放到草稿模型下一轮起笔的位置旁边。

不是把废稿贴在纸上让模型抄——是让模型在算下一块的时候,"手感"里还留着上一条路走到哪、往哪个方向走会撞墙的体感。

等等等等,先别急。我当时卡住的是另一个问题:一个被拒的词元永远不会被正式采纳,那它凭什么帮我生成下一个更合理的词元?

想了一会儿才反过劲来。我把它想反了。草稿模型不是把旧轨迹当标准答案,是当参照物。道理其实很朴素:草稿模型在某个位置选了 D,目标模型说不行——但那只说明 D 这一步概率不够高。D E F 这一段里,可能局部某个位置跟目标模型接下来的真实输出是吻合的;甚至整段方向都是对的,只是中间错了一两个词元。草稿模型不是全错,是局部有误差。

这就涉及一个更深的

画唠
画唠

把被讲玄的概念用图 + 比喻 + 动手实验拆到咔哒扣明白,错的也保留。

查看主页 →