跳转到内容

第 2 章 一个 Token 的旅程:训练和模型运行不是一回事

2.1 回答变了,究竟是什么变了?

Section titled “2.1 回答变了,究竟是什么变了?”

第 1 章 中,加入 travel-v2 后,助手把住宿限额从 600 改答为 750。我们很容易说它“学会了新制度”。但还有一个问题没弄清:它改变了学到的计算规则,还是用同一套规则处理了不同的信息?

先看一个简单的计算规则:“把输入乘以二”。给它一个数,它就按规则返回一个结果,这样的对应关系叫作函数。输入 3,输出 6;输入 4,输出 8。输出变了,乘数没变。把乘数换成五,才是改了规则。语言模型当然复杂得多,但同样要分清外部传入的内容和内部保存的数值。

本章要回答的是:生成回答时,哪些东西会变?还要做哪些操作,模型本身才会变?我们先沿着一次预测,看文本怎样进入计算、怎样得到结果,再看结果接着用来做什么:是延长输入序列,还是更新模型参数?

先记住刚才乘法中的三样东西:输入的 3、事先保存的乘数 2,以及算出的 6。到了语言模型里,它们分别对应输入的文字、保存的参数和计算结果。接下来的内容就沿着这三样东西展开:先把文字编码成数字,再计算概率、选出一个片段并接到后面;走训练这条路时,才会再去更新参数。

本章以简化的因果 Transformer 文本生成器为例。Transformer 是一种组织神经模型计算的方法的名称,现在还不需要了解它的各个部件。这里的“因果”只表示一种限制:预测下一个 Token 时,只能使用前面的 Token,不能提前看到要预测的内容。它并不是说模型发现了现实世界的因果关系。Transformer 原始论文是这里的架构基础;本章只梳理因果文本生成所需的路径,不重现论文中完整的编码器—解码器架构。Vaswani 等,2017

2.2 一次预测怎样从文字走到数值计算

Section titled “2.2 一次预测怎样从文字走到数值计算”

2.2.1 先确定输入,再把文本编码

Section titled “2.2.1 先确定输入,再把文本编码”

模型内部做的是数值计算,文字要先有相应的数字表示,才能参与计算。这里不是给整句话的“意思”编一个号,而是先把文字切成可以反复使用的片段,再逐个编号。

例 2.1——续写一句话。用户输入 The capital of France is,意思是“法国的首都是”。应用在发给模型之前,还可能加上指令、之前的对话或检索到的资料。这次实际提供的全部内容,就是本次运行的上下文。本例先只用下面这句话,按规定分成五个片段:

文本: The capital of France is
片段: [The] [␠capital] [␠of] [␠France] [␠is]
ID: 1 2 3 4 5

图中的方括号用来标出每个片段的边界,并没有在原句中添加括号。␠ 表示普通空格。分词器(tokenizer)按一套编码规则,把文本变成 Token 序列,并给出每个 Token 的编号。它能使用的全部条目组成词表(vocabulary)。这里,␠France 是一个完整片段,编号为 4。这个编号只用来找到词表条目,数字大小不表示“法国”的含义。第 3 章会给出这个小分词器的完整规则。

编号的顺序不能丢。[1,2,3,4,5] 是一个有先后的序列,调换顺序就改变了输入。编码也只能处理实际提供的文本;应用没发来的制度文件,不会在分词时凭空出现。

2.2.2 查出嵌入向量,再结合上下文计算

Section titled “2.2.2 查出嵌入向量,再结合上下文计算”

编号能告诉我们“这是哪个片段”,但编号的大小是人为安排的。把 France 编为 4,不表示它是编号 2 的两倍。因此,模型接下来会按编号查出另一组专门用于计算的数。这就像根据行号查表:行号负责找到条目,条目里保存的内容才是我们要用的东西。

模型拿到 ID 后,会用它从嵌入表(embedding table)中取出一行数。这一行叫作向量(vector),是一组按顺序排列、供后续计算使用的数值。本书的教学表规定,ID 4 对应 [2,1],意思是“第一个数为 2,第二个数为 1”,不是把 2 和 1 相加。向量有几个数,就说它有几维,这里是二维。现在只需把它看成放在一起的一组数;第 3 章会把这样的数对画成平面上的点。

表 2.1——片段、编号和查表得到的数值。

对象本例中的值作用
Token 片段␠France编码得到的一段文本
Token ID4在特定版本的词表中定位条目
输入嵌入[2,1]取出该位置事先保存的数值

这里并没有把整数四“算成”二和一,只是按编号取出已经存好的值。五个 Token 就按顺序取出五行。本例每行只有两个数,而且都是人工指定的;神经模型中的嵌入向量通常在训练中学得。

查完表,为什么还要继续算?因为无论问法国首都还是法国面积,France 查出来的都是同一行,但后面应该接的答案不同。模型还得把周围文字的信息结合起来。

Transformer 通过前后衔接的多个计算步骤来做这件事,这些步骤称为层。各层结合查出的向量和片段的位置信息继续计算,得到上下文表示(contextual representations)。它们不只取决于一个 Token 在词表中的条目,还可能受到当前可用的其他 Token 影响。只要嵌入表不变,␠France 最初查出的向量就不变;经过后续计算得到的表示,却要看它出现在什么序列中。

此处先弄清各环节的输入和输出,暂不推导注意力和矩阵乘法:输入的是按顺序排列的 Token 表示及位置信息,输出的是结合上下文算出的数值表示。前面说的参数也常被称为权重。即使所有权重都不变,只替换输入里的 France,也可能改变计算结果。具体怎样相互影响,后面会讲;这里先理解,固定的模型也能对不同上下文作出不同回答。

2.2.3 先算分数和概率,再选一个 ID

Section titled “2.2.3 先算分数和概率,再选一个 ID”

处理完已有文字,模型还要表示:接下来有哪些片段可选,对每个片段有多偏好?每个可选的片段就是一个候选项。到了输出环节,模型会为每个候选的下一 Token ID 算一个分数。这些原始分数叫作 Logits。Logit 可以是负数,也可以大于一,因此不能直接当作概率。要使用第 1 章的采样办法,还得把这些分数换成“每个候选项占多少选择机会”。这个转换叫作归一化。转换后得到概率分布:每一项都不小于零,所有项加起来等于一。原始分数可能为负,所以这里不能简单地拿每个分数除以总分。第 6 章会推导怎样转换。

我们先不展开这个计算,只看概率出来后怎么选。假设下一步的结果按下面三个标签归类,概率直接给定,不是用前面的二维嵌入算出来的。

表 2.2——给定概率及对应的采样区间。

候选标签概率对应区间
Paris(巴黎)0.7从 0 到 0.7,含左端、不含右端
Lyon(里昂)0.2从 0.7 到 0.9,含左端、不含右端
Other(其他)0.1从 0.9 到 1,含左端、不含右端

Other 代表其余可能结果,不是教学词表里的一个 Token。这张表只用于说明怎样在几个标签之间选择,不是一个真实模型的完整词表。先把三个概率读成 70%、20%、10%,也就是各自占多少选择机会。再从 0 开始分配区间:给 Paris 留出 0.7;接着给 Lyon 留出 0.2,右端就到了 0.9;最后留出 0.1 给 Other,恰好到 1。表里的区间端点就是这样得到的,三个区间首尾相接,没有重叠。

有了分布,还得规定怎么选,才能得到一个输出。贪心选择(greedy selection)总是选概率最大的候选,本例会选 Paris。采样(sampling)则看抽样值落在哪个区间:0.8 落在 Lyon 的区间,所以选 Lyon;恰好取到 0.7 时,也选 Lyon,因为第一个区间不包含右端的 0.7,第二个区间包含左端的 0.7。这样的左闭右开约定,避免了边界归属不清。

预测概率和选择输出,是两个步骤。同一个分布,采样时可能选出不同结果;不同的分布,也可能恰好有同一个最大项,于是贪心选择得到相同结果。因此,只看最后选中了哪个词,无法知道前面的计算是否相同。

这里的 0.7,只是这个例子中下一步选到 Paris 的概率。它不表示“这条事实有 70% 的可能是真的”,更不是经过校准的真实性判断。回答是否符合事实,仍要按第 1 章的方法另行核查。

2.3 把选中的 Token 接回去,继续生成

Section titled “2.3 把选中的 Token 接回去,继续生成”

假设选中了 ␠Paris,它在教学词表中的 ID 为 6。接下来,把 6 加到当前序列末尾。下一次预测就用这个更长的序列作输入。

表 2.3——例 2.1 连续生成两个 Token。

预测选择前的序列选中的 ID添加后的序列
第一次[1,2,3,4,5]6,␠Paris[1,2,3,4,5,6]
第二次[1,2,3,4,5,6]7,.[1,2,3,4,5,6,7]

第二行假设接着选中了句号。这是下一步的选择,不是由表 2.2 的数值直接推出来的。每一步都要根据当时已有的序列重新算分布。因此,生成 Paris 以后,后续预测就多了一项可用的信息。

输入与表示
  1. 文本片段1. 文本 → Token 片段
  2. 行编号2. 按顺序排列 Token ID
  3. 一组数字3. 查出嵌入向量
  4. 处理步骤4. Transformer 结合位置计算

数据按 1 → 2 → 3 → 4 传递。嵌入表和各层权重都属于参数。

预测与选择
  1. 处理步骤5. Logits → 概率
  2. 行编号6. 选出下一个 Token 的 ID
  3. 应用保存的记录7. 将 ID 加到序列末尾
  4. 文本片段8. 反分词,还原文字

数据按 5 → 6 → 7 → 8 传递;流程控制 ⇢:用加长后的 ID 序列回到第 3 步,或停止。

图 2.1——选出一个 Token 后,将其 ID 加回序列,继续生成。 本书原创图示 · CC BY-SA 4.0。

图 2.1 画出了这个循环:选出的 ID 加回序列,再进入下一轮计算。不断“预测、添加、再预测”,就是自回归生成(autoregressive generation)。它利用序列前面已有的 Token 继续生成,其中也包括自己刚生成的 Token。实际实现可以复用中间结果,不必每轮重算前面所有位置,但后续预测仍然依赖已有序列。第 30 章会介绍这类缓存方法。

反分词(detokenization)按配套的编码规则,把输出 ID 转回可读文字。界面可能攒够几个片段再一起显示,所以屏幕上每次出现一块文字,不一定就对应一个 Token。

真实系统可以在选中指定的结束 Token、满足设定的停止条件,或达到长度上限时停止生成。第 3 章的小词表只演示句子如何编码,没有设置自动结束用的 Token;第 4 章的字符模型则会明确约定开始和结束标记。无论采用哪种设置,生成结束标记而停止,与因为长度限制而被截断,都要分清。

普通生成过程中,有一点始终不变:序列可以变长,中间结果可以变化,但模型参数保持固定。参数包括嵌入表中的数值和各层学到的权重。运行时算出的中间数值,通常叫作激活值(activations)。读取参数来计算,并不等于修改参数,就像拿乘数来做乘法,不等于换掉乘数。

到这里,我们一直在使用已经保存好的参数。这些参数又是怎么来的?仍看刚才续写的句子。生成时,我们不知道后面是什么,所以要选;如果手里已经有完整句子,就可以先挡住后面的片段,让模型预测,再用挡住的内容核对结果。这就为训练提供了依据。

训练(training)根据指定的数据,估计或调整模型从数据中学到的状态。本章讨论的是预测下一 Token 的神经模型,它用已知文本来确定每一步应该预测什么。训练和生成都会先用当前参数算一次预测,区别在于拿到结果以后怎么处理。

例 2.2——下一 Token 就是训练目标。完整句子 The capital of France is Paris. 对应 [1,2,3,4,5,6,7]。一段序列从开头起取出的部分叫作前缀,例如 [1,2] 就是保留了前两个 ID 的前缀。完整句子已经给定,所以我们知道,[1] 后面是 2,[1,2] 后面是 3,以此类推。

表 2.4——每个预测位置对应的目标。

预测位置允许使用的前缀目标 ID 与片段
1[1]2,␠capital
2[1,2]3,␠of
3[1,2,3]4,␠France
4[1,2,3,4]5,␠is
5[1,2,3,4,5]6,␠Paris
6[1,2,3,4,5,6]7,.

拿第五行来说,它问的是:“已知 The capital of France is,接下来应该是什么?”答案是片段 ␠Paris。第四行少给一个片段,问的就是:“已知 The capital of France,接下来应该是什么?”答案变成了 ␠is。把分界线沿着一句现成的话移动,就能得到多道预测题。每道题都以原序列中紧接着的那个 Token 为目标。本例共有六个预测目标,没有规定如何预测句子开头,也没有设置句号之后的目标。训练程序虽然知道整句话,每个位置的预测却只能用规定范围内的前缀。否则,模型就能提前看到要回答的内容,做的便不再是预测。

训练时,正确的前缀已经全部给出,只要限制好每个位置能看到哪些内容,就可以同时处理多个位置。普通生成时则不同:当前 Token 还没选出来,下一步的输入序列就不完整。因此,两者虽然都预测下一 Token,计算的先后安排却可以不同。

2.4.2 算出误差,还要知道怎么改、真正去改

Section titled “2.4.2 算出误差,还要知道怎么改、真正去改”

有了目标,就能比较预测的好坏。例如,文本中接下来实际写的是 Paris,那么给 Paris 分配 0.1 的概率,就比给它分配 0.7 更不符合这个例子。只看最后选中了哪个词,会丢掉这种差别;训练还可以利用目标 Token 获得的概率来判断预测。

前向计算(forward calculation)用当前参数算出预测结果。损失(loss)用一个数衡量预测与给定目标差得有多远。训练下一 Token 模型时,模型给文本中实际出现的下一 Token 分配的概率越低,损失就越大。这里的目标来自训练文本;文本写了什么,并不保证现实中就是什么。

知道错得有多远,还没有告诉程序该怎么改。回到开头的乘法,假设输入 3,要求得到 9,当前乘数 2 却算出 6。把乘数稍微调大,结果会靠近 9;往小调,反而离目标更远。模型有许多参数,也需要知道:每个数往哪个方向稍作调整,会怎样影响损失。

梯度(gradient)描述的正是这种关系:参数在当前值附近发生微小变化时,损失会怎样变化。优化器(optimizer)再根据梯度和更新规则修改参数。所以要分清三个步骤:用损失衡量预测偏差,用梯度了解参数变化对损失的影响,最后实际更新参数。第 7 章会展开这些计算。这里先认识它们,是为了知道:怎样才算真正完成了一次神经模型的训练更新。

训练过程
  1. 文本片段1. 文本与已知目标
  2. 处理步骤2. 前向计算 → 损失 → 梯度
  3. 模型保存的数值3. 优化器更新 θ
  4. 模型保存的数值4. 保存检查点

数据从 1 传到 2;根据第 2 步更新参数 ⇒ 3;重复训练后,在第 4 步保存检查点。

模型运行过程
  1. 应用保存的记录1. 本次实际使用的上下文
  2. 模型保存的数值2. 参数 θ 不变
  3. 处理步骤3. 前向计算 → 概率
  4. 行编号4. 选出 ID,接到序列末尾

数据按 1 → 3 → 4 传递;第 3 步读取参数 2;添加 ID 后继续循环 ⇢,不更新参数。

图 2.2——三种箭头分别表示数据传递 →、参数更新 ⇒ 和流程控制 ⇢。 本书原创图示 · CC BY-SA 4.0。

图 2.2 中,训练把损失相关的信息用于更新参数;生成则把选中的 ID 加回序列。两条路径都有前向计算,但只有前一条包含本章所说的、根据损失更新参数的步骤。

因此,模型答错了,并不会自动学会改正。用户下一条消息指出错误,改变的是下一次输入;要改参数,还得另外执行训练。保存对话,存下的是文字,也不是新权重。即使进行了训练,也不一定是把某个事实写进一个专门的位置:更新可能改变许多参数之间的数值关系,也影响别的预测。

训练也不只限于这套梯度方法。第 4 章会通过计数拟合一个小模型。计数之所以算训练,是因为它根据指定数据估计模型状态;之后读取这些计数作预测,并不等于又训练了一遍。

保存下来的模型状态叫作检查点(checkpoint)。要正确运行它,必须配上对应的架构、兼容的分词器和 ID 映射。如果还要从中恢复训练,检查点也可能保存优化器等训练状态。单独一份聊天记录,两种检查点都算不上。

2.5 信息可能改在四个不同的地方

Section titled “2.5 信息可能改在四个不同的地方”

2.5.1 先弄清保存了什么,再比较变化

Section titled “2.5.1 先弄清保存了什么,再比较变化”

回到制度案例。应用可以修改的信息不止一种,只说“系统记住了”,还说不清到底发生了什么。

表 2.5——四类信息分别怎样变化。

保存位置内容举例怎样改变
模型参数嵌入向量和各层学到的权重训练更新,或加载另一个检查点
当前上下文问题、选取的消息和制度摘录组织一份不同的输入
外部数据模型之外的制度文档编辑或替换文档
应用状态保存的对话或审批记录写入新的应用记录

加载另一个检查点,确实换了运行时使用的参数,但加载本身不是训练;训练是先前产生这些参数的过程。同样,保存新文件和把新文件放进输入,也是两件事。文件更新了,应用完全可能还在发送旧内容。

这些区别也可以用一个简短的式子记下来。先把下面的式子读成一句话:“用保存的参数处理实际输入的序列,得到概率。”字母只是给前面已经认识的几样东西取了简短的名字。用 ss 表示实际输入的 Token 序列,用 θ\theta 表示模型参数;希腊字母 theta 在这里统称模型保存的那些数值。固定的计算过程输出一个概率分布,可以写成:

p=Fθ(s).p=F_\theta(s).

其中,pp 是下一 Token 的概率向量,FF 表示计算过程。括号里放的是交给计算过程的输入,下标 theta 说明使用哪一组参数。这只是把前面讲过的关系缩写出来,还没有推导模型内部怎么算。本章假定前向计算是确定的:只要 ss 和 θ\theta 都相同,算出的 pp 就相同。外部文件或保存的记录,要经应用处理、改变计算实际使用的输入,才能影响结果。得到分布之后,选择步骤仍然可能从同一个分布中选出不同的 Token。

2.5.2 用六组对照看清变化发生在哪里

Section titled “2.5.2 用六组对照看清变化发生在哪里”

例 2.3——用查表代替复杂的模型计算。为了分清表 2.5 中的四个位置,而不必运行神经网络,我们规定一个简单的查表函数。输出只有 600 和 750 两个完整答案标签,它们不是 Token ID。参数版本 A、B 分别对应下面两行,所有概率都直接给定。

表 2.6——查表函数的全部结果,答案顺序为 [600, 750]。

参数版本输入中使用 travel-v1输入中使用 travel-v2
A[0.8,0.2][0.1,0.9]
B[0.3,0.7][0.05,0.95]

这些数是为教学设定的,既不是训练出来的权重,也不是前面那几行嵌入算出的结果,更不代表真实模型的准确率。这样设定,是为了让我们能逐项查清:参数版本或输入中的制度版本变了,输出会怎样变。

例如,参数用 A,输入里放了 v2,就找 A 行与 v2 列的交点,读出 [0.1,0.9]:选 600 的机会是 10%,选 750 的机会是 90%。这个查表过程没有询问“外部文件里还存着什么”。接下来改变文件、历史记录等条件,就能看清哪些变化真正进入了计算。

表 2.7——六种条件下的输出。

场景参数实际输入的上下文外部文件保存的历史输出 [600, 750]
原始状态Av1v1无[0.8,0.2]
只换文件Av1v2无[0.8,0.2]
提供新文件Av2v2无[0.1,0.9]
只存历史Av1v1v2[0.8,0.2]
提供历史Av2v1v2[0.1,0.9]
更换参数Bv1v1无[0.3,0.7]

先看“原始状态”和“只换文件”。虽然外部文件从 v1 更新成了 v2,查表用的仍是 A 和 v1,所以结果还是 [0.8,0.2]。再看“只换文件”和“提供新文件”:这次把输入中的制度换成了 v2,查表便移到另一列,参数仍然是 A。

“只存历史”和“提供历史” 也是同样的道理。把 v2 存进历史记录,但仍给模型发送 v1,输出就不变。等到应用把保存的那段文字放进输入,上下文变了,输出才变。可见,只要保存文字,并在之后重新提供给模型,就可能让系统看起来一直“记得”,无须改动参数。

最后看“更换参数”:输入仍用旧制度,但换了参数版本。即使用户看到的问题和资料都没变,输出分布也变了。如果采用贪心选择,这一行和“提供新文件”都会回答 750,却是由不同变化造成的:一个换了参数,一个换了上下文。

这六种情况都是 part-i-v1 中事先确定的记录。分析每一行时,先找出参数版本和实际发给模型的上下文,再回到表 2.6 查它们的交点,就能得到结果。真实检索系统比这复杂,但同样要分清模型从训练中学到的信息与本次从外部拿到的信息。Lewis 等,2020

2.6 会按示例作答、会推理,就说明重新训练了吗?

Section titled “2.6 会按示例作答、会推理,就说明重新训练了吗?”

有了这六组对照,就能比较清楚地判断系统哪里发生了变化。不过,日常谈论模型时常说它在“学习”或“思考”,这些说法容易把刚分清的几件事又混在一起。比如,模型写出了解题步骤,并不表示生成循环中多出了一次参数更新。

模型运行(inference)是指把输入交给模型进行计算,也称 model execution 或 model run。解题推理(reasoning)是指一步步求解问题,例如从前提推到结论。模型可以在参数不变的情况下运行,并生成推理过程。这两个词说的是不同的事。

提示里给几个示例,就可能改变固定模型的作答方式。例如,用几条示范告诉它一种此前不熟悉的回答格式。这样的行为通常称为上下文学习(in-context learning)。这里的“学习”是通过输入中的示例来适应任务,不表示执行任务时做了梯度更新。Brown 等研究了不更新参数的少样本任务设置。具体到某个任务,这种方法有没有用,仍要评测。Brown 等,2020

当然,系统也可能收集反馈,之后再训练,或者在使用过程中安排在线调整。但这些都需要额外的流程。要与单纯依靠上下文改变回答区分开,就得检查到底保存了什么、修改了什么,不能因为答得有帮助,就反推参数一定更新过。

对模型给出的推理过程,还要另外判断。一串解释首先是输出文字,其中的步骤可能正确,也可能很有用,但不保证完整交代了答案在模型内部是怎样产生的。已有研究发现,模型的解释会遗漏实际影响回答的因素。这不意味着所有解释都错了,而是说:解释的逻辑是否成立、事实是否可靠,要单独检查,不能仅凭它声称展示了思考过程,就把它当作完整的计算记录。Turpin 等,2023

在制度案例中,好的解释应说明依据哪份文件,并正确地根据文件得出限额。读者据此可以判断答案是否有根据,但这仍不能证明模型产生了新检查点、自动进行了训练,或如实展示了内部的全部计算过程。

生成一个 Token,要经过文本片段、ID、嵌入向量、结合上下文算出的表示、分数和概率,最后才选出一个 ID。这个 ID 加到序列末尾,成为下一次预测的条件。普通生成就在这样的循环中进行,参数始终不变。

神经训练则要加上已知目标、损失、梯度和优化器更新。它根据预测误差改参数,而不只是把回答接长。放到整个系统中看,参数、当前上下文、外部数据和应用保存的状态,都可能各自变化。表 2.7 说明,无论回答变没变,只看答案,都无法确定究竟哪里变了。

第 3 章 会把编码过程展开到可以手算的程度:文本怎样切成片段,ID 怎样查出一行数,以及比较两行数究竟能说明什么。

  1. 采样边界。按表 2.2,抽样值为 0.699、0.7、0.899、0.9 时,分别选什么?哪些与贪心选择不同?如果相邻两个区间都包含 0.7,会留下什么问题?
  2. 跟踪变化。表 2.3 第一次添加 Token 后,什么变长了?请再指出两样没有改变的已存内容,以及一个下次前向计算时可能不同的结果。
  3. 预测目标。对序列 [8,9,10,11],按例 2.2 的约定写出每次预测所用的前缀和目标。为什么第一次预测的输入不能包含 ID 9?
  4. 证据够不够?应用记录了一次前向计算及其损失值。这能证明参数更新了吗?还需要哪些操作或证据?
  5. 查表。某次运行用参数 B,从历史记录中取出 v2 放进输入,外部文件仍为 v1。按表 2.6,输出是什么?为了得到这个结果,查表函数需要读取外部文件中的哪个字段?
  6. 答案相同,原因不同。在表 2.7 中找出两行:它们都用贪心选择回答 750,但变化发生在不同地方。再保存哪些记录,就能区分这两种情况?
  7. 检验是否永久学会。设计一个跨两次对话的实验,检查系统看似记住制度,是否只是因为应用重新提供了历史记录。即使实验支持这一解释,还不能对其他记忆方式下什么结论?
  8. 模型运行与解题推理。助手给出了一段正确的多步计算,应用保存了这次对话。其中,哪部分属于 reasoning,哪部分属于 inference,哪一步改变了应用状态?这些步骤中有哪一步能证明产生了新检查点?
  1. 依次选 Paris、Lyon、Lyon、Other。贪心选择始终选 Paris,所以除第一项外,其余都不同。如果 0.7 同时属于两个区间,取到它时就有两个候选,规则没说清该选谁。左闭右开保证每个合法抽样值只对应一个区间。
  2. ID 序列从五项变成六项;词表和嵌入表都没变。因为新序列包含 Paris,下一次计算得到的上下文表示或下一 Token 分布可能不同。结果变了,不等于参数变了。
  3. 分别是 [8]→9、[8,9]→10、[8,9,10]→11,共三次预测。第一次如果能从输入中读到 9,就提前拿到了答案,无法再检验它根据前缀预测的能力。
  4. 不能。只做评测时,也可以计算损失而不修改权重。神经训练还需要计算相关梯度,并实际执行优化器更新。要确认参数变了,必须有更新记录或参数状态等证据;算出了误差,不表示已经用它改了参数。
  5. 输出为 [0.05,0.95]。这个函数只查 B 和输入中的 v2,不需要读取外部文件的任何字段。选取哪份内容,是应用在调用它之前已经做好的。改动函数没有用到的外部文件,不会改变结果。
  6. “提供新文件”用参数 A 和新上下文 v2,“更换参数”用参数 B 和旧上下文 v1,都会贪心选中 750。记录参数或检查点版本,以及实际输入,就能分清两种原因;保留完整概率分布,也能看出它们不同。
  7. 第一次对话提供 v2,第二次记录应用有没有把那段文字重新放进输入。保持其余条件相同,比较带上历史和不带历史的情况。如果只有带上历史时才能稳定答出现行限额,就支持“在这个设置中,回答依赖所提供的历史”这一解释。但这既不能证明参数里完全没有相关知识,也不能排除其他保存信息的方式;还需要另外检查。
  8. 多步计算的内容属于需要检验的解题推理,即 reasoning;调用模型算出这些内容属于 inference;保存对话改变的是应用状态。题目没有任何一步保存了新学到的模型参数,所以不能据此确认产生了新检查点。