各位同学,我们就开始来上课吧。今天这堂课要讲的是 自我修正(Self-Correction: 语言模型在没有人为介入下发现并纠正自身错误的能力)。我们要探讨这些语言模型有没有自我修正的能力。今天这堂课我们想要讲的是,我们都知道,语言模型非常厉害,它可以根据人类给它的回馈修正自己要做的事情。比如,你给它一个输入,它给你一个输出,接下来你告诉它你做错了,告诉它错在哪里,往往语言模型有能力更正它原有的错误行为。但今天这堂课要讲的是,能不能在没有人力介入的情况下,语言模型输出一个答案后,它自己发觉自己是错的,自己修正自己的行为。这正是今天这堂课要探讨的主题。
类似的主题过去其实也有讲过。第一次讲到让语言模型自我反省、自我修正这件事,是在机器学习的2023年。那时正是 ChatGPT 的年代,人类文明刚刚建立。那时人类就发现这些语言模型某种程度上有自我反省的能力。今天课程内容有很大一部分是2025年机器学习第七讲的延伸。在去年的第七堂课,我们讲了怎么让模型有 推理(Reasoning: 模型通过一系列逻辑步骤得出结论的能力)的能力。当然,推理这件事今天大家可能一点都不陌生,几乎每一个你在线上用的语言模型都已经有推理的功能了。但在2025年,这仍然是一个相对比较新的技术。今天有很多内容就是2025年讲推理部分的延伸。我们来看看在过了一年之后有什么样新的进展。我们不会重复过去太多的内容,我们讲的都是新的东西。
今天呢,要讲三件事。怎么让模型做到自我修正呢?有三个不同的方向。第一个方向是修改 推理过程(Inference Process: 模型从输入生成输出的过程)。第二个方向是修改上次提到的 工作流程(Workflow/Harness: 改变模型任务执行的步骤或策略)。第三个部分是在模型的参数上直接改变它,这其实就是大家现在都很常听到的推理技术。
优化推理过程:自发错误检测与修正
我们就先从修改推理过程开始讲起。大家对于一个语言模型怎么做生成,想必都非常熟悉。语言模型的输入是一排 标记(Token: 文本或代码的基本单元),这些标记被丢到 变换器(Transformer: 一种基于自注意力机制的深度学习模型架构)之后,它们会变成一排 表示向量(Representation: 数据在模型内部的抽象数值形式),最后变成一个 概率分布(Probability Distribution: 表示每个可能输出结果的发生概率)。我们从这个概率分布中进行 采样(Sample: 从概率分布中随机选择一个输出),采样出一个标记,这个标记会变成下一个时间点的输入,再产生下一个概率分布,再产生下一个标记,这个过程就反复继续下去。
我们怎么在这个推理过程中让模型自我修正呢?这边分成两个可能的步骤。第一个步骤是有没有办法在生成过程中,模型在生成过程中会产生一些表示向量,它会产生一些概率分布。有没有可能从这些表示向量跟概率分布中看出模型有可能会犯错,看出模型现在讲的话有可能是错的,自动做 错误检测(Error Detection: 自动识别模型输出中可能存在的错误),然后根据错误检测的结果去修正模型最终的输出?这个检测跟修正在这里都假设是自动的,不需要人力介入的。有没有办法从模型生成过程中找出跟错误有关的信号,再用这些信号来修改最终的输出?这就是第一部分在推理时可以做的事情。
我们来看这两件事到底有没有可能做到?这边引用一些比较早期的文献,一篇2023年的文献,在2024年的课程里就有提过这篇论文。这篇论文的做法是,它收集了语言模型在回答正确时和错误时的表示向量。接下来,在这篇论文中,作者训练了一个 二元分类器(Binary Classifier: 一种将数据分为两个类别的机器学习模型),其工作就是分辨一个表示向量会导致正确的答案还是错误的答案。在他们的论文中发现,真的能训练出一个分类器,根据表示向量判断这个答案有可能是对的还是错的。而且这个分类器具有 泛化能力(Generalize: 模型在未见过的数据上表现良好的能力)。他们训练在一堆问题上,然后可以在另外一堆问题上测试,在某种程度上预测一个答案会不会被答对。这意味着代表答案是对的还是错的信号可以从表示向量中被抽取出来,我们只需要知道怎么抽取这些代表答案是正确还是错误的信号。
接下来,在2024年,有另外一篇论文叫做 True Facts,展示了将错误答案修正成正确答案是可能的。这篇论文的做法是:假设你已经收集到模型会答错时的大量表示向量,以及答对时的大量表示向量。接下来,你将答错的表示向量平均,答对的表示向量平均,然后将它们相减,得到一个黄色向量,代表正确与错误之间的差距。然后,你就把这个黄色向量加到模型本来会答错的问题上。模型本来看到这个问题,它产生这个表示向量,接下来会答错。你知道正确与错误的差距就是这个黄色向量。你把这个黄色向量直接加到导致错误答案的表示向量上,模型就有可能给出正确的答案。所以,在有了大量正确和错误的表示向量,知道它们差距之后,你甚至有可能利用这些信息来修正模型的答案。
侦测和修正都是可能自动进行的。但是像 True Facts 这篇论文,以及刚才讲的自动检测和自动修正,它们都有一个缺点,就是需要收集额外的资料。你需要先问模型一堆问题,知道它讲对时表示向量的样子,讲错时表示向量的样子,才能做刚才讲的操作。
对比解码:无需额外数据的主动修正机制
有没有办法在没有收集额外资料的情况下就检测出错误,然后进行修正呢?这边就要跟大家分享一个叫 对比解码(Contrastive Decoding: 通过对比模型在不同输入情境下的输出倾向来修正其决策的技术)的技术。它等于是刚才的错误检测加错误修正的结合,但是它不需要收集额外的资料。
对比解码的概念是:你问模型一个问题,它去预测下一个标记。这是模型在正常情况下得到的答案,你不确定它对错。但是接下来,同样的问题你做一些修改。至于这个输入要怎么做修改,等一下会有各式各样的做法。把这个输入做一些修改,制造出让模型一定会答错的状态。至于怎么保证它一定会答错,等一下还要再讲。假设模型在现在这个输入做一些修改的状态下,它非常有可能会答错。我们就知道模型答错时表示向量的样子。接下来,我们就把原来模型会产生的表示向量跟它答错时会产生的表示向量相减,得到正常状况跟答错状况的差距,也就是黄色的向量。然后,就把黄色的向量加到模型正常会回答问题的向量上,希望把模型现在的答案离错误的答案推得远一点。这时你就有可能让模型回答的正确率变高。
通常在做对比解码时,常见的一个操作是会把蓝色跟绿色的向量相减之后,前面乘上一个参数叫做 alpha,通常就设定成一个小于一的值。所以把黄色的向量加上蓝色的向量,你也可以把这个操作看成是现在把原来的蓝色向量(正常情况下模型会产生的表示向量)乘上一加alpha倍,然后减掉alpha倍的错误向量。就是把正确的成分,原来正常情况的成分稍微提高一点,然后减掉一些错误的成分,希望模型的答案因此变得更正确。
像这种对比解码的方法,常见的操作是,你对每一个标记,每一次生成标记时,你都要做一样的操作。所以在这个操作中,只生成了第一个标记。第一个标记被修正之后变成红色标记。接下来,再把这个红色标记当作下一个时间点的输入,制造出正常状态跟错误状态。然后接下来再反复刚才操作,把蓝色的减掉绿色的,乘上alpha得到黄色的向量,再把黄色的向量加上去,希望可以修正模型的输出。这就是对比解码的基本概念。所以它要做的事情就是每次模型在生成时,把它生成的结果离有可能是错的答案推得远一点。
像对比解码这种方法的优点是它没有动到模型的参数。所以这一招跟训练模型没有关系,你完全可以在训练模型之后,在推理阶段直接套用这个方法,看看结果会不会好一点。但是这个方法有一个缺点,就是它需要额外的运算。所以很明显,本来你只要推理一次,但现在你需要再多做一次额外的推理,产生错误的东西、错误的表示向量,你才有办法使用对比解码。所以这个方法是用额外的运算来换取可能比较正确的结果。
在对比解码中,文献上比较常见的操作是,这个表示向量通常不是拿中间的 隐藏层(Hidden Layer: 神经网络中处理输入数据并传递到下一层的中间层)。比较常见的操作是这里的东西,就是模型最终输出的那个概率分布,或者是在归一化成概率分布前的数值,也就是 对数几率(Logit: 在概率分布中未经过归一化处理的原始预测分数)。最常见的做法是这个状态跟这个状态分别跑到最后得到最终输出的对数几率或者是概率分布,再把这两个概率分布相减得到最终的输出。
对比解码其实不是最近几年才有的技术。早在2022年的文章,在还没有 ChatGPT,人类还在茹毛饮血,还不知道用火的时代,那时就已经有对比解码了。那时想法就跟刚才讲的概念基本上是一样的。他们说,要让模型来做文字接龙,比如“奥巴马生在火奴鲁鲁,生在哪一年?”要模型继续接龙下去。在这个句子中,如果你问当时比较好的模型,比如 GPTQ,比较大的版本要接哪一个字,它觉得概率最大的其实是“why”,但这其实是错的答案,因为前面已经讲过“why”了。这边正确的答案应该是“1961”,接一个年代出来。
按照对比解码的想法,你要先制造一个错误的答案。怎么制造错误的答案呢?在这篇论文中的假设是,如果我们拿一个比较小的模型,比如 GPTQ small,它产生出来的答案就当作是错的。所以今天比较好的模型产生一个概率分布,比较差的模型产生概率分布。虽然这两个模型都没有办法真的得到正确答案,就算是比较好的模型,概率最高的答案也不是“1961”,但是相减之后,概率最高的答案就变成“1961”。所以模型正确解码的结果并不是好的模型觉得概率最大的,而是好的模型跟坏的模型差距最大的那个标记才是应该被解码出来的标记。这就是对比解码原始的概念。当时他们选择直接在最终输出的对数几率上做概率的相加相减。没有选择表示向量,一个很直觉的原因是模型和模型它们的层数根本不一样,所以你根本没有对应的表示向量可以直接做相减。所以他们是直接相减在模型最终输出的概率分布上。这应该是我所知最早提到对比解码这个词汇的论文。这可能不是最早运用对比解码概念的论文,在这篇论文中还引用了一些前作,说是前作最通用的版本。所以也许它不是最早用对比解码概念的论文,但它最早用了对比解码名词的论文。
对比解码的演进:Dora、Layer CD 与 CAD
后来在2023年,也有另外一个应用到对比解码概念的方法叫做 Dora(Decoding by Contrastive Layers)。这个方法可能用得比较广,甚至今天在 Hugging Face Transformer 中,如果你使用 Hugging Face 推理套件,你也有一个标志可以直接让模型在推理时直接使用 Dora 这个技术。所以这个技术被直接写在 Hugging Face Transformer 的套件里,应用起来非常容易。
在讲 Dora 之前,要先提它背后用的一个概念,叫做 对数几率透镜(Logit Lens: 一种分析神经网络内部表示的方法,通过将中间层的表示直接映射到输出对数几率)。这个概念的意思是:假设你今天问语言模型一个问题,比如“发文”的中文翻译是什么,最终你得到最后一个层的表示向量,通过一个对数几率头部,可以给你一个概率分布,其中“花”可能是概率最大的。但有趣的是,你可以把对数几率头部接到中间的每一层,也可以给你一些有意思的解码结果。在文献上就发现,如果你用 Llama 2 要求它做翻译,把“发文”翻译成中文,中间这些表示向量解码出来会是“发”这个字的英文。所以可以想象,对 Llama 2 而言,它内心运作的过程是,当你要它把“发文”做翻译时,它是先翻成英文,然后再从英文翻译成中文。也就是说它内心在思考时比较喜欢用英文来思考。
Logit Lens 这篇论文其实没有一个对应的论文。多数人在引用这个技术时,往往是引用一篇博客。但其实在这篇博客之前,就已经有文献记载了跟 Logit Lens 一样的技术。这是我们实验室的文章,发表在2020年。当时也没有投稿到国际会议,觉得这个方法有什么用呢?只是一个奇妙的发现。甚至最后也没有执着一定要把它投稿到国际会议,就只是放在 arXiv 上面。在 Dora 这篇论文中,它有直接引用我们当时实验室发表的那篇论文。为什么 Dora 有引用我们实验室发表的论文呢?因为 Dora 的第一作者是我们实验室以前的专题生。他后来毕业之后去了 NTT,这篇 Dora 是他在 微软(Microsoft)实习时做的。他说他在做这个工作时,有想到过去学长做的类似 Logit Lens 的工作,然后他把这个工作应用在 Dora 这个技术中。
Dora 这个技术怎么应用 Logit Lens 呢?它的想法是,这些对比解码的方法,它在意的地方就是怎么找出一个错误的答案。所以 Dora 这个方法就是假设,如果我们用 Logit Lens 从中间的层做解码,那中间的层解码出来的结果比较有可能是错误的答案。所以 Logit Lens 的想法是说,我们会从最后一个层得到一个概率分布,但我们也从前面的层得到前面的层用 Logit Lens 产生出来的概率分布,然后两者相减当作最后的答案。当然,对这篇论文而言,一个很重要的地方是:要从哪一个层去做 Logit Lens 解码出来的概率分布才是最该拿来做相减的呢?哪一个层解码出来的才有可能比较是错误的呢?这篇论文中就用了比较复杂的方法来找出合适的层。大家有兴趣的话,再自己做研究。
其实,在 Dora 的前一篇,最原始的对比解码论文也有同样的问题。它说假设小模型输出的就是错的,但你凭什么认为小模型输出出来的就都是错的呢?它有时也会答对的。所以如何只在小模型答错时才相减,会变成这些论文非常重要的需要处理的议题。在对比解码那篇原始论文中,细节大家再去看原始论文,它用一个有点“AHA”的方法找出觉得不该用小模型修改答案的位置。所以这个方法是 Dora。它有一个很不错的优势是,不像原来的对比解码,你还要引入另外一个小模型,那其实就需要耗费额外的计算,还要耗费额外的内存。Dora 是用原来模型前面的层来产生错误的答案。前面的层本来就要跑,所以 Dora 这个方法在做推理时并不需要太多额外的计算,可以在只用非常少的 额外开销(Overhead: 完成一个任务所需的额外资源或时间)的情况下就修正模型的输出,得到有可能更正确的答案。
还有一个应用到不同层之间差异的方法叫做 层对比解码(Layer Contrastive Decoding, Layer CD)。这个方法是应用在影像上的。这篇论文是2025年的论文。它里面的发现是,当我们用影像模型时,现在有很多影像模型可以看一张图片。你问它问题,比如“这辆摩托车上的人,他穿的衣服上面的字是什么颜色的?”如果你用最后一个层当作语言模型的输入,这个最后一个层指的是 视觉编码器(Vision Encoder: 将图像数据转换为可被语言模型理解的表示形式),这些有视觉能力的语言模型往往要接一个视觉编码器。如果你拿视觉编码器的最后一个层去接给语言模型,这时你会发现语言模型在黑色跟白色之间摇摆不定。这个衣服是黑色的,但现在问的不是衣服的颜色,是衣服上字的颜色,所以正确答案是白色。最后一个层有点聪明,所以它知道应该是白色,但它又没有聪明到把白色排在最前面。怎么办呢?你就把比较前面的 浅层(Shallow Layer: 神经网络中靠近输入层的部分,提取低级特征)也丢给语言模型。浅层提取的资讯比较浅,它比较只能看到表象的东西,所以你问它颜色,它就很直觉地回答一些奇奇怪怪的颜色,然后把白色排在比较下面。它把黑色排在比较上面,白色排在比较下面,然后把两个概率相减之后,白色的概率就变成最高的概率,这时模型就可以得到正确的答案。这就是 Layer CD 的做法。
还有另外一个系列的做法,我们刚才讲是靠不同的层来制造错误的答案。另外一个制造错误答案的方法是直接给模型一个 降质咒语(Degrading Incantation: 一种特定的提示或指令,旨在使模型表现变差或产生错误输出),让它变笨。这一系列的做法其实有好几篇,它们叫做 指令对比解码(Instruction Contrastive Decoding, ICD)。这个降质咒语是什么呢?就说出来不值钱,你就在模型的输入后面多加一句“你都给出错误的答案”,或者“你是一个很糟糕的模型”,真的就这样。然后模型就变得比较笨,它答案就比较有可能是错的,然后再把错误的答案跟原来的答案相减,希望可以得到更正确的答案。
还有另外一个系列的做法,叫做 上下文感知解码(Context Aware Decoding, CAD)。上下文感知解码最早有一个应用是用在 检索增强生成(Retrieval Augmented Generation, RAG: 通过检索外部知识来增强语言模型生成答案的能力)上面。大家知道 RAG 是语言模型有时无法及时更新知识,所以你问一个问题,你会顺便去网络上查些相关的文章,把问题跟相关的文章一起丢给语言模型,期待它得到答案。但后来有些比较厉害的模型,它都不去读那些文章,因为它觉得“我已经知道答案了,何必读这些文章?”你问它美国总统是谁?虽然美国总统一直会换,但它不知道,所以它觉得美国总统它知道是谁,干嘛读这些从网络上搜集出来的文章?我用自己自身的知识参数里面的知识就已经回答了。所以很多模型往往不去读那些搜寻到的文章。怎么办?上下文感知解码的想法就是,我们干脆把这些搜寻到的文章不给语言模型看,先得到语言模型在没有这些文章时会得到的答案,再把这个可能是错误的答案跟语言模型读这些文章时会得到的答案相减,然后得到一个比较有可能是正确的答案。这就是上下文感知解码这个系列的想法。
所以,上下文感知解码就是用不给模型该有的资讯来制造出可能会答错的状态。这也是一个很古老的技术,2023年时这也是中古世纪就已经有的方法。这是直接从论文中截出来的图,它就是说,假设你给语言模型问题跟相关的文章,那正确的标记其概率还不是最高的。另外一个案例,你只给它问题不给它答案,让它先凭着自己原有的知识来得到答案,然后再把这两个案例相减,你最终可以得到正确的答案。这就是 CAD 的想法。
像 CAD 这样的技术也被用在影像上。我想这里这个影像的例子最直观,也许可以说服你这是一个有用、有可能会发挥作用的方法。所以一般我们在使用影像模型时,就是给它一张图片,问它一个问题。如果你今天给它这个黑色的香蕉,问它说“图中的香蕉是什么颜色?”这时模型会有点犹豫。它直觉会觉得香蕉就应该是黄色的,但是看影像又告诉它是黑色的,这时它就会犹豫不决。这些影像的语言模型往往是从文本模型微调过来的,所以它带有大量的 文本先验知识(Text Prior: 模型从大量文本数据中学到的,对词汇、语法和概念的固有理解和偏好),也就是说它会有大量的从文本中学到的先入为主的概念,所以它就会觉得香蕉就是黄色的。它有时甚至不会太管图片的细节,就凭着它的直觉,凭着它先入为主的概念给你答案。所以对这些影像模型而言,它往往是在它先入为主的概念跟影像之间互相拉锯。如果你今天给它一个很奇怪的影像,它往往无法答对,因为它有太多先入为主的概念,所以它会直觉觉得香蕉是黄色,但明明又看到黑色的东西,它就会在黄色跟黑色之间犹豫不决。
怎么让它做得更好?怎么去除它先入为主的概念呢?你就故意不给它图片,或者是你把图片加上很强的杂讯,让它看不清楚,然后问它“图片的香蕉是什么颜色?”这时它会觉得根本没有香蕉,那我就凭着我先入为主的概念来回答好了,答案是黄色。然后正好得到错误的答案,再把错误的答案跟原来的答案相减,模型就有可能得到正确的答案。这就是在影像上做上下文感知解码。
这里也是很早的技术,也是2023年就有的技术。我就直接截了一个论文的截图。这篇图片中跟我刚才讲的概念是一样的,有一个影像模型给它这张图片,然后问它“这个海滩上有什么东西?”模型给出了一些答案,它说看到人,看到阳伞,这都没问题。但它说它看到冲浪板,但其实那张照片里没有冲浪板。但是冲浪板很容易出现在海滩上,所以模型先入为主地觉得海滩的照片就应该有冲浪板,所以冲浪板也得到了蛮高的概率。接下来,他们就做上下文感知解码,给模型一张很模糊的图,因为这张图太模糊了,所以模型根本就懒得去看这张图片了,它直接就给了冲浪板很高的概率。它凭着它先入为主的观念给了冲浪板很高的概率。把这两者相减,最后冲浪板的概率就变得很低了。这里的公式跟我们刚才前面看到的对比解码的公式都是一样的:把正确的输出乘以(一减alpha)减掉错误的输出乘以alpha,得到最终输出的结果,就可以把冲浪板的概率,把这些有可能是错误答案的标记的概率压得很低。
在这篇原始论文中,它就是在图片上加一般的杂讯。后面的研究就开始研究要加什么样的杂讯才是特别有效的。通常,你希望制造出的这个错误的案例是模型特别容易发生误会的案例。比如在今年这篇论文中,它做的事情不是加一般的杂讯,而是把图片切成一块一块的再打乱,然后发现比加一般的杂讯结果更好。或者是一个今年六月的论文,它做的事情不是随便加杂讯,它觉得随便加杂讯这样模型不一定会答错。它做的事情是先用一些方法分析模型今天得到这个答案时,看的是图片里的什么位置,图片里哪些物件是最重要的,把重要的物件抹去后再做对比解码。所以这里有种种的变形。
这个技术既然可以用在影像上,那其实也可以用在语音上。这篇论文是一个 普渡大学(Purdue University)学生在我们实验室访问时做的一个研究成果,做了 音频感知解码(Audio Aware Decoding)。这跟影像上的概念是一样的,我们把影像换成声音。在解码时给模型正常的音讯,问它一个问题,看它得到什么样的答案。接下来故意把音讯拿掉,或者是把音讯换成 静音(Silence),然后再做解码,看它得到什么样的答案。把正确的答案乘以(一减alpha),错误的答案乘以alpha相减,然后得到最终的输出再做采样。这一招确实在语音上,在声音上也有发挥作用。至于它发挥了什么样的作用,你还可以看一下右上角放的这些引用的论文,这是我们实验室后来后续的一些研究成果,做了更多的分析,告诉你说为什么音频感知解码对这些语音语言模型也能发挥作用。
这篇论文,N T I(Minimum Test-Time Intervention),是希望可以减少对比解码需要的额外运算。我刚才说对比解码的缺点就是用算力来换取比较好的表现。那能不能用比较少的算力就得到对比解码的优势呢?这篇论文它先有一个假设是:当模型在做解码时,可能只有某几个标记是特别关键的。在这个位置,如果选择了不同的路径,那就会有截然不同的结果。但其他路径可能结果都差不多,这就像人生一样,人生可能有几个特别关键的转折点,比如选读哪个学校,跟谁结婚,可能会影响你后来的半辈子。但是多数时候,多数的抉择,比如早餐吃什么,或者下午穿什么样的衣服,可能都不会影响最后的结果。所以这篇论文就是想,我们在做对比解码时,能不能不要每一个标记都修改概率,只修改那些特别重要的标记?
我们再复习一下对比解码是怎么运作的。原来对比解码需要在每一个标记上都做。你给 大型语言模型(Large Language Model, LLM)一个正常的输入,它给你一个标记,然后你给它一个乱搞的输入,让它给你一个错误的答案,然后把这两者相减,得到更正确的结果,把更正确的结果当作下一个时间点的输入,然后在两个不同状况下得到正常结果跟错误结果再相减,再得到新的输出,再当作下一个时间点的输入。每一步解码时都要做类似的事情。
刚才讲的 NTI 的想法是,看我们能不能平常都不要做对比解码,只有当我们检测到觉得最关键的那个标记才开启对比解码去做修正。什么样的标记是最关键的呢?一个很直觉的想法是,如果在某一个位置,比如它的概率分布特别平均,就是它的概率分布有特别高的 信息熵(Entropy: 衡量信息不确定性的指标),在这个位置模型特别没办法决定接下来要解码哪一个标记时,也许就是开启对比解码,把这个位置解码的标记做得更正确的时机。直觉上的想法应该是,我平常都不做对比解码,就在这个地方才启动对比解码。当启动对比解码时,我们就要把输入弄坏,然后给模型在这里一样的输入,然后看看在同样的位置会输出哪一个标记,再相减得到最后的答案。这样好像可以节省额外的运算,但如果你仔细想想,这招有节省到额外的运算吗?好像其实是没有的。为什么其实没有?因为你要一直解码到这个位置,你要得到同样位置不同输入会解码出来的标记,你一样需要把这整个序列都跑过。所以其实你只选比较少的位置做对比解码,相较于左边这个运算,你其实没有节省到多少运算的额外开销,你仍然要解码一个非常长的序列才能够得到错误的答案。
所以,在 NTI 这篇论文中,它用到的一个非常重要的概念就是我们之前有讲过的 跨对话键值缓存(Cross-Dialogue KV Cache: 在多轮对话或生成任务中,重用模型早期计算的键值对,以提高效率)。还记得我们在讲 KV Cache 时,我们有说,假设今天有一个句子是“大家好,我是大金”。模型已经跑过这个句子,它就可以把每一个位置的键和值存起来。下一次模型在处理一个非常像的句子,比如“大家好,我是小金”时,“大家好,我是”这前面五个标记可以直接从另外一个句子它的 KV 直接复制过来,就不需要再做额外的运算。但是要记得只有 前缀(Prefix: 序列的起始部分)一样,也就是句子前面的几个字一样时才能够使用这一招。一旦中间的字有变,就不能用这一招了。所以虽然“金”在这里字是一样的,但因为中间“大”被换成了“小”,所以就不能直接复制它的 KV。
NTI 这篇论文就打算利用 KV Cache 这个特性。它的做法是:怎么得到错误的答案呢?过去有很多不同的做法,比如把前面的输入搞乱,但他说这种方法会导致你无法利用 KV Cache。所以如果要利用 KV Cache,你的搞乱模型的方式只能够加在最后面。也就是说,他们怎么得到错误的答案?他把原来模型解码到这里已经产生出来的结果(正常的输入加蓝色这一块标记)丢到模型里面,然后在最后再直接加两个标记,也不要多加,多加就要太花太多额外的运算了。那这两个标记呢,他发现输入“output error”是一个有用的输入。所以他就在原来的输入后面,就模型解码到这里了,在原来的输入后面直接加“output error”,然后看看模型会输出哪一个标记,然后这个标记(这个标记作为这个位置输出的概率分布)就当作是错误的答案去跟原来的模型正常产生的概率分布相减,然后得到新的结果。这里的好处就是这一大段都可以利用到缓存 KV Cache,你就不需要重新运算。唯一需要重新运算的只有“output error”这两个标记输入的位置而已。这招听起来是蛮离奇的。
这招有没有用呢?至少在性能上看起来,它有一个参数叫做 omega,可以对应到之前投影片的alpha,但是又有点不一样。我们就不细讲它有什么不一样。如果你有兴趣再自己去读这篇论文。总之omega等于一代表没有做对比解码,也就是模型正常的输出,正确率只有62%。omega设得越大,就代表说我们减掉越多对比解码的成分,减掉越多坏的成分。但坏的成分减掉太多,最终还是会坏掉的。但是如果你慎选减掉的成分的量,你其实可以从62%正确率进步到72%的正确率,看起来是有蛮不错的结果的。
讲到这边,大家可能会有一个疑惑,那我们要拿来搞坏模型的降质咒语只能用“output error”吗?“output error”是最有效的降质咒语吗?这篇文章也做了测试,他发现如果降质咒语是用“output error”,可以得到不错的结果。如果你把“output error”改成“output correct”,就会差一点,因为模型不该得到正确的结果,我们就是要拿到错误的结果。然后他说用“status error”结果也不错,如果改成“status true”就差一点。如果你改成“invalid logic”,也会有一定程度的效果,改成“valid logic”又差一点。他说那如果你加一些怪怪的字,什么“monkey”、“...”、“!”、“apple”,那结果都会很差,对比解码就不太能够发挥作用。所以这就是 NTI 这篇论文的做法,他希望减少对比解码的位置。
到目前为止,我们讲对比解码时,那些方法都是直接改在输出的概率分布上,或者是改在最后一层输出的对数几率上。那其实也有其他论文尝试改在其他的地方,你会发现这都是有一些比较新的论文。比如说,这是出自一篇今年一月的文章了。那它里面呢就是有比较了改在不同位置的做法,那里面就有提到说,像过去有一个叫 Vista 的做法,它就不是改在输出的对数几率上,它是改在 潜在表示(Latent Representation: 模型内部抽象的、非直接可观测的特征表示)上。那这篇论文呢叫做 ACG,它主要提出来的是想要说改在 注意力权重(Attention Weight: Transformer模型中衡量不同标记之间关联强度的系数)上才是最有效的。所以它就是用有影像也有文字的情况去得到一个注意力权重,然后去减掉只有文字没有影像时的注意力权重,然后它做对比解码,但它不是改在对数几率上,而是改在注意力权重上,那发现可以比只改在对数几率上得到更好的结果。所以不一定只能改在对数几率上,也可以改在其他的地方。至于改在什么地方最有效,我觉得仍然是一个现在可以研究的问题。
这一页投影片呢,就是总结了各式各样对比解码的招数。这里有两个需要考虑的要素,第一个就是怎么拿到错误的答案,另外一个就是要改在哪里。我刚才说多数论文都是直接改在最终的输出上面,但也有一些论文尝试改在隐藏表示或注意力权重上面。至于怎么拿到错误的结果,那有各式各样的想法。最早的对比解码它就说小模型输出的就是错的。Dora 是说浅层用 Logit Lens 输出的结果就是错的。Layer CD 是说用浅层的图像编码器就是错的。ICD 是说给模型一个降质咒语,它的答案就会是错的。像上下文感知解码 CAD 就是在做 RAG 时不给它检索到的文档,它的答案就是错的。 视觉对比解码(Visual Contrastive Decoding)就是把所有的影像拿掉加杂讯,或者是盖住重要的部分就会是错的。音频感知解码就是把输入的声音拿掉,或者是变成静音或加上杂讯就会是错的。NTI 呢,它是用降质咒语,那它发现用降质咒语的好处就是你这样才能够利用 KV Cache 的特性,这样才能够减少算力的消耗。然后有一些方法是移除不是输出的这个地方,不是改输出的地方,而是改中间的潜在表示。总之,这个表格整理了不同的对比解码技术。这是一个不需要训练模型的技术,所以它是一个,假设你做一做,不知道可以做什么了,反正不用训练模型,跑一下也没有什么损失的方法。
优化工作流程:生成与验证的协同
接下来呢,我们进入今天课程的第二部分,我们来讲修改工作流程。这里修改工作流程是什么意思呢?其实这种修改工作流程让模型可以做得更好的概念,过去也已经讲了很多了。在去年同样课程的第七讲的第二部分,就已经非常详尽地讲解有什么样工作流程的变形可以让模型推理可以做得更好。所以这里呢,我们就不再重复各式各样工作流程的变形。如果你有兴趣,再去看去年上课的录影。这里我们就只讲它最基本的概念,也就是 生成加验证(Generation + Verification)。事实上上次在讲 Harness 时也讲到,现在有一个非常常用的工作流程就是生成后面接验证。
什么是生成后面接验证呢?就是模型得到一个答案之后,接下来你给它一个指令,这个指令是要求模型去做反思的。讲到这边,你可能会想说,要求模型再去做反思,这不是需要人类介入吗?事实上这个步骤是不需要人类介入的,因为通常这个反思的指令是一个非常通用的指令,它跟前面的问题跟答案都是没有关系的。比如说这个反思的指令可能是“再给我想想”、“再检查一下”,就是这么泛用的指令。所以这个指令不需要由人类来输入,它就是由程式自动插入的。反正就是写一个程式,模型得到第一次答案之后,就自动插入一句话说“再检查一下”,看看模型会有什么样的反应。所以在这样的方法里面,它仍然算是模型自我修正,因为不需要任何人工的介入。然后期待模型看到这个要求它反思的指令之后,就可以自己发现错误,甚至自己更正错误。
有很多人会觉得,这样的想法太离奇了,模型一开始的答案就是错的,你凭什么觉得它能够在反思之后就得到正确的答案呢?这边提供给大家几个直觉上的想法,为什么这样子反思有可能会是有用的?第一个直觉的想法就是 批判比生成容易。就好像说,我不会写小说,但我还是可以知道一个小说好不好看。我没有办法写出金庸小说,但我知道金庸小说是特别好看的。所以批判比生成容易,有时模型在生成时没发现自己的错误,但是反过来,回过头来再检查一下,它是有可能发现自己的错误的。再来另外一个直觉的理由是, 生成过程无法回头。因为生成时模型需要做采样,做采样时,有时掷骰子就是会掷到错误的答案。但对模型来说,掷到错误的答案,这是一个覆水难收的事情。你的答案第一个标记错,值错了,那你只能够一步错,步步错,不断地用错误的答案硬掰下去。这为什么有时模型明明答错了,但还是要瞎掰它答错的理由?因为这个生成是无法回头的。但是如果我们在生成过程中插入“再检查一下”,那你知道模型真正知道的事情就是文字接龙,它并不知道什么叫做检查,它也不知道什么叫做正确的答案。但是插入“再检查一下”,也许这个句子在网络上大量的海量资料里面,后面往往就是接着修正这件事情。所以对模型来说,插入“再检查一下”,给它一个机会,后面接出可以修正前面答案的内容,不然它只能够按照错误的答案一直讲下去。这有可能是为什么这一种自我验证的方法,这种自我反思的方法有可能发挥作用,直觉上的原因。
但是这只是一些直觉,也不是这种直觉讲的东西不一定是对的。我们说批判比生成容易,那是从人的直觉来想的。你怎么知道对模型来说批判比生成容易呢?事实上,有一篇文章,我在这边忘了引用,我之后再把它补到时带上。就有一篇文章,他就说他试了模型批判跟生成能力的差异,他发现模型批判能力并没有比生成能力强。就是他的做法就是让模型生成出好多答案,有一些是正确的,有一些是错的,然后再拿去给模型自己问说,“你看这边有两个答案,你觉得哪一个比较对?”他发现模型没有办法挑出正确的答案来。他说模型要挑出正确的答案来,除非正确跟错误差距非常大,它才有办法挑出正确的答案来。所以从那篇论文来看,你可能会说,人类虽然批判比生成容易,但对模型来说不一定是如此。但是这边又再有一个转折,如果我要批评那篇论文的话,事实上那篇论文是把批评这件事情,把它当做一个选择题来看待。他是给模型四个选项,那四个选项都是它自己生出来的,问它哪一个选项最好,发现模型没有办法挑到好的。但你怎么确定是因为模型没有批判的能力?搞不好是模型没有做选择题的能力。尤其那又是一两年前的论文,那时候模型有时它答不对,不是因为它没有能力,而是它做不了这种题型,它不知道回答选择题时要选A、B、C、D四个代号,所以它答错了。所以再有一个反转,那篇论文讲的也不一定是对的。总之这里有很多研究的空间。所以这里我讲的只是两个直觉上的想法,这种直觉上的想法只是人类直觉想一想,它不一定是对的,不一定能套用到语言模型上。
自我反思的实证效果与算力成本
虽然直觉的想法不一定是对的,但是我们可以来看看实验上实证的结果。这是一个去年十月的论文,这篇论文就想说,有的人说自我反思有用,有的人说自我反思没有用,我们来做大规模的实验,看看自我反思到底有没有用。所以他们就找来了一大堆各式各样的模型,测在一大堆各式各样的 基准测试(Benchmark: 用于评估模型性能的标准数据集或任务)上。我们先看图片的上半部,上半部“internal”的意思代表是模型自我反思,没有额外人力的介入。那这里,它其实还试了很多种不同的反思方法,就反思也有很多不同的类型,比如叫模型“再想一想”,我跟模型说“你错了,给我改一下”,这也是不同的反思的方法。所以他试了好几个不同反思的方法,然后呢,再把结果平均在一起。零呢,代表说这是第一次答案的正确率。如果比零高,就代表反思有用;比零小,就代表反思没有用。从这个结果看起来,很多情况下反思还是有用的,但是它不是一个很稳定的方法,因为在很多状况下反思反而会变差,让模型做自我反省后,有些模型反而变差了,所以这不是一个非常稳定的方法。
“external”这个图的意思是说给模型一些外部的回馈,比如说如果是写程式的话,就把程式拿去跑一跑,然后看看跑出来的错误讯息,或者是让模型去网络搜寻,搜寻到一些额外的知识,再用这些额外的知识来答题。他发现如果是用外部的方法,其实是比较稳定的。如果看小于零的案例的话,外部回馈是小于零的案例是比较少的,那就算有小于零的案例也不会掉得非常多。所以整体来说,自我反思不是没有用,有时会有用,但没有非常稳定。那外部的反思,外部的回馈往往是比较有用的讯号。
另外一篇一个月后的论文,也支持这样子的想法。以下这两张图就是从 RefineBench 这篇论文引用出来的,他们也是想要做一些比较大规模的实验,来看看模型的自我反思到底能够做到什么样的地步。在这篇论文中,左边这个图用了 Claude 4,一个比较强的模型,就反思了从第一轮到第五轮。纵轴是正确率,这里三条线跑在三个不同的资料集上面。他们就发现,对 Claude 4 这种已经很强的模型而言,自我反思没有发挥太大的作用,虽然可以有小幅的进步,但是进步量非常的小。
右边这个图,他们是做在 Gemini 2.5 Pro 上,也是一个很强的模型。最下面这一条灰色的线是自我反思的结果,发现自我反思带来的进步非常的少。那什么样的额外讯号可以带来很大幅的进步呢?这一条线看起来进步很多的,就是模型先得到答案之后,接下来会得到外部的回馈,它有一个 检查清单(Checklist),然后它会去检查每一个项目是不是对的,然后它把检查清单里面一半的内容拿出来给模型看,只让模型看到一部分的反馈就有很大的进展。橙色这中间这一条线是给模型完整的检查清单,告诉它我们会检查什么样的内容,那告诉模型我会检查什么的内容,也可以大幅影响它的结果。那最终最好的结果,橙色最上面这一条线,就是给模型完整的回馈,这时模型表现的是最好的。所以这篇文章就有一个结论是,也许自我反思没有那么有用,它只会给予小幅的进步。如果给模型真正的额外的来自人工或者是外部系统的回馈,往往才是最有效的。所以这篇文章其中的结论就是外部的回馈往往才是最能让模型进步的回馈。
有一篇论文去仔细分析了这些模型在自我修正时它的行为。在自我修正时,有四个状况。第一个状况是修正之前是错的,修正之后是对的,这是我们最乐见的状况。有另外一种状况是修正之前本来就是对的,然后对的在修正以后还是对的,这是不过不失,单纯耗费算力而已。有的状况是修正前是错的,修正后也是错的,反正也没什么损失,也是耗费算力而已。最糟的状况是修正前是对的,修正之后想多了反而改错了,这是我们最不乐见的状况。他就想要知道,当这些模型你要求它做自我修正时,到底每一种状况它出现的概率有多大?
在这篇论文中,他定义了两个数值:一个数值叫做 信心水平(Confidence Level: 修正前正确,修正后依然正确的概率),意思是修正前是对的,修正后也是对的的概率。这个信心水平代表模型的信心程度,它对自己的答案有多有信心?如果它非常有信心,那它就不会去改答案,修正前是对的,修正后也是对的。他定义了另外一个分数叫做 批判分数(Critic Score: 修正前错误,修正后变为正确的概率),就是模型有多能接受批评。如果这个批判分数是修正前是错的,修正后是对的,就代表模型这个接受批评反思的能力,如果本来是错的,它能够改对,代表模型有很不错的反思的能力。
这两个指标跟模型修改前后的正确率是直接相关的。假设我们定义修改前的正确率叫做 acc1,修改后的正确率叫做 acc2。那 acc2 跟 acc1 之间的关系可以直接从信心水平和批判分数这两项看出来。你把修正前的正确率乘以信心水平,再加上(一减修正前的正确率)乘以批判分数,就会等于修正后的正确率。那接下来这篇论文就分析了各式各样不同的模型在三个不同任务上,它们的修正前正确率、修正后正确率、信心水平,还有批判分数。
结果如何呢?结果他发现说整体而言,多数模型都有比较高的信心水平,也就是模型其实通常对自己的答案蛮有信心的,它没有那么常把正确的答案因为想太多就改错了,到正确的答案它再想一想,觉得应该还是对。那批判分数,有很多模型都非常的低,意思就是说对很多模型而言,它是比较固执的,它很少把错的答案改对。那整体说来,模型是有不同的个性的。有些模型就是特别的顽固,像这里的 DC 跟 Mistral 都是比较顽固的模型,它们很少去修改自己的答案。但也有一些模型它是比较有弹性,比较常修改答案的,比如说 Llama 3 70B 在 GSM 8K 上面就有很高的修改答案的概率,或者是今天如果看 GPT-3.5 跟 GPT-4,它们其实也都有比较高的概率修改自己的答案。但这些模型如果它有比较高的概率修改自己的答案,往往导致的结果就是它的信心水平就会稍微低一点,它就比较没有办法坚持住自己的答案。所以顽固这件事跟接受批判这件事看起来它们是有点 权衡(Trade-off: 两种相互冲突的属性或目标之间的妥协),有点互斥的。一个顽固的模型就不容易接受别的批评,容易接受别的批评的模型,它就没有办法坚持住自己正确的答案。
另外这篇论文,我们说我们要叫模型做自我反思,你得插入一个句子,比如说“请检查自己的答案”。在这篇论文中,他分析了插入的这句话会怎么影响模型的行为。他们发现说你在这里插入的这个简短的指令,可能对模型到底是一个固执的模型,还是容易接受批评的模型,对它的行为其实是会有影响的。所以他这边就尝试了三个不同的指令。第一个是 中性指令,就是叫模型“再做一次”,它原来论文里面是英文的,我只是把它翻成中文而已。第二个是 肯定指令(Confidence Prompt),就是鼓励模型说“你应该是对的,只是再给我一次答案”。第三个就是 批判指令(Critic Prompt),就告诉它“你确定吗?你最好再给我想一想”,就暗示说它的答案应该是错的。
接下来,他就在 Llama 3 上面,在三个不同的任务上试了这三个不同的指令。你可以想象说假设叫模型“再做一次”中性的指令是模型原来会有的行为。如果你今天肯定模型原来的答案,这时你就会发现,当你肯定模型原来的答案时,它的信心水平上升了,它就比较有信心,它就不比较不会改答案。这时它也变得比较固执,它也比较不会去修改错误的答案。在三个不同的任务上都有类似的现象。所以如果你肯定模型是对的,它就有信心了,变得比较固执。那如果你质疑模型,让它觉得自己是错的,发现它的信心水平就下降了,它的批判分数,也就是它修改答案的可能性就上升了。所以你插入的那个句子,虽然那个句子不是人插入的,它就是用一个机器人,它这个 程式自动插入(Programmatic Injection)的,但那个句子对模型的行为是有很大的影响的。所以有可能,现在我们看到模型自我反思有时有用,有时没有用,也许就是因为不同文献里面插入了不同的指令,而每一个模型本身又有不同的个性。有些模型如果它总是特别有信心,那你就应该常常批判它。有些模型如果很容易没有信心,那你要多给它肯定。也许每个模型需要插入的这个反思的指令是不一样的。那每篇论文在处理反思指令还有尝试的模型都不一样,这也许就是为什么在文献上看到这个反思到底有没有用,看起来结论有时是有点 混杂(Mixed)的原因。
但接下来要问的另外一个问题是,反思这件事需要耗费额外的算力,而这个额外算力的投资到底划不划算呢?我们当然可以投资额外的算力让模型做反思,让它修改原来的答案。但是这个算力有没有可能有更划算的投资呢?这个算力可以投资在什么地方呢?与其叫模型根据之前的答案再反思,会不会让它直接产生新的答案?也许还是更有效率的。与其花额外的算力让模型把旧的答案拿去修改,会不会让它直接多采样几次,产生各种不同的答案,然后再 投票(Majority Vote: 通过多数决策来选择最终答案的方法)看看能不能得到最好的结果?假设反思跟这种产生多个答案,一口气产生多个答案再做投票这两个方法使用一样的算力,到底哪一个比较好呢?所以大家其实在自己做这种跟验证有关的实验时,你要注意,通常论文都会告诉你加上验证应该有用,但是这个有用到底是不是一个划算的有用呢?会不会有其他方法?其实同样算力的投资可以把模型的表现做得更好呢?
就有一篇论文做了这个尝试。我们先看左边这张图,左边这张图灰色这条线代表的是投票,就没有做反思,没有做验证。在这张图里面的纵轴代表的是分数,当然越高越好。横轴代表的是采样次数,从两次一直采样到二的七次方次。那采样次数越多,这种投票的方法,当然结果会越来越好。然后他说那我们来加上反思,那这个反思是要反思二的五次方次,这很多啊,要反思三十二次。所以他这里做的事情是对每一个产生出来的答案,它都反思三十二次。那结果如何呢?结果会发现说,当然在同样产生答案的次数下,如果你再加上额外的反思,结果都会比较好。甚至加上反思之后,你可以只用原来的四分之一的采样就得到一样的正确率。所以从这个左边这个图的实验里面,表面上你会看到,加上反思是有用的,你就很容易得到结论说,加上反思是一个不错的方法。但真的是这样子吗?这篇图的横轴并不是运算力,并不是算力。所以当你比较粉红色这一条线跟灰色这条线时,同样纵轴的这个点,它们耗费的运算资源并不是一样的,所以它们是没有办法直接比较的。
如果我们今天把横轴换成运算资源,结果会怎么样呢?所以他就做了第二个实验,这第二个实验的横轴就是投入的算力,纵轴是正确率。一样灰色这一条线是没有反思,只做投票的结果。这里不同颜色的线代表的是做反思,然后反思的次数,那从二的零次方,也就是一次、两次、四次、八次,一直到三十二次。然后他们发现说,假设你能够投入的算力是有限的,在投入有限算力的情况下,通常没有反思反而结果是比较好的。与其让模型再去检查之前的答案,还不如用同样的算力来多产生一些答案,结果还比较好。当然多产生一些答案这种方法,它在投入一定程度的算力之后就会达到极限。那你要在投入一定算力达到极限之后,再投入额外的算力去做验证,去验证前面的答案,去做反思才能够发挥作用。而他这边发现说,假设你要得到3.8%的进步,那你要投入一百倍以上的运算资源才有办法做到。所以这篇论文的结论就是做验证这件事,它像是一个 奢侈品,它是在你已经投入大量算力达到极限的情况下,再做验证才能发挥作用。那假设你算力是有限的,前期你应该花更多的运算资源来产生更多不同类型的答案,直到产生不同类型的答案这件事达到饱和之后,再加上让模型去做反思做验证这件事才能发挥作用。这是这篇文章告诉我们的。那我想这篇文章比较重要的教训就是告诉我们说,假设你今天要提出新的反思方法,成天都有人提出这种新的工作流程,那你要想想看你工作流程投入额外的运算资源是不是划算的。事实上我觉得这里最基础的基准线就是要比这种投票。所以如果你是提的这种新的工作流程,但是你没有比投票,那这个实验结果很有可能是会被大力质疑的。
修改模型参数:推理与强化学习的结合
好,那第三部分呢,我们想要讲的是让模型直接修改参数,也就是做推理。在刚才前一步里面,我们说工作流程它需要插入一个额外的指令。从工作流程到推理,它的差别就是能不能够直接把这个额外插入的指令拿掉,让模型自己生出答案之后,如果需要修改,它就自己一定会修改,它就自己知道它要修改。那虽然工作流程跟推理它都是自动的,都不需要真的人工的介入,但是推理还是有好处的。对工作流程来说,因为每次你都会硬插一个额外的指令进去,那就是逼模型说不管它答案对还是答案错,它都一定要做额外的思考,它都一定要产生额外的标记,这是一个比较浪费资源的做法。那如果是推理的话,那你期待模型自己可以学到,它该修改答案时自己就修改答案,不该修改答案时它就不修改答案。那也许这样可以让我们更节省算力,也许能够做到推理的模型是比要提醒它修改答案才能修改答案的模型更智能。
那这边有人就会想说,那我们要怎么让模型做到能够自己发现自己的答案有错而修改自己错误的答案呢?一个很直觉的想法是,也许我们就给模型越练越强,教它更多东西,它有更多正确的知识之后,也许它就更能修改自己的答案。但是有一篇论文否定了这样的想法。这篇论文发现说, 正确的知识并不等同于能够自我修正。你可以去看看这篇论文里面的数据。在它的第一页就举一个例子,他说假设你问模型问一个语言模型说,“告诉我一个出生在纽约的政治家”,那模型举了这个 希拉蕊(Hillary Clinton)。然后但是你可能会想说,模型举希拉蕊是不是因为它不知道希拉蕊在哪里出生的?那你问同一个模型希拉蕊在哪里出生的时候,它会知道希拉里是在芝加哥出生,不是在纽约出生。所以奇怪的地方就是,它明明有这个正确的知识,但是当它回答出错误的答案时,它居然没有惊觉我的答案是错的,而去修正自己原来的答案。
其实在这篇论文里面还有更多的实验,他们发现说自我修正是一个独特的能力,它不见得跟模型的知识有关联。自我修正是一种状态,它可以被抽成一个 转向向量(Steering Vector: 在模型的潜在空间中,代表特定概念或行为方向的向量)。当抽出那个转向向量以后,你甚至可以把这个转向向量加到模型里面,在模型不需要修正时,它也会自我修正。所以修正的能力跟有没有知识不一定能够画上等号。它是一种特别的状态,所以它可能需要额外做训练才能够具备自我修正的能力。所以接下来要讲的就是一些训练模型让它具有自我修正能力的方法。这其实就是对应到过去第七讲的第三部分跟第四部分,你如果还没有看过这部分的录影的话,那你可以之后再回去看这部分的录影。那在听今天的课程,你可能会有更多的收获。
我们先讲怎么直接教模型做自我修正。这边引用的是一篇叫做 Revised 的论文。他们发现说自我修正可以分成两部分。第一个是你得先发现有错,先做错误侦测,然后接下来才能够做错误修正。所以这两件事要分开来学。他们发现这两件事合在一起学比较难学,分开来学效果比较好。怎样怎么分开来学呢?他说第一步,先教错误侦测。怎么教错误侦测呢?你就要收集模型在不同输入时的答案。有时模型会答错,有时模型会答对。接下来就教模型说,看到这个错误的答案,那你要输出一个叫做“refine”的标记。看到这个正确的答案,你就直接输出那个“end of sentence”,就直接输出结束的符号,模型就不需要再反思再修改下去了。这是第一步,先教模型侦测自己的错误。
第二步,侦测出错误以后,要学习如何修正。所以就给模型自己的输入,它自己错误的输出跟“refine”这个标记。然后因为我们手上有训练资料是有正确答案,所以可以告诉模型正确答案长什么样子,要求它学会说,看到错误的输出,但后面接“refine”这个标记之后,要能够学习输出正确的答案。
Revised 这样的做法其实会有一些问题的。现在人们开始知道说,直接教模型自我修正可能有一些极限。什么样的极限呢?这有一篇2024年的论文就已经指出了这样的问题。这篇论文里面还讲了很多其他的事情,这是他们的其中一个发现。他们发现是这样子的,如果你教模型能够做修正这件事,你现在教模型能够看到自己错误的输出,它就可以输出“refine”的标记,然后甚至最后再接一个正确的答案。模型学会这件事以后,它的参数是不是就变了?因为是 微调模型(Fine-tuned Model: 在一个预训练模型的基础上,使用特定任务数据进行进一步训练的模型),所以它的参数就变了。那它参数变了以后,它就不再是同一个模型了。也就是说,它会犯的错不一样了。你在推理时,本来模型看到这个输入,它会给一个绿色的输出是错的。但现在模型不一样了,所以你给它同样的输入,它甚至不会给你绿色的输出,它给你一个红色的输出。我们叫它 异常值(Outlier)。虽然它可能还是错的,但它是不一样的错误。而对模型来说,之前训练时,它只看过怎么修改绿色的错误,它能够侦测修改绿色的错误,但是看到红色的错误是它训练时没有看过的,它可能就无能为力,反而会做得更差。所以直接教模型自我修正可能是有问题的。
所以怎么办呢?需要把产生答案跟自我修正这一整套的流程综合起来一起做训练。所以后来常用的做法就是直接做 强化学习(Reinforcement Learning, RL: 一种通过试错来学习最优行为的机器学习范式),这就对应到之前讲的第七讲的最后一段。强化学习的概念其实非常的直觉,反正就是给模型一个输入,然后接下来,它就开始做推理,开始输出一长串的标记,要输出什么不重要,它自己想。然后最后反正只要答案是对的就好了。如果最后答案是对的,就得到 正向奖励(Positive Reward)。最后答案如果是错的,就得到 负向奖励(Negative Reward)。像这种用强化学习来教模型做推理的概念,比较常用在数学或程式题上,因为数学或程式你是可以有非常明确的方法验证答案是错的还是对的,尤其数学答案就是个数字,所以答案是一翻两瞪眼的,对就是对,错就是错,你可以非常容易地提供回馈。像这种可以直接提供回馈的方法,现在有一个名词叫 可验证奖励的强化学习(Reinforcement Learning with Verifiable Reward, RLVR)。那也是强化学习的一种,只是说这种强化学习,你要得到的回馈是非常明确。
在这整个训练过程中,我们只在意最终的答案是对的还是错的,然后最终答案是对的就得到奖励,最终答案是错的就没有得到奖励。至于中间推理的过程会发生什么事不重要,答案对就好了。有趣的地方是,用这种强化学习的方法让模型做一下推理过程以后再产生正确答案,模型似乎蛮自然地就产生了验证,然后它就蛮自然地产生可以自己侦测错误,再自己修改错误的行为。模型往往会自己先提第一个答案,然后再回头看看说,“我这个答案对吗?”发现“有错哎”,那我自己再去修改自己的答案。看起来这整个推理的过程有机会让模型学到自我修正这件事。
讲到这边,你可能会想说,为什么模型做强化学习时还要学自我修正呢?为什么不一口气就直接答对呢?为什么要先错然后才答对呢?这个你就想想看,对人类来说,很多时候人类往往也是先犯错才答对的。在学校这十几年来,我的发现就是,往往学生都会犯非常类似的错误,那就是学长会去斥责学弟,“你怎么在实验时会犯这种错误?”然后在隔年那个学弟变成学长以后,会再去斥责另外一个学弟,“你怎么会犯一样的错误?”都忘了去年他其实也是被斥责的那一个人。所以我发现,有一些错误好像就是会反复发生。那会不会这些错误就是你没有经历过,你就是没有办法修正,你就是要先犯这个错,你才能够把它修正。那如果是有旁人来提醒,你就是没有办法能够意识到这个错误,你就是要自己先踩个雷,才有办法把雷排掉。会不会推理也是一样?有些问题在回答时,你就是很难一次答对,你就是要先犯错,然后才把错误答案修正,才能够答对。
这边引用一篇论文,这篇论文是心理学的论文。我之所以看到这篇论文,是因为它有出现在那个 News NIT 这个网站上面。那里面讲的这个主题叫做 思考的代价(Cost of Thinking)。他想要讲的是,模型的推理有时有点像是人类的思考。他们去叫语言模型跟人类去解一样的问题,然后接下来呢,他们去量语言模型耗费的标记数跟人类耗费的时间,发现这两者有一些正比的关系。右边就是这篇论文的截图,这个心理学的论文。那纵轴,每张小图代表不同的任务。纵轴是人类解题的时间,横轴是语言模型在解题时推理的标记。在有些任务上,但其实也不是所有的任务,两者呈现某种程度正比的关系。也许这就告诉我们说,不管是碳基生物还是硅基生物,思考本身就是需要有一些代价,你就是很难一次就答对。但如果你要批评这篇论文的话,那我的批评可能会是一个是标记,一个是时间,这两者之间能够对比吗?这两个是呢可以拿来做比较的吗?也许对人类来说,对应到语言模型的标记的部分,应该是你给那个人一张纸,然后让他解这个问题时,看看他在那个计算纸上面写多少字,这样比较能够跟语言模型的标记做类比吧。感觉用时间跟标记好像是不能够类比的。不过这就是额外有一个文献告诉你,这就是思考的代价。
推理的理论基础与RL争议
这里再从另外一个角度解释为什么我们需要推理。在2025年初,那时推理刚刚流行,所以在2025年2月有一系列的论文,他们都试图去解释为什么推理会有用。我这边就引用了三篇想法非常类似的文章,它们的想法是这样子的。我们当然可以要求模型一次就做对,我们可以要求模型看到输入立刻给我答案。我们也可以要求模型做推理,看到输入经过大 T 个步骤把这个解题的过程分成 T 个步骤,最后再得到答案。这两者究竟有什么不同呢?我们假设在做推理时,每一个步骤有 k 种不同的变化。那我们就假设说 k 种不同的变化,每个变化模型都要看过才能够答对。所以有 k 种变化,每种变化我们都要看过,那叫 k 笔资料模型才能够答对。但假设我们把这个推理的步骤一步一步的这个步骤拿掉,全部综合起来,那输入跟输出有几种不同的变化,就变成 k 的(大 T 加一)次方了。这里总共有 T 个步骤,所以就变成 k 的(大 T 加一)次方变化了。假设每种变化都需要一笔训练资料,那 k 的(大 T 加一)次方笔总变化显然需要非常大量的资料。而 T 个步骤,其实这里是(T 加一)个步骤,每步骤 k 个变化,那你每一个步骤都只需要少量的资料就可以训练起来。总体说起来,你也只需要 k 乘以(T 加一)笔资料就好了。所以今天假设你要叫模型一步做对,那你的变化会是指数级增长,你需要非常大量的资料才能够教会模型一步做对。如果你把一个问题分成多个步骤,再全部综合起来,那模型整体而言需要的训练资料是比较少。那这些论文基本上就是用类似的方法。那这些论文都是有更深的理论证明的,那我们就不讲,我这里就是一个科普式的方法来跟大家说明说为什么推理有可能是有用的。
如果你觉得这个讲法还是太抽象的话,那我们就举一个具体的例子。假设我们现在要做 奇偶校验(Parity Check: 一种简单的错误检测方法,用于判断二进制数据中1的个数是奇数还是偶数)。如果你不知道奇偶校验是什么的话,奇偶校验的意思是说给你一串二进制数字,给你一串零一零一的数字,然后现在模型要的输出是在这一串数字里面有奇数个一还是偶数个一。如果是奇数个一,模型就要输出一。如果是偶数个一,就要输出零。那像这第三个例子,总共五个一是奇数个一,所以就要输出一。那假设我们现在的输入的序列长度固定就是六个数字。那如果固定就是六个数字,输入跟输出有多少种对应关系呢?有二的六次方,总共六十四种关系。假设我们有一个很笨的模型,它就只会死背训练资料。你要教会它做奇偶校验,输入有六个数字的奇偶校验,那你需要有六十四笔资料,你要给它看六十四个可能性,那它把所有可能性背起来,它就能够做奇偶校验。
但是假设我们现在不要求模型直接得到答案,而是可以用多个步骤来解这个问题的,那奇偶校验这样的任务可以做一个简化,输入一样是六个二进制数字,但我们可以分成多个步骤来解。先把前两个数字加起来,然后做那个 异或(XOR: 逻辑运算符,当两个输入不同时输出真,相同时输出假),异或,大家知道吧?异或,如果是零跟零,那加起来就是零。然后把零跟一再去做异或,就得到一。一跟零做异或得到一,一跟零得到一,一跟零得到一,最后就会是正确答案。而在这里的每一个步骤其实都是输入两个数字,输出一个数字。刚才我们说我们做的就是异或,输入零零就是零,输入零一就是一,输入一零就是一,输入一一就是零。模型只要记得这个操作,它就可以解这里的问题了。所以每一个步骤只有四种变化。那这里总共要做五步才能够得到最终的答案。那我们再重复一下刚才步骤,用下面这个例子,那先把前面这两个数字做异或,所以得到零。然后零跟零做异或得到零,零跟一得到一,一跟一得到零,零跟一再得到一,最后这个数字就会是正确答案。我们把本来需要一步做到位,拆解成多个步骤,拆解成多个步骤以后,问题就变简单了。每一个步骤只有四种变化,总共五步,只需要二十个采样就可以让模型学会这件事。所以当我们教模型做推理时,其实我们是让模型用更少的训练资料就可以学会一个任务,或者是在同样的训练资料下,它可能可以学得更好,有更好的 泛化能力(Generalization: 模型在未见过的数据或任务上表现良好的能力)。
事实上很多文献都指出说,假设你今天要处理的是 域内问题(In-domain Problem: 训练数据和测试数据分布相似的问题),就你的训练资料跟测试资料它的分布是一样的,比如说非常类似的数学的题型,这时你就不需要推理,你其实可以直接叫模型输出答案,反正它可以直接把答案硬背起来。但是假设你要的是更聪明的模型,它有泛化的能力,那你需要教的模型做推理,那它可能更有泛化的能力,可以用更少量的资料就学到更多不同题型的解法。所以这就是推理的妙用。
讲到这边,我们刚才说在做完推理之后,本来不会反思的模型好像就展现会反思了。那有一系列的论文就在探讨说,当我们用强化学习这种方法教模型做推理时,它到底学到了什么?有一派的假设是这样子的。其实呢,模型能够做反思这件事,模型能够做推理这件事,早在强化学习之前它就已经会了。我们这边用一个树状图来表示模型在产生答案时,它有很多不同的路径。那之所以走不同的路径,是因为每次在某一个节点,每一个节点代表一个标记,要产生下一个标记时做采样,采样到不同的标记就会走不同的路径,得到不同的答案。那有一个假设是正确的路径,其实早在做强化学习之前,你的 基础模型(Base Model: 未经特定任务微调的原始预训练模型)就已经有机会采样到。那强化学习到底做了什么呢?强化学习多做的事情是,它把这些本来就已经存在的路径的概率提高,让它更容易被采样出来。也就是强化学习并没有创造出模型本来无法输出的东西。那验证、反思,这是模型本具的能力,我们只是让它有更高的机会出现而已。
那这么讲有什么样的证明呢?这边就引用一篇去年四月的文章。那其实有类似发现的文章,我只能告诉你满坑满谷。我这边只是引用了一篇比较早的、引用次数比较高的文章而已。这篇文章是这样讲的,他说我们来教模型解数学问题。那这篇文章做了很多很完整的实验,我这里只是截了其中一张图而已。横轴是采样次数。这采样次数什么意思呢?因为它纵轴算的不是一般的正确率,它算的是 Pass@k,也就是它让模型去做同一个问题 k 次,在 k 次里面只要一次答对就算对。所以横轴是模型的 k 到底可以有几次?k 等于256就是我们今天这样解这题就解256次,只要256次里面你解一题答对,我就算你答对。接下来就比较有做强化学习之前的模型是黑色这条线,跟有做强化学习,那这里做不同程度的强化学习得到的三条线,你会发现说,假设只能做一次,有做强化学习确实远比没有做强化学习好。所以如果只能采样一次,有做强化学习(就有做强化学习教模型做推理这件事),可以让模型更容易地采样到得到正确答案的那个路径。但是假设采样的次数非常多,这里开到256,有没有做强化学习其实是差不多的,甚至有做强化学习性能还差一点。所以这里告诉我们说,这些正确的答案是模型本来在做采样时,它就有可能可以产生出来的。只是你今天采样的次数不够多,采样次数够多,模型是有可能可以得到正确答案的。这是它本具的能力,是它与生俱来的,只是因为被其他的可能性、其他的错误的路径所覆盖。这让我想到就好像是在佛教华严经里面讲的,佛说我想看那原文是什么?佛是这样说的,他在开悟之后说:“奇哉奇哉,大地众生本具如来智慧德相,只因妄想执着而不能得证。”所以意思就是告诉我们每个人本来都有佛性,只是因为你被无明妄想所覆盖了,所以你的佛性才没有显现出来。对语言模型来说也是一样的,它本来是可以得到正确答案的,只是因为有其他太多的可能性干扰它,所以它没有办法得到正确答案。
这个发现有什么重要性呢?这个发现的重要性就是,既然本来就可以得到正确答案,那你其实也不需要做强化学习了,因为本来就可以得到正确答案啊。所以有没有可能透过没有训练模型的方法,只是更好的采样方法,就把正确答案采样出来?这就像禅宗顿教里面讲的,既然人人本具佛性,你只要放下一念清净,就可以直接开悟,就不需要花费长时间的修行。所以这里概念是一样的,能不能够不用强化学习训练模型就得到正确答案?后来在去年十月的时候,还真的有人提出了一个新的采样方法。它这个采样方法是一个比较厉害的方法,它很复杂,这些细节我们就不讲,大家可以再去研究这篇论文。同时它可以逼出原来模型的推理能力。这里这个图呢,最左边这个柱状图是没有做强化学习的模型,中间是有做强化学习的模型,右边是一个 免训练方法(Training-free Method: 不需要额外训练模型就能提升性能的方法),只是改了采样的演算法,它居然可以让它的模型在很多状况可以逼近强化学习的结果,甚至在某些状况还可以超过强化学习的结果。所以这是一派的说法,就是模型其实不用强化学习也能做推理,它本来就会反思,只是你没有让它展现出这个能力而已。
但是其实还有另外派的说法,另外派说法说强化学习真的可以让模型学会额外的能力。也就是那些强化学习时才展现出来的一些推理过程,有些是不存在于模型本来能够产生的路径之中的。在强化学习的过程中,确实学到了新的推理技巧,所以它才能够得到正确的答案。那有什么样的证据呢?这边就引用一篇去年六月的论文。我们先看这张图的上半部的两个图,做在两个不同的论文上面。上半部这两个图是想要复现之前说强化学习不能够学到新的思考方式的那些论文的实验。他说,假设我们观察 Pass@k,就在采样 k 次里面答对的概率,有没有强化学习在采样量大很多时,确实有没有做强化学习,非常的接近。那这篇论文想要提出的想法是说,这个最后答案是对,那真的代表模型有比较强的推理能力吗?有没有可能它就只是猜对而已?采样那么多次,今天有的题目答案的可能数字是有限的,答案一定落在一到十之间。你可以采样1024次,那每个数字都采样过啦,难怪它可以答对。会不会模型其实根本没有比较厉害,只因为采样很多次,所以看起来好像基础模型也有办法采样到正确答案。
所以他就做了另外一个实验。他这个另外一个实验,它叫做 思维链路径(Chain-of-Thought Path, COT Path),也就是说不能只有正确答案对才算对,要去检查那个计算的过程。计算过程如果有错,那也得算是错的。他如果把这个额外的限制加进去,就是计算过程有错也算是错的加进去,那你就发现,没有做强化学习的模型,确实就不如做强化学习的模型了。那这是一个例子告诉我们说,也许做强化学习还是教了模型新的能力。它要做强化学习模型比较有可能在计算过程中是对的。那如果要批评的话,这篇论文还是有一些可以批评的点,比如说怎么知道计算过程是对的?这里采样1024次呢?难道是人看吗?没有,当然是另外一个语言模型看的。那语言模型看的能够算是对的吗?这个就不好说了。所以这就是另外一个可以批评的点。
所以总之现在的状况就是,有人觉得 LLM 在没有强化学习之前就有推理的能力,有人觉得在强化学习之前没有推理的能力,有人觉得不行,有人觉得可以,那也有人觉得两者都有可能。你可以看看下面这篇文章,它的标题就告诉你说,它想要讨论的就是 RLVR 推理能力边界的争论(Debate on RLVR Reasoning Capability Boundary)。它想要探讨到底这个争执是哪里来的?为什么有人说强化学习,为什么有人说强化学习前就可以推理?有人说强化学习后会学到新的能力,到底强化学习有没有学到新的能力?那这篇论文的结论是,这有兴趣大家再自己详读。在这篇论文的结论就是两者都有,在不同的训练阶段,模型学到不同的事情。在训练的初期,模型比较容易利用现有的路径,只是改变它的概率。在训练的后期,就你训练强化学习训练得够久,模型也有机会展现它新的能力。那现在比较大的问题就是,那到底什么样的强化学习训练演算法要给模型什么样的 奖励信号(Reward Signal: 在强化学习中,指导模型学习的反馈机制),比较能够激发让它有新的能力?那在这篇论文里面,其实也提出来了一些想法,怎么让模型比较容易学会新的能力。总之这也是一个尚待研究中在争辩中的问题。这里只是提出跟大家讲说有这么样的一个问题。这个其实就是今天想要跟大家分享的内容,我们就讲了模型自我修正的可能性有三个不同的面向。
📌 文中提及的人物和组织
公司/组织: OpenAI, Hugging Face, Microsoft, NTT, Purdue University
产品/模型: ChatGPT, GPTQ, Llama 2, Llama 3, GPT-3.5, GPT-4, Gemini 2.5 Pro, Claude 4