NLP——自注意力机制和Bert

文字编码

图片本来就是数字组成的矩阵(张量),而文字是序列,需要通过编码,将一个文字编码为一个向量

输入一般为独热编码one-hot,一共21128个汉字,那么向量的长度就是21128,每个汉字的向量在对应向量上标1。

用独热编码输入一个字,通过全连接层fc,得到一个维度的输出(如768),表示该文字

文字的输出有三种:

每个文字都对应一个输出(词性识别)

一个句子对应一个输出(情感分析)

输入输出长度不对应(翻译任务)(这里不讨论这种,一般是生成任务)

在词性判断中,如果只有一个模型,做词性分类任务,那就会出现相同的字在一个句子中有不同的词性,应该考虑上下文来判断,RNN可以解决。

RNN(简易版)

通过将一个“传家宝”从头开始,每判断一个字的词性都将这个字输入进传家宝中,每次模型都会有两个输入输出,一个是字的词性,一个是新的传家宝,并将其用于下一次字输入进模型中,这样就能在判断当前字的词性时也能考虑前文的内容,综合判断词性。

如果传家宝中的某个内容,由于中间距离太远,受到干扰过多,导致后面无法清晰判断词性,因此lstm可以解决。

LSTM

LSTM是RNN的改进版,通过引入门控机制解决了RNN在处理长序列时的梯度消失问题。两者都依赖于循环结构来处理序列数据,但LSTM能够更好地捕捉长期依赖关系。

如果某个输入,比较“拉胯”,则将其上锁,不让其输入进传家宝,这样就影响不到后面了

RNN和LSTM的劣势就是太慢了!!要传家宝一个字一个字地传递

Self-attention 自注意力机制

rnn,lstm都是每个字都进入模型输出一个词性,而自注意力机制是输入一个句子(多个字),每个字都会有一个兼顾了上下文的特征,FC是分类头,经过了分类头得到一个输出

自注意力机制的优势

  • 并行化与传统的循环神经网络(RNN)相比,自注意力机制可以并行处理序列中的所有元素,大大提高了计算效率。RNN需要等待前面一个字得到输出后将隐藏状态传过来,才能进行第二个字的输入,是一种串行处理,计算效率很慢。
  • 长距离依赖:RNN在捕捉长距离的序列依赖时往往会遇到困难,因为梯度消失和梯度爆炸问题会导致模型难以学习长期依赖。自注意力机制通过直接计算序列中所有词元之间的关联性,能够更好地捕捉长距离依赖

  • 灵活的注意力权重自注意力机制为序列中的每个词元分配不同的注意力权重,这些权重可以根据上下文动态调整。RNN的权重通常是固定的,不太灵活。

注意力与输出

类似全连接,把注意力(类似权重)根据重要程度分配给每件事

每个元素对于输入的元素都有一个注意力权重,每个元素本身也有价值,将它们对应相乘并相加得到的就是输入元素的输出(类似卷积相乘再相加的过程)

注意力的计算:输入向量通过与一个Wq矩阵相乘(相当于变换了维度),得到了一个向量q(query查询  “扫码器”),再将每一个字向量都和另一个矩阵Wk相乘,得到多个向量 k1,k2...(key键 “二维码”),将q与每个k向量点乘(相当于每个字的二维码都去输入的扫码器那扫码),得到所有元素对应的一个值,将这个值再除以缩放因子\sqrt{d},d为k向量的维度,比如768。这样是防止进行点乘后的数值过大,导致通过softmax后梯度变得很小。

将所有得到的值组成的向量再通过softmax激活函数(相当于归一化),得到的就是一组所有token对于单个token的注意力概率向量(和为1)

得到注意力权重后,还需分别和每个元素的 v(value 价值)向量相乘再相加,得到的就是最后该token经过自注意力层的输出(输出和输入的维度是不会变的),而每个元素的 v 也是通过元素向量与一个Wv矩阵进行一次全连接维度变换得到的

后续每个token的输出过程相同(是并行输入的),就是用自身的扫码器query去扫每个元素的二维码key的过程,得到的就是每个元素的注意力权重\alpha,再将权重分别乘每个人的价值value再相加得到的就是输出

综上,其实整个自注意力机制就是在做矩阵运算,首先是a1,a2,a3,a4(假如有四个输入且都是78*1的向量)分别和Wq,Wk,Wv(768*768)三个方阵相乘,得到Q,K,V(768*4)三个矩阵

然后再进行“扫码”过程,即Q和K点乘,相当于KT*Q,等于一个4*4的矩阵,再通过除以\sqrt{d}经过softmax激活函数归一化后变成注意力矩阵4*4。

然后再将注意力矩阵和值V矩阵相乘得到最后的输出768*4,其中每一列都是一个输出,也就是说输入和输出的维度完全相同768*1,所有的矩阵运算,只有Wq,Wk,Wv三个矩阵是模型需要学习的参数(权重)矩阵

Transformer

Transformer架构是一种基于自注意力机制的深度学习模型,由Vaswani等人在2017年的论文《Attention is All You Need》中提出。它主要用于处理序列到序列(seq2seq)的任务,如机器翻译、文本摘要、语音识别等。Transformer模型摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),完全依赖于自注意力机制来捕捉输入序列中的长距离依赖关系。以下是Transformer模型的主要组成部分:

Transformer 架构

 编码器(Encoder)

Transformer的编码器由多个相同的层堆叠而成,每层包含两个主要子层:

  • 多头自注意力层(Multi-Head Self-Attention:允许模型在序列中的每个位置考虑所有其他位置的信息。
  • 前馈神经网络(Feed-Forward Neural Network):一个简单的全连接网络,用于进一步处理自注意力层的输出。

每个子层输出都会通过残差连接(Residual Connection)和层归一化(Layer Normalization)进行处理。

解码器(Decoder)

Transformer的解码器也由多个相同的层堆叠而成,每层包含三个主要子层:

  • 自注意力层:与编码器中的自注意力层类似,但有掩码(Masking)以防止未来位置的信息流入。
  • 编码器-解码器注意力层(Encoder-Decoder Attention Layer):允许解码器关注编码器的输出。
  • 前馈神经网络:与编码器中的前馈网络相同。

bert模型就是基于左边的编码器的一个预训练模型,而gpt就是基于右边解码器的一个模型

编码器 Encoder

编码器部分出了输入,都是由N个,如12个相同的层堆积而成

编码器输入

由于自注意力机制没有考虑位置信息,所以向输入序列中的每个token添加位置编码(Positional Encoding)来解决这个问题(有些问题最终需要输出相加,所以不同顺序的句子通过自注意力机制后得到的结果相加的值相等)具体的输入细节,在bert介绍了,只不过transformer输入少了一个segment embedding

多头注意力机制子层 Multi-Head Self-Attention

自注意力机制的改进,将Q,K,V分为多头分别处理,每个头可以学习到不同的注意力模式,关注不同的关系和特征。这增加了模型的表达能力,使其能够捕捉到更复杂和多样化的数据模式。

例如翻译一个句子,一个头负责关注别的token之间的语法关系,一个头关注语义关系等

  1. 线性变换:首先,对输入的序列分别与Wq,Wk,Wv三个共享的权重矩阵进行线性变换,以得到查询(Query,Q)、键(Key,K)和值(Value,V)三个矩阵,这一步和之前一样。

  2. 多头拆分:将每个矩阵(Q、K、V)拆分(均分)成多个头。视觉上看就是将QKV三个矩阵均分,但是本质上是通过了与每个头的权重矩阵相乘线性变换得到的。例如,如果我们分成2个头head,一共4个token,嵌入维度为768维,得到的初始QKV矩阵分别都是4*768维的矩阵。每一个头都会对应一组新的Wq,Wk,Wv子权重矩阵(类似多个卷积核,得到多个特征图的过程),将q向量都通过两组子权重矩阵后,会得到两个q1,q2向量,分别属于两个头。即4*768维的QKV经过“分割”,变成了两组4*384的Q1,K1,V1  Q2,K2,V2

  3. 每个头自注意力与输出计算:对于每个头,各自内部使用其对应的Q、K、V矩阵计算自注意力,再与v相乘得到每个token的输出,计算方式与之前完全相同。如果是两个头,则会得到两组输出,即两个4*386的输出

  4. 合并头的结果:将所有头的计算结果直接拼接起来(4*768 其实拼起来以后已经和输入的维度一样了),然后通过另一个线性层进行变换(乘一个权重矩阵Wo),得到最终的输出。输出的结果其实和输入也是一样的。这个线性变换的目的是将不同头学习到的表示合并起来,并且允许模型进一步调整这些特征的组合。

残差连接(Residual Connection)

残差连接不多做介绍,残差连接的优点在于它允许梯度直接流过网络,从而缓解了深层网络训练中的梯度消失问题,使得网络能够成功训练更深的架构(解决了失真问题)

通过自注意力层后,与残差连接相加的结果作为输出,还需要将这个输出做一个层归一化才能进入下一个子层

层归一化(Layer Normalization)

在Transformer模型中,层归一化被广泛使用,因为它能够处理变长的序列数据,并且不受到批量大小的限制。层归一化有助于模型快速收敛和稳定训练。

ps:这个图公式分子x多打了一点

层归一化和批量归一化相当于一个横向一个竖向

层归一化(Layer Normalization)

  • 层归一化是对单个样本的所有激活(元素)进行归一化,即对于每个样本,独立地对其所有特征进行归一化。
  • 它计算每个样本内特征的平均值和标准差,并使用这些统计量来缩放和偏移特征。
  • 层归一化不依赖于批量大小,因此适用于批量大小较小或变化的情况,如在RNNs或Transformer模型中的使用。

批量归一化(Batch Normalization)

  • 批量归一化会计算一个批次中所有样本在同一层的激活值的均值和方差,即对小批量内每个特征的所有样本的激活进行归一化。
  • 它计算小批量内每个特征的平均值和标准差,并使用这些统计量来缩放和偏移特征。
  • 批量归一化依赖于批量大小,因此批量大小不能太小,且在训练和推理时批量大小需要保持一致或进行适当的调整。

前馈神经网络(Feed-Forward Neural Network,FFN)

其实就是简单的线性变换,一层全连接 + relu激活函数 + 全连接,得到输出

FFN的目的是在自注意力层捕获的全局依赖关系的基础上,进一步处理和增强特征表示。在Transformer模型中,FFN与自注意力层交替出现,共同构建了模型的深度和复杂性

经过FFN后,同自注意力子层一样,也要通过残差连接,再通过一个层归一化,才得到子层的最终输出

解码器(Decoder)

敬请期待....

Bert

 bert是通过自监督预训练(一种无监督学习),将大量的文本数据训练出来的一个预训练模型(一种特征提取器,解码器),用于下游任务只需要微调

自监督预训练

预训练阶段得到的是编码器的参数,这些参数定义了模型如何将输入文本转换为深层次的嵌入表示。这些预训练的权重是后续微调阶段的基础,使得模型能够在特定任务上快速收敛并取得良好的性能。

  • Masked Language Model (MLM): 随机遮蔽输入序列中的一些tokens,然后模型尝试预测这些被遮蔽的tokens。这迫使模型学习上下文信息来理解每个token的含义。且遮住的部分(如15%)中,还会有80%是直接遮住的,15%会替换一个词,剩余的15%不变(虚晃模型增加复杂性)

  • Next Sentence Prediction (NSP): 给定两个句子A和B,模型预测B是否是A的下一句(两句话是否连续)。这有助于模型理解句子间的关系。

bert 结构

  1. 嵌入层(输入层) Input Embeddings

    • Token Embeddings:将单词或词元映射为固定大小的向量。
    • Segment Embeddings:区分输入序列中的不同句子或片段。
    • Positional Embeddings:捕捉词元在序列中的位置信息。
    • 这些嵌入会被相加得到每个词元的最终嵌入表示。
  2. 编码器层 Encoder

    • BERT由多个相同的编码器层堆叠而成,每个编码器层包括两个主要子层:
      • Multi-Head Self-Attention:允许模型在处理每个词元时同时考虑序列中的其他词元,捕捉不同词元之间的关系。
      • Positionwise Feed-Forward Networks:对每个位置上的词元分别应用前馈神经网络,以学习更复杂的特征表示。
    • 每个子层周围都有一个残差连接和层归一化步骤,以帮助训练深层网络。
  3. 输出层 pooler-output

    • BERT的输出可以是整个输入序列的编码表示,特别是序列中第一个词元(通常是一个特殊的分类词元 [CLS])的输出,常用于分类任务。
    • 也可以用池化提取出1*768维向量

       4.分类头 classifier

                将输出层的输出加过经过一个线性变换,转为目标维度的输出(如情感分析,就只要输 出二维向量即可)

bert 输入 Input Embeddings

1、分词 Tokenization

一个句子首先通过一个分词器tokenizer得到三个长度相同的输出向量input_ids,attention_mask,token_type_ids,这个过程是要我们自己进行的,三个向量作为bert的参数传入,传入bert模型后的处理都是预训练模型内部自动处理的,直到得到最后的Input Embeddings输入。

input_ids

表示句子划分并且通过了添加了特殊标记后的token序列形式(如开头加[CLS],每个句子末位加[SEP],这些特殊标记也是一个token,也有对应的索引),向量为一行多列,列数默认为序列的长度(token的个数),每个值表示的都是该token在词汇表中位置的索引,以此来找到词汇表中每个token表示的token embeddings向量。也可以指定向量长度,多余的部分用0填充,超出部分会被截断。如指定了最大长度为5,有4个token: [101,24,1331,102,0,0]

attention_mask

用于指示哪些位置是有真实token,哪些是填充的

  • 值为 1:表示该位置的 token 是实际数据,模型在处理时应考虑这部分信息。
  • 值为 0:表示该位置的 token 是填充数据,模型在自注意力计算时应忽略这些位置。

有token的位置就是1,填充的就为0,比如 [1,1,1,1,1,0,0]

token_type_ids

用于区分一个输入样本中的两个句子(情感分析这种,一个输入序列就属于一个句子,如果是问答,就有一问一答两个句子),序列为每个token分配一个标签,通常是0或1,表示它属于第一个句子还是第二个句子。如 [0,0,0,0,0,0]

2、嵌入层(Embedding Layer)

嵌入层最后的输入也由三个部分组成,且嵌入维度(如768)相同,最后的模型输入input是由三个部分相加得到的,嵌入层就是通过将上面传进来的三个参数向量,通过嵌入层的三个预训练权重矩阵来得到指定嵌入维度的输入的。注意,是每一个token都会对应3个768维的向量,相加得到每一个token的768维的input

Token Embeddings

将三个向量输入进bert后进入embedding嵌入层,嵌入层包含一个预训练的权重矩阵(即词汇查找表,如长为21128,嵌入维度为768,则矩阵为21128*768,参数量同矩阵大小),BERT模型的嵌入层会使用input_ids的索引值来查找每个token对应的token embeddings。如 4个token,映射得到的Token Embeddings就是 4*768的向量

Segment Embeddings(段落嵌入)

同上,也有一个预训练的权重矩阵(2*768),因为只能区分两个句子,嵌入层会根据传进来的token_type_ids知晓每个token的句子所属情况,最后得到768维的Segment Embeddings。如 4个token,映射得到的Segment Embeddings也是 4*768的向量

Position Embeddings(位置嵌入)

Position embeddings 是为了给模型提供序列中每个token的位置信息。由于selfattention不具备处理序列顺序的内在能力,位置嵌入通过向输入序列中的每个token添加位置信息来解决这个问题。bert有一个"max_position_embeddings",表示bert可以处理的最大不同位置数(一般为512),也就相当于最大的文本输入长度差不多为512。同时也有一个预训练的权重矩 512*768,也会根据每个token的位置信息得到一个768维的Position Embeddings

bert 输出 pooler-output

输入经过多层自注意力机制层是不会改变维度的,如果输入的是5*768的embedding向量,则自注意力层输出的也是5*768,但是最后只需要一维的结果(例如分类),所以先要经过一层pooler-output层,将5*768的矩阵转为1*768向量,最后再经过一个分类头linear,就能按照目标类别输出一个一维向量,如1*2情感分类。

虽然是叫pooler-output层,但是不一定使用了pooling池化的技术

pooler-output层

pooler-output输出层有多种方法降维,最常见的是直接取第一个token[CLS]作为结果输出:

  1. 获取[CLS] token作为输出:pooler层首先提取序列中第一个token(通常是 [CLS]的输出向量,这个向量是768维的。这个token的最终嵌入(经过Transformer编码器的多层处理后)被用来进行分类任务,如情感分析或文本分类。这是因为[CLS] token的嵌入被认为包含了整个序列的聚合信息。

  2. 平均池化输出:将5个768维向量加权求平均值的结果作为输出向量

分类头 classifier

将输出层的输出加过经过一个线性变换Linear,转为目标维度的输出(如情感分析,就只要输 出二维向量即可,即 1*768 -> 1*2向量),如果是分类任务还需要转化为概率的形式,即经过一个softmax激活函数得到最后的概率输出。

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
BERT(Bidirectional Encoder Representations from Transformers)是一种基于Transformer模型的预训练语言模型。它的核心是注意力机制,通过自注意力机制来编码和理解文本表示。 BERT注意力机制是通过计算输入序列中每个位置与其他位置之间的相关性来实现的。具体来说,BERT使用了多头自注意力机制,将输入序列分为多个子序列,并为每个子序列分配一个注意力头。每个注意力头都会计算每个位置与其他位置之间的相关性,并将这些相关性作为权重来加权计算每个位置的表示。 通过多头自注意力机制BERT能够捕捉到输入序列中不同位置之间的依赖关系和语义信息。这使得BERT能够更好地理解文本的上下文和语义,并生成更准确的文本表示。 下面是一个示例代码,示了如何使用BERT注意力机制来编码文本表示: ```python import torch from transformers import BertModel, BertTokenizer # 加载预训练的BERT模型和分词器 model_name = 'bert-base-uncased' tokenizer = BertTokenizer.from_pretrained(model_name) model = BertModel.from_pretrained(model_name) # 输入文本 text = "Hello, how are you?" # 分词和编码 tokens = tokenizer.encode(text, add_special_tokens=True) input_ids = torch.tensor([tokens]) # 获取注意力掩码 attention_mask = torch.ones(input_ids.shape) # 使用BERT模型编码文本表示 outputs = model(input_ids, attention_mask=attention_mask) # 获取编码后的文本表示 encoded_text = outputs.last_hidden_state # 打印编码后的文本表示 print(encoded_text) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值