文章目录
0 引言
2022年被称为大模型元年,ChatGPT4的横空出世引起了国内外的研究热潮,而GPT4正是基于Transformer这一架构,本文详细介绍Transformer架构,介绍其从输入到输出的全部计算流程。
1 总体框架
Transformer最早被用于文本翻译任务,假设其输入是英文的“Today is a sunny day.”,输出为中文的“今天是个晴朗的日子。”在模型的计算流程中,包括以下步骤:
- 输入编码:将输入序列转换为其对应的向量表示
- Encoder:编码器,编码器会对完整的输入句子通过自注意力机制和前馈网络生成State,代表原始输入被编码器编码之后形成的中间语义状态
- Decoder Block:解码器,解码器层需要融合解码器产出的中间状态State,和解码器已经生成出的信息Y1,Y2…Yi-1,来生成i时刻需要生成的单词Yi
- 概率输出:通过线性变化和softmax,得到每个单词的概率分布
在下文中,主要分成两个部分介绍:输入编码和模型。输入编码中介绍分词、词嵌入和位置编码。模型中首先介绍自注意力机制,然后介绍基于自注意力机制的Encoder和Decoder模块,最后总体介绍transformer的计算过程。
2 输入编码
2.1 分词
分词,即将一个文本序列分成一个一个的单元,这一个一个的单元被称为token。在以往的英文分词方法中,根据空格进行切分。在“Today is a sunny day”这个序列中,产生5个token,每个token映射成一个向量,从而实现序列的向量化。但这种分词方法存在一些缺点,如动词的不同形式(如wash,washed,washes)会被视为不同的token,导致映射字典非常庞大,同时无法很好地挖掘动词间的语法规律。
Transformer中采用Byte Pair Encoding(BPE) 的分词算法,BPE算法的核心思想是迭代合并出现频率高的字符对,从而降低映射字典的大小,同时可以学到如语法规律等泛化特征。
BPE算法流程如下:
- 设定最大分词词典数量vocab size,初始化一个词典
- 将语料中所有文本切成单个字符形式加入词典,并且将<eos>空格符等特殊字符也加入词典
- 对已经切为字符的语料,全局统计一轮连续两个字符出现组合的频率
- 取最大频率的组合,将这两个字符合并为一个整体,将这个整体添加到词典,并且在语料中将这两个字符也同步全部替换为这个新的整体,当作一个词
- 重复step 3和step 4直到达到vocab size或者无法再合并为止
2.2 词嵌入
通过分词把序列转化为一个一个单元后,需要将其映射为向量,实现文本的非结构化数据到结构化数据的转换。在转化过程中,除计算和存储的考量外,还需要考虑向量化表示后词的相似度,如下图所示,向量化表示后的“Mathematics”和“Statics”相似度应该更高,“Tiger”和"lion"的相似度应该更高。
在transformer中,通过嵌入层实现嵌入向量的表示,通常使用预训练好的词嵌入向量,如Word2Vec、GloVe或FastText等,这些预训练向量已经学习到了词汇之间的语义和语法关系,从而能更好地理解和生成自然语言。
2.3 位置编码
在Transformer的encoder采用了并行计算的方法,并行计算提高了模型的计算效率,但是丢失了句子中的位置信息,Transformer采用positional encoding的方法加入位置信息,位置编码如公式1,偶数位置采用正弦函数,奇数位置采用余弦函数进行编码。
P
E
(
p
o
s
,
2
i
)
=
sin
(
p
o
s
/
1000
0
2
i
/
d
model
)
P
E
(
p
o
s
,
2
i
+
1
)
=
cos
(
p
o
s
/
1000
0
2
i
/
d
model
)
(1)
\begin{aligned} P E_{(p o s, 2 i)} & =\sin \left(p o s / 10000^{2 i / d_{\text {model }}}\right) \\ P E_{(p o s, 2 i+1)} & =\cos \left(p o s / 10000^{2 i / d_{\text {model }}}\right) \end{aligned}\tag{1}
PE(pos,2i)PE(pos,2i+1)=sin(pos/100002i/dmodel )=cos(pos/100002i/dmodel )(1)
其中,
p
o
s
pos
pos代表token的位置,
d
m
o
d
e
l
d_{model}
dmodel为词嵌入的维度。
最终,将token的嵌入向量和位置编码向量两者相加,得到了最终的输入向量。
3 模型
3.1 自注意力机制
如下图所示,序列被拆分为token。在翻译每个token时,需要关注该token在序列中的上下文信息,如“海山数据库”这个token,在翻译时需要更多的关注“海山数据库”(本身),“性能领先”(特点),“数据库产品”(定义)和“使用成本”(特点)等token,其余token在翻译时需要分配的注意力相对较少,图中线的粗细表示其他token对当前token的重要程度,即构建长短依赖关系。
如何实现自注意力机制,可采用向量内积的方法。在2.2节的词嵌入中,两个token在内积时具有更大的值,表示其相似度更高,因此,将当前token与其余token进行内积,可求出两者之间的相似度。
得到其余token对当前token的相似度,即注意力得分后,采用 s o f t m a x softmax softmax得到概率分布。这个概率分布即表示该序列中所有token对该位置的贡献,将概率分布与特征向量进行加权求和,便得到了加入注意力后的特征向量,计算过程如公式3所示:
A t t e n t i o n ( X ) = s o f t m a x ( X X T ) X (3) Attention(X) = softmax(XX^T)X\tag{3} Attention(X)=softmax(XXT)X(3)
在transformer中,引入了 Q Q Q, K K K, V V V的概念。 Q Q Q表示Query,即查询向量; K K K表示Key,即关键字向量; V V V表示Value,即值向量。这三个向量由原始的 X X X通过 W Q W^Q WQ, W K W_K WK和 W V W_V WV三个矩阵相乘而来,这三个矩阵均为可学习的参数,学习到具体序列中更抽象的特征。Transformer中最终的注意力公式如4所示:
Attention ( Q , K , V ) = softmax ( Q K T d k ) V Q = W Q X K = W K X V = W V X (4) \operatorname{Attention}(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) V \\ Q = W^QX\\ K = W^KX\\ V = W^VX \tag{4} Attention(Q,K,V)=softmax(dkQKT)VQ=WQXK=WKXV=WVX(4)
式中, d k \sqrt{d_{k}} dk是一个scaling参数,是为了避免得到的注意力分布过于陡峭,从而使得在训练过程中梯度保持稳定。
多头注意力(Multi-head Attention)
如下图所示,假设每个token的映射向量长度为
d
m
o
d
e
l
d_{model}
dmodel,多头注意力则是将
d
m
o
d
e
l
d_{model}
dmodel拆分成多个长度相同的
d
k
d_k
dk,同时在维度更小的
d
k
d_k
dk上进行上述的自注意力操作,并行计算结束后将最终的计算结果拼接在一起,得到最终的输出结果。使用多头注意力的优势在于,模型可以同时在不同的子空间中学习到不同的信息和模式,这样就能够更加全面和灵活地捕获数据中的复杂依赖关系。
3.2 Encoder
编码器模块由6个相同的block堆叠而成,每个block包括2层,第一层即多头注意力机制,第二层是一个前馈网络,在每一层都使用了归一化,然后将每一层的输入和输出进行了残差连接,避免深度模型训练时出现梯度爆炸,每个block如下图所示:
3.3 Decoder
解码器模块同样由6个相同的block堆叠而成,每个block如下图所示。相比于编码器,解码器的block多一层Masked Multi-Head Attention层。Transformer模拟人类的翻译习惯,采用顺序输出的方式,在翻译当前token的时候,不知道后面的翻译内容,因此使用一个Mask将后面的特征掩蔽,保证对当前位置
i
i
i的预测只依赖于小于
i
i
i的已知输出。
3.4 Encoder-Decoder架构
Transformer的Encoder和Decoder架构如下图所示,计算流程如下:
- Inputs经过分词、词嵌入后实现序列到向量的映射,再加上位置编码得到最终的输入向量
- Encoder模块通过自注意力机制和前馈神经网络计算得到中间语义状态
- Decoder模块接encoder模块的中间语义状态和和解码器已经生成出的信息Y1,Y2…Yi-1,来生成i时刻需要生成的单词Yi(在i=1的时刻,解码器的输入值为一个起始符)
- 输出层通过线性层和softmax得到输出的概率分布,得到最终的计算结果