【NLP相关】Transformer模型:从Seq2Seq到自注意力机制(Transformer原理、公式推导和案例)

news2024/10/6 6:00:55

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️

👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈

Transformer

【NLP相关】Transformer模型:从Seq2Seq到自注意力机制

自然语言处理(NLP)是人工智能(AI)领域中的一个重要分支。在NLP领域中,Transformer模型是目前最先进的模型之一,它通过引入自注意力机制和编码器-解码器结构,显著提高了NLP任务的性能。本文将介绍Transformer模型的原理、优势和劣势,并提供相应的案例和代码。

1. Transformer模型的原理

Transformer模型最初用于解决序列到序列(Seq2Seq)的问题,例如翻译任务。在传统的Seq2Seq模型中,编码器将源语言序列转换为固定长度的向量,解码器再将此向量转换为目标语言序列。这种方法存在的一个问题是,如果源语言序列很长,则编码器无法捕捉到其完整的语义信息。

Transformer模型通过引入自注意力机制来解决这个问题。自注意力机制允许模型在编码阶段动态地关注输入序列中的不同部分,从而更好地捕捉其语义信息。此外,Transformer模型使用了多头注意力机制和残差连接等技术,使得模型能够更好地处理长序列,并提高模型的鲁棒性和泛化能力。

Transformer模型的结构包括编码器和解码器。编码器和解码器都由多个编码器层和解码器层组成。每个编码器层包括自注意力机制和全连接层,而每个解码器层包括自注意力机制、编码器-解码器注意力机制和全连接层。

2. Transformer模型的优势和劣势

Transformer模型的优势主要有以下几个方面:

  • (1)处理长序列的能力
    由于引入了自注意力机制和多头注意力机制,Transformer模型可以处理长序列,而不会出现信息丢失的问题。

  • (2)并行计算的能力
    由于不需要像循环神经网络(RNN)一样依次计算序列中的每个元素,因此Transformer模型的计算效率比RNN更高,并且可以方便地进行并行计算。

  • (3)易于实现和调整
    Transformer模型的结构简单,易于实现和调整,因此适用于各种不同的NLP任务。

然而,Transformer模型也存在一些劣势:

  • (1)需要大量的计算资源
    由于模型的结构较为复杂,因此需要大量的计算资源来训练和部署模型。

  • (2)容易过拟合
    对于一些简单的NLP任务,Transformer模型的性能可能不如同其他复杂的深度学习模型一样,Transformer模型可能会过度拟合,并且需要大量的数据和超参数调整来提高性能。

3. 公式推导

下面我们对Transformer模型的公式进行推导。在Transformer模型中,输入序列经过一个编码器(Encoder)和一个解码器(Decoder)来生成输出序列。编码器和解码器都由多个层组成,每个层都包括一个多头自注意力(Multi-Head Self-Attention)和一个前馈神经网络(Feedforward Neural Network)子层。

我们首先介绍一下自注意力机制(Self-Attention)。在传统的注意力机制中,我们需要将输入序列和上下文向量(Context Vector)进行加权求和,得到一个加权后的序列表示。而在自注意力机制中,我们将输入序列作为键(Key)、值(Value)和查询(Query)进行处理,并利用它们之间的相似性来计算加权和。

假设我们有一个长度为 n n n 的输入序列 x = ( x 1 , x 2 , . . . , x n ) \mathbf{x} = (x_1, x_2, ..., x_n) x=(x1,x2,...,xn),我们将 x \mathbf{x} x 中的每个元素经过一个嵌入层(Embedding Layer)转换为一个 d d d 维的向量表示,得到一个矩阵 X ∈ R n × d \mathbf{X} \in \mathbb{R}^{n \times d} XRn×d。我们将 X \mathbf{X} X 作为查询、键和值进行处理,得到三个矩阵 Q , K , V ∈ R n × d \mathbf{Q}, \mathbf{K}, \mathbf{V} \in \mathbb{R}^{n \times d} Q,K,VRn×d。我们可以使用点积(Dot Product)、缩放点积(Scaled Dot Product)或其他方法来计算 Q \mathbf{Q} Q K \mathbf{K} K 之间的相似性得分矩阵 S ∈ R n × n \mathbf{S} \in \mathbb{R}^{n \times n} SRn×n,并将得分矩阵通过 Softmax 函数归一化得到注意力矩阵 A ∈ R n × n \mathbf{A} \in \mathbb{R}^{n \times n} ARn×n
S = Q K T S=QK^T S=QKT
A = S o f t m a x ( S d ) A=Softmax(\frac{S}{\sqrt{d}}) A=Softmax(d S)
其中 d \sqrt{d} d 是一个缩放因子,用来防止内积的值过大或过小。注意力矩阵 A \mathbf{A} A 中的每一行表示输入序列中一个位置对于所有位置的注意力权重,即该位置应该关注输入序列中的哪些位置。然后,我们将注意力矩阵 A \mathbf{A} A 与值矩阵 V \mathbf{V} V 相乘,得到一个加权和向量 C ∈ R n × d \mathbf{C} \in \mathbb{R}^{n \times d} CRn×d

C = A V C=AV C=AV
注意力机制的优势在于它能够自适应地对输入序列进行不同程度的关注,从而捕捉输入序列中的重要信息。同时,由于自注意力机制可以同时计算多个位置的注意力权重,因此可以很容易地进行并行计算。

在Transformer 模型中,我们还引入了多头自注意力机制(Multi-Head Self-Attention),它可以将单个自注意力机制拆分为多个子空间,并在每个子空间上执行自注意力机制,从而更好地捕捉不同层次和不同角度的特征。具体来说,我们将输入序列和上下文向量分别转换为 h h h 组查询、键和值,得到 h h h 组注意力矩阵 A 1 , A 2 , . . . , A h {\mathbf{A}_1, \mathbf{A}_2, ..., \mathbf{A}_h} A1,A2,...,Ah,并将它们拼接起来得到一个增广矩阵 A ∈ R n × h d \mathbf{A} \in \mathbb{R}^{n \times h d} ARn×hd,然后通过一个线性变换将其转换为最终的加权和向量 C ∈ R n × d \mathbf{C} \in \mathbb{R}^{n \times d} CRn×d。这个过程可以用下面的公式表示:
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , h e a d 2 , . . . , h e a d h ) W 0 MultiHead(Q,K,V) = Concat(head_1,head_2,...,head_h)W^0 MultiHead(Q,K,V)=Concat(head1,head2,...,headh)W0
w h e r e where where
h e a d i = S e l f A t t e n t i o n ( Q W 0 Q , K W i K , V W i V ) head_i=SelfAttention(QW^Q_0,KW^K_i,VW^V_i) headi=SelfAttention(QW0Q,KWiK,VWiV)
W i Q , W i K , W i V ∈ R d × d / h , W O ∈ R h d × d W^Q_i,W^K_i,W^V_i\in R^{d\times d/h},W^O\in R^{hd \times d} WiQ,WiK,WiVRd×d/h,WORhd×d

其中, SelfAttention \text{SelfAttention} SelfAttention 表示单个自注意力机制, Concat \text{Concat} Concat 表示拼接操作, W i Q , W i K , W i V \mathbf{W}^Q_i, \mathbf{W}^K_i, \mathbf{W}^V_i WiQ,WiK,WiV 分别表示第 i i i 组查询、键和值的权重矩阵, W O \mathbf{W}^O WO 表示线性变换的权重矩阵。

多头自注意力机制的优势在于它可以捕捉不同子空间之间的交互,从而更好地表示输入序列中的特征。例如,在语言模型任务中,一个头可能更加关注输入序列中的词性信息,而另一个头可能更加关注输入序列中的语义信息。通过多头自注意力机制,我们可以同时考虑这两种信息,并将它们整合到最终的表示中。

除了多头自注意力机制,Transformer 模型中还引入了前馈神经网络(Feedforward Neural Network)子层。前馈神经网络子层由两个线性变换和一个激活函数组成,其中第一个线性变换将输入向量转换为一个中间表示向量,第二个线性变换将中间表示向量转换为最终表示向量。具体来说,我们可以将输入向量 x \mathbf{x} x 在前馈神经网络子层中表示为:
F F N ( x ) = R E L U ( x W 1 + b 1 ) W 2 + b 2 FFN(x)=RELU(xW_1+b_1)W_2+b_2 FFN(x)=RELU(xW1+b1)W2+b2

其中, W 1 , W 2 ∈ R d hidden × d \mathbf{W}_1, \mathbf{W}2 \in \mathbb{R}^{d{\text{hidden}} \times d} W1,W2Rdhidden×d b 1 ∈ R d hidden \mathbf{b}1 \in \mathbb{R}^{d{\text{hidden}}} b1Rdhidden b 2 ∈ R d \mathbf{b}_2 \in \mathbb{R}^{d} b2Rd ReLU \text{ReLU} ReLU 表示整流线性单元激活函数。

前馈神经网络子层的优势在于它可以在不改变序列长度的情况下,通过非线性变换和增加参数的方式扩展模型的表示能力。通过前馈神经网络子层,Transformer 模型可以更好地学习序列中的非局部特征,例如长距离依赖关系等。

最后,Transformer 模型还引入了残差连接和层归一化,用于加速模型的收敛和提高模型的表达能力。具体来说,残差连接可以使模型更容易训练,避免了梯度消失和梯度爆炸问题;层归一化可以加速模型的收敛,同时提高模型的鲁棒性和泛化能力。

4. 案例和代码

我们以情感分类任务为例,介绍Transformer模型的实现。我们使用IMDB电影评论数据集,其中包含25,000条电影评论,每条评论有一个二元标签,表示正面或负面情感。

我们使用PyTorch深度学习框架实现Transformer模型,代码如下所示:

import torch
import torch.nn as nn
import torch.optim as optim
from torchtext.datasets import IMDB
from torchtext.data import Field, LabelField, BucketIterator

class TransformerModel(nn.Module):
    def __init__(self, input_dim, emb_dim, n_heads, n_layers, hidden_dim, output_dim, dropout):
        super().__init__()
        self.embedding = nn.Embedding(input_dim, emb_dim)
        self.positional_encoding = PositionalEncoding(emb_dim, dropout)
        self.encoder_layers = nn.ModuleList([EncoderLayer(emb_dim, n_heads, hidden_dim, dropout) for _ in range(n_layers)])
        self.fc = nn.Linear(emb_dim, output_dim)

    def forward(self, src):
        embedded = self.embedding(src)
        positional_encoded = self.positional_encoding(embedded)
        encoded = positional_encoded
        for layer in self.encoder_layers:
            encoded = layer(encoded)
        mean_encoded = encoded.mean(dim=1)
        output = self.fc(mean_encoded)
        return output

class PositionalEncoding(nn.Module):
    def __init__(self, emb_dim, dropout, max_len=5000):
        super().__init__()
        self.dropout = nn.Dropout(p=dropout)
        self.pe = torch.zeros(max_len, emb_dim)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, emb_dim, 2).float() * (-math.log(10000.0) / emb_dim))
        self.pe[:, 0::2] = torch.sin(position * div_term)
        self.pe[:, 1::2] = torch.cos(position * div_term)
        self.pe = self.pe.unsqueeze(0)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1)]
        return self.dropout(x)

class EncoderLayer(nn.Module):
    def __init__(self, emb_dim, n_heads, hidden_dim, dropout):
        super().__init__()
        self.self_attn = nn.MultiheadAttention(emb_dim, n_heads, dropout)
        self.layer_norm1 = nn.LayerNorm(emb_dim)
        self.positionwise_feedforward = nn.Sequential(
            nn.Linear(emb_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, emb_dim),
            nn.Dropout(p=dropout),
        )
        self.layer_norm2 = nn.LayerNorm(emb_dim)
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, src):
        src2, _ = self.self_attn(src, src, src)
        src = src + self.dropout(src2)
        src = self.layer_norm1(src)
        src2 = self.positionwise_feedforward(src)
        src = src + self.dropout(src2)
        src = self.layer_norm2(src)
        return src

TEXT = Field(tokenize='spacy', lower=True, include_lengths=True)
LABEL = LabelField(dtype=torch.float)

train_data, test_data = IMDB.splits(TEXT, LABEL)

MAX_VOCAB_SIZE = 25_000
TEXT.build_vocab(train_data, max_size=MAX_VOCAB_SIZE)
LABEL.build_vocab(train_data)

BATCH_SIZE = 64

train_iterator, test_iterator = BucketIterator.splits(
													(train_data, test_data),
													batch_size=BATCH_SIZE,
													sort_within_batch=True,
													device=device)

INPUT_DIM = len(TEXT.vocab)
EMB_DIM = 256
N_HEADS = 8
N_LAYERS = 4
HIDDEN_DIM = 512
OUTPUT_DIM = 1
DROPOUT = 0.1

model = TransformerModel(INPUT_DIM, EMB_DIM, N_HEADS, N_LAYERS, HIDDEN_DIM, OUTPUT_DIM, DROPOUT).to(device)

optimizer = optim.Adam(model.parameters())
criterion = nn.BCEWithLogitsLoss().to(device)

def train(model, iterator, optimizer, criterion):
	model.train()
	epoch_loss = 0
	epoch_acc = 0
	for batch in iterator:
		src, src_len = batch.text
		optimizer.zero_grad()
		output = model(src.to(device)).squeeze(1)
		loss = criterion(output, batch.label.to(device))
		acc = binary_accuracy(output, batch.label.to(device))
		loss.backward()
		optimizer.step()
		epoch_loss += loss.item()
		epoch_acc += acc.item()
	return epoch_loss / len(iterator), epoch_acc / len(iterator)

def evaluate(model, iterator, criterion):
	model.eval()
	epoch_loss = 0
	epoch_acc = 0
	with torch.no_grad():
		for batch in iterator:
			src, src_len = batch.text
			output = model(src.to(device)).squeeze(1)
			loss = criterion(output, batch.label.to(device))
			acc = binary_accuracy(output, batch.label.to(device))
			epoch_loss += loss.item()
			epoch_acc += acc.item()
	return epoch_loss / len(iterator), epoch_acc / len(iterator)

def binary_accuracy(preds, y):
	rounded_preds = torch.round(torch.sigmoid(preds))
	correct = (rounded_preds == y).float()
	acc = correct.sum() / len(correct)
	return acc

N_EPOCHS = 10

for epoch in range(N_EPOCHS):
	train_loss, train_acc = train(model, train_iterator, optimizer, criterion)
	valid_loss, valid_acc = evaluate(model, test_iterator, criterion)
	print(f'Epoch: {epoch+1:02}')
	print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc100:.2f}%')
	print(f'\t Val. Loss: {valid_loss:.3f} | Val. Acc: {valid_acc100:.2f}%')

在这个示例中,我们使用了nn.MultiheadAttentionnn.LayerNorm和线性层等PyTorch中的标准模块来构建Transformer模型的编码器。我们还定义了一个Positional Encoding模块来对输入的序列进行编码,以便模型能够理解单词在序列中的位置。模型的损失函数为二元交叉熵损失,优化器为Adam。

5. 一些常见的基于Transformer构建实现的模型

  • BERT(Bidirectional Encoder Representations from Transformers) 模型:BERT 模型是由 Google 在 2018 年提出的一种预训练模型,它基于 Transformer 模型,并使用了双向的上下文信息,从而更好地学习文本的表示。BERT 模型已经在众多自然语言处理任务上取得了最优的效果,例如文本分类、问答系统、命名实体识别等。
  • GPT(Generative Pre-trained Transformer) 模型:GPT 模型是由 OpenAI 在 2018 年提出的一种预训练模型,它同样基于 Transformer 模型,并使用了单向的上下文信息,从而更好地生成文本。GPT 模型已经在自然语言生成和文本生成任务上取得了最优的效果。
  • XLNet(eXtreme MultiLingual & MultiTasked Pretraining) 模型:XLNet 模型是由 CMU 和 Google 在 2019 年提出的一种预训练模型,它基于 Transformer 模型,并使用了全局的上下文信息,从而更好地学习文本的表示。XLNet 模型已经在多语言和多任务的自然语言处理任务上取得了最优的效果。
  • T5(Text-to-Text Transfer Transformer) 模型:T5 模型是由 Google 在 2020 年提出的一种预训练模型,它基于 Transformer 模型,并使用了文本到文本的转换方式,从而更好地实现了通用的自然语言处理能力。T5 模型已经在多个任务上取得了最优的效果,例如机器翻译、摘要生成、问答系统等。

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️

👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/385736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

逆向练习之 mingyue.exe wp

目录 一.查壳 二.主函数 三.operate函数 四.storage函数及4618和4620指针功能的解释 五.judge函数 六.求解flag 七.其他--ida字符识别问题 一.查壳 64位无壳 二.主函数 1.这里的pointer_4618和4620是两个相邻的八字节内存单元,其中4620是字符串链表表头head 2.puts和s…

自动驾驶规划 - 5次多项式拟合

简介 自动驾驶运动规划中会用到各种曲线,主要用于生成车辆的轨迹,常见的轨迹生成算法,如贝塞尔曲线,样条曲线,以及apollo EM Planner的五次多项式曲线,城市场景中使用的是分段多项式曲线,在EM …

springCloud之OAuth2

认证授权过程 在认证和授权的过程中涉及的三方包括: 1、服务提供方,用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表。 2、用户,存放在服务提供方的受保护的资源的拥有者。 3、客户端&am…

【spring】事务

概述 1、什么事务 事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败 2、事务四个特性(ACID) (1)原子性 (2)一致性 (3…

java语言跨平台的特性:“一次编译,到处运行”

“一次编译,到处运行”是java语言跨平台的特性,平台指的是操作系统平台。 程序从源代码到运行的三个必经阶段:编码——编译——运行,调试。 首先编码阶段,需要编码语言是一个程序设计语言,而我们的java是程…

ChatGPT解答:python大批量读写ini文件时,性能很低,有什么解决方法吗,给出具体的思路和实例

ChatGPT解答: python大批量读写ini文件时,性能很低,有什么解决方法吗,给出具体的思路和实例 ChatGPTDemo Based on OpenAI API (gpt-3.5-turbo). python大批量读写ini文件时,性能很低,有什么解决方法吗&…

springboot工程搭建的几种方式

一、通过idea工具搭建,如下: 新建Project和Module,选择Spring initializr,点击Next,进入到如下页面填写 填写完后点击Next 到如下页面,根据你的具体所需,选择要使用的技术依赖 点击Next 点击FIn…

巾帼绽芬芳 一起向未来(中篇)

编者按:为了隆重纪念纪念“三八”国际妇女节113周年,快来与你全方位、多层次分享交流“三八”国际妇女节的前世今生。分上篇(节日简介、节日发展和节日意义)、中篇(节日活动宗旨和世界各国庆祝方式)和下篇&…

云原生之docker网络详解

云原生之docker网络详解一、相关概念1.2、CNM1.3、libnetwork二、实操2.1、docker network常用命令2.2、运行一个docker容器,查看CNM三个概念2.3、查看docker0在内核路由表上的记录2.4、查看网络列表2.5、网络隔离效果展示2.6、host驱动网络一、相关概念 1.1、网桥…

链表经典刷题--快慢指针与双指针

本篇总结链表解题思路----快慢指针,其实也就是双指针,这个快慢并不单纯指“快慢”,它更多的可以表示,速度快慢,距离长度,时间大小等等,用法很有趣也很独特,理解它的思想,…

「并发编程实战」常见的限流方案

「并发编程实战」常见的限流方案 文章目录「并发编程实战」常见的限流方案一、概述二、计数器限流方案三、时间窗口限流方案四、令牌桶限流方案五、漏桶限流方案六、高并发限流算法小结文章参考: 追忆四年前:一段关于我被外企CTO用登录注册吊打的不堪往事…

01 | n2n虚拟局域网

1 n2n简介 为了满足两个不同局域网的机器进行通信,让不同网段的机器能够进行P2P( 点对点 peer-to-peer ) 通信。2 n2n源码 https://github.com/ntop/n2n.git3 n2n名词 3.1 SuperNode 超级节点 SuperNode 相当与注册中心, 它会记录边缘节点的连接信息,…

案例09-数据类型不一致导致equals判断为false

一:背景介绍 在判断课程id和班级id的时候如果一致就像课程信息进行更新,如果不一致就插入一条新的数据。其实两个变量的值是一致的但是类型是不一致的。这就导致数据库中已经有一条这样的数据了,在判断的时候结果为false,就有插入…

【这一篇就够】mysql创建JSON数据的索引

一. 创建索引 由于json有两类不同的数据形式,即:json对象(如:{"id": 1, "name":"he"}),json数组(如:["1","2","3"]&…

nexus安装与入门

安装 nexus-3.31.1-01-unix.tar.gz 链接:https://pan.baidu.com/s/1YrJMwpGxmu8N2d7XMl6fSg 提取码:kfeh 上传到服务器,解压 tar -zvxf nexus-3.31.1-01-unix.tar.gz进入bin目录,启动 ./nexus start查看状态 ./nexus status默…

初始Linux操作系统

个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。个人主页:小李会科技的…

Linux常用命令等

目录 1.Linux常用命令 (1)系统命令 (2)文件操作命令 2.vim编辑器 3.linux系统中,软件安装 (1) rpm 安装,RedHat Package Manager (2)yum 安装 (3)源代码编译安装 1.Linux常用命令 Linux命令是非常多的,对于像嵌入式开发工程师,运维工程师需要掌握的命令是非常多的.对于…

旋转矩形框标注--roLabelImg的使用

1. 旋转目标标注roLabelImg roLabelImg是一款开源的,可标注带旋转角度的矩形区域的标注软件。roLabelImg源码github地址: https://github.com/cgvict/roLabelImg labelme和labelimg只能标矩形框,但不能标注旋转角度。roLabelImg既能标矩形框也能标注矩形框的选择角度,因此…

复旦发布中国版 ChatGPT :MOSS

不知道这个人工智能,有没有获得完整的一生。ChatGPT 是最先进的 AI,也是最热门的应用 —— 自去年 11 月底发布以来,它的月活跃用户两个月超过一亿,轻松拿到了全球互联网史上用户增长速度的第一。它也是一种门槛很高的技术。由于 …

服务预热配置化在泛型化方法上的实践

背景 由于开发过程中,个别dubbo接口的调用会在服务发布过程中,出现P99耗时报警问题。因此我们计划通过预热服务接口,通过预热来触发JIT,构建DB资源长链接。实现服务接口上线后,耗时过长,资源等待等问题&am…