一文读懂Transformer架构中的编码器

Transformer架构是由Vaswani等人在2017年提出的一种神经网络架构,主要用于自然语言处理任务。它的核心组成部分是编码器(Encoder)和解码器(Decoder),本篇将为各位同学介绍一下如何创建Transformer中的编码器(Encoder)。

一、如何理解编码器(Encoder)

Transformer架构中的编码器(Encoder)是模型的核心组成部分之一,主要用于处理输入序列并将其编码为连续的向量表示。我们可以从以下几方面去理解编码器:

1. 结构概述

Transformer编码器由多个相同的层叠加而成,每一层主要由两个子层组成:

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

  • 前馈神经网络(Feed-Forward Neural Network)

每个子层后面都有一个残差连接(Residual Connection)和层归一化(Layer Normalization)。

2. 多头自注意力机制

自注意力机制允许模型在处理输入时关注到序列中不同位置的信息。在多头自注意力机制中,输入向量首先被线性变换为查询(Query)、键(Key)和值(Value)三部分。步骤如下:

(1) 线性变换:对于输入序列中的每个词,生成对应的查询、键和值向量。

(2) 计算注意力权重:通过对查询向量与所有键向量进行点积,计算出注意力权重。然后通过Softmax函数将这些权重归一化。

(3) 加权求和:将得到的权重与对应的值向量进行加权求和,得到每个词的新的表示。

(4) 多头机制:上述过程会并行进行多个头(h),每个头都有独立的参数,最后将所有头的输出拼接在一起,经过线性变换得到最终的输出。

3. 前馈神经网络

每个自注意力层后面是一个前馈神经网络,该网络对每一个位置的输出进行独立的非线性变换。通常由两个线性变换和一个ReLU激活函数组成。

4. 残差连接与层归一化

在每个子层(自注意力和前馈网络)之后,都会添加残差连接,意味着子层的输入将与输出相加。这有助于缓解深度网络中的梯度消失问题。接下来是层归一化,确保每一层的输出在训练过程中保持稳定。

5. 位置编码

由于Transformer不使用递归或卷积结构,因此需要位置编码(Positional Encoding)来提供序列中词的位置信息。位置编码与输入嵌入相加,让模型理解词的顺序。

Transformer编码器通过自注意力机制有效地捕捉输入序列中词之间的关系,结合前馈神经网络、残差连接和层归一化,构成了功能强大的特征提取模块。这种架构不仅在自然语言处理领域取得了优异的表现,还被广泛应用于其他任务,如图像处理和生成模型等。

二、构建编码器(Encoder)

下面是一个使用 PyTorch 构建 Transformer 编码器的完整代码示例,各位同学在各种应用中构建编码器时可以参考以下方法:

import torch
import torch.nn as nn
import torch.nn.functional as F
# 定义多头自注意力机制
class MultiHeadAttention(nn.Module):
    def __init__(self, embed_size, heads):
        super(MultiHeadAttention, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads
        assert (
            self.head_dim * heads == embed_size
        ), "嵌入尺寸必须能被头数整除"
        self.values = nn.Linear(embed_size, embed_size, bias=False)
        self.keys = nn.Linear(embed_size, embed_size, bias=False)
        self.queries = nn.Linear(embed_size, embed_size, bias=False)
        self.fc_out = nn.Linear(embed_size, embed_size)
    def forward(self, x):
        N = x.shape[0]  # 批次大小
        seq_length = x.shape[1]  # 序列长度
        # 通过线性层生成键、值、查询
        values = self.values(x)
        keys = self.keys(x)
        queries = self.queries(x)
        # 将数据分为多个头
        values = values.view(N, seq_length, self.heads, self.head_dim)
        keys = keys.view(N, seq_length, self.heads, self.head_dim)
        queries = queries.view(N, seq_length, self.heads, self.head_dim)
        values = values.permute(0, 2, 1, 3)  # (N, heads, seq_length, head_dim)
        keys = keys.permute(0, 2, 1, 3)      # (N, heads, seq_length, head_dim)
        queries = queries.permute(0, 2, 1, 3) # (N, heads, seq_length, head_dim)
        # 计算注意力分数
        energy = torch.einsum("nqhd,nkhd->nqkh", [queries, keys])  # (N, queries, keys, heads)
        attention = F.softmax(energy / (self.embed_size ** (1 / 2)), dim=3)  # 归一化
        # 加权求和
        out = torch.einsum("nqkh,nvhd->nqhd", [attention, values]).reshape(N, seq_length, self.heads * self.head_dim)
        return self.fc_out(out)
# 定义前馈神经网络
class FeedForward(nn.Module):
    def __init__(self, embed_size, forward_expansion):
        super(FeedForward, self).__init__()
        self.fc1 = nn.Linear(embed_size, forward_expansion)
        self.fc2 = nn.Linear(forward_expansion, embed_size)
    def forward(self, x):
        return self.fc2(F.relu(self.fc1(x)))
# 定义编码器层
class EncoderLayer(nn.Module):
    def __init__(self, embed_size, heads, forward_expansion, dropout):
        super(EncoderLayer, self).__init__()
        self.attention = MultiHeadAttention(embed_size, heads)
        self.norm1 = nn.LayerNorm(embed_size)
        self.norm2 = nn.LayerNorm(embed_size)
        self.feed_forward = FeedForward(embed_size, forward_expansion)
        self.dropout = nn.Dropout(dropout)
    def forward(self, x):
        attention = self.attention(x)
        x = self.dropout(self.norm1(attention + x))  # 残差连接和层归一化
        forward = self.feed_forward(x)
        x = self.dropout(self.norm2(forward + x))  # 残差连接和层归一化
        return x
# 定义整个编码器
class Encoder(nn.Module):
    def __init__(self, embed_size, num_layers, heads, forward_expansion, dropout, input_dim):
        super(Encoder, self).__init__()
        self.layers = nn.ModuleList(
            [
                EncoderLayer(embed_size, heads, forward_expansion, dropout)
                for _ in range(num_layers)
            ]
        )
        self.dropout = nn.Dropout(dropout)
        self.embedding = nn.Embedding(input_dim, embed_size)
    def forward(self, x):
        N, seq_length = x.shape
        x = self.dropout(self.embedding(x))  # 嵌入层
        for layer in self.layers:
            x = layer(x)  # 逐层传递
        return x
# 测试编码器
if __name__ == "__main__":
    embed_size = 256  # 嵌入维度
    num_layers = 6    # 编码器层数
    heads = 8         # 注意力头数
    forward_expansion = 512  # 前馈网络的扩展维度
    dropout = 0.1     # dropout 概率
    input_dim = 10000  # 输入词汇表大小
    x = torch.randint(0, input_dim, (32, 10))  # 模拟输入 (批次大小, 序列长度)
    encoder = Encoder(embed_size, num_layers, heads, forward_expansion, dropout, input_dim)
    out = encoder(x)
    print(out.shape)  # 输出的形状

这段代码实现了一个基于 PyTorch 的 Transformer 编码器的基本结构,包括多头自注意力机制、前馈神经网络、编码器层等。你可以根据需要调整参数,例如嵌入维度、层数、头数等。

三、编码器超参数的影响

调整Transformer编码器的超参数以优化性能,可以从以下几个方面进行:

1. 层数(Number of Layers):

增加编码器的层数可以增强模型的学习能力,使其能够捕捉更复杂的特征和关系。但同时,过多的层数可能导致过拟合和训练成本的增加。需要根据具体任务和数据集大小来平衡层数。

2. 头数(Number of Heads):

在多头自注意力机制中,头数的增加可以提高模型对不同子空间信息的捕捉能力。但头数过多可能会导致参数量大幅增加,增加训练难度和计算成本。

3. 模型维度(Model Dimension):

即隐藏层的维度,较大的模型维度可以提供更多的表示能力,但也会增加模型的参数量和计算复杂度。需要根据任务的复杂性和可用计算资源来调整。

4. 前馈网络维度(Feed Forward Network Dimension)

前馈网络的维度影响模型的非线性变换能力。较大的维度可以提供更强的变换能力,但也会增加计算负担。

5. dropout率(Dropout Rate):

Dropout是一种正则化技术,可以减少模型过拟合的风险。合理的dropout率可以帮助模型泛化得更好,但过高的dropout率可能会导致信息丢失。

6. 学习率(Learning Rate):

学习率对模型的训练速度和最终性能有重要影响。较低的学习率可能导致训练速度慢,而较高的学习率可能导致训练不稳定。可以使用学习率衰减策略或自适应学习率优化算法(如Adam)来调整。

7. 批量大小(Batch Size):

批量大小影响模型训练的稳定性和内存消耗。较大的批量可以提高内存利用率,但可能影响模型的收敛速度和泛化能力。

8. 优化器选择(Optimizer Selection):

不同的优化器(如SGD、Adam、RMSprop等)对模型的训练动态和最终性能有不同的影响。选择合适的优化器和其参数(如动量、衰减率等)对模型性能至关重要。

综上所述,调整Transformer编码器的超参数是一个需要综合考虑多个因素的过程,需要根据具体任务、数据集和计算资源进行实验和调整。

四、如何系统学习掌握AI大模型?

AI大模型作为人工智能领域的重要技术突破,正成为推动各行各业创新和转型的关键力量。抓住AI大模型的风口,掌握AI大模型的知识和技能将变得越来越重要。

学习AI大模型是一个系统的过程,需要从基础开始,逐步深入到更高级的技术。

这里给大家精心整理了一份全面的AI大模型学习资源,包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享

1. 成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

这里,我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。
在这里插入图片描述

2. 大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

在这里插入图片描述

3. 大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

在这里插入图片描述

4. 2024行业报告

行业分析主要包括对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

在这里插入图片描述

5. 大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

在这里插入图片描述

6. 大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

在这里插入图片描述

全套的AI大模型学习资源已经整理打包,有需要的小伙伴可以微信扫描下方CSDN官方认证二维码,免费领取【保证100%免费

VIT(Vision Transformer)是一种基于Transformer结构的视觉编码器模型。它将图像分割为一系列的图像块(patches),然后将这些图像块转换为序列数据,再通过Transformer模型进行处理。 VIT的编码器结构主要包括以下几个部分: 1. 图像块分割:将输入图像分割为固定大小的图像块,通常是将图像划分为非重叠的块。 2. 嵌入层(Embedding):将每个图像块映射到一个低维特征向量,常用的方式是通过一个线性变换将每个图像块的像素值转换为一个固定大小的向量。 3. 位置编码(Positional Encoding):为了保留序列的位置信息,在嵌入特征向量中添加位置编码,使得不同位置的图像块可以在模型中进行区分。 4. Transformer编码器层:VIT使用多层Transformer编码器来处理嵌入特征向量序列。每个Transformer编码器层由多头自注意力机制(Multi-head Self-Attention)、前馈神经网络(Feed-Forward Neural Network)和残差连接(Residual Connections)组成。 5. 全局平均池化(Global Average Pooling):为了得到整个图像的表示,对最后一个Transformer编码器层的输出进行全局平均池化操作,将序列数据转换为一个固定维度的向量表示。 6. 分类层:将全局平均池化的输出连接到一个分类层(通常是一个全连接层),用于进行最终的分类预测。 总结起来,VIT的编码器结构可以看作是将图像块分割、嵌入、位置编码和多层Transformer编码器结合起来,最后通过全局平均池化和分类层进行预测。这种结构使得VIT能够在视觉任务中取得很好的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值