Transformer详解
词嵌入的系统性讲解
1. 词嵌入的概念与目标
词嵌入(Word Embedding) 是将 离散的标记(如单词、子词片段) 映射为 连续的向量表示 的方法。词嵌入是神经网络模型处理自然语言的第一步,它的目标是将词汇的离散信息转化为具有语义信息的密集向量,便于模型捕捉词语之间的语义关系。
在 Transformer 模型 中,词嵌入是模型输入的第一层,它负责将输入序列中的每个标记(Token)转换为定长的向量表示,这个向量随后被传递给模型的自注意力层等模块进行进一步处理。
2. 输入标记如何映射为向量
2.1 标记化(Tokenization)
输入文本首先会被拆分成更小的标记单元,通常是单词或子词片段。例如,对于输入句子:
“我喜欢学习”,通过 标记化 的处理,句子会被拆分为:
[
X = [\text{“我”}, \text{“喜欢”}, \text{“学习”}]
]
标记化的结果可以是单词或更小的子词单元(例如 WordPiece 或 BPE),取决于具体使用的标记化方法。
2.2 词汇表与词嵌入矩阵的映射
每个标记都会在 词汇表(Vocabulary) 中找到对应的索引。词汇表是模型预定义的一个单词或标记的集合,其中每个标记都有一个唯一的索引。例如:
标记 | 词汇表索引 |
---|---|
我 | 102 |
喜欢 | 456 |
学习 | 789 |
通过索引,我们可以查找对应的 词嵌入矩阵。词嵌入矩阵是一个大小为 ( |V| \times d_{model} ) 的矩阵,其中:
- ( |V| ) 是词汇表的大小(如 10,000 个标记)。
- ( d_{model} ) 是嵌入向量的维度(如 512 维)。
嵌入查找 过程如下:
- 输入标记 ( x_i ) 会在词汇表中找到对应的索引编号(例如,标记 “我” 对应索引 102)。
- 然后,通过查找嵌入矩阵 ( E ) 的第 ( 102 ) 行,我们得到标记 “我” 的向量表示 ( h_{\text{“我”}} )。
嵌入查找公式:
对于每个标记 ( x_i ),其嵌入向量表示为:
[
h_i = E[x_i]
]
其中:
- ( E[x_i] ) 表示嵌入矩阵 ( E ) 中第 ( x_i ) 个标记对应的嵌入向量。
- 每个 ( h_i \in \mathbb{R}^{d_{model}} ) 是标记 ( x_i ) 的嵌入表示。
3. 词嵌入的训练过程
3.1 嵌入矩阵的初始化
在模型训练初期,嵌入矩阵 中的向量值是随机初始化的。这意味着每个单词的嵌入向量最初没有语义信息,模型需要通过大量的训练数据逐步学习到合理的词语向量表示。
假设句子 “我喜欢学习” 中每个词的嵌入向量是随机的:
- 词 “我” 的初始向量 ( a_0 = [0.1, -0.2, 0.5, \dots, 0.3] )
- 词 “喜欢” 的初始向量 ( b_0 = [0.4, 0.3, -0.1, \dots, 0.5] )
- 词 “学习” 的初始向量 ( c_0 = [0.6, -0.3, 0.2, \dots, 0.7] )
3.2 训练词嵌入:如何计算损失
在训练过程中,模型通过预测下一个词汇,并根据实际标签计算损失,从而不断优化嵌入向量。我们以 语言建模 为例:
- 输入句子:“我喜欢学习”
- 模型目标:给定词 “我”,预测下一个词应为 “喜欢”,并继续预测 “学习”。
模型如何进行预测:
- 假设模型在一开始通过向量 ( a_0 )(“我”)进行预测,模型错误地预测了词 B(向量为 ( b_0 )),而正确答案应当是词 C(向量为 ( c_0 ))。
- 我们可以计算模型预测与真实词汇之间的损失。通常使用 交叉熵损失函数,它衡量模型的输出分布与实际分布之间的差异。
损失函数公式:
[
\text{Loss} = - \log(\hat{y}_{\text{C}})
]
其中:
- ( \hat{y}_{\text{C}} ) 是模型对词 C(正确答案)的预测概率。
- 损失值越大,说明模型预测得越差;损失值越小,说明模型的预测更接近正确答案。
模型的优化过程:
- 通过 反向传播 和 梯度下降,模型会根据损失函数的值来调整嵌入矩阵中的向量。具体来说,模型会调整 ( a_0 ) 使其接近理想的向量 ( a_1 ),并使错误预测的 ( b_0 ) 远离正确的目标。
最终,通过多次训练,模型会逐步调整嵌入矩阵中的每个向量,使得每个词的向量表示越来越接近它们在语义空间中的正确位置。
位置编码(Positional Encoding)系统性解析
1. 什么是位置编码?
位置编码(Positional Encoding)是 Transformer 模型中的一个机制,旨在为模型提供序列中标记的位置信息。由于 Transformer 不像 RNN 或 LSTM 具有天然的顺序处理能力,模型需要通过显式的位置信息来理解每个标记在输入序列中的位置。
作用:
- 位置编码确保 Transformer 模型能够感知到每个标记的顺序信息和相对位置关系。
- 它通过将位置编码与词嵌入相加,结合了标记的语义信息和位置信息,使模型既能理解单词的含义,也能知道它在序列中的位置。
2. 位置编码的数学公式
Transformer 使用**正弦函数(sin)和余弦函数(cos)**来生成位置编码。
- 对于偶数维度的编码:
[
\text{PE}(pos, 2i) = \sin\left(\frac{pos}{10000^{\frac{2i}{d_{model}}}}\right)
] - 对于奇数维度的编码:
[
\text{PE}(pos, 2i+1) = \cos\left(\frac{pos}{10000^{\frac{2i}{d_{model}}}}\right)
]
其中:
- ( pos ) 是标记在输入序列中的位置,比如第 1 个单词的位置是 ( pos = 1 )。
- ( i ) 是嵌入向量的维度索引,维度索引从 0 到 ( d_{model} - 1 )。
- ( d_{model} ) 是嵌入向量的维度大小,通常为 512、768 或 1024 等。
3. 位置编码如何捕捉绝对位置信息
每个位置 ( pos ) 的编码是唯一的,正弦和余弦函数确保每个位置生成一个不同的编码。正弦和余弦的周期性提供了平滑的变化,但不会导致重复,因为它们在不同维度上的频率是不同的。
- 频率缩放机制:通过分母 ( 10000^{\frac{2i}{d_{model}}} ),确保不同维度上的正弦和余弦函数的频率不同。
- 在低维度,正弦和余弦函数的变化频率较高,能够捕捉相邻位置的差异。
- 在高维度,正弦和余弦函数的变化频率较低,能够捕捉更长距离的依赖关系。
示例:绝对位置信息
假设我们有一个嵌入维度 ( d_{model} = 4 ),我们分别计算位置 ( pos = 1 ) 和 ( pos = 2 ) 的编码:
-
对于 ( pos = 1 ):
[
\text{PE}(1, 0) = \sin(1) \approx 0.841, \quad \text{PE}(1, 1) = \cos(1) \approx 0.540
]
[
\text{PE}(1, 2) = \sin(0.01) \approx 0.009999, \quad \text{PE}(1, 3) = \cos(0.01) \approx 1
] -
对于 ( pos = 2 ):
[
\text{PE}(2, 0) = \sin(2) \approx 0.909, \quad \text{PE}(2, 1) = \cos(2) \approx -0.416
]
[
\text{PE}(2, 2) = \sin(0.02) \approx 0.019999, \quad \text{PE}(2, 3) = \cos(0.02) \approx 0.9998
]
即使正弦和余弦函数是周期函数,通过这种频率缩放的机制,每个位置在不同维度上会有不同的变化速率,从而确保不会出现重复的编码。这些独特的编码为每个位置提供了绝对的位置信息。
4. 为什么通过频率缩放能避免重复?
正弦和余弦函数的周期性是一个潜在的问题,如果我们不对输入值进行控制,确实可能导致重复。频率缩放通过改变不同维度的频率,确保即使在极端情况下,位置编码也不会重复。
极端情况下的示例:
假设我们有两个极端位置 ( pos_1 = 1 ) 和 ( pos_2 = 10000 ):
- 低维度(频率变化快):即便这些位置的差异不大,正弦和余弦函数的周期变化确保它们不会在低维度重复。
- 高维度(频率变化慢):即使在高维度的变化较小,正弦和余弦函数的输入不同,确保生成的编码在这些维度上也不会重复。
通过多个维度的变化,即使某些维度上可能出现重复,其他维度的不同速率变化也能确保整体编码不会重复。
5. 位置编码如何捕捉相对位置信息
位置编码不仅提供绝对位置信息,还通过正弦和余弦的变化捕捉相对位置信息。
我们可以通过三角函数的加法公式来理解这一点:
[
\sin(\alpha + \beta) = \sin(\alpha)\cos(\beta) + \cos(\alpha)\sin(\beta)
]
[
\cos(\alpha + \beta) = \cos(\alpha)\cos(\beta) - \sin(\alpha)\sin(\beta)
]
这意味着两个位置的编码可以通过它们的相对位置进行线性组合,从而表达它们之间的关系。位置编码通过这些函数的变化捕捉到标记之间的相对顺序,使得模型能够推断标记之间的距离。
6. 词嵌入和位置编码相加
位置编码并不是单独工作,而是和词嵌入相加,生成最终的输入表示。这个向量包含了词语的语义信息(来自词嵌入)和它的位置信息(来自位置编码)。
示例:词嵌入和位置编码的相加
假设我们有:
- 词嵌入向量:( h_{\text{“我”}} = [0.5, -0.1, 0.3, \dots] )
- 位置编码向量:( \text{PE}(1) = [0.841, 0.540, 0.009999, 1] )
它们会逐元素相加:
[
h_{\text{“我”}}^\prime = h_{\text{“我”}} + \text{PE}(1) = [0.5 + 0.841, -0.1 + 0.540, 0.3 + 0.009999, \dots]
]
[
h_{\text{“我”}}^\prime