4. Transformer_3_解码器部分

1. 解码器介绍

2. 解码器层

2.1 解码器层的作用

作为解码器的组成单元,每个解码器层根據给定的输入向目标方向进行特征提取操作,即解码过程;

2.2 解码器层的代码分析

init中:参数:size, self_attn, src_attn, feed_forward, dropout;size词嵌入维度、self_attn自注意力机制、src_attn一般注意力、feed_forward前馈全连接层对象、dropout随机失活的系数;

forward中:参数: x, memory, source_mask, target_mask;x是来自解码器端的输入、memory来自编码器的输出结果、target_mask作用在第一个子层连接层结构即sentence_mask防止未来信息被掩盖、source_mask即padding_mask对目标文本的语句的pad进行mask;x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x, target_mask))第一个子连接层:输入的第一个参数x即为解码器的x、lambda式对应的为 实现子层连接结构 class SubLayerConnectionforward(self, x, sublayer)中的 sublayerself.self_attn(..)返回的是自注意力机制(QKV都=x)的对象;最终返回一个新的x。

再送给第二个子连接层:x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m, source_mask))输入的第一个参数x是上一步输出的第一个子连接层的输出结果、第二个参数返回的self.src_attn(x, m, m, source_mask)不是自注意力,而是一般注意力(Q=x,KV=m,Q!=K=V);再将返回的结果送给第三个子连接层 feed_forward;

python 复制代码
# todo 1.定义解码器层(由3个子连接层构成)
class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        # size词嵌入维度,self_attn自注意力机制QKV,src_attn一般注意力机制Q!=K=V,feed_forward前馈全连接层
        self.size = size
        self.self_attn = self_attn
        self.src_attn = src_attn
        self.feed_forward = feed_forward
        # 克隆3个子层连接对象
        self.sub_layers = clones(SublayerConnection(size, dropout), 3)

    def forward(self, y, encoder_output, source_mask, target_mask):
        # y[2,4,512]:来自解码器的输入,encoder_output[2,4,512]:来自编码器的输出结果,
        # source_mask:作用在第二个子层连接结构的多头注意力机制对象上,进行padding_mask,
        # target_mask:作用在第一个子层连接结构的多头自注意力机制对象上,进行sentence_mask
        # 1.将y送入第一个子层连接结构得到 多头自注意力机制 + add + norm 之后的结果
        y1 = self.sub_layers[0].forward(y, lambda y: self.self_attn(y, y, y, target_mask))
        # y1 = self.sub_layers[0](y, lambda y: self.self_attn(y, y, y, target_mask)) #forward可省略

        # 2.将y1送入第二个子层连接结构得到 多头注意力机制 + add + norm 之后的结果
        y2 = self.sub_layers[1].forward(y1, lambda y1: self.src_attn(y1, encoder_output, encoder_output, source_mask))
        # y2 = self.sub_layers[1](y1, lambda y1: self.src_attn(y1, encoder_output, encoder_output, source_mask))
        # 3.将y2送入第三个子层连接结构得到 前馈全连接层+add+norm 之后的结果
        y3 = self.sub_layers[2](y2, self.feed_forward)
        return y3


# 定义解码器(由3个子连接层构成) 测试
def test_decoder_layer():
    # 定义假如解码器端的输入也是2行6列
    y = torch.tensor([[3, 4, 7, 10, 5, 70],
                      [2, 5, 8, 19, 20, 34]])
    # 1.经过embedding层得到的词嵌入结果
    my_embed = Embedding(vocab_size=2000, d_model=512)
    embed_y = my_embed(y)
    print(f'解码器embedding之后的结果:{embed_y.shape}')  # [2, 6, 512]
    # 2.经过position encoding位置编码层得到的位置编码信息
    my_pe = PositionEncoding(d_model=512, dropout_p=0.1, max_len=60)
    position_y = my_pe(embed_y)
    print(f'解码器位置编码之后结果:{position_y.shape}')  # [2, 6, 512]
    # 3.实例化多头自注意力机制的对象
    self_atten = MultiHeadAttention(embedding_dim=512, head=8, dropout=0.1)
    src_atten = copy.deepcopy(self_atten)
    # 4.实例化前馈全连接层对象
    feed_forward = FeedForward(d_model=512, d_ff=1024)
    # 5.实例化解码器层对象
    decoder_layer = DecoderLayer(size=512, self_attn=self_atten, src_attn=src_atten, feed_forward=feed_forward,
                                 dropout=0.1)
    # 6.整理解码器层的输入:y, encoder_output, source_mask, target_mask
    encoder_output = test_encoder()
    print(f'编码器层输出的结果:{encoder_output.shape}')  # [2, 4, 512]
    # target_mask --> 解码器的query和key --> [2, 6, 512] --> query和key的转置相乘之后 --> [2, 6, 6]
    target_mask = torch.zeros(8, 6, 6)
    # target_mask --> 解码器的query --> [2, 6, 512] --> 和key(编码器) --> [2, 4, 512] --> query和key的转置相乘之后 --> [2, 6, 4]
    source_mask = torch.zeros(8, 6, 4)
    output = decoder_layer(position_y, encoder_output, source_mask, target_mask)
    print(f'解码器层得到结果:{output.shape}')  # [2, 6, 512]


if __name__ == '__main__':
    test_decoder_layer()

3. 解码器

解码器是由6个解码器层堆叠而成;

3.1 解码器的作用

根据编码器的结果以及上一次预测的结果,对下一次可能出现的'值'进行特征表示;

3.2 解码器的代码分析

解码器是由6个解码器层堆叠而成;

init中:参数:layer, N;克隆了6个解码器层,最后一个进行规范化,前向传播时将这6层循环迭代,第一层的得到的结果送入第二层,第二层的结果送到第三层,...,一直送到第6层,第6层得到的结果经过norm得到最终结果;

python 复制代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
import copy
from dm1_input import *
from dm2_encoder import *


# todo 1.定义解码器层(由3个子连接层构成)
class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        # size词嵌入维度,self_attn自注意力机制QKV,src_attn一般注意力机制Q!=K=V,feed_forward前馈全连接层
        self.size = size
        self.self_attn = self_attn
        self.src_attn = src_attn
        self.feed_forward = feed_forward
        # 克隆3个子层连接对象
        self.sub_layers = clones(SublayerConnection(size, dropout), 3)

    def forward(self, y, encoder_output, source_mask, target_mask):
        # y[2,4,512]:来自解码器的输入,encoder_output[2,4,512]:来自编码器的输出结果,
        # source_mask:作用在第二个子层连接结构的多头注意力机制对象上,进行padding_mask,
        # target_mask:作用在第一个子层连接结构的多头自注意力机制对象上,进行sentence_mask
        # 1.将y送入第一个子层连接结构得到 多头自注意力机制 + add + norm 之后的结果
        y1 = self.sub_layers[0].forward(y, lambda y: self.self_attn(y, y, y, target_mask))
        # y1 = self.sub_layers[0](y, lambda y: self.self_attn(y, y, y, target_mask)) #forward可省略

        # 2.将y1送入第二个子层连接结构得到 多头注意力机制 + add + norm 之后的结果
        y2 = self.sub_layers[1].forward(y1, lambda y1: self.src_attn(y1, encoder_output, encoder_output, source_mask))
        # y2 = self.sub_layers[1](y1, lambda y1: self.src_attn(y1, encoder_output, encoder_output, source_mask))
        # 3.将y2送入第三个子层连接结构得到 前馈全连接层+add+norm 之后的结果
        y3 = self.sub_layers[2](y2, self.feed_forward)
        return y3


# 定义解码器(由3个子连接层构成) 测试
def test_decoder_layer():
    # 定义假如解码器端的输入也是2行6列
    y = torch.tensor([[3, 4, 7, 10, 5, 70],
                      [2, 5, 8, 19, 20, 34]])
    # 1.经过embedding层得到的词嵌入结果
    my_embed = Embedding(vocab_size=2000, d_model=512)
    embed_y = my_embed(y)
    print(f'解码器embedding之后的结果:{embed_y.shape}')  # [2, 6, 512]
    # 2.经过position encoding位置编码层得到的位置编码信息
    my_pe = PositionEncoding(d_model=512, dropout_p=0.1, max_len=60)
    position_y = my_pe(embed_y)
    print(f'解码器位置编码之后结果:{position_y.shape}')  # [2, 6, 512]
    # 3.实例化多头自注意力机制的对象
    self_atten = MultiHeadAttention(embedding_dim=512, head=8, dropout=0.1)
    src_atten = copy.deepcopy(self_atten)
    # 4.实例化前馈全连接层对象
    feed_forward = FeedForward(d_model=512, d_ff=1024)
    # 5.实例化解码器层对象
    decoder_layer = DecoderLayer(size=512, self_attn=self_atten, src_attn=src_atten, feed_forward=feed_forward,
                                 dropout=0.1)
    # 6.整理解码器层的输入:y, encoder_output, source_mask, target_mask
    encoder_output = test_encoder()
    print(f'编码器层输出的结果:{encoder_output.shape}')  # [2, 4, 512]
    # target_mask --> 解码器的query和key --> [2, 6, 512] --> query和key的转置相乘之后 --> [2, 6, 6]
    target_mask = torch.zeros(8, 6, 6)
    # target_mask --> 解码器的query --> [2, 6, 512] --> 和key(编码器) --> [2, 4, 512] --> query和key的转置相乘之后 --> [2, 6, 4]
    source_mask = torch.zeros(8, 6, 4)
    output = decoder_layer(position_y, encoder_output, source_mask, target_mask)
    print(f'解码器层得到结果:{output.shape}')  # [2, 6, 512]


# todo 2.定义解码器(由6个解码器层堆叠而成)
class Decoder(nn.Module):
    def __init__(self, layer, N):
        super(Decoder, self).__init__()
        # 克隆6个解码器层
        self.layers = clones(layer, N)
        # 规范化层
        self.norm = LayerNorm(layer.size)

    def forward(self, y, encoder_output, source_mask, target_mask):
        for layer in self.layers:
            y = layer(y, encoder_output, source_mask, target_mask)
        return self.norm(y)


# 定义解码器(由6个解码器层堆叠而成) 测试
def test_decoder():
    # 定义假如解码器端的输入也是2行6列
    y = torch.tensor([[3, 4, 7, 10, 5, 70],
                      [2, 5, 8, 19, 20, 34]])
    # 1.经过embedding层得到的词嵌入结果
    my_embed = Embedding(vocab_size=2000, d_model=512)
    embed_y = my_embed(y)
    print(f'解码器embedding之后的结果:{embed_y.shape}')  # [2, 6, 512]
    # 2.经过position encoding位置编码层得到的位置编码信息
    my_pe = PositionEncoding(d_model=512, dropout_p=0.1, max_len=60)
    position_y = my_pe(embed_y)
    print(f'解码器位置编码之后结果:{position_y.shape}')  # [2, 6, 512]
    # 3.实例化多头自注意力机制的对象
    self_atten = MultiHeadAttention(embedding_dim=512, head=8, dropout=0.1)
    src_atten = copy.deepcopy(self_atten)
    # 4.实例化前馈全连接层对象
    feed_forward = FeedForward(d_model=512, d_ff=1024)
    # 5.实例化解码器层对象
    decoder_layer = DecoderLayer(size=512, self_attn=self_atten, src_attn=src_atten, feed_forward=feed_forward,
                                 dropout=0.1)
    # 6.整理解码器层的输入:y, encoder_output, source_mask, target_mask
    encoder_output = test_encoder()
    print(f'编码器层输出的结果:{encoder_output.shape}')  # [2, 4, 512]
    # target_mask --> 解码器的query和key --> [2, 6, 512] --> query和key的转置相乘之后 --> [2, 6, 6]
    target_mask = torch.zeros(8, 6, 6)
    # target_mask --> 解码器的query --> [2, 6, 512] --> 和key(编码器) --> [2, 4, 512] --> query和key的转置相乘之后 --> [2, 6, 4]
    source_mask = torch.zeros(8, 6, 4)
    # 实例化解码器对象
    decoder = Decoder(decoder_layer, N=6)
    output = decoder(position_y, encoder_output, source_mask, target_mask)
    print(f'解码器层得到结果:{output.shape}')  # [2, 6, 512]


if __name__ == '__main__':
    # test_decoder_layer()
    test_decoder()
相关推荐
HLC++5 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼9 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼9 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
大鱼>10 小时前
深入Real-ESRGAN架构:RRDBNet设计精髓与ONNX/TensorRT部署优化
人工智能·深度学习·架构
壮哥_icon10 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
2zcode11 小时前
项目文档:基于MATLAB深度卷积神经网络的肺癌CT影像智能检测系统设计与实现
深度学习·matlab·cnn
m沐沐11 小时前
【深度学习】卷积神经网络 数据增强、保存最优模型实现,详细解读
人工智能·python·深度学习·机器学习·cnn·数据增强
硅谷秋水12 小时前
PhyGround:生成式世界模型中的物理推理基准测试
人工智能·深度学习·机器学习·计算机视觉·语言模型
用户693717500138412 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记12 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求