← 进阶 vibe codingTransformer 把这些计算接起来

免费文章 · 02 理解模型怎样生成回答

Transformer 把这些计算接起来


  上一节,我们看到注意力机制会把不同位置的信息按权重汇总,得到新的向量。但这还不是完整的计算过程:模型怎样区分词语的先后顺序?汇总的信息还要经过哪些处理,最后才能变成下一枚 token 的候选得分?

  这些问题,就需要把前面学到的机制放在一起理解。Transformer 是一种神经网络架构,它将位置信息、注意力、前馈网络等计算组织起来,让信息经过一层层处理,最终参与输出的预测。

  这一节,我们沿着许多文本生成模型采用的仅解码器(decoder-only)Transformer,先看看信息怎样从输入走到输出,再拆开其中一层,理解各个部件怎样配合。这样,以后接触不同模型的结构和实现方式时,我们就能看清它们有哪些共同原理,又在哪些地方有所不同。

一次生成,先经过整个网络

  前面我们分别了解了 token、向量和注意力,现在把这些计算连起来看看。

  输入的文本首先经过分词器,转换成 token ID,再通过嵌入表得到各位置的向量。接下来,模型结合位置信息,让这些向量依次经过多层 Transformer 块,不断更新其中的表示。最后,输出层将当前位置的表示转换成词表中各个候选 token 的得分,也就是 logits。经过概率转换和选择,就得到了下一枚 token。

logits 与输出投影是什么?

  logits 是模型给各个候选 token 算出的原始得分。模型内部先用向量表示当前信息,再把它换算成“词表中每个候选各有一个得分”;这个转换步骤称为输出投影。

  原始得分可以为负,也不需要相加等于 1。softmax 把这些得分转换成概率:高得分分到较大的比例,所有候选的概率合计为 1。例如人工得分 [2, 1, 0] 对应的概率约为 [66.52%, 24.47%, 9.00%]。它描述下一枚 token 的选择,不是整段回答的正确率。

  选出的 token 会接到已有前文后面,模型再根据新的序列继续预测。这里其实有两个不同的过程:生成一枚 token,需要经过多层网络的计算;生成一段完整的回答,则需要反复预测下一枚 token。 因此,模型有多少层和最终生成多少枚 token 是两回事。即使模型有很多层,也可以只生成一枚 token。

内容相同,位置为什么仍然重要

  来看两句话:“小林帮助小周”和“小周帮助小林”。它们包含完全相同的词,但顺序一变,帮助者和被帮助者就调换了。模型不仅需要知道每个 token 表示什么,还要知道它们出现在什么位置。

  回想上一节的注意力计算。如果保持查询不变,只交换两组 K、V 的位置,在没有位置信息、可见范围也不变的情况下,注意力权重会跟着交换,但最终加权汇总的结果仍然相同。也就是说,仅靠这样的内容匹配,无法从排列顺序本身区分两种情况。

  为此,Transformer 需要让位置信息参与计算。最直观的方法,是为每个位置准备一个不同的位置向量,再将它加到对应 token 的嵌入上。这样,即使是同一个 token,出现在不同位置时,得到的向量也会不同,后续计算便能利用这些差异区分位置。

  这也是 2017 年最初提出的 Transformer 所采用的思路。不过,位置信息不一定要直接加到输入向量上。例如,Qwen3 使用的旋转位置编码(RoPE),会根据位置对注意力计算中的 Q、K 进行旋转,让它们的匹配得分反映相对位置关系。两种方式的具体计算不同,但目的都是让模型在处理内容时,也能利用这些内容的位置关系。

拆开一个块:汇总以后还要加工什么

  前面我们已经知道,注意力负责从不同位置汇总信息。但这些信息汇总以后,还需要怎样处理?接下来,我们拆开一个 Transformer 块,看看其中的计算怎样衔接。

  我们先用一个简化的单层 Transformer 来观察。输入是 A、B、C、D,字母只是 token 的代号。它的参数由我们人为设定,用来演示信息怎样流动,不代表真实模型的理解能力。

  先看 B 所在的位置。模型会取得 B 的嵌入向量,并让位置信息参与计算。随着计算进行,这个位置的向量也会不断更新,这就是它当前的表示。随后,注意力机制会从允许读取的位置汇总信息,把上下文信息带进 B 的表示。

  接下来,前馈网络(FFN)会把这些信息再加工一次。我们可以把它理解为一个处理函数:接收当前位置已有的信息,经过组合与调整,算出新的表示,再交给后续计算。在真实模型里,这个函数的加工方式由训练学到的参数决定。

  两者的分工可以这样理解:注意力负责汇总不同位置的信息,FFN 负责加工当前位置已经拿到的信息。 在同一层里,各位置使用同一个 FFN 处理函数,但传入的是各自的表示。虽然 FFN 不会在这一步重新读取其他位置,它处理的信息已经包含了注意力带来的上下文。

选读:FFN 的计算细节

  如果想进一步了解 FFN 怎样加工向量,我们可以沿用前面的简化网络。它的词表包含 A–E 五个 token,向量维度为 4,所有参数都由我们人为设定,没有经过训练。下面的数值只是用来展示计算过程。

  这个 FFN 会先把输入的 4 维向量转换成 6 维,经过一个非线性函数,再转换回 4 维。这样既能在更宽的表示空间中加工信息,也能让输出恢复原来的维度,以便通过残差连接与原来的表示相加。

  为什么中间需要非线性函数?因为如果只有连续的线性变换,不管叠加多少次,最终仍然可以合并成一次线性变换。加入非线性函数,网络才能表达更复杂的映射关系。

  这里我们使用 ReLU,它的规则很简单:负数变成 0,正数保持不变。例如,B 在第一次投影后得到六个数值:

  [-0.1730, 0.6447, -0.4481, -0.0293, 0.7119, -0.4643]

  经过 ReLU,就变成了:

  [0, 0.6447, 0, 0, 0.7119, 0]

  随后,第二次投影会把这六个数值重新转换成四维向量,交给后续计算。这些数字来自人为设定的网络,不能把某一维直接理解成“情绪”“语法”等具体含义。

  2017 年提出的 Transformer 也使用了这样的两层变换与 ReLU,只是实际维度大得多。现代模型还会采用 SwiGLU 等带门控的前馈结构,通过一组计算结果调节另一组信息的传递方式。具体实现有所不同,但它们都在进一步加工当前位置的向量表示。

  那么,经过这些计算,原来的表示会被直接替换吗?并不是。注意力和 FFN 都配有残差连接,将各自计算出的结果加到进入该环节前的表示上。这样,原有信息就有了一条直接传递的路径,模型可以在此基础上继续调整。

残差连接:为什么要加回输入?

  注意力和 FFN 计算出新的结果后,为什么还要把原来的输入加回来?这是因为残差连接会为输入保留一条直接传递的路径,让它与当前环节计算出的结果相加,再交给后续网络。

  比如,原来的向量是 [1, 2],新算出的结果是 [0.2, -0.1],相加后就得到 [1.2, 1.9]。这里的数字只是为了说明计算方式。

  这样一来,原有表示可以继续传递,新计算的结果则在它的基础上发挥作用。这种设计也有助于深层网络的训练,让信息和梯度更容易向前、向后传递。不过,它并不保证每一次计算都会让最终回答更准确。

  此外,模型还需要控制计算过程中数值的变化,这就用到了归一化。它会按照一定规则调整每个位置的向量数值,帮助保持计算稳定。

  这样,注意力、FFN、残差连接和归一化就共同构成了 Transformer 块的主要计算环节:注意力汇总信息,FFN 加工表示,残差连接保留直接传递的路径,归一化帮助稳定计算。

归一化和输出概率是一回事吗?

  前面提到的归一化,是按照一定规则调整模型内部的向量数值,让后续计算更加稳定。而我们之前学过的 softmax,则是把候选 token 的得分转换成总和为 1 的概率,用于选择下一枚 token。

  两者虽然都在处理一组数值,但用途不同:归一化帮助稳定模型内部的计算,输出端的 softmax 则用于得到候选 token 的概率分布。 因此,不能把内部向量的数值直接理解成下一枚 token 的生成概率。

  一个 Transformer 块完成计算后,会把更新后的表示交给下一个块。就像一条逐层加工的流水线,后面的层会在前一层的结果上继续处理。虽然各层结构相似,但通常拥有各自训练得到的参数,因此可以从不同方面进一步加工信息。

  那么,经过最后一个 Transformer 块,下一枚 token 就出来了吗?还没有。此时得到的仍然是向量表示。对于常见的仅解码器模型,我们会取当前序列最后一个位置的表示,经过最终归一化和输出投影(LM Head),转换成词表中每个候选 token 的得分。

  这就回到了前面学过的生成过程:模型通过 softmax 将得分转换成概率,再根据选择策略确定下一枚 token。新 token 被接到前文后面,模型又开始下一轮计算。

  到这里,从输入文本、逐层加工到生成下一枚 token,整条计算路线就连起来了。

每个位置能读取哪些内容

  这里还有一个问题:训练时,我们通常已经有了完整的文本,模型会不会提前看到后面需要预测的内容?比如训练文本是 A B C D,模型需要根据 A 预测 B,根据 A B 预测 C,根据 A B C 预测 D。如果计算到 B 所在的位置时,就能直接读取 C、D,相当于提前看到了后面的答案。

  为此,Transformer 可以通过因果遮罩(causal mask)限制注意力的读取范围:每个位置只能读取自己和前面的内容,不能读取后面的位置。例如,B 所在的第 2 位可以读取 A 和 B,却不能读取 C、D。

  这样,即使训练时同时计算多个位置,每个位置也只能依据允许读取的前文进行预测。而真正逐步生成时,后面的 token 还没有产生,模型自然也无法提前读取。因果遮罩让训练时的注意力计算遵守这一限制,与逐步生成的要求保持一致。

从这条路线认识具体模型

  前面我们沿着仅解码器 Transformer,了解了模型从输入到输出的计算过程。不过,Transformer 并不只有这一种结构。

  2017 年最初提出 Transformer 时,它主要用于机器翻译:编码器(Encoder)先处理原文,解码器(Decoder)再结合原文信息,逐步生成译文。而今天许多文本生成模型采用的是仅解码器(decoder-only)结构,将提示和已经生成的内容放在同一条序列中,根据已有前文继续预测下一枚 token。

  不同模型还会在位置编码、归一化和前馈网络等环节采用不同的设计。理解这些部件的作用后,我们再阅读模型的技术说明,就能知道某项新设计改变了哪个环节、可能带来什么影响。不过,结构上的差异并不直接代表实际效果的好坏,最终仍要结合具体任务判断。

读模型说明时,先辨认名称的用途

  例如,Qwen3 技术报告里会出现 RoPE、RMSNorm 和 SwiGLU。先把它们放回刚才的整体路线,就容易判断在讲什么:

名称

在这条路线里的用途

RoPE

让位置信息参与计算的一种方法

RMSNorm

归一化的一种方法,用于调整内部数值

SwiGLU

FFN 的一种设计,用于加工当前位置的表示

  不必在这里记住这些方法的公式。先能把名称与职责对应起来,以后遇到相关说明,再围绕具体问题继续查阅。这些是具体模型的设计选择,各个模型并不一定采用同一套方法。

  这些原理也能帮助我们理解日常使用 AI 时发生的变化。比如补充人物设定、调整资料顺序,改变的是模型这次接收到的信息,以及后续计算得到的表示,并不意味着模型参数被重新训练。而资料进入上下文,也不代表模型一定会正确利用。至于怎样组织信息、怎样让模型更好地利用上下文,我们会在后面的课程中继续深入。

  到这里,我们已经看到文本怎样经过向量表示、注意力汇总和多层计算,最终得到下一枚 token 的候选得分。那么,既然知道了模型怎样生成回答,我们又能怎样影响这个过程? 下一节就从推理投入、采样方式和生成预算开始,看看这些设置分别会带来什么变化。

讨论

登录后参与讨论