从 Transformer 到 Bert 学习笔记

零、 写在前面

最近在学习Bert,从Transformer开始补基础,写点笔记做记录。因为是初涉及,内容未必准确,仅供参考学习,欢迎一起讨论。(图来源为论文或其他文章,都放在参考资料里了)

一、Transformer 介绍

1.1 引言

Transformer模型以其革命性的设计和优越的性能,彻底改变了序列到序列(Sequence-to-Sequence)任务的处理方式,成为自然语言处理领域的经典之作。

Transformer模型的最大特点之一是其完全基于注意力机制,摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN)结构。通过多头自注意力机制和前馈神经网络层的组合,Transformer实现了更加高效、灵活和并行化的序列处理能力。这种结构的设计使得Transformer在翻译、语言建模等任务中取得了优异的性能表现,同时大大缩短了训练时间,提高了模型的可解释性和泛化能力。

即将一个文本序列作为输入,并产生另一个文本序列作为输出。例如机器翻译,将一个输入的英语句子翻译成西班牙语。

论文:《Attention Is All You Need》

https://arxiv.org/abs/1706.03762icon-default.png?t=N7T8https://arxiv.org/abs/1706.03762

1.2 模型输入

按照模型顺序来梳理可能更好理解一点,数据在输入Encoder之前要经过词嵌入层和位置编码层。

1.2.1 Embedding

词嵌入(Word Embeddings)是将输入的每个单词转换为一个固定维度的向量。在Transformer中,通常使用的是预训练的词嵌入方法,如Word2Vec、GloVe或通过训练数据生成的嵌入矩阵。

  • 转换单词为向量:每个输入单词会被映射到一个维度为 d_{model}​ 的向量,这个向量表示了该单词在语义空间中的位置。对于Transformer模型,通常选择d_{model} = 512

  • 共享嵌入矩阵:在Transformer模型中,编码器和解码器会共享相同的嵌入矩阵,这不仅减少了参数的数量,还使得模型能够在编码器和解码器之间共享表示。

1.2.2 Position Encoding

由于Transformer模型不使用循环神经网络或卷积神经网络,所以缺乏对序列中单词位置的固有了解。为了弥补这一点,Transformer引入了位置编码(Positional Encoding),它提供了关于输入序列中每个单词相对或绝对位置的信息。

  • 固定位置编码:Transformer使用了一种基于正弦和余弦函数的固定位置编码。具体公式如下:

 PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)

PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)

        其中,pos是位置,i 是维度的索引。这样每个位置的编码都是一个 d_{model} 维的向量,且每个维度的编码值都是一个正弦或余弦函数。

  • 意义:位置编码的设计使得模型能够在不学习新的参数的情况下捕捉到序列的位置信息。通过这种方式,不同位置的单词能够获得不同的编码,从而使得模型能够区分相同单词在不同位置的不同语义。

1.2.3 组合

位置编码被直接加到词嵌入上,形成了带有位置信息的词向量。这种方法简单而有效,能够帮助模型在不引入复杂计算的情况下捕捉序列的位置信息。

通过词嵌入和位置编码的结合,Transformer模型能够有效地表示输入序列中单词的语义和位置信息,从而在后续的自注意力机制中进行更加准确和有意义的计算。

1.3 注意力机制

1.3.1 注意力简介

注意力机制是核心组件,用于在序列中捕捉单词之间的依赖关系。通过这种机制,模型可以关注序列中不同位置的单词,并根据其相关性进行加权计算。注意力机制主要包括生成查询(Query)、键(Key)和值(Value)矩阵,并通过这些矩阵进行计算。

  • 查询(Query, Q)

    • 查询矩阵 Q 是从输入序列生成的,用于匹配键矩阵中的内容。
    • 具体来说,查询向量表示当前处理的单词“关注”其它单词时的条件。
  • 键(Key, K)

    • 键矩阵 K 也是从输入序列生成的,它表示所有单词的特征,用于与查询矩阵进行匹配。
    • 键向量的作用是帮助模型确定每个单词的重要性或相关性。
  • 值(Value, V)

    • 值矩阵 V 同样从输入序列生成,它包含了序列中每个单词的实际内容。
    • 值向量是在计算注意力得分后加权平均的对象,最终用于生成注意力输出。

Query, Key, Value 实际上是三个独立的线性层。每个线性层都有自己独立的权重。输入数据与三个线性层分别相乘,产生 Q、K、V。

1.3.2 注意力计算

过程分为这几个步骤:

  1. 计算查询 Q 和键 K 的点积,得到一个相关性得分矩阵。
  2. 为了避免在高维空间中点积值过大,使用缩放因子 \sqrt{d_k} 对点积结果进行缩放。
  3. 对缩放后的点积结果应用Softmax函数,得到每个值向量的权重分布。(Softmax函数确保了权重的总和为1,使得注意力得分可以解释为概率分布。)
  4. 使用注意力权重对值矩阵 V 进行加权求和,得到最终的注意力输出。

具体公式:

\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

贴个论文原图:

1.3.3 注意力理解

先通过向量视角来看矩阵:

再看 Q 和 K转置 之间的矩阵乘法(即点积),产生的矩阵叫 “因子矩阵”:

当然图里没画出除 根号d 和 Softmax 的过程,不过不影响理解,再看乘V:

因子矩阵是该特定单词的 Q值 与所有单词的 K值 的点积,V矩阵是每个词的编码值,两者相乘就相当于把相似相进行了二次验证和放大。

个人感觉像:该单词的 相似性得分 × 编码值得分 = 注意力得分

1.4 多头注意力机制

多头注意力机制是对上述注意力机制的扩展,通过引入多个头部来捕捉不同子空间的信息,同时也更便于进行并行计算。

1. 将查询、键和值矩阵通过不同的线性变换投影到低维空间,生成 h个头部的 Q_i, K_i, V_i

Q = [Q_1, Q_2, \ldots, Q_h]

\quad K = [K_1, K_2, \ldots, K_h]

\quad V = [V_1, V_2, \ldots, V_h]

        每个Q_i, K_i, V_i的长度为 d_k = d_{model} / h

        即直接进行切割,但是有文章中提到:切分 只是逻辑上的切分,所有注意力头共用线性层,只是分别在其逻辑部分上进行操作

2. 对于每个头 i,计算注意力输出:

\text{Attention}(Q_i, K_i, V_i) = \text{softmax}\left(\frac{Q_i K_i^T}{\sqrt{d_k}}\right) V_i

        其中,Q_i K_i^T生成一个形状为 \left ( L,L \right ) 的注意力得分矩阵,通过 softmax 进行归一化,然后与 V_i相乘。

3. 将所有头的输出拼接起来:

\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, \ldots, \text{head}_h) W_O

        其中,\text{head}_i = \text{Attention}(Q_i, K_i, V_i),拼接后形状为(L, h \times d_k),然后通过一个线性变换矩阵 W_O(形状为  (h \times d_k, d_{model}) ) 进行变换,得到最终的多头注意力输出。

贴个论文原图:

1.5 前馈神经网络

在每个Transformer编码器层中,前馈神经网络(FFN)是一个关键组成部分。它是一个逐点(point-wise)的全连接网络,即它独立地作用于每个位置的表示向量。

1.5.1 网络结构

FFN通常包含两层全连接网络,并使用激活函数进行非线性变换。具体来说,对于输入向量 x,前馈神经网络的计算步骤:

        1. 线性变换和激活函数

h = \text{ReLU}(xW_1 + b_1)

        其中,W_1 是第一个线性变换的权重矩阵,b_1 是偏置,ReLU 是激活函数。

        这里注意,中间的内部层维度 d_{ff}=2048,即 W_1 的维度是\left ( d_{model},d_{ff} \right ) 。这种设计的目的是增加模型的非线性能力使得模型可以在高维空间中进行复杂的变换和学习,从而更好地捕捉输入数据中的复杂模式。

        2. 第二次线性变换

\text{FFN}(x) = hW_2 + b_2

        其中,W_2​ 是第二个线性变换的权重矩阵,b_2 是偏置。 W_2 的维度是\left ( d_{ff},d_{model} \right )

1.5.2 目的和意义

  1. 增加模型的非线性表达能力:FFN通过激活函数引入非线性,使得模型能够更好地拟合复杂的函数和捕捉输入数据中的非线性关系。
  2. 逐点操作:FFN在序列的每个位置上独立作用。这意味着它不会引入新的位置间依赖关系,而是对每个位置的表示进行独立的变换。这对于保持序列信息的独立性和完整性非常重要。
  3. 提升表示能力:通过两个线性变换和激活函数的组合,FFN能够对每个位置的表示进行更深层次的处理,提取更高级的特征。
  4. 效率高:由于FFN是逐点操作,因此可以在并行计算架构(如GPU)上高效实现。这对于处理长序列和大规模数据非常重要。

1.6 残差连接

        残差连接(Residual Connection)是一种技巧,用于防止深层神经网络训练过程中出现梯度消失的问题。其基本思想是将输入直接与某一层的输出相加,从而形成一个“捷径”路径。这可以帮助模型更容易地学习到恒等映射,从而缓解深层网络中的梯度消失问题。

\text{LayerNorm}(x + \text{Sublayer}(x))

        其中:

  • x 是当前层的输入。
  • \text{Sublayer}(x) 是当前子层的输出(例如,多头自注意力机制或前馈神经网络)。
  • \text{LayerNorm} 是层规范化操作。

这个公式表示将输入 x 和子层的输出 \text{Sublayer}(x) 相加,然后对结果进行层规范化处理。

1.7 编码器 Encoder

经过前面的铺垫,这里对编码器部分的结构进行介绍。

先贴论文原图:

在Transformer架构中,编码器中的层是串行连接的。也就是说,每一层的输出作为下一层的输入。这种层次结构使得信息在层与层之间逐步传递和处理。

每个编码器层中的两个子层的详细步骤如下:

单个编码器层(第 i 层)

  1. 子层1:多头自注意力机制

    • 输入 X_i 经过多头自注意力机制,计算出注意力加权的表示 A_i 
    • 残差连接: A_i + X_i
    • 层规范化: \text{LayerNorm}(A_i + X_i)
  2. 子层2:前馈神经网络

    • 上一步的输出 \text{LayerNorm}(A_i + X_i) 经过前馈神经网络,得到新的表示 F_i ​。
    • 残差连接: F_i + \text{LayerNorm}(A_i + X_i)
    • 层规范化: \text{LayerNorm}(F_i + \text{LayerNorm}(A_i + X_i))

多个层之间的连接

编码器层的结构如上所述,每一层的输出作为下一层的输入,从而形成串行连接,论文中这里的N=6

这种层与层之间的串行连接确保了输入序列中的信息在多个层次上被处理和整合,从而获得更丰富和抽象的表示。通过残差连接和层规范化,模型在训练过程中能够更有效地传递梯度,避免梯度消失问题。

1.8 解码器 Decoder

解码器的结构和编码器类似,但具有一些关键区别,特别是在处理顺序信息和生成输出方面。

1.8.1 输入结构

解码器的输入结构和处理过程确实是稍微复杂一些。解码器的输入分为两个部分:编码器的输出已经生成的部分输出

  • Shifted Right Outputs (偏移输出)

    • 在生成任务中(如机器翻译),解码器需要根据已经生成的部分输出来预测下一个词。因此,在训练过程中,我们将 目标输出序列向右偏移一个位置,然后作为解码器的输入。这意味着,位置 i 的输入是位置 i-1 的目标词,而第一个位置的输入是一个特殊的开始符号(例如 <start>)。
    • 这个偏移操作确保了解码器在训练时能够模拟预测过程:基于前面的输出预测当前的词。
  • Output Embedding (输出嵌入)

    • 与编码器的输入嵌入类似,解码器也将偏移后的输出序列通过嵌入层转换为固定维度的向量表示。这些嵌入向量和位置编码一起输入到解码器的第一层。

为什么不直接使用编码器的输出来输入?

        编码器-解码器架构的设计目的是将输入序列编码成一个固定长度的表示(通过编码器),然后解码器根据这个表示和已经生成的部分输出,逐步生成目标序列。因此,解码器需要同时利用编码器的输出(即输入序列的编码表示)和已经生成的部分输出。

1.8.2 掩码多头注意力设计

Masked Multi-Head Attention 是解码器中的第一个子层,它的设计目的是在自回归生成过程中,确保当前位置的预测只依赖于之前的位置,而不能看到未来的位置。这种设计在训练和推理过程中都非常重要。

在解码器中,我们需要确保在位置 i 生成的输出只能依赖于位置小于 i 的信息,而不能看到位置 i之后的词。这是通过在计算注意力权重时引入一个掩码 (mask) 来实现的。

  1. 掩码矩阵的构建
    • 掩码矩阵是一个上三角矩阵,定义为

              M[i, j] = \begin{cases} 0 & \text{if } i \ge j \\ -\infty & \text{if } i < j \end{cases}

    • 这个掩码矩阵在计算注意力权重时会添加到点积结果上,确保在 Softmax 计算时,未来的位置被屏蔽掉。
  2. 掩码的应用
    • 在计算点积注意力时,点积结果为 QK^T,然后将掩码矩阵 M 添加到这个结果上。
    • 经过掩码操作的点积结果再通过Softmax函数,得到的注意力权重会在未来的位置上接近零,确保这些位置对当前位置的输出没有影响。

1.8.3 解码器结构

贴个论文原图:

总结来说,解码器的特殊之处在于它的结构设计和掩码机制,确保在生成序列时只能基于已知信息进行预测,从而保证输出的正确性和连贯性。

二、Bert 介绍

BERT是一个新型的语言表示模型,全称是 双向编码器表示的转换器(Bidirectional Encoder Representations from Transformers)。

与之前的单向或浅层表示模型相比,BERT的 双向性和深度 使其能够更好地捕捉语言的复杂性。预训练完成后,BERT可以通过添加一个额外的输出层并进行微调,适应多种NLP任务,如问答和语言推理,而无需进行大量特定任务的架构修改。

论文是《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》

https://arxiv.org/abs/1810.04805icon-default.png?t=N7T8https://arxiv.org/abs/1810.04805

2.1 输入构造

BERT的输入表示由三个部分的嵌入向量相加而成:标记嵌入(Token Embeddings)、段落嵌入(Segment Embeddings)和位置嵌入(Position Embeddings)。

2.1.1 三个嵌入向量

标记嵌入和位置嵌入部分和 Transformer相同,不过据说:BERT使用 WordPiece 嵌入,这是一种子词级别的嵌入方法,可以有效处理未登录词(OOV,Out-of-Vocabulary)和减少词汇表大小。

段落嵌入:

        段落嵌入用于区分输入文本中的不同句子,BERT能够处理单句和句对输入。

  • 对于单句输入(如文本分类任务),所有标记的段落嵌入相同,通常为 E_A
  • 对于句对输入(如问答任务),第一个句子的所有标记的段落嵌入为E_A,第二个句子的所有标记的段落嵌入为E_B

2.1.2 [CLS] 和 [SEP]标记

  • [CLS]:这是一个特殊的分类标记,放在输入序列的最前面。对于分类任务,模型会使用这个标记对应的输出表示来进行分类。
  • [SEP]:这是一个分隔标记,用于区分两个句子。对于单句输入,在句子末尾添加一个[SEP]标记。对于句对输入,在两个句子之间和第二个句子末尾分别添加一个[SEP]标记。

2.1.3 举例

这里为了方便理解,举一个句对输入的例子(如问答任务)的例子:

假设输入的句对为:"问题:这本书的作者是谁?" 和 "这本书是由张三写的。"

输入序列为:[CLS] 这 本 书 的 作者 是 谁 [SEP] 这 本 书 是 由 张三 写 的 [SEP]

  • 标记嵌入:\text{Embed([CLS])},\text{Embed(Who)},...,\text{Embed([SEP])},\text{Embed(Zhang San)},...,\text{Embed([SEP])}
  • 段落嵌入:E_A, E_A, E_A, E_A, E_A, E_A, E_A, E_A, E_A, E_B, E_B, E_B, E_B, E_B, E_B, E_B, E_B, E_B
  • 位置嵌入:P_0, P_1, P_2, P_3, P_4, P_5, P_6, P_7, P_8, P_9, P_{10}, P_{11}, P_{12}, P_{13}, P_{14}, P_{15}, P_{16}, P_{17}

最终输入表示为这三者的逐元素相加。

这里贴一下论文原图:

2.2 训练方法

2.2.1 预训练任务

  • 掩码语言模型(Masked Language Model, MLM):BERT通过掩码部分输入来进行训练,即在输入序列中随机掩码一些标记(大约15%),然后让模型预测这些掩码位置的原始标记。这使得模型能够从双向(左右上下文)学习语义表示。
  • 下一句预测(Next Sentence Prediction, NSP):在这个任务中,BERT的输入是句子对,模型需要预测第二个句子是否是第一个句子的连续句子。这个任务帮助模型理解句子间的关系,增强句子级别的理解能力。

2.2.2 双向性

        BERT通过MLM预训练任务实现双向性,即在所有层中同时考虑了左侧和右侧的上下文。这样的双向编码使得BERT能够在理解句子时拥有更丰富的语义信息。

        标准Transformer(如GPT)是单向的,模型在预测一个标记时只能利用左侧的上下文。这种单向性适用于生成任务,但在需要全面理解上下文的任务中不如双向模型有效。

2.3 输出层设计

BERT模型的输出层设计允许它适应各种下游任务。通过在预训练的BERT模型之上添加不同的输出层,BERT能够适应不同类型的自然语言处理任务。

1. 句子分类任务

        例如情感分析、文档分类等任务,需要对整个句子或文本进行分类。

        在这种任务中,使用特殊标记 [CLS] 对应的最终隐藏状态作为整个输入序列的表示。该表示被输入到一个全连接层,随后通过Softmax或其他适当的激活函数得到分类结果

2. 句子对分类任务

        例如自然语言推断(NLI)、句子对相似性判断等任务,需要判断两个句子之间的关系。

        类似于句子分类任务,使用 [CLS] 标记对应的最终隐藏状态作为输入,经过全连接层和激活函数进行分类。

3. 序列标注任务

        例如命名实体识别(NER)、词性标注(POS tagging)等任务,需要对序列中的每个标记进行分类。

        对BERT模型的每个标记的最终隐藏状态进行分类。即对于每个标记,都使用对应位置的隐藏状态作为输入,经过全连接层和激活函数得到分类结果。

4. 问答任务

        例如SQuAD问答任务,需要从段落中找到答案的起始位置和结束位置。

        在这种任务中,模型输出两个标记位置的概率分布,一个用于预测答案的起始位置,另一个用于预测答案的结束位置。具体来说,对每个标记的最终隐藏状态使用两个独立的全连接层,分别对应起始位置和结束位置的分类。

5. 生成任务

        例如文本生成、机器翻译等任务,需要生成一个新的序列。

        BERT原始设计中不直接用于生成任务,但可以通过结合解码器架构(如GPT)来实现生成任务。输出层通常是一个基于当前隐藏状态的标记概率分布,通过softmax得到每个位置可能的下一个标记。

2.4 Bert 补充

        除了上面提到过的差异(结构差异下面具体讲,WordPiece嵌入,训练方式等),Bert还有其一些特殊,这里进行补充:

2.4.1 Transformer变种

        尽管BERT基本结构是基于标准的Transformer编码器,但它的一些变种引入了不同的Transformer变种,比如:

  • RoBERTa:优化了预训练策略,例如更长时间的训练和更大的批量大小,去掉了NSP任务。
  • ALBERT:参数共享机制减少了模型参数,使用Sentence Order Prediction替代NSP任务。
  • DistilBERT:蒸馏模型,参数更少,但性能接近BERT。

2.4.2 可扩展性和适应性

        BERT的架构设计使其可以方便地扩展到更大规模的模型(如BERT_{LARGE}),以及可以并行化处理大规模数据,这对于大规模预训练至关重要。

        BERT的预训练模型可以通过微调(Fine-Tuning)快速适应不同的下游任务,这种适应性使其在各种自然语言处理任务中表现优异。

2.4.3 社区支持与生态系统

        由于BERT的开创性成功,它得到了广泛的社区支持,产生了大量的改进和变种模型,并且在各种应用中得到了验证。大量开源工具和库(如Hugging Face's Transformers库)使得使用BERT变得更加方便。

三、两者比较

3.1 任务差异

Transformer 的优势与适用任务

  • 生成性任务:如机器翻译、文本生成、文本摘要、对话系统。
  • 自回归特性:适用于需要逐步生成序列的任务。

BERT 的优势与适用任务

  • 理解性任务:如句子分类、句子对分类、命名实体识别、问答系统、文本分类、文本蕴涵。
  • 双向编码:利用上下文的完整信息,提高了模型的理解能力。

3.2 结构差异

这里对两者具体结构的参数进行比对,先说明一下参数:

  1. Layer:层数,每层为一个多头和一个前馈;
  2. Hidden Units:编码器输出向量维度;
  3. Self-Attention Heads:并行的多头数量;
  4. Diff:前馈网络中间层的维度;
  5. Total Parameters:总的参数量;
TransformerBERT_{base}BERT_{large}
1.Layer61224
2.Units5127681024
3.Heads81216
4.Diff204830724096
5.Total34.6 M110 M340 M

四、参考资料

https://www.zhihu.com/question/445556653/answer/2882383919icon-default.png?t=N7T8https://www.zhihu.com/question/445556653/answer/2882383919https://zhuanlan.zhihu.com/p/604450283icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/604450283Transformer 之多头注意力_transformer的多头注意力机制-CSDN博客文章浏览阅读1.9k次。写在前边:学习 Transformer 的过程中,找到了博客中关于Transformer系统的介绍文章,感觉非常棒,于是进行了翻译。原文链接在文末。翻译主要采用 “DeepL+人工”的方式进行,并加入了一些自己的理解。_transformer的多头注意力机制https://blog.csdn.net/hellozhxy/article/details/131173868变形金刚——Transformer入门刨析详解-CSDN博客文章浏览阅读8.6w次,点赞112次,收藏435次。Transformer详解_transformerhttps://blog.csdn.net/m0_67505927/article/details/123209347

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值