深度学习理论基础(七)Transformer编码器和解码器

学习目录:

深度学习理论基础(一)Python及Torch基础篇
深度学习理论基础(二)深度神经网络DNN
深度学习理论基础(三)封装数据集及手写数字识别
深度学习理论基础(四)Parser命令行参数模块
深度学习理论基础(五)卷积神经网络CNN
深度学习理论基础(六)Transformer多头自注意力机制
深度学习理论基础(七)Transformer编码器和解码器

本文目录

  • 学习目录:
  • 前述: Transformer总体结构框图
  • 一、编码器encoder
    • 1. 编码器作用
    • 2. 编码器部分
      • (1)单个编码器层代码
      • (2)编码器总体代码
  • 二、解码器decoder
    • 1. 解码器作用
    • 2. 解码器部分
      • (1)单个解码器层代码
      • (2)解码器总体代码
  • 三、Transformer
    • 1. 框图
    • 2. 代码

  

前述: Transformer总体结构框图

在这里插入图片描述
(1)嵌入层:编码器的输入是一系列的词嵌入(Word Embeddings),它将文本中的每个词映射到一个高维空间中的向量表示。
  嵌入层的作用是将离散符号转换为连续的向量表示,降低数据维度同时保留语义信息,提供词语的上下文信息以及初始化模型参数,从而为深度学习模型提供了有效的输入表示。

class Embedder(nn.Module):
    def __init__(self, vocab_size, d_model):
        super().__init__()
        self.d_model = d_model
        self.embed = nn.Embedding(vocab_size, d_model)
    def forward(self, x):
        return self.embed(x)

(2)位置编码器:为了使 Transformer 能够处理序列信息,位置编码被引入到词嵌入中,以区分不同位置的词。通常使用正弦和余弦函数来生成位置编码。
  一句话中同一个词,如果词语出现位置不同,意思可能发生翻天覆地的变化,就比如:我爱你 和 你爱我。这两句话的意思完全不一样。可见获取词语出现在句子中的位置信息是一件很重要的事情。但是Transformer 的是完全基于self-Attention地,而self-attention是不能获取词语位置信息的,就算打乱一句话中词语的位置,每个词还是能与其他词之间计算attention值,就相当于是一个功能强大的词袋模型,对结果没有任何影响。所以在我们输入的时候需要给每一个词向量添加位置编码。
   位置编码是通过在输入序列的每个位置上添加一个与位置相关的固定向量来实现的。这个向量会在前向传播过程中与输入的词嵌入向量相加,以产生具有位置信息的新的向量表示。

●公式:
在这里插入图片描述
PE:表示位置编码矩阵,可先使用 torch.zeros(行,列) 创建一个全0的矩阵,然后再通过操作将其中的某些元素赋值,形成含有位置信息的矩阵。
pos:表示输入序列所在行的位置。范围0~输入序列矩阵行长度。
d_model :输入、输出向量的维度大小。
i:取值范围为 [ 0, d_model] ,但每次移动步长为2。 因为当 i 为偶数时,使用sin函数,当 i 为奇数时,使用cos函数。

●代码:

class PositionalEncoder(nn.Module):
    def __init__(self, d_model, max_seq_len = 200, dropout = 0.1):
        super().__init__()
        self.d_model = d_model   #输入维度
        self.dropout = nn.Dropout(dropout)

        pe = torch.zeros(max_seq_len, d_model)  # 创建一个形状为 (max_seq_len, d_model) 的位置编码矩阵,元素权威0
        for pos in range(max_seq_len):
            for i in range(0, d_model, 2):
                pe[pos, i]     = math.sin(pos / (10000 ** ((2 * i)/d_model)))
                pe[pos, i + 1] = math.cos(pos / (10000 ** ((2 * i)/d_model)))
                
        pe = pe.unsqueeze(0)   # 在第0维度上添加一个维度,变成 (1, max_seq_len, d_model)
        
        # PE位置编码矩阵其中的元素修改好后,可以注册位置编码矩阵为模型的 buffer,即封装起来。
        self.register_buffer('pe', pe) 
     
    def forward(self, x):
       # 将输入乘以一个与模型维度相关的缩放因子
        x = x * math.sqrt(self.d_model)
        # 将位置编码添加到输入中
        seq_len = x.size(1)
       	pe = self.pe[:, :seq_len].clone().detach()  # 从缓冲区中获取位置编码
       	
        if x.is_cuda:
            pe = pe.cuda()  # 将位置编码移到GPU上,如果输入张量也在GPU上
            
        x = x + pe         # 输入向量,加上位置编码器。
        return self.dropout(x)   # 加上丢弃层,防止过拟合。

(3)多头注意力层:这是编码器的核心组件之一。它允许模型在输入序列中学习词与词之间的依赖关系,通过计算每个词对其他词的注意力权重来实现。多头机制允许模型在不同的表示空间中并行地学习多种关注方向。多头注意力层详情查看地址!

def attention(q, k, v, d_k, mask=None, dropout=None): 
    scores = torch.matmul(q, k.transpose(-2, -1)) /  math.sqrt(d_k)
    
    if mask is not None:
        mask = mask.unsqueeze(1)
        scores = scores.masked_fill(mask == 0, -1e9)   
         
    scores = F.softmax(scores, dim=-1)
   
    if dropout is not None:
        scores = dropout(scores)
        
    output = torch.matmul(scores, v)
    return output

class MultiHeadAttention(nn.Module):
    def __init__(self, heads, d_model, dropout = 0.1):
        super().__init__()
        
        self.d_model = d_model  #输入向量的维度
        self.d_k = d_model // heads  #每个头分配向量的维度
        self.h = heads
        
        self.q_linear = nn.Linear(d_model, d_model)
        self.k_linear = nn.Linear(d_model, d_model)
        self.v_linear = nn.Linear(d_model, d_model)
               
        self.dropout = nn.Dropout(dropout)
        self.out = nn.Linear(d_model, d_model)
    
    def forward(self, q, k, v, mask=None):
        bs = q.size(0)
        # perform linear operation and split into N heads
        q = self.q_linear(q).view(bs, -1, self.h, self.d_k)
        k = self.k_linear(k).view(bs, -1, self.h, self.d_k) 
        v = self.v_linear(v).view(bs, -1, self.h, self.d_k)
        
        # transpose to get dimensions bs * N * sl * d_model
        k = k.transpose(1,2)
        q = q.transpose(1,2)
        v = v.transpose(1,2)
        
        scores = attention(q, k, v, self.d_k, mask, self.dropout)
        concat = scores.transpose(1,2).contiguous().view(bs, -1, self.d_model)
        output = self.out(concat)
    
        return output

 if __name__ == '__main__':  
		heads = 8
		d_model = 64
		
		# 创建输入张量 x2 和 mask
		# 假设 x2 和 mask 的形状为 [batch_size, seq_len, embedding_dim]
		batch_size = 16
		seq_len = 10
		embedding_dim = d_model
		
		x2 = torch.randn(batch_size, seq_len, embedding_dim)
		mask = torch.zeros(batch_size, seq_len)  # 假设没有特殊的 mask
		
		# 实例化 MultiHeadAttention 模型
		attn = MultiHeadAttention(heads, d_model, dropout=0.1)
		
		# 使用 MultiHeadAttention 进行前向传播
		output = attn(x2, x2, x2, mask)
		print(output.shape)  # 输出张量的形状

(4) 规范化层:用于在神经网络中对输入数据进行归一化操作。在多头自注意力层之后,通常会添加残差连接和规范化层来加速训练和提高模型稳定性。

●公式:
在这里插入图片描述
① α 是可学习的缩放参数。
② mean(x) 是输入张量 x 在最后一个维度上的均值。
③ std(x) 是输入张量 x 在最后一个维度上的标准差。
④ bias 是可学习的偏置参数。
⑤ eps 是一个非常小的数,用于防止分母为零。

●代码:

"""规范化层"""
class Norm(nn.Module):
    def __init__(self, d_model, eps = 1e-6):
        super().__init__()
    
        self.size = d_model  #输入维度
        
        # 创建了一个大小为 self.size 的张量,其中所有元素的值都初始化为 1。
        #并将这个张量转换为一个可学习的参数,使得它可以被模型访问和更新。
        self.alpha = nn.Parameter(torch.ones(self.size))
        self.bias = nn.Parameter(torch.zeros(self.size))
        
        self.eps = eps
    
    def forward(self, x):
        norm = self.alpha * (x - x.mean(dim=-1, keepdim=True)) / (x.std(dim=-1, keepdim=True) + self.eps) + self.bias
        return norm

(5) 残差连接:主要是通过将数据处理后与原数据相加来得到下一层新的输入数据。目的是为了保存原图信息,防止重要信息的丢失。残差连接使得模型能够更有效地传递梯度,并减轻了训练深层网络时的梯度消失问题。
   残差连接要求两个输入的形状相同,以便加法操作后输出张量的形状相同。
   通常情况下,残差连接被应用在规范化之后,因为这样可以确保输入和输出的分布一致性,并且有助于提高模型的稳定性和收敛速度。

(6) 前馈全连接层:在多头自注意力层之后,还有一个前馈全连接层,它对每个位置的词向量进行非线性变换和映射。这个前馈全连接层的作用是对输入张量进行两个线性变换,并通过激活函数进行非线性变换,以增加网络的表达能力。

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff=2048, dropout = 0.1):
        super().__init__() 
    
        # We set d_ff as a default to 2048
        self.linear_1 = nn.Linear(d_model, d_ff)
        self.dropout = nn.Dropout(dropout)
        self.linear_2 = nn.Linear(d_ff, d_model)
    
    def forward(self, x):
        x = self.dropout(F.relu(self.linear_1(x)))
        x = self.linear_2(x)
        return x

  

一、编码器encoder

1. 编码器作用

  编码器的作用是将输入序列转换为语义表示,学习输入序列中词与词之间的依赖关系,并提取输入序列的特征表示,为解码器生成目标序列提供有用的信息。
在这里插入图片描述

2. 编码器部分

(1)单个编码器层代码

在这里插入图片描述

  框图解析:对于输入数据,我们先将数据传入注意力机制,然后进行规范化。最后与原数据进行残差连接。前馈网络也如此。这种写法是框图上的顺序写法。但是为了是输入的数据是规范的数据,我们通常先将输入数据进行规范化操作,将规范后的数据传入注意力机制,然后与原数据进行残差连接。详细过程如下:

class EncoderLayer(nn.Module):
    def __init__(self, d_model, heads, dropout=0.1):
        super().__init__()
        self.norm_1 = Norm(d_model)  #定义两个规范化层
        self.norm_2 = Norm(d_model)
        self.attn = MultiHeadAttention(heads, d_model, dropout=dropout) #定义多头注意力层
        self.ff = FeedForward(d_model, dropout=dropout)   #前馈全连接层
        self.dropout_1 = nn.Dropout(dropout)   #定义两个丢弃层
        self.dropout_2 = nn.Dropout(dropout)
        
    def forward(self, x, mask):
       x1 = self.norm_1(x)
       x2 = x + self.dropout_1(self.attn(x1,x1,x1,mask))
       
       x3 = self.norm_2(x2)
       x4 = x2 + self.dropout_2(self.ff(x3))
       return x4   
      
       
"""    框图结构中的写法如下:  
    
    def forward(self, x, mask):
        x1 = self.dropout_1( self.attn(x,x,x,mask) ) #对输入进行注意力机制,并通过丢弃层,防止过拟合。
        x1 = self.norm_1(x1) #对x1进行规范化。
        x2 = x + x1    #进行残差连接,注意力中qkv全部来自自身。
        
        x3 = self.dropout_2(self.ff(x2)) #将残差连接后的数据传入前馈全连接层
        x3 = self.norm_2(x3) #对输入x2进行规范化
        x4 = x2 + x3  #进行残差连接
        return x4    
"""

(2)编码器总体代码

这里需要将上述的编码器层进行克隆复制n份。
在这里插入图片描述

 """编码器总体""   
 #克隆多层编码器层  
 def get_clones(module, N):
    return nn.ModuleList([copy.deepcopy(module) for i in range(N)])
 
class Encoder(nn.Module):
    def __init__(self, vocab_size, d_model, N, heads, dropout):
        super().__init__()
        self.N = N      #n个编码器层
        self.embed = Embedder(vocab_size, d_model)    #嵌入层
        self.pe = PositionalEncoder(d_model, dropout=dropout)   #位置编码
        self.layers = get_clones(EncoderLayer(d_model, heads, dropout), N) #复制n个编码器层
        self.norm = Norm(d_model)  #规范化层
        
    def forward(self, src, mask):
        x = self.embed(src)
        x = self.pe(x)
        for i in range(self.N):
            x = self.layers[i](x, mask)
        return self.norm(x)      #确保输出的数据为规范数据

  

二、解码器decoder

1. 解码器作用

在这里插入图片描述

2. 解码器部分

(1)单个解码器层代码

在这里插入图片描述

class DecoderLayer(nn.Module):
    def __init__(self, d_model, heads, dropout=0.1):
        super().__init__()
        self.norm_1 = Norm(d_model)   #定义规范化层
        self.norm_2 = Norm(d_model)
        self.norm_3 = Norm(d_model)
        
        self.dropout_1 = nn.Dropout(dropout)  #定义丢弃层
        self.dropout_2 = nn.Dropout(dropout)
        self.dropout_3 = nn.Dropout(dropout)
        
        self.attn_1 = MultiHeadAttention(heads, d_model, dropout=dropout)  #多头注意力层
        self.attn_2 = MultiHeadAttention(heads, d_model, dropout=dropout)
        self.ff = FeedForward(d_model, dropout=dropout)  #前馈全连接层

    def forward(self, x, e_outputs, src_mask, trg_mask):
        x2 = self.norm_1(x)
        x = x + self.dropout_1(self.attn_1(x2, x2, x2, trg_mask))
        x2 = self.norm_2(x)
        x = x + self.dropout_2(self.attn_2(x2, e_outputs, e_outputs, src_mask))
        x2 = self.norm_3(x)
        x = x + self.dropout_3(self.ff(x2))
        return x

  

(2)解码器总体代码

在这里插入图片描述

def get_clones(module, N):
    return nn.ModuleList([copy.deepcopy(module) for i in range(N)])

class Decoder(nn.Module):
    def __init__(self, vocab_size, d_model, N, heads, dropout):
        super().__init__()
        self.N = N
        self.embed = Embedder(vocab_size, d_model)   #嵌入层
        self.pe = PositionalEncoder(d_model, dropout=dropout) #位置编码
        self.layers = get_clones(DecoderLayer(d_model, heads, dropout), N) #复制n层解码器层
        self.norm = Norm(d_model)  #规范化层
    def forward(self, trg, e_outputs, src_mask, trg_mask):
        x = self.embed(trg)  
        x = self.pe(x)
        for i in range(self.N):
            x = self.layers[i](x, e_outputs, src_mask, trg_mask)
        return self.norm(x)

  

三、Transformer

1. 框图

在这里插入图片描述

2. 代码

class Transformer(nn.Module):
    def __init__(self, src_vocab, trg_vocab, d_model, N, heads, dropout):
        super().__init__()
        self.encoder = Encoder(src_vocab, d_model, N, heads, dropout)  #编码器总体
        self.decoder = Decoder(trg_vocab, d_model, N, heads, dropout)  #解码器总体
        self.out = nn.Linear(d_model, trg_vocab)  #全连接层输出
    def forward(self, src, trg, src_mask, trg_mask):
        e_outputs = self.encoder(src, src_mask) 
        d_output = self.decoder(trg, e_outputs, src_mask, trg_mask)
        output = self.out(d_output)
        return output
        
modle=Transformer()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE5、CesiumForUnreal实现加载建筑轮廓GeoJson数据生成白模功能

1.实现目标 在UE5.3中,通过加载本地建筑边界轮廓面GeoJson数据,获取底面轮廓和楼高数据,拉伸生成白模,并支持点选高亮。为防止阻塞Game线程,使用了异步任务进行优化,GIF动图如下所示: 其中建筑数量:128871,顶点索引数量:6695748,三角面数量:2231916,顶点数量:165…

golang 归并回源策略

前言 下面是我根据业务需求画了一个架构图,没有特别之处,很普通,都是我们常见的中间件,都是一些幂等性GET 请求。有一个地方很有意思,从service 分别有10000 qps 请求到Redis,并且它们的key 是一样的。这样…

CSS - 你遇到过动画卡顿的问题吗

难度级别:中高级及以上 提问概率:70% 回答这道题,首先要说的就是,浏览器在每一帧动画里大概做了什么事情。首先浏览器会执行Javascript,或是操作DOM元素,紧接着需要对DOM元素进行样式计算,当计算完成后,就需要针对DOM元素的位置以及大小…

2024年MathorCup妈妈杯数学建模思路D题思路解析+参考成品

1 赛题思路 (赛题出来以后第一时间在群内分享,点击下方群名片即可加群) 2 比赛日期和时间 报名截止时间:2024年4月11日(周四)12:00 比赛开始时间:2024年4月12日(周五)8:00 比赛结束时间&…

oracle hang分析使用

oracle hang分析测试 使用hang分析大部分原因在于产生锁资源的争用 1-2:只有hanganalyze输出,不dump任何进程 3:Level2Dump出在IN_HANG状态的进程 4:Level3Dump出在等待链里面的blockers(状态为LLEAF/LEAF_NW/IGN_DMP) 5&…

软件设计师29--并发控制

软件设计师29--并发控制 考点1:事务的特性例题: 考点2:并发问题并发产生的问题丢失更新不可重复读问题读“脏”数据 考点3:封锁协议例题: 考点1:事务的特性 原子性(Atomicity)&…

好文阅读-数据库-CREATE TABLE AS

添加链接描述 收获如下: 1 DROP DELETE TRUNCATE对比 2 CREATE TABLE AS 这种方式创建表不会复制表的索引,主键,外键约束,包括自增ID。因此应该使用 CREATE TABLE LIKE。 3 数据的处理可以通过建立临时表的方式,之后还…

【实战解析】YOLOv9全流程训练至优化终极指南

【实战解析】YOLOv9全流程训练至优化终极指南 0.引言1.环境准备2.数据预处理(1)数据准备(2)按比例划分数据集(3)xml转txt脚本(4)配置文件 3.模型训练(1)单GPU…

超越基准 | 基于每个高斯变形的3D高斯溅射方法及其高效训练策略

作者:小柠檬 | 来源:3DCV 在公众号「3DCV」后台,回复「原论文」可获取论文pdf 添加微信:dddvision,备注:3D高斯,拉你入群。文末附行业细分群 详细内容请关注3DCV 3D视觉精品课程:…

ctfshow web入门 命令执行 web53--web77

web53 日常查看文件 怎么回事不让我看十八 弄了半天发现并不是很对劲,原来我发现他会先回显我输入的命令再进行命令的回显 ?cnl${IFS}flag.php||web54 绕过了很多东西 基本上没有什么命令可以用了但是 grep和?通配符还可以用 ?cgrep${IFS}ctfshow${IFS}???…

JavaCollection集合--单列集合——JavaCollections类

目录 集合--->容器 代码 运行 Java集合API 单列集合 Collectio接口 List接口实现类 ArrayList 数组实现 概念 代码 运行 代码 ArrayList方法 代码 运行 LinkedList 链表实现 概念 代码 运行 Vector 数组实现 概念 代码 运行 List接口集合…

知识推理技术解析与实战

目录 一、引言二、知识推理基础知识表示方法本体论语义网络图形数据库 推理机制概述演绎推理归纳推理类比推理 实践代码示例 三、知识推理的核心技术自动推理系统规则引擎推理算法 知识图谱的运用构建知识图谱知识推理与查询 推理算法深度分析转导推理逻辑推理概率推理 实践代码…

java智慧校园系统源码+SaaS智慧学校系统源码+PC端

java智慧校园系统源码SaaS智慧学校系统源码PC端 有演示,可正常上线运营可授权PC端,SaaS服务模式开发环境:Javaspringbootvueelement-uimysql开发语言:JavaspringbootVUE 小程序 全套源码 建设一个一流的智慧校园,使先进…

MuJoCo 入门教程(五)Python 绑定

系列文章目录 前言 本笔记本提供了使用本地 Python 绑定的 MuJoCo 物理入门教程。 版权声明 DeepMind Technologies Limited 2022 年版权所有。 根据 Apache License 2.0 版(以下简称 "许可协议")授权;除非遵守许可协议&am…

操作系统1

概念 操作系统 组织和管理计算机系统中的软件和硬件,组织计算机系统工作流程、控制程序执行,提供给用户工作环境和友好的接口。 3个作用: 管理计算机中运行的程序和分配各种软硬件资源为用户提供友善的人机洁界面为应用程序的开发和运行提供…

二维相位解包理论算法和软件【全文翻译- 噪声滤波(3.53.6)】

3.5 噪音过滤 在本节中,我们将简要讨论相位数据的滤波问题。除了提高信噪比之外,噪声滤波还有助于减少残差的数量,从而大大简化相位解包过程。不过,我们必须注意到一个重要的问题。正如我们在第 1 章中指出的,相位本身并不是信号。它只是信号的一种属性。因此,应该过滤的…

ACM ICPS独立出版 | 第三届智能无人系统与人工智能国际会议(SIUSAI 2024)

会议简介 Brief Introduction 2024年第三届智能无人系统与人工智能国际会议(SIUSAI 2024) 会议时间:2024年5月17日-19日 召开地点:中国青岛 大会官网:www.siusai.org 2024年第三届智能无人系统与人工智能国际会议(SIUSAI 2024)由青岛大学主办…

基于java JSP 实现的固定资产管理系统

开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea 系统展示 前台首页功能模块 固…

UV胶水能够粘接聚苯乙烯PS吗?

UV胶水能够粘接聚苯乙烯PS吗? 聚苯乙烯(Polystyrene,简称PS)是一种常见的合成聚合物,属于热塑性塑料。它是由苯乙烯单体聚合而成的,具有轻质、透明或半透明、电绝缘性好等特点。常见: 包装材料白色泡沫塑料…

[ESP32] 用RMT模块做红外遥控发射

本文采用ESP32内部只带的RMT模块作为发送红外遥控的发射器。 红外协议来自 美的R05D功能说明书: https://wenku.baidu.com/view/c46594141ed9ad51f01df2c3.html 通常编码格式为: L,A,A’,B,B’,C,C’, S, L,A,A’,B,B’,C,C’ T第一帧和第二帧相同采用MSB在先&…