《昇思MindSpore丨大模型25天打卡营学习心得+day1——Transformer 基本概念和FAQ》
收藏回复举报
《昇思MindSpore丨大模型25天打卡营学习心得+day1——Transformer 基本概念和FAQ》
新人帖
发表于2024-08-30 16:00:07
0 查看

由于无法上传图片,帖子中图片使用了数字代替。

可以点击 http://3ms.huawei.com/km/blogs/details/15769773?l=zh-cn 查看完整的文章

定义 

Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构,它在2017年由Vaswani等人首次提出。Transformer架构引入了自注意力机制(self-attention mechanism),这是一个关键的创新,使其在处理序列数据时表现出色。 

以下是Transformer的一些重要组成部分和特点: 

 

自注意力机制(Self-Attention):这是Transformer的核心概念之一,它使模型能够同时考虑输入序列中的所有位置,而不是像循环神经网络(RNN)或卷积神经网络(CNN)一样逐步处理。自注意力机制允许模型根据输入序列中的不同部分来赋予不同的注意权重,从而更好地捕捉语义关系。 

多头注意力(Multi-Head Attention):Transformer中的自注意力机制被扩展为多个注意力头,每个头可以学习不同的注意权重,以更好地捕捉不同类型的关系。多头注意力允许模型并行处理不同的信息子空间。 

位置编码(Positional Encoding):由于Transformer没有内置的序列位置信息,它需要额外的位置编码来表达输入序列中单词的位置顺序。 

残差连接和层归一化(Residual Connections and Layer Normalization):这些技术有助于减轻训练过程中的梯度消失和爆炸问题,使模型更容易训练。 

编码器和解码器:Transformer通常包括一个编码器用于处理输入序列和一个解码器用于生成输出序列,这使其适用于序列到序列的任务,如机器翻译。 

本质 

transformer的目的是给输入数据找一个合理的、看起来智能的输出,去掉各种神经网络相关的信息,这就类似于写一个SQL,从数据库里面去查询信息。 

 

比如根据名称查所有叫张三的学生: 

 

写一个SQL是这样的:select age from students where name = '张三'. 

 

这里的张三就是需要查询的语句,命名为 : Query 

 

查询出来的值 age(年龄) 就是Value. 

 

如果是这种非常直白的查询,没有经过神经网络,也就没有智能。怎么才能更智能,神经网络怎么用才行? 

 

分析下看看:像上述的sql,他的where条件的核心是一个等号。这个就是查询语句与值的一个关系。 

 

结论:要把Query和Value建立关系,这个关系在神经网络里面基本不会是相等的关系,应该是一个概率:遍历所有数据,找到所有关联,跟谁的关联最大(概率最大)就用这个Value。 

 

核心就做一件事情: 找关联 

想把找关系这件事情做好,可不容易。 

 

谁也不知道一个输入,跟谁关联最大,只能遍历所有数据,或者用算法找一个近似最大的Value。 

 

为了遍历数据,最好是把所有数据都映射到一个id上去,比如把每个字,每个词语都建立一个索引,命名为Index。 

 

有了这个大而全的索引,就可以把Query,Value都映射到这个索引的空间里面。 

 

也就是说,query,value都可以用Index的一组值表示。这种方式解决了方便计算的问题,但是还没有解决关联的问题,关联在哪里找? 

 

再分析分析:举例来说,一个词语“苹果”,和词语“水果”,“动物” 可能都有关系,大家都知道苹果属于水果,某些动物喜欢吃水果,某些动物不喜欢吃水果,等等,这些都存在着千丝万缕的关系(长程依赖、多义词等等),都藏在文本里面,需要通过一种方式把关系确定下,这个方式就是权重矩阵 

 

权重矩阵 

权重矩阵 有2个作用: 

 

训练前(语言表示):替代Index,原来是词语映射成索引,现在是把词语映射成Embedding里面的向量。 

训练中(关系表示):表达关系!表达当前训练场景下,词语和词语之间的关系,并不断更新(以便让Loss更小),这个矩阵在Transformer架构中就是 WQ、WK、WVWQ、WK、WV 权重矩阵,权重矩阵是随机初始化(训练时会不断变化)或者基于之前的训练得来的 

现在解决了2个大问题:词语的表示、词语的关联(把Query和Value之间用矩阵连起来,然后不断优化这个矩阵) 

 

还要解决一些小问题: 

 

语句出现的顺序非常重要,要保留,需要把语句的顺序也编码进去。 

一个词语可能跟前后的其他词语都有关系(尤其是代词),需要把整个句子都编码进去。 

注意力机制 

为了解决第2个问题,引入了注意力机制。 

 

由于任务(query)不同,同一句话,我们的注意力也是极有可能不同的,如下图所示: 

 

 

不同的上下文环境下,表达的意思不一样,核心内容不同。 

 

自注意力机制(Self-Attention) 

除了关注一个句子的核心内容之外,还需要关注句子本身,查看每个单词对于周边单词的重要性。 

 

这样可以很好的理清句子中的逻辑关系,如代词指代。 

 

1111 

 

如上图所示,The这个单词在整个句子中,跟其他单词的的关系是有差别的。 

 

多头注意力机制(Multi-Head Attention) 

每个单词在情感、关系、状态等不同的维度。 

 

为了体现多个维度,就需要同时关注多个维度的信息,这就是多头注意力机制。 

 

2222 

 

如上图所示,不同的颜色,代表不同的注意力,红色可能是指代关系,it 与The animal关系比较深(注意力分数则比较高),在另外一个维度上(比如状态)it与tired(累了)关系比较深。 

 

通过多头注意力机制,可以更完整的体现句子或单词的含义。 

 

代码示例: 

3333 

 

4444 

 

注意: 

 

所有W_开头的都是线性变换(nn.Dense) 

线性变换的目的是引入神经网络,增加可训练性 

所有W_开头的矩阵都是可训练的 

Transformer与传统NLP的区别 

将自注意力机制和多头注意力机制运用到模型中 

引入了位置编码 

以上处理带来的2个优点 

 

更容易并行训练,更高效 

在处理长序列的任务中表现优秀,可快速捕捉长距离中的关联信息 

结构 

包含4个部分:输入、输出、encoder、decoder 

每个encoder包含6(也可能是12,24个)个encoder block 

每个encoder block包含1个全连接神经网络FFN + 1个 Multi-Head Attention 

每个decoder包含6个block 

每个decoder block包含 1个全连接神经网络FFN + 1个 Multi-Head Attention + 1个Masked Multi-Head Attention 

 

其中 

 

word Embedding:将序列转换为模型能够理解的词向量表示,其中包含了内容信息 

positional encoding:在内容信息基础上添加位置信息 

编码器 Encoder 

一系列Encoder block 负责处理输入的源序列,并将输出信息整合到一堆上下文向量中,作为Decoder中的一个输入 

 

每个encoder block包含1个全连接神经网络FFN + 1个 Multi-Head Attention 

 

子层之间使用残差连接(residual connection),并使用了层规范化(layer normalization)。 

 

二者统称为 “Add&Norm” 

 

结构图: 

 

5555 

 

基于位置的前馈神经网络 

这个网络用来对输入中的每个位置进行非线性变换。 

 

由2个线性层构成,层与层之间需要经过ReLU激活函数。 

 

相比于固定的ReLU函数,基于位置的前馈神经网络可以处理更加复杂的关系,可以捕获到不同位置的信息,并为每个位置提供不同的转换。 

 

其代码示例如下: 

 

6666 

 

注意: 

 

输入维度 (dmodel):这是输入向量的维度,也是 Transformer 中每个向量的维度。 

隐藏层维度 (dff):这是第一层线性变换的输出维度,也是第二层线性变换的输入维度。 

通常dff大于dmodel,以增加模型的表达能力。 

输出维度与输入维度一致:维度经过第一层变换后,维度变大,经过第二层变换后恢复成原始维度 

Add&Norm 

本质上是残差连接后紧接了一个LayerNorm层 

 

数学表达式如下: 

 

 

从结构图上可以看出来,这个Sublayer有2个来源: 

 

Muti head attention 多头注意力的结果 

FFN的结果,基于位置的前置神经网络的结果 

其中 

 

Add:残差连接,帮助缓解网络退化问题,需要满足x与SubLayer(x)形状要一致 

 

Norm:Layer Norm,层归一化,帮助模型更快的收敛 

 

代码示例如下: 

 

7777 

 

Encoder的构建 

 

经过2次组合: 

 

Muti+AddNorm + FFN+AddNorm = Encoder Block(Encoder Layer) 

Embedding+PositionEncoding+n个Encoder Block(Encoder Layer) 

Encoder Layer 

这个比较简单,按照图实现代码 

 

8888 

 

完整的Encoder编码器 

9999 

 

Decoder 

1010 

 

Decoder的输入有2个:右移的序列和encoder的输出 

右移的序列在训练阶段是目标语言序列,在推理阶段是上次推理的输出 

比Encoder多了一层Masked Multi-Head Attention。所以有2层注意力机制 

第一层:计算目标序列的注意力分数的掩码多头自注意力; 

第二层:用于计算上下文序列与目标序列对应关系,其中Decoder掩码多头注意力的输出作为query,Encoder的输出(上下文序列)作为key和value 

Encoder和Decoder的关键区别 

输入序列的不同:编码器的输入是源语言的句子,而解码器的输入是目标语言的序列(在训练阶段)或模型生成的序列(在推理阶段)。 

时间掩码:解码器使用时间掩码来确保生成过程遵循时间上的因果关系,而编码器没有这样的要求。 

带掩码的多层注意力 

掩码机制在深度学习中是一个比较常见的机制,其本质是遮掩,隐藏一些信息。 

 

时间掩码 

时间掩码(Temporal Masking)主要用于解码器(Decoder)部分的自注意力机制中,目的是确保模型在生成序列时只能访问到之前的位置信息,而不能访问到未来的信息。这种机制保证了解码器在生成序列时遵循了时间上的因果关系。 

 

时间掩码的作用 

时间掩码的作用是阻止解码器中的自注意力机制查看未来的时间步。在训练阶段,解码器的输入序列包含了目标序列的全部信息,但是为了让模型学会预测下一个词,必须确保在预测第t 个词时,模型只能看到第(t−1) 个词的信息。 

 

实现方法 

时间掩码的实现通常通过创建一个遮罩矩阵来完成,该矩阵决定了哪些位置的注意力得分会被置为非常小的值(通常是负无穷),从而在经过softmax函数后这些位置的注意力权重几乎为零。这样一来,模型就不会考虑这些位置的信息。 

 

工作原理 

构建时间掩码矩阵:创建一个上三角矩阵,主对角线以上的元素被置为非常小的值。 

应用掩码:在计算注意力权重之前,将时间掩码矩阵与注意力得分相加。 

计算注意力权重:对加权后的得分应用softmax函数,得到注意力权重矩阵。 

计算加权和:使用注意力权重矩阵对值向量进行加权求和,得到最终的输出 

时间掩码矩阵的变化 

当序列只有 [A] 时,时间掩码矩阵为: 

[[0, -inf, -inf, -inf]] 

 

 

当序列增长为 [A, B] 时,时间掩码矩阵变为: 

[[0, -inf, -inf, -inf], 

[0,  0,  -inf, -inf]] 

 

1 2 

 

当序列增长为 [A, B, C] 时,时间掩码矩阵变为: 

[[0, -inf, -inf, -inf], 

[0,  0,  -inf, -inf], 

[0,  0,   0,  -inf]] 

 

1 2 3 

 

当序列增长为 [A, B, C, D] 时,时间掩码矩阵变为: 

[[0, -inf, -inf, -inf], 

[0,  0,  -inf, -inf], 

[0,  0,   0,  -inf], 

[0,  0,   0,   0]] 

 

1 2 3 4 

 

Decoder Block(Decoder Layer) 

Decoder中的一个层包含了2层注意力机制+1层FFN 

 

示例代码如下: 

 

1111 

 

完整的Decoder 

将DecoderLayer堆叠n_layer次,添加word embedding与positional encoding,以及线性层。 

 

线性层经过SoftMax处理后,输出的dec_outputs为对目标序列的预测 

 

示例代码如下: 

 

1212 

 

完整的Transformer 

有了Encoder和Decoder,Transformer的实现就非常简单了。 

 

详见注释 

 

class Transformer(nn.Cell): 

    def __init__(self, encoder, decoder): 

        super().__init__() 

        self.encoder = encoder 

        self.decoder = decoder 

         

    def construct(self, enc_inputs, dec_inputs, src_pad_idx, trg_pad_idx): 

        """ 

        enc_inputs: [batch_size, src_len] 

        dec_inputs: [batch_size, trg_len] 

        """ 

        # encoder的输出:源序列信息tensor 

        # en_outputs 的 shape:[batch_size,src_len,d_model] 

        enc_outputs, enc_self_attns = self.encoder(enc_inputs, src_pad_idx) 

  

        # dec_outputs 的 shape:[batch_size,trg_len,trg_vocab_size]  

        # trg_len:预测词的长度,包含了所有预测词 

        # trg_vocab_size:对每个词典都预测了一个概率 

        dec_outputs, dec_self_attns, dec_enc_attns = self.decoder(dec_inputs, enc_inputs, enc_outputs, src_pad_idx, trg_pad_idx) 

  

        # dec_logits的shape:[batch_size*trg_len,trg_vocab_size] 

        # 变换:前2个维度合并,方便后续计算每个词的最大概率 

        dec_logits = dec_outputs.view((-1, dec_outputs.shape[-1])) 

  

        return dec_logits, enc_self_attns, dec_self_attns, dec_enc_attns 

 

 

FAQ 

1.以 Transformer 为代表的的 Neuron Network 为什么能表达复杂信息,有什么优势? 

层数足够,可以表达任意复杂度的信息。通用逼近定理(Universal Approximation Theorem)表明,一个具有足够多神经元的单隐藏层前馈神经网络可以以任意精度逼近任何连续函数。 

非线性映射能力:神经网络中的每个神经元都通过非线性激活函数对输入进行变换,从而使网络具有了非线性映射能力。多层神经网络通过组合多个非线性变换,可以逐步构建出更复杂的非线性映射,从而实现对任意复杂度的信息的表示和学习。 

大规模并行计算:神经网络中的多个过程,比如多层encoder,多头注意力等可以通过高度并行,GPU运算等方式高效进行,能够处理大量的输入特征和参数 

优势 

灵活性:可以通过调整网络架构和参数适应不同的数据和任务 

自动特征学习:可以无需手工设计特征提取器 

自动端到端学习:可以实现直接从原始输入到最终输出结果,无需人工介入。 

2.Transformer中有那些注意力(Attention)机制? 

Encoder的自注意力机制和多头注意力机制 

Decoder的自注意力机制和多头注意力机制 

Encoder-Decoder的注意力机制:第一个Decoder Layer会使用最后一个Encoder的输出作为key和Value 

自注意力机制:用于捕捉输入序列中不同位置之间的依赖关系,以提取输入序列的表示 

 

多头注意力机制:用于捕获不同维度的不同位置之间的依赖关系 

 

3.Encoder和Decoder中的Attention有什么不同? 

由于Decoder与Encoder有以下2点不同: 

 

掩码不同:Decoder多了一层Masked Multi head attention 

输入不同:Decoder的输入来源除了encoder的输出还有目标输出序列 

导致了以下第3个不同: 

 

位置编码不同:目标输出序列中也带了位置编码信息,所以Decoder的位置编码信息也有2个来源 

4.Attention中如何使用Masking(掩码)的? 

掩码起到遮掩,隐藏的作用,一般是为了隐藏未来的信息。 

 

通过将要被mask的位置对应的注意力分数设置为负无穷大,softmax函数在计算权重或概率时,就导致某个数据乘以负无穷大后,数据仍然是负无穷大,从而丢弃这些信息。 

 

Encoder中使用掩码防止模型在处理输入时,关注到当前位置之后的信息 

Decoder中使用掩码防止模型在生成输出序列时,关注到当前位置之后的信息 

Encoder-Decoder中使用掩码防止Decoder在使用Encoder的输入序列时,关注到未处理的信息。 

5.为什么在获取输入词向量之后需要对矩阵乘以embedding size的开方?意义是什么? 

为了保持向量的尺度稳定。Embedding的值通常是随机初始化的,乘以开方后的结果能保证在后续的点乘计算中,值的尺度不会过大或过小,从而有利于模型的训练稳定性。 

 

6.Transformer中的残差结构是什么?有什么意义? 

Transformer中的残差结构(Residual Connection)是在每个子层输出后,加入输入的原始信息,通过直接相加实现。这有助于缓解深层网络中的梯度消失问题,保证信息流的顺畅,促进训练过程的稳定和快速收敛 

 

7.Decoder阶段的多头自注意力和encoder的多头自注意力有什么区别? 

Decoder阶段的多头自注意力需要进行sequence mask,以防止模型在训练时看到未来的单词。 

 

8.Transformer的并行化提现在哪个地方?Decoder端可以做并行化吗? 

Transformer的并行化体现在注意力机制和前馈神经网络上,因为每个时间步的计算彼此独立。 

 

Decoder端不能完全并行化,因为当前步的输出依赖于前一步的结果,但自注意力机制部分可以并行化 

 

9.Transformer训练的时候学习率是如何设定的? 

预热策略: Transformer通常使用预热(warm-up)策略和学习率衰减相结合的方法。在训练的前一部分迭代中,学习率逐渐增加,然后按照预定的方式逐渐减少。 

 

10.Transformer中使用Dropout是如何设定的? 

Transformer中使用Dropout层来防止过拟合,具体位置包括: 

 

自注意力机制中的注意力权重计算后。 

前馈神经网络的输出。 

残差连接后的输出。 

设定:通常Dropout概率设定为0.1,但可以根据具体任务和数据进行调整 

 

测试时:不使用Dropout:在测试或推理阶段,Dropout不再使用,即不会随机丢弃节点,而是使用所有节点参与计算 

 

11. Transformer中有那些可训练的参数?分别是什么功能? 

Embedding 层: 

功能: 将输入词汇映射到稠密向量表示。 

 

可训练参数: Embedding矩阵。 

 

Positional Encoding: 

功能: 为序列中的每个位置添加位置信息。 

 

可训练参数: 在某些实现中,位置编码可能是固定的(例如基于正弦和余弦函数),但在其他实现中也可以是可学习的。 

 

Multi-Head Attention: 

功能: 允许模型关注不同位置的不同表示子空间。 

 

可训练参数: Query、Key 和 Value 的线性变换权重矩阵。 

 

Add & Norm (残差连接与层归一化): 

功能: 在注意力层和前馈网络层之后添加残差连接,并对其进行归一化处理。 

 

可训练参数: 归一化层中的缩放因子(通常为γ)和偏移项(通常为β)。 

 

Feed Forward Networks (FFN): 

功能: 提供非线性变换,增强模型的学习能力。 

 

可训练参数: FFN 中的权重矩阵和偏置项。 

 

Output Layer: 

功能: 将Transformer的输出转换为最终的概率分布或分类标签。 

 

可训练参数: 输出层的权重矩阵和偏置项。 

 

Dropout: 

功能: 在训练过程中随机丢弃一部分神经元的输出,用以减少过拟合。 

 

可训练参数: Dropout本身没有可训练参数,但其行为受超参数控制。 

 

请注意,虽然dropout不包含可训练参数,但它对于调整模型的泛化能力至关重要,并且是模型训练过程的一部分。 

本帖最后由 匿名用户2024/09/02 15:28:22 编辑

我要发帖子