深度学习 - Transformer 组成详解

整体结构

在这里插入图片描述

1. 嵌入层(Embedding Layer)

在这里插入图片描述
生活中的例子:字典查找

想象你在读一本书,你不认识某个单词,于是你查阅字典。字典为每个单词提供了一个解释,帮助你理解这个单词的意思。嵌入层就像这个字典,它将每个单词(或输入序列中的每个标记)映射到一个高维向量(解释),这个向量包含了单词的各种语义信息。

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import mathclass EmbeddingLayer(nn.Module):def __init__(self, vocab_size, d_model, max_seq_length=512):super(EmbeddingLayer, self).__init__()# vocab_size: 词汇表的大小,即输入序列中可能的不同标记的总数。# d_model: 每个嵌入向量的维度,即词嵌入向量的长度。# max_seq_length: 序列的最大长度,用于位置嵌入。self.embedding = nn.Embedding(vocab_size, d_model)  # 词嵌入层self.pos_embedding = nn.Embedding(max_seq_length, d_model)  # 位置嵌入层self.d_model = d_model# 初始化位置编码pe = torch.zeros(max_len, d_model)# 生成词位置列表position = torch.arange(0, max_len).unsqueeze(1)# 根据公式计算词位置参数div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model))# 生成词位置矩阵my_matmulres = position * div_term# 给位置编码矩阵奇数列,赋值sin曲线特征pe[:, 0::2] = torch.sin(my_matmulres)# 给位置编码矩阵偶数列,赋值cos曲线特征pe[:, 1::2] = torch.cos(my_matmulres)# 形状变化 [max_seq_length,d_model]-->[1,max_seq_length,d_model]pe = pe.unsqueeze(0)# 把pe位置编码矩阵 注册成模型的持久缓冲区buffer; 模型保存再加载时,可以根模型参数一样,一同被加载# 什么是buffer: 对模型效果有帮助的,但是却不是模型结构中超参数或者参数,不参与模型训练self.register_buffer('pe', pe)def forward(self, x):seq_length = x.size(1)  # 序列长度pos = torch.arange(0, seq_length, device=x.device).unsqueeze(0)  # 生成位置索引return self.embedding(x) * math.sqrt(self.d_model) + self.pe[:,:x.size()[-1], :]  # 词嵌入和位置嵌入相加

2. 多头自注意力机制(Multi-Head Self-Attention)

在这里插入图片描述
生活中的例子:小组讨论

想象你在一个小组讨论中,每个人(每个位置上的单词)都提出自己的观点(Query),并听取其他人的意见(Key和Value)。每个人对所有其他人的观点进行加权平均,以形成自己的新观点。多头注意力机制类似于多个小组同时进行讨论,每个小组从不同的角度(头)讨论问题,然后将所有讨论结果合并在一起。

class MultiHeadSelfAttention(nn.Module):def __init__(self, d_model, nhead):super(MultiHeadSelfAttention, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。self.nhead = nheadself.d_model = d_model# 定义线性变换层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.out_linear = nn.Linear(d_model, d_model)self.scale = (d_model // nhead) ** 0.5  # 缩放因子def forward(self, x):batch_size = x.size(0)  # 获取批大小# 线性变换并分成多头q = self.q_linear(x).view(batch_size, -1, self.nhead, self.d_model // self.nhead).transpose(1, 2)k = self.k_linear(x).view(batch_size, -1, self.nhead, self.d_model // self.nhead).transpose(1, 2)v = self.v_linear(x).view(batch_size, -1, self.nhead, self.d_model // self.nhead).transpose(1, 2)# 计算注意力得分scores = torch.matmul(q, k.transpose(-2, -1)) / self.scaleattn = torch.nn.functional.softmax(scores, dim=-1)  # 计算注意力权重context = torch.matmul(attn, v).transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)  # 加权求和out = self.out_linear(context)  # 最后一层线性变换return out

3. 前馈神经网络(Feed-Forward Network)

在这里插入图片描述
生活中的例子:信息过滤和处理

想象你在整理会议纪要,需要对会议地录音进行归纳、总结和补充。前馈神经网络类似于这个过程,它对输入的信息进行进一步处理和转换,以提取重要特征。

class FeedForwardNetwork(nn.Module):def __init__(self, d_model, dim_feedforward, dropout=0.1):super(FeedForwardNetwork, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在前馈神经网络中使用的dropout比率,用于正则化。self.linear1 = nn.Linear(d_model, dim_feedforward)  # 第一个线性层self.dropout = nn.Dropout(dropout)  # dropout层self.linear2 = nn.Linear(dim_feedforward, d_model)  # 第二个线性层def forward(self, x):return self.linear2(self.dropout(torch.nn.functional.relu(self.linear1(x))))  # 激活函数ReLU和dropout

4. 层归一化(Layer Normalization)

在这里插入图片描述
生活中的例子:团队合作中的标准化

想象你在一个团队中工作,每个人都有不同的工作习惯和标准。为了更好地合作,团队决定采用统一的工作标准(如文档格式、命名规范等)。层归一化类似于这种标准化过程,它将输入归一化,使得每个特征的均值为0,标准差为1,以稳定和加速训练。

class LayerNorm(nn.Module):def __init__(self, d_model, eps=1e-6):super(LayerNorm, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# eps: 用于数值稳定的小值,防止除以零。self.gamma = nn.Parameter(torch.ones(d_model))  # 缩放参数self.beta = nn.Parameter(torch.zeros(d_model))  # 偏移参数self.eps = eps  # epsilon,用于数值稳定def forward(self, x):mean = x.mean(dim=-1, keepdim=True)  # 计算均值std = x.std(dim=-1, keepdim=True)  # 计算标准差return self.gamma * (x - mean) / (std + self.eps) + self.beta  # 归一化

5. 残差连接(Residual Connection)

在这里插入图片描述
生活中的例子:备忘录

想象你在会议上记了很多笔记。为了确保不会遗漏任何重要信息,你在总结时会参照这些笔记。残差连接类似于这个过程,它将每层的输入直接加到输出上,确保信息不会在层与层之间丢失。

class ResidualConnection(nn.Module):def __init__(self, d_model, dropout=0.1):super(ResidualConnection, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# dropout: 在残差连接中使用的dropout比率,用于正则化。self.norm = LayerNorm(d_model)  # 层归一化self.dropout = nn.Dropout(dropout)  # dropout层def forward(self, x, sublayer):return x + self.dropout(sublayer(self.norm(x)))  # 残差连接

6. 编码器层(Encoder Layer)

在这里插入图片描述
生活中的例子:多轮面试

想象你在参加多轮面试,每轮面试都有不同的考官,考察不同的方面(如专业知识、沟通能力等)。每轮面试都帮助你更全面地展示自己。编码器层类似于这种多轮面试的过程,每层处理输入序列的不同方面,逐层提取和增强特征。

class EncoderLayer(nn.Module):def __init__(self, d_model, nhead, dim_feedforward, dropout=0.1):super(EncoderLayer, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在各层中使用的dropout比率,用于正则化。self.self_attn = MultiHeadSelfAttention(d_model, nhead)  # 多头自注意力机制self.feed_forward = FeedForwardNetwork(d_model, dim_feedforward, dropout)  # 前馈神经网络self.sublayers = nn.ModuleList([ResidualConnection(d_model, dropout) for _ in range(2)])  # 两个子层(注意力和前馈网络)def forward(self, src):src = self.sublayers[0](src, lambda x: self.self_attn(x))  # 应用自注意力机制src = self.sublayers[1](src, self.feed_forward)  # 应用前馈神经网络return src

7. 解码器层(Decoder Layer)

在这里插入图片描述
生活中的例子:逐步解谜

想象你在玩一个解谜游戏,每解决一个谜题(每层解码器),你都会得到新的线索,逐步解开整个谜题。解码器层类似于这种逐步解谜的过程,每层结合当前解码的结果和编码器的输出,逐步生成目标序列。

class DecoderLayer(nn.Module):def __init__(self, d_model, nhead, dim_feedforward, dropout=0.1):super(DecoderLayer, self).__init__()# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在各层中使用的dropout比率,用于正则化。self.self_attn = MultiHeadSelfAttention(d_model, nhead)  # 多头自注意力机制self.cross_attn = MultiHeadSelfAttention(d_model, nhead)  # 编码器-解码器注意力self.feed_forward = FeedForwardNetwork(d_model, dim_feedforward, dropout)  # 前馈神经网络self.sublayers = nn.ModuleList([ResidualConnection(d_model, dropout) for _ in range(3)])  # 三个子层(自注意力、交叉注意力、前馈网络)def forward(self, tgt, memory):tgt = self.sublayers[0](tgt, lambda x: self.self_attn(x))  # 应用自注意力机制tgt = self.sublayers[1](tgt, lambda x: self.cross_attn(x, memory))  # 应用编码器-解码器注意力tgt = self.sublayers[2](tgt, self.feed_forward)  # 应用前馈神经网络return tgt

8. 编码器(Encoder)

在这里插入图片描述

class Encoder(nn.Module):def __init__(self, num_layers, d_model, nhead, dim_feedforward, dropout=0.1):super(Encoder, self).__init__()# num_layers: 编码器层的数量,即堆叠的编码器层数。# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在各层中使用的dropout比率,用于正则化。self.layers = nn.ModuleList([EncoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_layers)])  # 堆叠多个编码器层def forward(self, src):for layer in self.layers:src = layer(src)  # 依次通过每个编码器层return src

9. 解码器(Decoder)

class Decoder(nn.Module):def __init__(self, num_layers, d_model, nhead, dim_feedforward, dropout=0.1):super(Decoder, self).__init__()# num_layers: 解码器层的数量,即堆叠的解码器层数。# d_model: 输入和输出的维度,即每个位置的特征向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在各层中使用的dropout比率,用于正则化。self.layers = nn.ModuleList([DecoderLayer(d_model, nhead, dim_feedforward, dropout) for _ in range(num_layers)])  # 堆叠多个解码器层def forward(self, tgt, memory):for layer in self.layers:tgt = layer(tgt, memory)  # 依次通过每个解码器层return tgt

10. Transformer模型

class TransformerModel(nn.Module):def __init__(self, vocab_size, d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout=0.1):super(TransformerModel, self).__init__()# vocab_size: 词汇表的大小,即输入序列中可能的不同标记的总数。# d_model: 每个嵌入向量的维度,即词嵌入向量的长度。# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。# num_encoder_layers: 编码器层的数量,即堆叠的编码器层数。# num_decoder_layers: 解码器层的数量,即堆叠的解码器层数。# dim_feedforward: 前馈神经网络的隐藏层维度。# dropout: 在各层中使用的dropout比率,用于正则化。self.embedding = EmbeddingLayer(vocab_size, d_model)  # 嵌入层self.encoder = Encoder(num_encoder_layers, d_model, nhead, dim_feedforward, dropout)  # 编码器self.decoder = Decoder(num_decoder_layers, d_model, nhead, dim_feedforward, dropout)  # 解码器self.fc = nn.Linear(d_model, vocab_size)  # 最后一层线性变换,将输出维度映射到词汇表大小def forward(self, src, tgt):src = self.embedding(src)  # 嵌入输入序列tgt = self.embedding(tgt)  # 嵌入目标序列memory = self.encoder(src)  # 编码器处理输入序列output = self.decoder(tgt, memory)  # 解码器处理目标序列output = self.fc(output)  # 映射到词汇表大小return output

训练示例

# 参数
# vocab_size: 词汇表的大小,即输入序列中可能的不同标记的总数。
# d_model: 每个嵌入向量的维度,即词嵌入向量的长度。
# nhead: 注意力头的数量,多头注意力机制中并行的注意力计算数。
# num_encoder_layers: 编码器层的数量,即堆叠的编码器层数。
# num_decoder_layers: 解码器层的数量,即堆叠的解码器层数。
# dim_feedforward: 前馈神经网络的隐藏层维度。
# dropout: 在各层中使用的dropout比率,用于正则化。
# batch_size: 每个训练批次中的样本数量。
# seq_length: 输入序列的长度。
# num_epochs: 训练的轮数,即遍历整个训练集的次数。
vocab_size = 1000
d_model = 512
nhead = 8
num_encoder_layers = 6
num_decoder_layers = 6
dim_feedforward = 2048
dropout = 0.1
batch_size = 32
seq_length = 10
num_epochs = 10# 数据集
src = torch.randint(0, vocab_size, (batch_size, seq_length))
tgt = torch.randint(0, vocab_size, (batch_size, seq_length))dataset = TensorDataset(src, tgt)
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)# 模型实例
model = TransformerModel(vocab_size, d_model, nhead, num_encoder_layers, num_decoder_layers, dim_feedforward, dropout)# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 训练
for epoch in range(num_epochs):for src_batch, tgt_batch in dataloader:tgt_input = tgt_batch[:, :-1]  # 目标输入tgt_output = tgt_batch[:, 1:]  # 目标输出optimizer.zero_grad()output = model(src_batch, tgt_input)  # 前向传播output = output.permute(1, 2, 0)  # 调整形状以匹配损失函数loss = criterion(output, tgt_output)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新参数print(f"Epoch {epoch+1}/{num_epochs}, Loss: {loss.item()}")print("训练完成")

代码说明

  1. EmbeddingLayer:将输入序列和位置嵌入映射到高维空间。
  2. MultiHeadSelfAttention:实现多头自注意力机制,包括查询、键和值的线性变换和注意力计算。
  3. FeedForwardNetwork:前馈神经网络,用于进一步处理特征。
  4. LayerNorm:层归一化,用于稳定训练过程。
  5. ResidualConnection:残差连接,帮助训练更深的网络。
  6. EncoderLayer:将多头自注意力机制和前馈神经网络组合在一起,形成编码器层。
  7. DecoderLayer:包括多头自注意力机制、编码器-解码器注意力和前馈神经网络,形成解码器层。
  8. Encoder:由多个编码器层堆叠而成。
  9. Decoder:由多个解码器层堆叠而成。
  10. TransformerModel:将编码器和解码器组合在一起,形成完整的Transformer模型。

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

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

相关文章

道路救援入驻派单小程序开源版开发

道路救援入驻派单小程序开源版开发 1、用户立即救援 2、后台收到救援通知,派单救援师傅. 道路救援入驻派单小程序通常会包含一系列功能,旨在方便救援服务提供商、用户和后台管理系统之间的交互。以下是一个可能的功能列表: 用户端功能&…

Camera开发-相机输出常用数据格式

作者简介: 一个平凡而乐于分享的小比特,中南民族大学通信工程专业研究生在读,研究方向无线联邦学习 擅长领域:驱动开发,嵌入式软件开发,BSP开发 作者主页:一个平凡而乐于分享的小比特的个人主页…

OpenGL-ES 学习(6)---- 立方体绘制

目录 立方体绘制基本原理立方体的顶点坐标和绘制顺序立方体颜色和着色器实现效果和参考代码 立方体绘制基本原理 一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形 顶点的坐标体系如下图所示,三维坐标…

【极速入门版】编程小白也能轻松上手Comate AI编程插件

文章目录 概念使用错误检测与修复能力API生成代码生成json格式做开发测试 在目前的百模大战中,AI编程助手是程序员必不可少的东西,市面上琳琅满目的产品有没有好用一点的,方便一点的呢?今天工程师令狐向大家介绍一款极易入门的国产…

three.js - MeshStandardMaterial(标准网格材质)- 金属贴图、粗糙贴图

金属贴图、粗糙贴图 金属贴图:metalnessMap 和 粗糙贴图:roughnessMap,是用于模拟物体表面属性的两种重要贴图技术,这两种贴图,通常与基于物理的渲染(PBR)材质(如:MeshSt…

nuxt3项目打包后获取.env设置的环境变量无效的解决办法

问题描述 在nuxt3项目开发过程中,设置了开发环境变量和生产环境变量,在本地开发时都能正常获取,但打包部署时获取不到,设置如下: //.env.development文件示例 SERVER_API_PATHhttp://192.168.25.100//.env.productio…

Elasticsearch环境搭建|ES单机|ES单节点模式启动|ES集群搭建|ES集群环境搭建

文章目录 版本选择单机ES安装与配置创建非root用户导入安装包安装包解压配置JDK环境变量配置single-node配置JVM参数后台启动|启动日志查看启动成功,访问终端访问浏览器访问 Kibana安装修改配置后台启动|启动日志查看浏览器访问 ES三节点集群搭建停止es服务域名配置…

小区物业管理收费系统源码小程序

便捷、透明、智能化的新体验 一款基于FastAdminUniApp开发的一款物业收费管理小程序。包含房产管理、收费标准、家属管理、抄表管理、在线缴费、业主公告、统计报表、业主投票、可视化大屏等功能。为物业量身打造的小区收费管理系统,贴合物业工作场景,轻…

未来20年人工智能将如何塑造社会

照片由Brian McGowan在Unsplash上拍摄 更多资讯,请访问 2img.ai “人工智能会成为我们的救星还是我们的末日?” 几十年来,这个问题一直困扰着哲学家、科学家和科幻爱好者。 当我们踏上技术革命的边缘时,是时候透过水晶球&#x…

【java算法专场】双指针(上)

目录 前言 基本原理 对撞指针 快慢指针 移动零 算法思路 算法步骤 代码实现 算法分析 复写零 算法思路 算法步骤 代码实现 快乐数 算法思路 算法步骤 代码实现 盛最多水的容器 ​编辑算法思路 代码实现 前言 双指针是一种在数组或链表等线性数据结构中高效…

CV每日论文--2024.6.26

1、StableNormal: Reducing Diffusion Variance for Stable and Sharp Normal 中文标题:StableNormal:减少扩散方差以实现稳定且锐利的法线 简介:本文介绍了一种创新解决方案,旨在优化单目彩色输入(包括静态图片与动态…

CCS的安装步骤

CCS的安装步骤 安装之前有几件重要的事情要做: 首先肯定是要下载安装包啦!点击此处是跳到官网下载地址安装包不能处的路径中不能包含中文关闭病毒防护和防火墙,以及其他杀毒软件最后是在重启后进行安装 主要的步骤如下: 找到安…

PDF转成清晰长图

打开一个宝藏网址在线PDF转换器/处理工具 - 在线工具系列 点击图下所示位置 按照图下所示先上传文件,设置转换参数后点击转换,等待 等待转换完成后,可以在转换结果处选择下载地址,点击即可进行下载使用了。对比了其他几个网站的转…

.NET C# Asp.Net Core Web API 配置 Nginx

.NET C# Asp.Net Core Web API 配置 Nginx 目录 .NET C# Asp.Net Core Web API 配置 Nginx1 创建Asp.Net Core Web API应用2 接口代码3 发布4 启动服务5 Nginx安装6 配置Nginx7 启动Nginx8 测试9 Nginx日志10 附: 1 创建Asp.Net Core Web API应用 2 接口代码 Weath…

高考志愿填报选专业,解读“冲稳保”三步策略

高考界流传着一句话“一分压倒千人”,在特定的分数段,比别人高一分,高考排名就比别人高一千并不是危言耸听,而利用好这些分数和排名,则有利于我们人生进入新的阶段。 纵观每年的高考,无论是老师考生还是家…

“北京到底有谁在啊”影视APP开发,解锁最简单的快乐

随着电视剧《玫瑰的故事》在腾讯视频APP热播,APP也增加了很多热度,一款丰富的影视APP,无论是热门大片、经典影视剧、还是最新综艺节目,能畅享无限精彩的影视内容! 开发影视APP,需要专业的技术服务商来解决…

[leetcode]k-th-smallest-in-lexicographical-order 字典序的第K小数字

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int getSteps(int curr, long n) {int steps 0;long first curr;long last curr;while (first < n) {steps min(last, n) - first 1;first first * 10;last last * 10 9;}return steps;}int find…

kettle使用手册 安装9.0版本 建议设置为英语

0.新建转换的常用组件 0. Generate rows 定一个字符串 name value就是字符串的值 0.1 String operations 字段转大写 去空格 1. Json input 来源于一个json文件 1.json 或mq接收到的data内容是json字符串 2. Json output 定义Jsonbloc值为 data, 左侧Fieldname是数据库查…

vue3-登录小案例(借助ElementPlus+axios)

1.创建一个vue3的项目。 npm create vuelatest 2.引入Elementplus组件库 链接&#xff1a;安装 | Element Plus npm install element-plus --save 在main.js中引入 import ElementPlus from "element-plus";import "element-plus/dist/index.css";ap…

SAP ABAP 常用实用类

文章目录 前言一、输出 展示 数据信息 a.将 JSON 格式化为可读 并以弹框形式输出 b.将内表内容以表格形式输出 c.弹框形式显示 HTML 内容。也能显示包含js 的html。也可以显示pdf 图片 二、输入 获取 数据信息 a.弹框 添加 输入框…