一、介绍
1、核心思想
利用自注意力机制来捕获输入序列中各元素之间的全局依赖关系,无论这些元素之间的实际距离有多远。
-
自注意力机制:允许模型在处理序列的每个元素时,考虑到序列中的所有其他元素,从而捕捉它们之间的关系和依赖,这对于理解上下文和语言的复杂性至关重要。
-
多头注意力:通过并行地使用多个注意力机制(称为“头”),Transformer能够在不同的表示子空间中捕捉到序列的不同特征。
-
位置编码:由于Transformer本身不具备处理序列顺序的能力,通过添加位置编码到输入序列,模型能够利用序列中元素的位置信息。
2、优点
-
高效的并行计算:与传统的循环神经网络不同,Transformer可以处理整个序列的所有元素而无需顺序迭代,这使得其特别适合于现代并行计算硬件。
-
长距离依赖捕捉能力:自注意力机制使得Transformer能够有效地处理长距离依赖问题,这在处理长文本或复杂序列关系时尤为重要。
-
灵活性和广泛的适用性:Transformer架构可以被应用于多种序列处理任务,包括但不限于语言理解、文本生成、机器翻译等。
3、应用
-
自然语言处理:如机器翻译、文本摘要、情感分析、问答系统等。
-
语音和音频处理:如语音识别、音乐生成等。
-
图像处理和计算机视觉:通过将图像切割成序列化的片段,Transformer也被应用于图像分类、物体检测等任务。
-
跨模态任务:如图像字幕生成、视觉问答等,Transformer可以处理来自不同模态(如文本和图像)的数据。
二、Transformer架构
1、输入部分
Transformer模型的输入模块主要由两部分组成:嵌入层(Embedding Layer)和位置编码(Positional Encoding)。
这两部分共同作用,将原始的输入序列转换为模型能够处理的形式,同时保留序列中的单词信息和单词的位置信息。
1.1 嵌入层(Embedding Layer)
嵌入层的主要任务是将输入序列中的每个单词或标记(token)转换为固定维度的向量。
在Transformer模型中,嵌入层的主要任务是将每个单词或标记转换为一个高维空间中的向量。这个过程可以理解为将单词从稀疏的、通常是一维的、基于索引的表示(比如单词在词典中的索引)转换为稠密的、多维的表示。
工作原理
假设一个微型词汇表:“King”, “Queen”, “Man”, “Woman”。对应地,我们为每个单词分配一个唯一的索引:King=0, Queen=1, Man=2, Woman=3。在未使用嵌入层之前,可能会使用独热编码(One-Hot Encoding)来表示这些单词,即:
-
King = [1, 0, 0, 0]
-
Queen = [0, 1, 0, 0]
-
Man = [0, 0, 1, 0]
-
Woman = [0, 0, 0, 1]
引入嵌入层后,会初始化一个嵌入矩阵,其大小为词汇量 x 嵌入维度
。假设我们选择的嵌入维度为2(实际应用中通常远大于2,例如128、256、512等),那么对于上述的四个单词,我们可能会初始化如下的嵌入矩阵:
[ [ 0.2, 0.8], # King[-0.5, 0.4], # Queen[ 0.1, -0.3], # Man[-0.1, -0.7] ] # Woman
在这个矩阵中,每一行代表一个单词的嵌入向量。例如,“King”的嵌入向量是[0.2, 0.8]。
当输入一个单词时,嵌入层会根据这个单词的索引在嵌入矩阵中查找对应的嵌入向量。比如,如果输入的单词是“King”,索引为0,嵌入层就会输出[0.2, 0.8]作为这个单词的表示。
意义
嵌入层通常作为神经网络的第一层出现,其嵌入向量会随着模型的训练不断更新和优化,以更好地捕捉和表示单词之间的复杂关系和语义信息。这种密集且富含语义的表示方式,为深度学习模型处理自然语言提供了强大的基础。
2、位置编码
由于Transformer模型使用的是自注意力机制,没有像循环神经网络(RNN)那样的递归结构,所以它本身并不能理解序列中元素的顺序,因此Transformer模型本身不具有处理序列顺序的能力(这是因为其使用的自注意力机制会同时考虑序列中所有元素的关系,而不关注元素的顺序),这就需要通过位置编码来向模型提供位置信息。
位置编码通过为序列中每个单词的嵌入向量添加一个与其位置相关的向量来实现。这个位置向量与单词的嵌入向量具有相同的维度,使得两者可以通过加法或其他方式结合起来。
计算公式
对于序列中的每个位置pos,和每个维度 i ,位置编码 ( pos , i ) 是这样计算的:
其中,pos 是位置,i 是维度索引,
是嵌入向量的维度,PE代表整个词的数组。
通过这种方式,对于每个位置,我们计算一对正弦和余弦值,每对对应嵌入向量中的两个维度。
假设嵌入向量的维度是4,要为位置0和位置1编码:
-
对于位置0,其位置编码是:
-
PE_{(0,0)} = sin(0 / 10000^{0/4}) = sin(0) = 0
PE_{(0,1)} = cos(0 / 10000^{0/4}) = cos(0) = 1
-
$PE_{(0,2)} = sin(0 / 10000^{2/4}) = sin(0) = 0
-
PE_{(0,3)} = cos(0 / 10000^{2/4}) = cos(0) = 1
-
所以,位置0的位置编码向量是 [0, 1, 0, 1]
-
-
对于位置1,其位置编码是:
-
PE_{(1,0)} = sin(1 / 10000^{0/4}) = sin(1/10000^0) = sin(1)
-
PE_{(1,1)} = cos(1 / 10000^{0/4}) = cos(1/10000^0) = cos(1)
-
PE_{(1,2)} = sin(1 / 10000^{2/4}) = sin(1/10000^{0.5}) = sin(1/100)
-
PE_{(1,3)} = cos(1 / 10000^{2/4}) = cos(1/10000^{0.5}) = cos(1/100)
-
所以,位置1的位置编码向量是 [sin(1), cos(1), sin(1/100), cos(1/100)]
-
import numpy as npseq_len = 4
d = 4
n = 10000# 初始化矩阵
PE = np.zeros((seq_len, d))for pos in range(seq_len):# 防止索引超出dfor i in np.arange(int(d/2)):den = np.power(10000, (2 * i) / d)PE[pos, 2*i] = np.sin(pos / den)PE[pos, 2*i + 1] = np.cos(pos / den)print(PE)
说明
位置编码的值完全由单词或标记在序列中的位置决定,而且这种决定关系是预先定义好的,不会随训练而改变。
这意味着,与嵌入向量不同,位置编码并不是模型训练过程中学习得到的参数。它们是根据每个位置的索引,通过预定义的数学公式计算得到的,然后加到对应位置的嵌入向量上,以此来提供序列中各位置的相对和绝对位置信息。
这样做使得Transformer模型能够理解序列中不同元素的顺序,即使模型的自注意力机制本身并不关注输入元素的顺序。