注意力机制和Transformer原理,其他文章看不懂就看这个吧,根据《python深度学习》 和 《动手学深度学习》两本书总结而成

 

 

注意力机制和Transformer原理,网上一堆文章都没有说清楚,自己根据《python深度学习》 和 《动手学深度学习》这两本书结合起来总结下。

两本书的地址:

https://zh.d2l.ai/d2l-zh.pdf

https://weread.qq.com/web/reader/33f32c90813ab71c6g018fffk1f032c402131f0e3dad99f3

 

【先说attention,它要解决什么问题】

注意力机制主要解决的是序列处理中的长距离依赖问题。

在处理序列数据(如文本或时间序列)时,我们经常需要捕捉输入中的不同部分之间的依赖关系。例如,在机器翻译中,一个词的翻译可能依赖于句子中的其他词。然而,传统的序列处理模型,如循环神经网络(RNN),在处理长序列时,可能会遇到长距离依赖问题,即模型难以捕捉到序列中相隔较远的元素之间的依赖关系。

注意力机制通过为序列中的每个元素分配一个权重,使模型能够关注到与当前任务最相关的信息,从而有效地解决了长距离依赖问题。例如,在机器翻译中,当模型翻译一个词时,注意力机制可以使模型关注到句子中与当前词相关的其他词,无论这些词与当前词的距离有多远。

总的来说,注意力机制提高了模型处理序列数据的能力,特别是在处理长序列和捕捉长距离依赖关系时的能力。

【attention的输入和输出】

注意力机制的输入通常包括三部分:Query(查询),Key(键),Value(值)。这些都是由深度学习模型的前一层产生的向量。

1. 输入:Query、Key和Value。在自然语言处理任务中,例如,这些可能分别代表当前的词(Query),上下文中的其他词(Key),以及这些词的相关信息(Value)。

2. 计算注意力分数:首先,模型会计算Query和每个Key之间的相似度。这通常通过计算它们的点积或者其他相似度度量方法来完成。这个相似度分数反映了Query和每个Key的匹配程度。

3. 应用softmax函数:然后,模型会对这些分数应用softmax函数,将它们转化为概率分布。这样,和Query更匹配的Key会得到更高的权重。

4. 计算加权和:最后,模型会计算Value的加权和,权重就是上一步计算得到的概率分布。这样,和Query更匹配的Value(即更重要的信息)会得到更大的权重。

5. 输出:输出就是上一步计算得到的加权和,它反映了输入信息中对当前任务最重要的部分(也就是最重要的value被选择出来)。

这就是注意力机制的基本流程。需要注意的是,实际的注意力机制可能会更复杂,例如在Transformer模型中使用的是多头注意力机制(Multi-Head Attention),它会同时计算多个不同的注意力分布,然后将它们合并起来。

如果是python写一个简单的attention,大概是如下样子:

import numpy as np

def softmax(x):
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0)

def attention(query, key, value):
    scores = np.dot(query, key)
    scores = softmax(scores)
    output = np.dot(scores, value)
    return output

 -------

因为Transformer架构是基于注意⼒机制的,先说《注意⼒机制》

 

 

 

 

 

 

 我们接下来看Transformer。

 

Transformer架构从2017年开始,一种新的模型架构开始在大多数自然语言处理任务中超越RNN,它就是Transformer。Transformer由Ashish Vaswani等人的奠基性论文“Attention Is All You Need”4引入。这篇论文的要点就在标题之中。事实证明,一种叫作神经注意力(neural attention)的简单机制可以用来构建强大的序列模型,其中并不包含任何循环层或卷积层。4Ashish Vaswani et al. Attention Is All You Need. 2017.这一发现在自然语言处理领域引发了一场革命,并且还影响到其他领域(ChatGPT核心之一就是这个模型)。神经注意力已经迅速成为深度学习最有影响力的思想之一。本节将深入介绍它的工作原理,以及它为什么对序列数据如此有效。然后,我们将利用自注意力来构建一个Transformer编码器。

11.4.1 理解自注意力

你在阅读本书时,可能会略读某些章节而精读另外一些章节,这取决于你的目标或兴趣。如果你的模型也这样做,那会怎么样?这个想法很简单但很强大:所有的模型输入信息并非对手头任务同样重要,所以模型应该对某些特征“多加注意”,对其他特征“少加注意”。这听起来熟悉吗?

本书前面已经两次介绍过类似的概念。 ==》下面就是传统的原始注意力模型!

(1)卷积神经网络中的最大汇聚:查看一块空间区域内的特征,并选择只保留一个特征。这是一种“全有或全无”的注意力形式,即保留最重要的特征,舍弃其他特征。

(2)TF-IDF规范化:根据每个词元可能携带的信息量,确定词元的重要性分数。重要的词元会受到重视,而不相关的词元则会被忽视。这是一种连续的注意力形式。有各种不同形式的注意力,但它们首先都要对一组特征计算重要性分数。特征相关性越大,分数越高;特征相关性越小,分数越低,如图11-5所示。如何计算和处理这个分数,则因方法而异。

 

至关重要的是,这种注意力机制不仅可用于突出或抹去某些特征,还可以让特征能够上下文感知(context-aware)。你刚刚学过词嵌入,即捕捉不同单词之间语义关系“形状”的向量空间。在嵌入空间中,每个词都有一个固定位置,与空间中其他词都有一组固定关系。但语言并不是这样的:一个词的含义通常取决于上下文。你说的“mark the date”(标记日期)与“go on a date”(去约会),二者中的“date”并不是同一个意思,与你在市场上买的date(椰枣)也不是同一个意思。 ==》核心表达的是:transformer擅长处理上下文,比如一词多义!!!

 

 显然,一个好的嵌入空间会根据周围词的不同而为一个词提供不同的向量表示。这就是自注意力(self-attention)的作用。自注意力的目的是利用序列中相关词元的表示来调节某个词元的表示,从而生成上下文感知的词元表示。来看一个例句:“The train left the station on time”(火车准时离开了车站)。再来看句中的一个单词:“station”(站)。我们说的是哪种“station”?是“radio station”(广播站),还是“International Space Station”(国际空间站)?我们利用自注意力算法来搞清楚,如图11-6所示。

 

第1步是计算“station”向量与句中其余每个单词之间的相关性分数。这就是“注意力分数”。我们简单地使用两个词向量的点积来衡量二者的关系强度。它是一种计算效率很高的距离函数,而且早在Transformer出现之前,它就已经是将两个词嵌入相互关联的标准方法。在实践中,这些分数还会经过缩放函数和softmax运算,但目前先忽略这些实现细节。

第2步利用相关性分数进行加权,对句中所有词向量进行求和。与“station”密切相关的单词对求和贡献更大(包括“station”这个词本身),而不相关的单词则几乎没有贡献。由此得到的向量是“station”的新表示,这种表示包含了上下文。具体地说,这种表示包含了“train”(火车)向量的一部分,表示它实际上是指“train station”(火车站)。对句中每个单词重复这一过程,就会得到编码这个句子的新向量序列。

对句中每个单词重复这一过程,就会得到编码这个句子的新向量序列。类似NumPy的伪代码如下。

 

 

 

当然,你在实践中需要使用向量化实现。

 

一般的自注意力:查询−键−值模型

到目前为止,我们只考虑了输入序列只有一个的情况。但是,Transformer架构最初是为机器翻译而开发的,它需要处理两个输入序列:当前正在翻译的源序列(比如“How's the weather today?”)与需要将其转换成的目标序列(比如“¿Quétiempo hace hoy?”5)。

5源序列是英语,目标序列是西班牙语,两句话的意思都是“今天天气怎么样”。——译者注

Transformer是一种序列到序列(sequence-to-sequence)模型,它的设计目的就是将一个序列转换为另一个序列。本章稍后会深入介绍序列到序列模型。

现在我们先回到本节主题。自注意力机制的作用如下所示。

 

 

 

这个表达式的含义是:“对于inputs(A)中的每个词元,计算该词元与inputs(B)中每个词元的相关程度,然后利用这些分数对inputs(C)中的词元进行加权求和。”重要的是,A、B、C不一定是同一个输入序列。一般情况下,你可以使用3个序列,我们分别称其为查询(query)、键(key)和值(value)。这样一来,上述运算的含义就变为:“对于查询中的每个元素,计算该元素与每个键的相关程度,然后利用这些分数对值进行加权求和。”

这些术语来自搜索引擎和推荐系统,如图11-7所示。想象一下,你输入“沙滩上的狗”,想从数据库中检索一张图片。在数据库内部,每张照片都由一组关键词所描述——“猫”“狗”“聚会”等==》这个图很关键哈!!!

 

 

 

我们将这些关键词称为“键”。搜索引擎会将你的查询和数据库中的键进行对比。“狗”匹配了1个结果,“猫”匹配了0个结果。然后,它会按照匹配度(相关性)对这些键进行排序,并按相关性顺序返回前n张匹配图片。

从概念上来说,这就是Transformer注意力所做的事情。你有一个参考序列,用于描述你要查找的内容:查询。你有一个知识体系,并试图从中提取信息:值。每个值都有一个键,用于描述这个值,并可以很容易与查询进行对比。你只需将查询与键进行匹配,然后返回值的加权和。

 

再回到前面注意力机制:讨论注意力机制中的查询(query)、键(key)和值(value),本质上和transformer是一样的。

⾃主性的与⾮⾃主性的注意⼒提⽰解释了⼈类的注意⼒的⽅式,下⾯来看看如何通过这两种注意⼒提⽰,⽤神经⽹络来设计注意⼒机制的框架。

 

==》和前面沙滩狗表达的意思是一样的!!!

 

注意力机制的例子:

 

 

 

 

 

==》我的感觉就类似ARIMA自回归模型 y的输出是当前yi的加权平均

 

 

 

好了有了上面的基础以后,理解查询键值就容易了!!!然后就是评分函数的选取了:

 

 常见注意力模型有下面几类,其中transformer也是其中著名代表。

 

 几种模型结构都简单说下:

 

 

 

 

关于多头注意力,为啥叫多头,另外一本书里说得非常好!类似CNN里的多个卷积核。

 

 

==》说白了就是让前后位置也作为特征。

 

 

是不是觉得transformer就是一个杂糅体,将各个模型的优点都汇总到一起,什么残差网络,attention,编码解码器啊这些,还有word之前的前后位置信息也作为特征。

 

注意:图中有一个(掩蔽)掩码多头注意力,我们看看gpt的作用解释

Transformer模型中的掩码多头注意力(Masked Multi-Head Attention)是一种特殊的多头注意力机制,它通过使用掩码(Mask)来防止模型在处理序列数据时“看到”未来的信息。

在自然语言处理任务中,我们通常需要模型按照序列的顺序处理数据,例如在处理句子时,模型需要先处理句子的前面部分,再处理句子的后面部分。但是,在Transformer模型的多头注意力机制中,模型会同时处理序列中的所有元素,这就可能导致模型在处理某个元素时“看到”它后面的元素,从而获取到未来的信息。
为了解决这个问题,我们可以使用掩码多头注意力。在掩码多头注意力中,我们会创建一个掩码矩阵,然后将这个矩阵和注意力分数矩阵相加。掩码矩阵中的每个元素都对应于注意力分数矩阵中的一个元素,如果我们不希望模型在处理某个元素时“看到”它后面的元素,我们就可以在掩码矩阵中将对应的元素设置为一个非常大的负数。这样,在进行softmax操作时,这个元素的权重就会接近于零,从而防止模型“看到”未来的信息。

以下是一个简单的掩码多头注意力的实现:

def masked_multi_head_attention(querykeyvaluemask):
    # Calculate attention scores
    scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(query.size(-1))
 
    # Apply mask to scores
    scores = scores.masked_fill(mask == 0, -1e9)
 
    # Calculate attention weights
    weights = F.softmax(scores, dim=-1)
 
    # Calculate output
    output = torch.matmul(weights, value)
 
    return output 
 

在这个函数中,query、key和value是多头注意力的输入,mask是掩码矩阵。函数首先计算注意力分数,然后使用masked_fill函数将掩码矩阵中为0的位置对应的注意力分数设置为一个非常大的负数,然后计算注意力权重,并根据权重和value计算输出。

 

最后总结NLP模型特点:

 

 

 

 

最后:

是不是发现transformer可以处理前面的问题了?

你说的“mark the date”(标记日期)与“go on a date”(去约会),二者中的“date”并不是同一个意思,与你在市场上买的date(椰枣)也不是同一个意思。

就是因为transformer擅长处理上下文和词序感知。

 

写在最后:

 

 

 

 

 

 因此,如果想对包含1000个词的文件进行分类,并且你有100 000份文件(比例为100),那么应该使用二元语法模型。如果想对平均长度为40个单词的推文进行分类,并且有50 000条推文(比例为1250),那么也应该使用二元语法模型。但如果数据集规模增加到500 000条推文(比例为12 500),那么就应该使用Transformer编码器。对于IMDB影评分类任务,应该如何选择呢?我们有20 000个训练样本,平均词数为233,所以根据我们的经验法则,应该使用二元语法模型,这也证实了我们在实践中的结果。

 

这在直觉上是有道理的:序列模型的输入代表更加丰富、更加复杂的空间,因此需要更多的数据来映射这个空间;与此相对,普通的词集是一个非常简单的空间,只需几百或几千个样本即可在其中训练logistic回归模型。此外,样本越短,模型就越不能舍弃样本所包含的任何信息——特别是词序变得更加重要,舍弃词序可能会产生歧义。

 

对于“this movie is the bomb”和“this movie was a bomb”这两个句子6,它们的一元语法表示非常接近,词袋模型可能很难分辨,但序列模型可以分辨出哪句是负面的、哪句是正面的。对于更长的样本,词频统计会变得更加可靠,而且仅从词频直方图来看,主题或情绪会变得更加明显。

 6第一句的意思是“这部电影很棒”,而第二句的意思是“这部电影很烂”。——译者注

 

 

posted @ 2023-03-12 21:24  bonelee  阅读(1138)  评论(0编辑  收藏  举报