一句话总结:词嵌入(Embedding)提供 Token 的内容特征,位置编码(Positional Encoding)提供顺序线索。原始 Transformer 把它们相加,是为了在不增加 d_model、不新增投影参数的情况下,把两种信号放进同一条 residual stream;这是一种有效的紧凑设计,不是数学上的无损打包。


14.1 回顾:输入处理的两个步骤

在第 4 章和第 5 章,我们分别学习了:

章节组件作用
第 4 章Embedding把 Token ID 变成向量(语义信息)
第 5 章Positional Encoding给向量添加位置信息

这一章,我们来深入理解:为什么这两个信息要通过"相加"来结合?


14.2 两种信息的本质

14.2.1 词嵌入:语义信息

回顾第 4 章的 Embedding 查找表:

Embedding查找表

更准确地说,每个 Token 在查找表里有一行可学习参数。训练会让这些向量承载词法和统计特征,我们常把它概括成“语义信息”。下面仍用原来的例子帮助直觉,但相邻关系不是每个模型原始 embedding table 都必须满足的定律:

  • "国王"和"王后"的向量接近(都是皇室)
  • "国王"和"苹果"的向量很远(没有关系)

Embedding 回答的问题是:这个词是什么意思?

14.2.2 位置编码:位置信息

回顾第 5 章的位置编码:

正弦位置编码在不同维度使用不同频率

原始 Transformer 的位置编码是一组正弦/余弦函数,每个位置会算出一个依赖位置下标的向量:

  • 位置 0 对应一组数值
  • 位置 1 对应另一组数值
  • ...

位置编码回答的问题是:这个词在句子的什么位置?

14.2.3 两种信息都很重要

考虑这两个句子:

  • "我爱你"
  • "你爱我"

它们包含完全相同的词,但意思完全不同。位置改变了含义。

所以 Transformer 需要同时知道:

  1. 每个词是什么(Embedding)
  2. 每个词在哪里(Positional Encoding)

14.3 结合方式:相加 vs 拼接

14.3.1 两种选择

有两种直观的方式来结合 Embedding 和 Positional Encoding:

方式一:拼接(Concatenation)

输入向量 = [Embedding; Positional Encoding]
维度:d_model + d_model = 2 × d_model

方式二:相加(Addition)

输入向量 = Embedding + Positional Encoding
维度:d_model(不变)

Transformer 选择了相加。为什么?

14.3.2 相加的优势

1. 维度不增加

如果 d_model = 512,拼接会产生 1024 维向量。接下来有两条路:

  • 让后续网络也保持 1024 维:activation 宽一倍;对于输入和输出都随模型宽度增加的方阵投影,参数量与矩阵乘法开销约变为四倍。
  • 先把 1024 维投影回 512 维:网络仍可正常工作,但会多出一个 1024 × 512 的可学习投影。

所以,拼接不是“错误方法”,也不是所有参数都会统一翻倍。只是与直接相加相比,它要么扩大后续网络,要么增加一次投影。相加则不新增参数,输出仍是 512 维。

2. 两种信号都会影响结果

两个向量相加后,会叠加成同一个输入:

embedding = [0.5, 0.3, -0.2, 0.8, ...]  # 语义
position  = [0.1, 0.0, 0.1, -0.1, ...]  # 位置
combined  = [0.6, 0.3, -0.1, 0.7, ...]  # 两种信号共同影响它

要注意:只看 combined,一般不能唯一还原原来的两个向量。因为许多不同的 (embedding, position) 都会得到同一个和。这里的目标也不是把两者无损压缩后再拆开,而是让模型学会利用这组混合信号。

3. 训练会围绕这种接口共同适配

Token embedding、Attention 的投影矩阵,以及可学习的位置向量(如果采用这种方式)会一起训练。模型不需要恢复两张原始表,只需要让混合后的表示对预测任务有用。

14.3.3 一个直观的类比

想象你在一个派对上:

  • 你的外表(Embedding):告诉别人"你是谁"
  • 你站的位置(Positional Encoding):告诉别人"你在哪"

别人看到你时,会同时利用“你是谁”和“你站在哪里”。这个类比只说明两类线索可以共同参与判断;它不表示把两者相加以后还能逐项无损还原。


14.4 计算方式示例

14.4.1 具体计算

词嵌入与固定位置编码相加,以及词嵌入的一次 SGD 更新

看这张图,我们来追踪一个维度上的玩具计算。为了把算术讲清楚,这里用最简单的 SGD;真实训练通常还会使用 AdamW 等优化器,并同时更新大量参数。

假设:

old_embedding_value = 0.9   # 某个词的 embedding 中的一个值
positional_encoding = 0.1   # 对应位置的位置编码值

输入阶段(相加):

combined = embedding + positional_encoding
         = 0.9 + 0.1
         = 1.0

训练阶段(假设 SGD 更新这个 embedding 值):

new_embedding_value = old_embedding_value - lr * error_gradient
                    = 0.9 - 0.1 * (-0.4)
                    = 0.9 + 0.04
                    = 0.94

下一次前向传播:

new_combined_value = new_embedding_value + positional_encoding
                   = 0.94 + 0.1
                   = 1.04

14.4.2 关键观察

注意这个过程中:

  1. Embedding 是可学习的:在训练过程中不断更新
  2. 这里的 Positional Encoding 是固定的:原始 Transformer 的正弦/余弦值不参与训练;如果换成可学习位置 embedding,它也会收到梯度并更新
  3. 相加发生在每次前向传播:不是一次性的

14.5 深层逻辑:为什么这种设计有效?

14.5.1 先看一次线性投影

令 Token embedding 为 E,位置向量为 P,输入就是:

Z = E + P
Q = Z @ Wq = E @ Wq + P @ Wq
K = Z @ Wk = E @ Wk + P @ Wk

这不是“正交以后自动分家”,而是线性变换的分配律。Wq 和 Wk 会在训练中适配,让内容与位置的混合对 Attention 有用。

14.5.2 Attention 看到的是四类交互

把 QKᵀ 展开,会得到四类项:

(E Wq)(E Wk)ᵀ   # 内容-内容
(E Wq)(P Wk)ᵀ   # 内容-位置
(P Wq)(E Wk)ᵀ   # 位置-内容
(P Wq)(P Wk)ᵀ   # 位置-位置

这比“语义占一些维度、位置占另一些正交维度”更准确。模型既能利用“小沈阳”和“赵本山”的内容关系,也能利用两者在句子中的方向和距离;内容与位置的交叉项本身也可能有用。

14.5.3 不要求无损分离

加法映射 (E, P) → E + P 是多对一的,因此 Attention 一般不能从和向量中唯一还原 E 与 P。但语言模型的任务不是复原输入前的两张表,而是预测下一个 Token。只要这套共同训练的表示保留了对预测有用的线索,设计就成立。


14.6 变体:不同的位置编码方法

14.6.1 原始方法:相加固定编码

input = Embedding(token_ids) + PositionalEncoding(positions)

这是原始 Transformer(2017)使用的方法,采用正弦余弦固定编码。

注意:GPT-2 虽然也是"相加",但使用的是可学习的位置编码,而非固定的正弦编码。

14.6.2 可学习位置编码

GPT-1、GPT-2 和 GPT-3 采用的是可学习的绝对位置 embedding。这不代表所有后来带有 GPT 名称或 decoder-only 结构的模型都使用同一种方法。

import torch
from torch import nn

class LearnablePositionalEncoding(nn.Module):
    def __init__(self, max_len, d_model):
        super().__init__()
        # 位置编码也是一个可学习的 Embedding
        self.pe = nn.Embedding(max_len, d_model)

    def forward(self, x):
        seq_len = x.size(1)
        if seq_len > self.pe.num_embeddings:
            raise ValueError("sequence length exceeds max_len")
        positions = torch.arange(seq_len, device=x.device)
        return x + self.pe(positions)

它不需要手工规定正弦频率,可以从训练数据中学习位置模式;代价是 lookup table 有一个原生范围,超出范围时需要扩表并继续训练或采用其他扩展办法。

14.6.3 RoPE:旋转位置编码

更现代的方法是 RoPE(Rotary Position Embedding),它不是简单地相加,而是通过旋转来编码位置:

Q_rotated = rotate(Q, position)
K_rotated = rotate(K, position)

RoPE 的优势:

  • 用绝对位置决定旋转角度,但旋转后的 Q·K 会显式依赖两个位置的相对位移
  • 不给 residual stream 额外相加一个位置向量

LLaMA、GPT-NeoX、Mistral 等模型使用 RoPE。不过,RoPE 不等于模型可以直接无损外推到任意长度。超过训练上下文时,往往还需要位置插值、频率缩放或继续训练。这个话题我们在第 25 章详细讨论。


14.7 实际代码:输入处理完整流程

14.7.1 PyTorch 实现

import torch
from torch import nn

class TransformerInput(nn.Module):
    def __init__(self, vocab_size, d_model, max_len, dropout=0.1):
        super().__init__()
        # 词嵌入
        self.token_embedding = nn.Embedding(vocab_size, d_model)
        # 位置编码(可学习)
        self.position_embedding = nn.Embedding(max_len, d_model)
        # Dropout
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        # x: [batch_size, seq_len] 的 token IDs
        if x.size(1) > self.position_embedding.num_embeddings:
            raise ValueError("sequence length exceeds max_len")

        # 1. 词嵌入
        token_emb = self.token_embedding(x)  # [batch, seq, d_model]

        # 2. 可学习的绝对位置 embedding
        positions = torch.arange(x.size(1), device=x.device)
        pos_emb = self.position_embedding(positions)  # [seq, d_model]

        # 3. 相加
        combined = token_emb + pos_emb  # [batch, seq, d_model]

        # 4. Dropout
        return self.dropout(combined)

这段代码演示的是 GPT-2 风格的可学习绝对位置,所以没有混入原始 Transformer 对 Token embedding 乘以 √d_model 的另一套约定。

14.7.2 维度追踪

输入 token_ids: [4, 16]           # 4个句子,每句16个token

Token Embedding:
  查表: token_embedding([4, 16])
  输出: [4, 16, 512]               # 每个token变成512维向量

Position Embedding:
  位置: [0, 1, 2, ..., 15]
  查表: position_embedding([16])
  输出: [16, 512]                  # 每个位置有512维向量
  广播: [4, 16, 512]               # 广播到batch维度

相加:
  [4, 16, 512] + [4, 16, 512] = [4, 16, 512]

输出: [4, 16, 512]                 # 包含语义+位置信息的向量

14.8 常见问题

14.8.1 相加会不会让信息混淆?

从数学上说,会丢掉唯一可逆性。 单看 E + P,不能保证还原出唯一的 E 和 P。

但模型不需要做这件事。它只需要利用混合表示完成预测,而 Token embedding、位置表示和后续投影都是围绕这个接口设计或共同训练的。原始 Transformer 的实验也说明,这种紧凑做法在实际任务上可行。

14.8.2 为什么要注意两种信号的尺度?

如果位置编码太大,会"淹没"词嵌入的信息:

embedding = [0.5, 0.3, -0.2]   # 语义信息
position  = [10, 20, -15]       # 位置信息(太大了!)
combined  = [10.5, 20.3, -15.2] # 主要是位置信息

如果两者的尺度极端失衡,较大的那一项会主导初始表示。但不存在“位置编码必须很小”的统一定律。正弦/余弦值落在 [-1, 1];原始 Transformer 同时把 Token embedding 乘以 √d_model。可学习位置 embedding 的尺度则由初始化和训练共同决定。

14.8.3 可学习 vs 固定位置编码哪个好?

类型优点缺点
固定(正弦/余弦)公式可计算到训练长度以外,不新增位置参数算得出更远位置,不等于模型一定能在更长序列上泛化
可学习绝对位置能学习训练任务中的位置模式lookup table 有固定范围,扩展通常需要改表并继续训练
RoPEQ·K 显式包含相对位移长上下文扩展仍可能需要缩放、插值或训练

没有一种方法对所有模型都最好。原始 Transformer 论文报告过:在当时的翻译实验中,可学习位置 embedding 与固定正弦方式结果几乎相同。选择取决于模型结构、训练长度和长上下文目标。


14.9 本章总结

14.9.1 核心概念

信息类型来源表示什么是否可学习
词嵌入Embedding 查表词的语义是
位置编码位置 Embedding/正弦函数词的位置取决于实现
输入向量两者相加语义 + 位置-

14.9.2 为什么相加而不是拼接

  1. 维度不变:不增加计算量
  2. 没有新增投影参数:两组同维向量可以直接进入 residual stream
  3. 交互可学习:Attention 能利用内容、位置以及它们的交叉项

14.9.3 核心认知

词嵌入提供“是什么”的线索,位置编码提供“在哪里”的线索。原始 Transformer 用相加把它们放进同一个 d_model:这个和不是可逆压缩,也不依赖未经证明的正交假设;它是一种参数少、接口简单,并且能让 Attention 学习多类交互的设计。


本章交付物

学完这一章,你应该能够:

  • 解释词嵌入和位置编码分别表示什么
  • 说出为什么选择相加而不是拼接
  • 理解相加后信息如何被 Attention 利用
  • 知道可学习位置编码和固定位置编码的区别

下一章预告

现在我们理解了输入是如何准备的:词嵌入 + 位置编码 → 相加 → 输入向量。

下一章,我们将把所有组件串起来,追踪数据从输入到输出的完整前向传播过程。这是理解 Transformer 如何工作的最后一块拼图!

引用本文 / Cite
Zhang, Wayland (2026). 第 14 章:词嵌入与位置信息的深层逻辑 - 为什么相加而不是拼接. In Transformer 架构:从直觉到实现. https://waylandz.com/llm-transformer-book/%E7%AC%AC14%E7%AB%A0-%E8%AF%8D%E5%B5%8C%E5%85%A5%E4%B8%8E%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E7%9A%84%E6%B7%B1%E5%B1%82%E9%80%BB%E8%BE%91-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%9B%B8%E5%8A%A0%E8%80%8C%E4%B8%8D%E6%98%AF%E6%8B%BC%E6%8E%A5/
@incollection{zhang2026transformer_14_-_-,
  author = {Zhang, Wayland},
  title = {第 14 章:词嵌入与位置信息的深层逻辑 - 为什么相加而不是拼接},
  booktitle = {Transformer 架构:从直觉到实现},
  year = {2026},
  url = {https://waylandz.com/llm-transformer-book/%E7%AC%AC14%E7%AB%A0-%E8%AF%8D%E5%B5%8C%E5%85%A5%E4%B8%8E%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E7%9A%84%E6%B7%B1%E5%B1%82%E9%80%BB%E8%BE%91-%E4%B8%BA%E4%BB%80%E4%B9%88%E7%9B%B8%E5%8A%A0%E8%80%8C%E4%B8%8D%E6%98%AF%E6%8B%BC%E6%8E%A5/}
}