深度学习理论基础(七)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_modelself.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) 的位置编码矩阵,元素权威0for 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 outputclass 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 = headsself.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 headsq = 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_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 outputif __name__ == '__main__':  heads = 8d_model = 64# 创建输入张量 x2 和 mask# 假设 x2 和 mask 的形状为 [batch_size, seq_len, embedding_dim]batch_size = 16seq_len = 10embedding_dim = d_modelx2 = 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 = 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) 残差连接:主要是通过将数据处理后与原数据相加来得到下一层新的输入数据。目的是为了保存原图信息,防止重要信息的丢失。残差连接使得模型能够更有效地传递梯度,并减轻了训练深层网络时的梯度消失问题。
   残差连接要求两个输入的形状相同,以便加法操作后输出张量的形状相同。
   通常情况下,残差连接被应用在规范化之后,因为这样可以确保输入和输出的分布一致性,并且有助于提高模型的稳定性和收敛速度。

(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 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):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 = 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 outputmodle=Transformer()

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

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

相关文章

数据仓库面试总结

文章目录 1.什么是数据仓库?2.ETL是什么?3.数据仓库和数据库的区别(OLTP和OLAP的区别)4.数据仓库和数据集市的区别5.维度分析5.1 什么是维度?5.2什么是指标? 6.什么是数仓建模?7.事实表7.维度表…

Qt使用iostream的cout

在QT想使用iostream的cout。 参考以下博客: (转载)Qt中使用cout输出的方法 pro里加上; CONFIG console勾选 Run in Terminal clean工程,重新构建 上面是cout的,下面是我的另一个函数的qDebug输出的。

【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】

目录 1、毕业旅行问题(今日头条2019笔试题) 2、蒙德里安的梦想(算法竞赛进阶指南) 3、最短Hamilton路径(《算法竞赛进阶指南》&模板) 4、国际象棋(第十二届蓝桥杯省赛第二场C A组/B组&#…

vue+springboot多角色登录

①前端编写 将Homeview修改为manager Manager&#xff1a; <template><div><el-container><!-- 侧边栏 --><el-aside :width"asideWidth" style"min-height: 100vh; background-color: #001529"><div style"h…

Jetpack Compose -> 状态机制的背后秘密

前言 上一章我们讲解了 Jetpack Compose 的无状态、状态提升、单向数据流 本章我们讲解下状态机制的背后秘密 List 前面我们讲过&#xff0c;通过 by mustableStateOf() 就可以被 Compose 自动订阅了&#xff1b;我们前面是通过 String 类型进行的自动订阅&#xff0c;那么换成…

C语言 | Leetcode C语言题解之第13题罗马数字转整数

题解&#xff1a; 题解&#xff1a; int romanToInt(char* s) {int symbolValues[26];symbolValues[I - A] 1;symbolValues[V - A] 5;symbolValues[X - A] 10;symbolValues[L - A] 50;symbolValues[C - A] 100;symbolValues[D - A] 500;symbolValues[M - A] 1000;int a…

基于Spring boot+Vue的业余排球俱乐部会员管理系统

5 系统功能模块的具体实现 5.1超级会员角色 5.1.1 登录 超级管理员登录通过用户名和密码去数据库查询用户表&#xff0c;该名称是否在用户表中存在&#xff0c;如果存在&#xff0c;则通过用户名和密码查询密码是否正确&#xff0c;然后吧用户的信息存在jwt的负载里&#xf…

【学习】渗透测试有哪些重要性

随着信息技术的迅猛发展&#xff0c;网络安全问题日益凸显。渗透测试作为网络安全防御的重要手段之一&#xff0c;旨在模拟黑客攻击&#xff0c;发现并修复潜在的安全漏洞&#xff0c;提高网络系统的安全性。本文将介绍渗透测试的概念、重要性、实施步骤及实践案例&#xff0c;…

PPT 操作

版式 PPT中&#xff0c;巧妙使用母版&#xff0c;可以提高效率。 双击母版&#xff0c;选择其中一个版式&#xff0c;插入装饰符号。 然后选择关闭。 这个时候&#xff0c;在该版式下的所有页面&#xff0c;就会出现新加入的符号。不在该版式下的页面&#xff0c;不会出现新加…

springboot 反射调用ServiceImpl时报错:java.lang.NullPointerExceptio、,mapper为null【解决方法】

springboot 反射调用ServiceImpl时报错&#xff1a;java.lang.NullPointerException、mapper为null【解决方法】 问题描述问题分析解决方案创建SpringBootBeanUtil编写调用方法 executeMethod调用 总结 问题描述 在使用Spring Boot时&#xff0c;我们希望能够通过反射动态调用…

0基础安装配置Linux-ubuntu环境

Vmtools的安装参见 0基础教你安装VM 17PRO-直接就是专业许可证版_vm17许可证-CSDN博客 在vmtools中安装ubuntu 等待安装 这时候发现没有继续按钮&#xff0c;我们关闭这个界面&#xff0c;进入系统中&#xff0c;先更改分辨率 点击这个三角&#xff0c;因为还么有安装成功&am…

初识ES(ES的基本概念、倒排索引、索引和文档的CRUD)

1、ES是什么&#xff1f; 一个开源的分布式搜索引擎&#xff0c;可以用来实现搜索、日志统计、分析、系统监控等功能。ES的底层是基于Lucene实现的。 Lucene是一个Java语言的搜索引擎类库。 什么是elastic stack&#xff08;ELK&#xff09;&#xff1f; elasticsearch。存储、…

JMeter+Ant+Jenkins构建接口报告(无人驾驶版)

展示结果&#xff1a; uc浏览器打开测试报告&#xff0c;绿色显示脚本结果 搭建操作步骤如下 1.jemter写好脚本 2.下载并配置ant环境变量&#xff1a;加上activation.jar、commons-lang3-3.8.1.jar、mail.jar 这3个包 mail.jar需要引用到jmeter 3.下载安装Jenkins 并进行构建…

第五、六章

函数 三要素 &#xff08;1&#xff09;是组织好的 &#xff08;2&#xff09;可重复使用的 &#xff08;3&#xff09;实现特定功能的代码段 定义格式 def 函数名(传入参数)&#xff1a;函数体return 返回值 注意&#xff1a; &#xff08;1&#xff09;参数不需要&…

chrome 浏览器 有自带的自动字幕功能,支持英文,控制您的音乐、视频等媒体内容

chrome 浏览器 有自带的自动字幕功能&#xff0c;支持英文&#xff0c;控制您的音乐、视频等媒体内容

大模型新漏洞!Anthropic警告:新式“多轮越狱”攻破AI防线,或祸起长文本

如何让一个AI回答一个它本不应该作答的问题&#xff1f; 有很多这种所谓的“越狱”技术&#xff0c;而Anthropic的研究人员最近发现了一种新方法&#xff1a;如果首先用几十个危害性较小的问题对大型语言模型&#xff08;LLM&#xff09;进行预热&#xff0c;就能诱使其告诉你…

827. 最大人工岛

827. 最大人工岛 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;错误经验吸取 原题链接&#xff1a; 827. 最大人工岛 https://leetcode.cn/problems/making-a-large-island/description/ 完成情况&#xff1a; 解题思路&#xff1a; 这…

fastlio2 保存每帧的点云和每帧的里程计为单独的文件做后端回环优化和手动回环优化

为了 提供数据做后端回环优化和手动回环优化,需要保存每帧的点云和每帧的里程计为单独的文件,并且需要保存的名字为ros时间戳。 效果很好,比我自己写的手动回环模块好用 // This is an advanced implementation of the algorithm described in the // following paper: /…

Java | Leetcode Java题解之第13题罗马数字转整数

题目&#xff1a; 题解&#xff1a; class Solution {Map<Character, Integer> symbolValues new HashMap<Character, Integer>() {{put(I, 1);put(V, 5);put(X, 10);put(L, 50);put(C, 100);put(D, 500);put(M, 1000);}};public int romanToInt(String s) {int …

Godot插值、贝塞尔曲线和Astar寻路

一、插值 线性插值是采用一次多项式上进行的插值计算&#xff0c;任意给定两个值A和B&#xff0c;那么在A和B之间的任意值可以定义为&#xff1a;P(t) A * (1 - t) B * t&#xff0c;0 < t < 1。 数学中用于线性拟合&#xff0c;游戏应用可以做出跟随效果&#xff08;…