深度学习理论基础(七)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_modelself.embed = nn.Embedding(vocab_size, d_model)def forward(self, x):return self.embed(x)

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

class PositionalEncoder(nn.Module):def __init__(self, d_model, max_seq_len = 200, dropout = 0.1):super().__init__()self.d_model = d_modelself.dropout = nn.Dropout(dropout)# create constant 'pe' matrix with values dependant on # pos and ipe = torch.zeros(max_seq_len, d_model)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 + 1))/d_model)))pe = pe.unsqueeze(0)self.register_buffer('pe', pe)def forward(self, x):# make embeddings relatively largerx = x * math.sqrt(self.d_model)#add constant to embeddingseq_len = x.size(1)pe = Variable(self.pe[:,:seq_len], requires_grad=False)if x.is_cuda:pe.cuda()x = x + pereturn 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 outputclass MultiHeadAttention(nn.Module):def __init__(self, heads, d_model, dropout = 0.1):super().__init__()self.d_model = d_modelself.d_k = d_model // headsself.h = headsself.q_linear = nn.Linear(d_model, d_model)self.v_linear = nn.Linear(d_model, d_model)self.k_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 headsk = self.k_linear(k).view(bs, -1, self.h, self.d_k)q = self.q_linear(q).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_modelk = 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

(4) 残差连接与规范化层:在多头自注意力层之后,通常会添加残差连接和规范化层来加速训练和提高模型稳定性。残差连接主要是保存原图信息,防止过拟合

"""规范化层"""
class Norm(nn.Module):def __init__(self, d_model, eps = 1e-6):super().__init__()self.size = d_model# create two learnable parameters to calibrate normalisationself.alpha = nn.Parameter(torch.ones(self.size))self.bias = nn.Parameter(torch.zeros(self.size))self.eps = epsdef forward(self, x):norm = self.alpha * (x - x.mean(dim=-1, keepdim=True)) \/ (x.std(dim=-1, keepdim=True) + self.eps) + self.biasreturn norm

(5) 前馈全连接层:在多头自注意力层之后,还有一个前馈全连接层,它对每个位置的词向量进行非线性变换和映射。

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 2048self.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):x2 = self.norm_1(x)x = x + self.dropout_1(self.attn(x2,x2,x2,mask))    #残差连接x2 = self.norm_2(x)x = x + self.dropout_2(self.ff(x2))return x    

(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 = Nself.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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

纯CSS实现未读消息显示99+

在大佬那看到这个小技巧&#xff0c;我觉得这个功能点还挺常用&#xff0c;所以给大家分享下具体的实现。当未读消息数小于100的时候显示准确数值&#xff0c;大于99的时候显示99。 1. 实现效果 2. 组件封装 <template><span class"col"><sup :styl…

JavaEE 初阶篇-深入了解线程池(线程池创建、线程池如何处理任务)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 线程池概述 1.1 线程池的优点 1.2 不使用线程池的问题 1.3 线程池的工作原理图 1.4 如何创建线程池&#xff1f; 2.0 通过 ThreadPoolExecutor 类自定义创建线程…

基于springboot+vue的地方美食分享网站(全套资料)

一、系统架构 前端&#xff1a;vue | element-ui 后端&#xff1a;springboot | mybatis-plus 环境&#xff1a;jdk8 | mysql | maven | node 二、代码及数据库 三、功能介绍 01. 用户端-登录 02. 用户端-首页 03. 用户端-外国美食 04. 用户端-中式美食 05. 用户端-热…

Centos7使用docker安装Jenkins(含pipeline脚本语句)

一、下载Jenkins docker pull jenkins/jenkins:lts 二、启动Jenkins docker run \-u root \--rm \-d \-p 8081:8080 \-p 50000:50000 \-v /root/docker/jenkins/var/jenkins_home:/var/jenkins_home \-v /var/run/docker.sock:/var/run/docker.sock \-v /usr/bin/docker:/usr…

2024.4.4-day09-CSS 布局模型(标准流模型、浮动模型)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.4-学习笔记1 CSS 布局模型1.1 标准流1.2 CSS 浮动1.3 去除塌陷 2…

记Postman参数化

因为需要在WEB页面上处理部分数据&#xff0c;手动操作太慢&#xff0c;所以考虑使用接口方式处理&#xff0c;因急于使用&#xff0c;用Python Request的方式&#xff0c;写代码也来得慢&#xff0c;故采用Postman加外部文件参数化方式来实现。 接口请求是Post方式&#xff0c…

光伏接口转接器配合光伏规约转换器实现发电用电信息采集支持接入各个型号逆变器

1.产品概述 DAQ-GP-485PIA光伏接口转接器&#xff08;以下简称转接器&#xff09;是我公司针对光伏发电领域国家电网公司最新需求设计的&#xff0c;光伏接口转接器是配合光伏规约转换器&#xff0c;实现逆变器发电、用电信息采集的设备。支持锦浪、古瑞瓦特、固德威、华为、奥…

115.不同的子序列

给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例 1&#xff1a; 输入&#xff1a;s "rabbbit", t "rabbit" 输出&#xff1a;3 解释&#xff1a; 如下所示, 有 3 种可以从 s 中…

[AI in sec]-039 DNS隐蔽信道的检测-特征构建

DNS隐蔽信道是什么 DCC是指利用DNS数据包中的可定义字段秘密传递信息的通道。其中,“DNS 协议”是目前网络上使用的标准域名解析协议;“可定义字段”是DNS 数据包中的 QNAME 字段、RDATA 字段及RawUDP字段。利用DNS数据包可以构建2种信道:存储信道及时间信道。DCC可以被用于…

CTF之GET和POST

学过php都知道就一个简单传参&#xff0c;构造payload:?whatflag得到 flag{3121064b1e9e27280f9f709144222429} 下面是POST那题 使用firefox浏览器的插件Hackbar勾选POST传入whatflag flag{828a91acc006990d74b0cb0c2f62b8d8}

通过Omnet++官网tictoc教程学习在Omnet++中构建和运行仿真 Part1Part2

introduce开始模型介绍构建项目添加 NED 文件添加C 文件添加 omnetpp.ini总结 运行仿真启动仿真程序运行仿真调试运行时错误崩溃断点调试下一事件 调试/运行 日志序列图可视化 Omnet官网 TicToc教学 introduce 在 Omnet安装完成后&#xff0c;samples/tictoc 中有该例子的完整…