Transformer — 直观而全面地解释 探索现代机器学习的新浪潮:逐步拆解Transformer

本文介绍了自然语言处理的发展历程,从词向量嵌入到循环神经网络(RNN)和LSTM,再到Transformer架构,重点讲解了Transformer的核心组件,如多头自注意力机制和位置编码,以及其在编码器-解码器模型中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


img

NLP发展简史

在本文中,您将了解到变压器架构,这是几乎所有尖端大型语言模型架构的核心。我们将从一些相关的自然语言处理概念的简要时间表开始,然后逐步介绍变压器的工作原理。

这对谁有用? 对自然语言处理(NLP)感兴趣的任何人。

这篇文章有多高级? 这不是一篇复杂的文章,但涉及到很多概念,所以对于经验较少的数据科学家来说可能有些困难。

先决条件: 对标准神经网络有良好的工作理解。对嵌入、编码器和解码器有一些基本的了解可能也会有帮助。

在变压器之前的NLP简要时间表

以下部分包含在进入变压器之前需要了解的有用概念和技术。如果您感到自信,可以跳过这些部分。

词向量嵌入

对于理解自然语言处理,对词向量嵌入的概念有一个基本的理解是非常重要的。实质上,词向量嵌入将单词转化为某种表示其含义的向量。
img
一个词向量嵌入器的工作是将单词转化为能够捕捉它们一般含义的数字。

具体细节可能因实现而异,但最终结果可以被视为一个“单词空间”,其中该空间遵循某些方便的关系。**单词很难进行数学运算,但包含有关单词信息以及它们与其他单词关系的向量则更容易进行数学运算。**将单词转化为向量的任务通常被称为“嵌入”。

Word2Vec是自然语言处理领域的一篇里程碑论文,旨在创建一个遵循某些有用特性的嵌入。基本上,他们希望能够用单词进行代数运算,并创建了一个嵌入来实现这一点。使用Word2Vec,你可以嵌入单词“king”,减去“man”的嵌入,加上“woman”的嵌入,然后得到一个最接近的嵌入为“queen”的向量。
img

在词嵌入上进行代数运算的概念演示。如果你将每个点都看作是从原点出发的向量,如果你从“king”的向量中减去“man”的向量,并加上“woman”的向量,结果向量将接近于“queen”这个词。实际上,这些嵌入空间的维度要高得多,而“接近度”的度量可能不太直观(如余弦相似度),但直觉仍然相同。

随着技术的进步,词嵌入一直是一个重要的工具,GloVe、Word2Vec和FastText都是流行的选择。子词嵌入通常比完整的词嵌入更强大,但超出了本文的范围。

循环神经网络(RNN)

现在我们可以将单词转换为具有一定意义的数字,我们可以开始分析单词序列。早期的一种策略是使用循环神经网络,你可以训练一个神经网络,它会在连续的输入上进行自我反馈。
img

RNN的一般思想

RNN的一般思想是一个正常的全连接神经网络,它将自己的输出作为下一步的输入。
img
如果RNN有3个隐藏神经元并且在2个输入上使用,它可能会是什么样子。红色箭头是递归连接,连接了来自后续循环层的信息。蓝色箭头是内部连接,类似于密集层。为了说明目的,神经网络被复制了,但请记住,网络实际上是反馈到自身,这意味着第二个(和后续的)模块的参数与第一个模块相同。

与传统神经网络不同,因为循环网络反馈到自身,所以它们可以用于任意长度的序列。对于长度为10或长度为100的序列,它们的参数数量将相同,因为它们为每个递归连接重复使用相同的参数。

这种网络风格被应用于许多建模问题,通常可以归类为序列到序列建模、序列到向量建模、向量到序列建模和序列到向量到序列建模。
img

长/短期记忆(LSTMs)

LSTM是为了改善循环网络记住重要信息的能力而创建的。LSTM具有短期记忆和长期记忆,可以在序列中的任何给定元素中将某些信息存入或从长期记忆中删除。
img
一个简介LSTM

从概念上讲,LSTM有三个关键的子组件,“遗忘门”用于遗忘以前的长期记忆,“输入门”用于将事物提交到长期记忆中,“输出门”用于制定下一次迭代的短期记忆。
img

LSTM中的参数

这个特定的LSTM期望一个维度为3的输入向量,并且保存维度为2的内部状态向量。向量的维度是可配置的超参数。同时,注意每个门的末尾都有"S"和"T"。它们代表sigmoid或tanh激活函数,用于将值压缩到特定范围,如0到1或-1到1。这种"压缩"是使网络能够"遗忘"和"记住"特定信息的关键。图片由作者制作,灵感来自来源

LSTM和类似的架构,如GRU,在前面的部分中被证明是对经典RNN的重大改进。将内存作为一个独立的概念进行保存和检索被证明是非常强大的。然而,虽然LSTM可以建模更长的序列,但对于许多语言建模任务来说,它们的遗忘能力太强。此外,由于它们依赖于先前的输入(如RNN),它们的训练很难并行化,结果就是速度慢。

通过对齐实现注意力

具有里程碑意义的论文Neural Machine Translation by Jointly Learning to Align and Translate推广了注意力的一般概念,并成为变换器中使用的多头自注意机制的概念前身。

我在Medium上有一篇关于这个特定主题的文章,其中包含了PyTorch的示例代码。简而言之,这篇论文中的注意力机制会查看所有潜在的输入,并决定在任何给定的输出中向RNN呈现哪个输入。换句话说,它决定哪些输入当前是相关的,哪些输入当前是不相关的。

这种方法被证明在翻译任务中具有巨大的影响。它使循环网络能够确定哪些信息当前是相关的,从而在翻译任务中实现了前所未有的性能。
img

Transformer

在之前的章节中,我们介绍了一些关于树木的知识。现在我们将看一下transformer,它通过结合先前成功的和新颖的想法来改变自然语言处理。
img

Transformer图示 来源

我们将逐个元素地介绍transformer,并讨论每个模块的工作原理。虽然有很多内容需要讲解,但它并不是数学密集型的,概念也相当易于理解。

高层架构

在最基本的层面上,transformer是一种编码器/解码器模型,有点像我们之前讨论过的序列到向量到序列模型。编码器将一些输入压缩成表示整个输入含义的嵌入。解码器然后采用这个嵌入,并递归地构建输出。
img
一个工作在序列到向量到序列任务中的transformer,简而言之。输入(我是一个经理)被压缩成一些抽象的表示,编码整个输入的含义。解码器像我们之前讨论的RNN一样,循环地工作来构建输出。

输入嵌入和位置编码

img
在原始图表中的输入嵌入。来源

Transformer的输入嵌入与先前讨论的策略类似;类似于word2vect的词空间嵌入器将所有输入词转换为向量。这个嵌入器与模型本身一起进行训练,实质上是一个通过模型训练改进的查找表。因此,词汇表中的每个单词都会有一个随机初始化的向量,随着模型对每个单词的了解而改变。

与循环策略不同,transformer一次性对整个输入进行编码。因此,编码器可能会丢失有关输入中单词位置的信息。为了解决这个问题,transformer还使用位置编码器,它是一个编码有关特定单词在序列中位置的信息的向量。

"""
绘制每个索引的位置编码。
单个令牌的位置编码将是图像中的水平行。

灵感来自 https://machinelearningmastery.com/a-gentle-introduction-to-positional-encoding-in-transformer-models-part-1/

"""

import numpy as np
import matplotlib.pyplot as plt

# 根据向量嵌入和序列定义这些
sequence_length = 512
embedding_dimension = 1000

# 生成位置编码
def gen_positional_encodings(sequence_length, embedding_dimension):
    # 创建一个空占位符
    positional_encodings = np.zeros((sequence_length, embedding_dimension))

    # 遍历序列中的每个元素
    for i in range(sequence_length):

        # 计算该序列位置向量的值
        # 如在attention is all you need论文的3.5节中定义的那样
        # https://arxiv.org/pdf/1706.03762.pdf
        for j in np.arange(int(embedding_dimension/2)):
            denominator = np.power(sequence_length, 2*j/embedding_dimension)
            positional_encodings[i, 2*j] = np.sin(i/denominator)
            positional_encodings[i, 2*j+1] = np.cos(i/denominator)

    return positional_encodings

# 渲染
fig, ax = plt.subplots(figsize=(15,5))
ax.set_ylabel('Sequence Index')
ax.set_xlabel('Positional Encoding')
cax = ax.matshow(gen_positional_encodings(sequence_length, embedding_dimension))
fig.colorbar(cax, pad=0.01)

img
位置编码示例。Y轴表示后续单词,X轴表示特定单词位置编码内的值。图像中的每一行表示一个单独的单词。

"""
渲染出几个单独的例子

灵感来自于 https://machinelearningmastery.com/a-gentle-introduction-to-positional-encoding-in-transformer-models-part-1/
"""
# 生成位置编码
positional_encodings = gen_positional_encodings(100, 50)
# 创建一个图形对象
fig = plt.figure(figsize=(15, 4))    
# 循环4次
for i in range(4):
    # 创建子图
    ax = plt.subplot(141 + i)
    # 计算索引
    idx = i*10
    # 绘制位置编码的某一列
    plt.plot(positional_encodings[:,idx])
    # 设置子图标题
    ax.set_title(f'positional encoding {idx}')
# 显示图形
plt.show()
"""

img
相对于序列中不同索引的位置向量的值。K代表序列中的索引,图形表示向量中的值。

该系统使用正弦和余弦函数一起编码位置,您可以在本文中对此有一些直观的理解:

更频繁地使用频率:从简单到高级频率分析的手册。探索一种在数据中广泛被低估的重要工具…blog.roundtableml.com

我不会过多强调,但有一个有趣的注释;这种编码位置的系统与电机中使用的位置编码器非常相似,其中两个相位差90度的正弦波允许电机驱动器理解电机的位置、方向和速度。

用于编码单词位置的向量被添加到该单词的嵌入中,创建一个包含有关该单词在句子中位置和单词本身的信息的向量。您可能会想:“如果将这些波浪形添加到嵌入向量中,那么是否会掩盖原始嵌入的一些含义,可能会使模型混淆”?对此,我会说神经网络(变压器用于其可学习参数)非常擅长理解和操作平滑连续函数,因此对于足够大的模型来说,这实际上没有太大影响。

多头自注意力:高级

这可能是变压器机制中最重要的子组件之一。
img
原始图表中的多头自我注意机制。来源

在作者看来,将其称为“注意力”机制有点不准确。实际上,它是一种“关联”和“情境化”机制。它允许单词与其他单词互动,将输入(每个单词的嵌入向量列表)转换为表示整个输入含义的矩阵。
img
多头自注意力,简而言之。该机制在数学上将不同单词的向量组合在一起,创建一个编码整个输入更深层含义的矩阵。

这个机制可以看作是四个独立的步骤:

  1. 创建查询(Query)、键(Key)和值(Value)

  2. 分成多个头

  3. 注意力头

  4. 组合最终输出

多头自注意力步骤1) 创建查询(Query)、键(Key)和值(Value)

首先,不要过于担心“查询(Query)”,“键(Key)”和“值(Value)”这些名称。这些名称在某种程度上受到数据库的启发,但实际上只是在最模糊的意义上。查询(Query)、键(Key)和值(Value)本质上是嵌入输入的不同表示,它们将在整个注意力机制中相互关联。
img
将嵌入输入转化为查询键和值。输入的维度为num_words乘以embedding_size,查询、键和值的维度与输入相同。实质上,一个密集网络将输入投影到一个具有三倍特征数量的张量中,同时保持序列长度。

上面显示的密集网络包括多头自注意机制中唯一可学习的参数。多头自注意可以被视为一个函数,模型学习输入(查询、键和值),以最大化该函数在最终建模任务中的性能。

多头自注意机制第二步)分成多个头部

在进行自注意的实际上下文化之前,我们将查询、键和值分成多个块。核心思想是,我们可以以多种不同的方式相互关联单词,而不是单一的方式。通过这样做,我们可以编码更加微妙和复杂的含义。
img

多头自注意力机制第三步:注意力头

在这个例子中,我们有3个注意力头。因此,查询、键和值被分成3个部分并传递给每个头。请注意,我们是沿着特征轴而不是单词轴进行划分。每个单词的不同嵌入方面被传递到不同的注意力头中,但每个单词仍然存在于每个注意力头中。

现在我们有了查询、键和值的子组件,它们被传递给一个注意力头,我们可以讨论注意力头如何通过矩阵乘法组合值以对结果进行上下文化。在《注意力就是你所需要的》中,这是通过矩阵乘法完成的。
img
矩阵乘法。来源

在矩阵乘法中,一个矩阵的行与另一个矩阵的列通过点积相乘,得到一个结果矩阵。在注意力机制中,查询(Query)和键(Key)进行矩阵乘法运算,得到我所称的“注意力矩阵”。
img
使用查询和键计算注意力矩阵。请注意,为了使矩阵乘法得到正确的注意力矩阵形状,键被转置。

这是一个相当简单的操作,因此很容易低估其影响。此时使用矩阵乘法强制每个单词的表示与其他每个单词的表示相结合。由于查询和键由密集网络定义,注意机制学习如何将查询和键转换为优化此矩阵内容。

现在我们有了注意力矩阵,可以将其与值矩阵相乘。这有三个关键目的:

  1. 通过关联输入的另一个表示来增加一些情境化。

  2. 创建一个系统,使查询和键的功能用于转换值,从而允许自注意力或交叉注意力,具体取决于查询、键和值的来源。

  3. 也许最重要的是,它使注意力机制的输出与输入的大小相同,这使得某些实现细节更容易处理。
    img

多头自注意力机制 第4步) 组合最终输出

在上一节中,我们使用查询(query)、键(key)和值(value)构建了一个新的结果矩阵,该矩阵与值矩阵具有相同的形状,但具有更多的上下文意识。

请记住,注意力头只计算输入空间的一个子组件的注意力(沿特征轴划分)。
img
回想一下,输入被分成了多个注意力头。在这个例子中,有3个头。

现在,每个头都输出一个不同的结果,然后可以将它们连接在一起。
img
每个注意力头的结果被连接在一起。

矩阵的形状与输入矩阵完全相同。然而,与输入不同的是,每行与一个单词相关联,这个矩阵更加抽象。
img
回想一下,注意力机制简而言之,将嵌入的输入转换为一个抽象的上下文丰富的表示。

加和归一化

img
在原始图表中添加和规范化。来源

在编码器中,Add和Norm操作被应用两次,而且每次的效果都是相同的。这里有两个关键概念:跳跃连接和层规范化。

跳跃连接在机器学习中被广泛使用。我最喜欢的例子是使用U-net架构进行图像分割,如果你熟悉的话。基本上,当你进行复杂操作时,模型很容易“偏离自己”。这有各种各样的花哨数学定义,比如梯度爆炸和秩崩溃,但从概念上讲,它非常简单;模型可能会过度思考一个问题,因此重新引入旧数据以重新引入一些更简单的结构可能会很有用。
img
一个跳跃连接的加法可能是这样的。在这个例子中,左边的矩阵表示原始编码输入。中间的矩阵表示注意力矩阵的超上下文结果。右边表示跳跃连接的结果:一个仍然包含一些原始输入顺序的上下文感知矩阵。

层归一化与跳跃连接类似,从概念上来说,它可以控制不稳定性。对这个数据进行了很多操作,导致了不知道有多大和多小的值。如果你对这个矩阵进行数据科学处理,你可能需要处理非常小和非常大的值。这被认为是有问题的。

层归一化计算均值和标准差(值的分布范围有多广),并使用这些值将数据压缩回一个合理的分布。

前馈

img
在原始图表中进行前馈。来源

这部分很简单。我们可以从注意力机制后的加法规范化输出中获取,并通过一个简单的密集网络进行传递。我喜欢把它看作是一个投影,模型可以学习如何将注意力输出投影到对解码器有用的格式中。

前馈网络的输出然后通过另一个加法规范化层传递,这将产生最终输出。这个最终输出将被解码器用来生成输出。

解码器的一般功能

我们已经完全涵盖了编码器,并且具有高度上下文化的输入表示。现在我们将讨论解码器如何使用该表示来生成一些输出。
img
高级别表示了编码器输出与解码器之间的关系。解码器在每个递归循环的输出中引用编码输入。

解码器与编码器非常相似,只有一些细微的差异。在我们讨论这些差异之前,让我们先谈谈相似之处。
img

Transformer架构 来源

如上图所示,解码器使用相同的词向量嵌入方法,并使用相同的位置编码器。解码器使用“掩码”多头自注意力,我们将在下一节中讨论,并使用另一个多头注意力块。

第二个多头自注意力使用编码输入作为键和值,并使用解码器输入生成查询。因此,注意力矩阵从编码器和解码器的嵌入中计算得出,然后应用于编码器的值。这使得解码器能够根据编码器输入和解码器输入决定最终输出。

其余部分与其他模型可能相同。结果通过另一个前馈、添加规范化、线性层和softmax传递。这个softmax会输出一个词袋的概率,例如,允许模型决定输出的词。

掩码多头自注意力

因此,解码器真正新的地方就是“掩码”注意力。这与这些模型的训练方式有关。

递归神经网络的一个核心缺陷是需要按顺序训练它们。RNN密切依赖于对前一步的分析来通知下一步。
img
RNNs建立了步骤之间的紧密依赖关系。

这使得训练RNNs非常缓慢,因为训练集中的每个序列都需要按顺序逐个通过模型进行馈送。通过对注意力机制进行一些小心的修改,transformers可以解决这个问题,使得模型可以并行地训练整个序列。

细节可能有些棘手,但本质是这样的:在训练模型时,您可以访问所需的输出序列。因此,您可以将整个输出序列(包括尚未预测的输出)馈送到解码器中,并使用掩码将其从模型中隐藏。这使您可以同时训练序列的所有位置。
img

结论

就是这样!我们分解了一些技术创新,这些创新导致了transformer的发现以及transformer的工作原理,然后我们讨论了transformer作为编码器-解码器模型的高级架构,并讨论了重要的子组件,如多头自注意力,输入嵌入,位置编码,跳跃连接和归一化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数智笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值