深度学习 - Transformer 组成详解

整体结构

在这里插入图片描述

1. 嵌入层(Embedding Layer)

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

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

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import math

class 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 = nhead
        self.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.scale
        attn = 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.mfbz.cn/a/749150.html

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

相关文章

初识 Embedding,为何大家都基于它搭建私人智能客服?

随着 AI 技术的发展,大家在日常使用过程中经常会碰到一些目前 GPT4 也无法解决的问题: 无法获取个人私有数据信息,进行智能问答无法获取最新信息,LLM 模型训练都是都是有截止日期的无法定制化私有的专属模型,从而在某…

算法常见问题

1.c虚函数 虚函数是用来实现多态(polymorphism) 的一种机制。通过使用虚函数,可以在子类中重写父类中定义的方法,并且在运行时动态地确定要调用哪个方法。 在类定义中将一个成员函数声明为虚函数,需要使用 virtual 关键字进行修饰 。 通过指向…

山海相逢,因你而至!第九届全球边缘计算大会·深圳站圆满召开!

2024年6月22日,第九届全球边缘计算大会在深圳盛大开幕。本次盛会由边缘计算社区主办,并获得了EMQ、研华科技、华为等重量级单位的鼎力支持。大会汇聚了来自全球各地的业界精英,共同探讨边缘计算的前沿技术、应用趋势以及创新实践,…

Isaac Sim 9 物理(1)

使用Python USD API 来实现 Physics 。 以下内容中,大部分 Python 代码可以在 Physics Python 演示脚本文件中找到,本文仅作为个人学习笔记。 一.设置 USD Stage 和物理场景 Setting up a USD Stage and a Physics Scene USD Stage不知道怎么翻译&#…

docker 部署的 wordpress 接入阿里云短信服务 详细实操介绍

一、阿里云短信服务配置: 1、登录 阿里云短信服务 完成指引短信相关配置 2、创建RAM用户 并完成授权 出于安全及规范考虑 需通过RAM 用户来完成OponApl 接口调用,创建成功需完成短信接口(AliyunDysmsFullAccess、AliyunDysmsReadOnlyAccess…

【大模型】大模型微调方法总结(二)

1.Adapter Tuning 1.背景 2019年谷歌的研究人员首次在论文《Parameter-Efficient Transfer Learning for NLP》提出针对 BERT 的 PEFT微调方式,拉开了 PEFT 研究的序幕。他们指出,在面对特定的下游任务时,如果进行 Full-Fintuning&#xff0…

执行yum命令报错Could not resolve host: mirrors.cloud.aliyuncs.com; Unknown error

执行yum命令报错 [Errno 14] curl#6 - "Could not resolve host: mirrors.cloud.aliyuncs.com; Unknown error 修改图中所示两个文件: vim epel.repo vim CentOS-Base.repo 将所有的http://mirrors.cloud.aliyuncs.com 修改为http://mirrors.aliyun.com。 修改…

数据库逻辑结构设计-实体和实体间联系的转换、关系模式的优化

一、引言 如何将数据库概念结构设计的结果,即用E-R模型表示的概念模型转化为关系数据库模式。 E-R模型由实体、属性以及实体间的联系三个要素组成 将E-R模型转换为关系数据库模式,实际上就是要将实体及实体联系转换为相应的关系模式,转换…

【深度学习】基于深度离散潜在变量模型的变分推理

1.引言 1.1.讨论的目标 阅读并理解本文后,大家应能够: 掌握如何为具有离散潜在变量的模型设定参数在可行的情况下,使用精确的对数似然函数来估计参数利用神经变分推断方法来估计参数 1.2.导入相关软件包 # 导入PyTorch库,用于…

LLM vs SLM 大模型和小模型的对比

语言模型是能够生成自然人类语言的人工智能计算模型。这绝非易事。 这些模型被训练为概率机器学习模型——预测适合在短语序列中生成的单词的概率分布,试图模仿人类智能。语言模型在科学领域的重点有两个方面: 领悟情报的本质。 并将其本质体现为与真实…

Java学习十一—Java8特性之Stream流

一、Java8新特性简介 2014年3月18日,JDK8发布,提供了Lambda表达式支持、内置Nashorn JavaScript引擎支持、新的时间日期API、彻底移除HotSpot永久代。 ​ Java 8引入了许多令人兴奋的新特性,其中最引人注目的是Lambda表达式和Stream API。以…

十年磨一剑,华火电燃组合灶重磅问世,引领厨房新时代

十年磨一剑,华火研发团队经过不懈努力,成功将等离子电生明火技术与电陶炉红外线光波炉技术精妙融合,打造出的这款具有划时代是意义的电燃组合灶HH-SZQP60,终于在 2024 年6月震撼登场,该灶以其卓越的创新技术和独特的产…

day01-项目介绍及初始化-登录页

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 day01-项目介绍及初始化-登录页一、人力资源项目介绍1.1项目架构和解决方案主要模块解决的问题 二、拉取项目基础代码1.引入库2.升级core-js版本到3.25.5按照完整依…

一篇文章带你玩懂数据库的基础函数

数据库的函数 单行函数1.数据函数2.字符串函数3.时间函数4.流程函数 多行函数聚合函数 阅读指南: 本文章讲述了对于数据库的单行和多行函数,如果读者感兴趣,后续我们会更新高级的操作在我们的对于数据库教程的合集中,大家可以来很…

振弦采集仪在大型工程安全监测中的应用探索

振弦采集仪在大型工程安全监测中的应用探索 振弦采集仪是一种用于监测结构振动和变形的设备,它通过采集振弦信号来分析结构的动态特性。在大型工程安全监测中,振弦采集仪具有重要的应用价值,可以帮助工程师和监测人员实时了解结构的状况&…

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇Kerberos委派安全非约束系约束系RBCD资源系Spooler利用

红队内网攻防渗透 1. 内网横向移动1.1 委派安全知识点1.1.1 域委派分类1.1.2 非约束委派1.1.2.1 利用场景1.1.2.2 复现配置:1.1.2.3 利用思路1:诱使域管理员访问机器1.1.2.3.1 利用过程:主动通讯1.1.2.3.2 利用过程:钓鱼1.1.2.4 利用思路2:强制结合打印机漏洞1.1.2.5 利用…

利用Linked SQL Server提权

点击星标,即时接收最新推文 本文选自《内网安全攻防:红队之路》 扫描二维码五折购书 利用Linked SQL Server提权 Linked SQL server是一个SQL Server数据库中的对象,它可以连接到另一个SQL Server或非SQL Server数据源(如Oracle&a…

Techviz:XR协作工作流程,重塑远程电话会议新形式

在当今快速发展的数字环境中,无缝远程协作的需求正在成为企业多部门协同工作的重中之重,尤其是对于制造业、建筑和设计等行业的专业人士而言,这一需求更加迫切。传统的远程电话会议协作形式存在着延滞性,已经渐渐跟不上当今快节奏…

脑洞爆裂,OLED透明屏与红酒柜相结合

当OLED透明屏与红酒柜相结合时,我们可以设想一个极具创新性和实用性的产品,将科技美学与品酒文化完美融合。以下是我为这种结合提出的一些创新设想: 透明展示与虚拟标签 透明展示:OLED透明屏能够直接安装在红酒柜的玻璃门或侧面&a…

面试突击指南:Java基础面试题3

1.介绍下进程和线程的关系 进程:一个独立的正在执行的程序。 线程:一个进程的最基本的执行单位,执行路径。 多进程:在操作系统中,同时运行多个程序。 多进程的好处:可以充分利用CPU,提高CPU的使用率。 多线程:在同一个进程(应用程序)中同时执行多个线程。 多线程…