当前位置: 首页 > article >正文

深入解析 Transformer 模型:编码器和解码器的完整实现

14. encoder-decoder

深入解析 Transformer 模型:编码器和解码器的完整实现

Transformer 模型自提出以来,就以其并行计算的高效性和卓越的自然语言处理性能受到广泛关注。本文将深入介绍 Transformer 的整体架构,包括编码器(Encoder)和解码器(Decoder)模块的具体实现和作用,带你逐步理解如何构建一个完整的 Transformer 模型。


Transformer 的整体结构

Transformer 模型主要包含两个关键部分:编码器(Encoder)和解码器(Decoder)。

  1. 编码器:编码器将输入序列中的每个词转换为特征向量,并生成一个编码输出,这些编码包含了输入序列的语义信息。
  2. 解码器:解码器根据编码器的输出及已生成的词语,逐步生成目标输出序列。

整体流程:

  • 输入嵌入层和位置编码:将输入词和目标词嵌入到向量空间并添加位置信息。
  • 多层编码器块和解码器块的堆叠:编码器块和解码器块分别进行多层堆叠,以捕获深层次的上下文关系。
  • 输出层:解码器生成的结果经过线性层输出为词汇表大小的向量,以生成目标词。

Transformer 编码器和解码器的代码实现

以下代码实现了一个完整的 Transformer 类,包括编码器、解码器和输出层的组合。

import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    def __init__(self, embed_size, max_length=100):
        super(PositionalEncoding, self).__init__()
        self.encoding = torch.zeros(max_length, embed_size)
        position = torch.arange(0, max_length, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, embed_size, 2).float() * (-math.log(10000.0) / embed_size))
        self.encoding[:, 0::2] = torch.sin(position * div_term)
        self.encoding[:, 1::2] = torch.cos(position * div_term)
        self.encoding = self.encoding.unsqueeze(0)

    def forward(self, x):
        return x + self.encoding[:, :x.size(1), :].to(x.device)

class Transformer(nn.Module):
    def __init__(self, src_vocab_size, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
        super(Transformer, self).__init__()
        self.encoder = TransformerEncoder(src_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
        self.decoder = TransformerDecoder(tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
        self.fc_out = nn.Linear(embed_size, tgt_vocab_size)

    def forward(self, src, tgt, src_mask, tgt_mask):
        enc_out = self.encoder(src, src_mask)
        dec_out = self.decoder(tgt, enc_out, src_mask, tgt_mask)
        out = self.fc_out(dec_out)
        return out


代码解析:逐步分析 Transformer 主要模块的实现

1. 编码器类 TransformerEncoder

编码器的主要任务是将输入序列转换为一个编码表示,它包含以下几个步骤:

class TransformerEncoder(nn.Module):
    def __init__(self, src_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
        super(TransformerEncoder, self).__init__()
        self.word_embedding = nn.Embedding(src_vocab_size, embed_size)
        self.position_encoding = PositionalEncoding(embed_size, max_length)
        self.layers = nn.ModuleList(
            [EncoderBlock(embed_size, heads, forward_expansion, dropout) for _ in range(num_layers)]
        )
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask):
        out = self.word_embedding(x)
        out = self.position_encoding(out)
        out = self.dropout(out)
        for layer in self.layers:
            out = layer(out, mask)
        return out

  • 输入嵌入:将输入的词索引转化为嵌入向量。
  • 位置编码:为每个词嵌入添加位置信息,使得模型能够识别输入词的顺序。
  • 多层编码器块的堆叠:通过堆叠多个 EncoderBlock 层,使得模型可以学习深层次的上下文关系。

2. 解码器类 TransformerDecoder

解码器模块负责生成目标序列中的每一个词。它结合了编码器的输出和当前生成的词语,以保证生成结果与上下文一致。

class TransformerDecoder(nn.Module):
    def __init__(self, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length):
        super(TransformerDecoder, self).__init__()
        self.word_embedding = nn.Embedding(tgt_vocab_size, embed_size)
        self.position_encoding = PositionalEncoding(embed_size, max_length)
        self.layers = nn.ModuleList(
            [DecoderBlock(embed_size, heads, forward_expansion, dropout) for _ in range(num_layers)]
        )
        self.fc_out = nn.Linear(embed_size, tgt_vocab_size)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, enc_out, src_mask, tgt_mask):
        out = self.word_embedding(x)
        out = self.position_encoding(out)
        out = self.dropout(out)
        for layer in self.layers:
            out = layer(out, enc_out, src_mask, tgt_mask)
        return self.fc_out(out)

  • 输入嵌入和位置编码:与编码器类似,将目标序列的词索引转化为嵌入向量,并添加位置信息。
  • 多层解码器块的堆叠:堆叠多个解码器块,每个块包含自注意力和编码器-解码器注意力。
  • 输出层:将解码器输出映射到目标词汇表大小,用于生成目标序列的下一个词。

编码器-解码器块的核心组件

1. EncoderBlock 的实现

编码器块(EncoderBlock)由自注意力机制、多层前馈神经网络和残差连接组成。

class EncoderBlock(nn.Module):
    def __init__(self, embed_size, heads, forward_expansion, dropout):
        super(EncoderBlock, 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, mask):
        attention = self.attention(x, x, x, mask)
        x = self.dropout(self.norm1(attention + x))
        forward = self.feed_forward(x)
        out = self.dropout(self.norm2(forward + x))
        return out

  • 多头自注意力层:捕捉序列中词与词之间的关系,帮助模型理解上下文信息。
  • 残差连接和正则化:保持梯度稳定,避免梯度消失,并防止模型过拟合。
  • 前馈神经网络:用于进一步提取特征信息。

2. DecoderBlock 的实现

解码器块(DecoderBlock)相比编码器块多了一个“编码器-解码器注意力层”,用于将编码器的输出信息整合进解码器的生成过程中。

class DecoderBlock(nn.Module):
    def __init__(self, embed_size, heads, forward_expansion, dropout):
        super(DecoderBlock, self).__init__()
        self.attention = MultiHeadAttention(embed_size, heads)
        self.norm1 = nn.LayerNorm(embed_size)
        self.norm2 = nn.LayerNorm(embed_size)
        self.norm3 = nn.LayerNorm(embed_size)

        self.encoder_decoder_attention = MultiHeadAttention(embed_size, heads)
        self.feed_forward = FeedForward(embed_size, forward_expansion)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, enc_out, src_mask, tgt_mask):
        attention = self.attention(x, x, x, tgt_mask)
        x = self.dropout(self.norm1(attention + x))

        enc_dec_attention = self.encoder_decoder_attention(x, enc_out, enc_out, src_mask)
        x = self.dropout(self.norm2(enc_dec_attention + x))

        forward = self.feed_forward(x)
        out = self.dropout(self.norm3(forward + x))

        return out

  • Masked Self-Attention:生成每个目标词时只能关注到当前和之前的词,确保生成词的顺序一致。
  • 编码器-解码器注意力层:根据编码器的输出,结合当前词的上下文信息生成目标词。
  • 前馈神经网络和残差连接:增强模型的非线性表达能力,确保梯度流畅传递。

测试 Transformer 模型

以下代码用于测试 Transformer 模型

的整体结构是否正确,确保编码器和解码器的搭配工作正常。

# 测试代码
src_vocab_size = 10000
tgt_vocab_size = 10000
embed_size = 512
num_layers = 6
heads = 8
forward_expansion = 4
dropout = 0.1
max_length = 100

src_seq_length, tgt_seq_length, batch_size = 20, 20, 2
src = torch.randint(0, src_vocab_size, (batch_size, src_seq_length))
tgt = torch.randint(0, tgt_vocab_size, (batch_size, tgt_seq_length))
src_mask, tgt_mask = None, None

# 实例化 Transformer 模型并进行前向传播
model = Transformer(src_vocab_size, tgt_vocab_size, embed_size, num_layers, heads, forward_expansion, dropout, max_length)
out = model(src, tgt, src_mask, tgt_mask)

print("Transformer 模型输出形状:", out.shape)

  • 预期输出(batch_size, tgt_seq_length, tgt_vocab_size),例如 (2, 20, 10000)

总结

我们完成了 Transformer 模型中编码器和解码器的构建,并将它们组合成完整的模型。编码器负责将输入序列转化为高维特征,解码器在生成每个目标词时参考编码器输出,从而生成语义一致的输出序列。了解 Transformer 的内部结构有助于我们进一步优化模型,适用于各种 NLP 任务,如机器翻译和文本生成等。希望本文能帮助你理解 Transformer 编码器和解码器的核心设计和实现流程。


http://www.kler.cn/a/383198.html

相关文章:

  • Debian 12 安装配置 fail2ban 保护 SSH 访问
  • 京东大数据治理探索与实践 | 京东零售技术实践
  • Redis 持久化机制详解
  • 取多个集合的交集
  • GUI07-学工具栏,懂MVC
  • Android Studio新建项目在源码中编译
  • 易考八股文之谈谈对sentinel的理解和作用?
  • 关于路由笔记
  • Qt C++,Link custom data to the QCustomPlot data
  • 如何用Neo4j做知识图谱
  • yelp数据集上识别潜在的热门商家
  • 机器学习—前向传播的一般实现
  • 爬虫入门urllib 和 request(二)
  • Backend - Python 爬取网页数据并保存在Excel文件中
  • 【React】JSX规则
  • 产品经理必备秘籍:打造有效的产品 Roadmap
  • 原生鸿蒙应用市场:赋能开发者全生命周期服务体验
  • GAN的基本原理
  • Linux学习笔记之vim入门
  • 【数据结构】二叉树——层序遍历
  • HTML5+css3(伪类,动态伪类,结构伪类,否定伪类,UI伪类,语言伪类,link,hover,active,visited,focus)
  • 网络优化如何利用改IP软件解除地域限制
  • VBA02-初识宏——EXCEL录像机
  • Windows核心编程笔记——DLL基础
  • 【AI视频换脸整合包及教程】AI换脸新星:Rope——让换脸变得如此简单
  • LeetCode题练习与总结:O(1) 时间插入、删除和获取随机元素 - 允许重复--381