0基础跟德姆(dom)一起学AI 自然语言处理18-解码器部分实现

1 解码器介绍

解码器部分:

  • 由N个解码器层堆叠而成
  • 每个解码器层由三个子层连接结构组成
  • 第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接
  • 第二个子层连接结构包括一个多头注意力子层和规范化层以及一个残差连接
  • 第三个子层连接结构包括一个前馈全连接子层和规范化层以及一个残差连接
  • 说明:
  • 解码器层中的各个部分,如,多头注意力机制,规范化层,前馈全连接网络,子层连接结构都与编码器中的实现相同. 因此这里可以直接拿来构建解码器层.

2 解码器层

2.1 解码器层的作用

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

2.2 解码器层的代码实现

# 解码器层类 DecoderLayer 实现思路分析
# init函数 (self, size, self_attn, src_attn, feed_forward, dropout)
    # 词嵌入维度尺寸大小size 自注意力机制层对象self_attn 一般注意力机制层对象src_attn 前馈全连接层对象feed_forward
    # clones3子层连接结构 self.sublayer = clones(SublayerConnection(size,dropout),3)
# forward函数 (self, x, memory, source_mask, target_mask)
    # 数据经过子层连接结构1 self.sublayer[0](x, lambda x:self.self_attn(x, x, x, target_mask))
    # 数据经过子层连接结构2 self.sublayer[1](x, lambda x:self.src_attn(x, m, m, source_mask))
    # 数据经过子层连接结构3 self.sublayer[2](x, self.feed_forward)

class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        # 词嵌入维度尺寸大小
        self.size = size
        # 自注意力机制层对象 q=k=v
        self.self_attn = self_attn
        # 一遍注意力机制对象 q!=k=v
        self.src_attn = src_attn
        # 前馈全连接层对象
        self.feed_forward = feed_forward
        # clones3子层连接结构
        self.sublayer = clones(SublayerConnection(size, dropout), 3)

    def forward(self, x, memory, source_mask, target_mask):
        m = memory
        # 数据经过子层连接结构1
        x = self.sublayer[0](x, lambda x:self.self_attn(x, x, x, target_mask))
        # 数据经过子层连接结构2
        x = self.sublayer[1](x, lambda x:self.src_attn (x, m, m, source_mask))
        # 数据经过子层连接结构3
        x = self.sublayer[2](x, self.feed_forward)
        return  x
  • 函数调用
def dm_test_DecoderLayer():
    d_model = 512
    vocab = 1000  # 词表大小是1000
    # 输入x 是一个使用Variable封装的长整型张量, 形状是2 x 4
    x = Variable(torch.LongTensor([[100, 2, 421, 508], [491, 998, 1, 221]]))

    emb = Embeddings(d_model, vocab)
    embr = emb(x)

    dropout = 0.2
    max_len = 60  # 句子最大长度
    x = embr  # [2, 4, 512]
    pe = PositionalEncoding(d_model, dropout, max_len)
    pe_result = pe(x)
    x = pe_result  # 获取位置编码器层 编码以后的结果


    # 类的实例化参数与解码器层类似, 相比多出了src_attn, 但是和self_attn是同一个类.
    head = 8
    d_ff = 64
    size = 512
    self_attn = src_attn = MultiHeadedAttention(head, d_model, dropout)

    # 前馈全连接层也和之前相同
    ff = PositionwiseFeedForward(d_model, d_ff, dropout)
    x = pe_result

    # 产生编码器结果 # 注意此函数返回编码以后的结果 要有返回值
    en_result = dm_test_Encoder()
    memory = en_result
    mask = Variable(torch.zeros(8, 4, 4))
    source_mask = target_mask = mask

    # 实例化解码器层 对象
    dl = DecoderLayer(size, self_attn, src_attn, ff, dropout)

    # 对象调用
    dl_result = dl(x, memory, source_mask, target_mask)

    print(dl_result.shape)
    print(dl_result)
  • 输出效果
torch.Size([2, 4, 512])
tensor([[[-27.4382,   0.6516,   6.6735,  ..., -42.2930, -44.9728,   0.1264],
         [-28.7835,  26.4919,  -0.5608,  ...,   0.5652,  -2.9634,   9.7438],
         [-19.6998,  13.5164,  45.8216,  ...,  23.9127,  22.0259,  34.0195],
         [ -0.1647,   0.2331, -36.4173,  ..., -20.0557,  29.4576,   2.5048]],

        [[ 29.1466,  50.7677,  26.4624,  ..., -39.1015, -27.9200,  19.6819],
         [-10.7069,  28.0897,  -0.4107,  ..., -35.7795,   9.6881,   0.3228],
         [ -6.9027, -16.0590,  -0.8897,  ...,   4.0253,   2.5961,  37.4659],
         [  9.8892,  32.7008,  -6.6772,  ..., -11.4273, -21.4676,  32.5692]]],
       grad_fn=<AddBackward0>)

2.3 解码器层总结[¶](#2.3 解码器层总结¶)

  • 学习了解码器层的作用:

    • 作为解码器的组成单元, 每个解码器层根据给定的输入向目标方向进行特征提取操作,即解码过程.
  • 学习并实现了解码器层的类: DecoderLayer

    • 类的初始化函数的参数有5个, 分别是size,代表词嵌入的维度大小, 同时也代表解码器层的尺寸,第二个是self_attn,多头自注意力对象,也就是说这个注意力机制需要Q=K=V,第三个是src_attn,多头注意力对象,这里Q!=K=V, 第四个是前馈全连接层对象,最后就是droupout置0比率.
    • forward函数的参数有4个,分别是来自上一层的输入x,来自编码器层的语义存储变量mermory, 以及源数据掩码张量和目标数据掩码张量.
    • 最终输出了由编码器输入和目标数据一同作用的特征提取结果.

3 解码器

3.1 解码器的作用

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

3.2 解码器的代码分析

# 解码器类 Decoder 实现思路分析
# init函数 (self, layer, N):
    # self.layers clones N个解码器层clones(layer, N)
    # self.norm 定义规范化层 LayerNorm(layer.size)
# forward函数 (self, x, memory, source_mask, target_mask)
    # 数据以此经过各个子层  x = layer(x, memory, source_mask, target_mask)
    # 数据最后经过规范化层  return self.norm(x)
    # 返回处理好的数据

class Decoder(nn.Module):

    def __init__(self, layer, N):
        # 参数layer 解码器层对象
        # 参数N 解码器层对象的个数

        super(Decoder, self).__init__()

        # clones N个解码器层
        self.layers = clones(layer, N)

        # 定义规范化层
        self.norm = LayerNorm(layer.size)

    def forward(self, x, memory, source_mask, target_mask):

        # 数据以此经过各个子层
        for layer in self.layers:
            x = layer(x, memory, source_mask, target_mask)

        # 数据最后经过规范化层
        return self.norm(x)
  • 函数调用
# 测试 解码器
def dm_test_Decoder():
    d_model = 512
    vocab = 1000  # 词表大小是1000
    # 输入x 是一个使用Variable封装的长整型张量, 形状是2 x 4
    x = Variable(torch.LongTensor([[100, 2, 421, 508], [491, 998, 1, 221]]))

    emb = Embeddings(d_model, vocab)
    embr = emb(x)

    dropout = 0.2
    max_len = 60  # 句子最大长度
    x = embr  # [2, 4, 512]
    pe = PositionalEncoding(d_model, dropout, max_len)
    pe_result = pe(x)
    x = pe_result  # 获取位置编码器层 编码以后的结果


    # 分别是解码器层layer和解码器层的个数N
    size = 512
    d_model = 512
    head = 8
    d_ff = 64
    dropout = 0.2
    c = copy.deepcopy

    # 多头注意力对象
    attn = MultiHeadedAttention(head, d_model)

    # 前馈全连接层
    ff = PositionwiseFeedForward(d_model, d_ff, dropout)

    # 解码器层
    layer = DecoderLayer(d_model, c(attn), c(attn), c(ff), dropout)
    N = 6
    # 输入参数与解码器层的输入参数相同
    x = pe_result

    # 产生编码器结果
    en_result = demo238_test_Encoder()
    memory = en_result

    # 掩码对象
    mask = Variable(torch.zeros(8, 4, 4))

    # sorce掩码 target掩码
    source_mask = target_mask = mask

    # 创建 解码器 对象
    de = Decoder(layer, N)

    # 解码器对象 解码
    de_result = de(x, memory, source_mask, target_mask)
    print(de_result)
    print(de_result.shape)
  • 输出结果
tensor([[[ 0.1853, -0.8858, -0.0393,  ..., -1.4989, -1.4008,  0.8456],
         [-1.0841, -0.0777,  0.0836,  ..., -1.5568,  1.4074, -0.0848],
         [-0.4107, -0.1306, -0.0069,  ..., -0.2370, -0.1259,  0.7591],
         [ 1.2895,  0.2655,  1.1799,  ..., -0.2413,  0.9087,  0.4055]],

        [[ 0.3645, -0.3991, -1.2862,  ..., -0.7078, -0.1457, -1.0457],
         [ 0.0146, -0.0639, -1.2143,  ..., -0.7865, -0.1270,  0.5623],
         [ 0.0685, -0.1465, -0.1354,  ...,  0.0738, -0.9769, -1.4295],
         [ 0.3168,  0.6305, -0.1549,  ...,  1.0969,  1.8775, -0.5154]]],
       grad_fn=<AddBackward0>)
torch.Size([2, 4, 512])
相关推荐
AI浩9 分钟前
【面试总结】FFN(前馈神经网络)在Transformer模型中先升维再降维的原因
人工智能·深度学习·计算机视觉·transformer
可为测控19 分钟前
图像处理基础(4):高斯滤波器详解
人工智能·算法·计算机视觉
ℳ₯㎕ddzོꦿ࿐1 小时前
解决Python 在 Flask 开发模式下定时任务启动两次的问题
开发语言·python·flask
CodeClimb1 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
一水鉴天1 小时前
为AI聊天工具添加一个知识系统 之63 详细设计 之4:AI操作系统 之2 智能合约
开发语言·人工智能·python
Channing Lewis1 小时前
什么是 Flask 的蓝图(Blueprint)
后端·python·flask
倔强的石头1061 小时前
解锁辅助驾驶新境界:基于昇腾 AI 异构计算架构 CANN 的应用探秘
人工智能·架构
B站计算机毕业设计超人1 小时前
计算机毕业设计hadoop+spark股票基金推荐系统 股票基金预测系统 股票基金可视化系统 股票基金数据分析 股票基金大数据 股票基金爬虫
大数据·hadoop·python·spark·课程设计·数据可视化·推荐算法
觅远2 小时前
python+playwright自动化测试(四):元素操作(键盘鼠标事件)、文件上传
python·自动化
佛州小李哥2 小时前
Agent群舞,在亚马逊云科技搭建数字营销多代理(Multi-Agent)(下篇)
人工智能·科技·ai·语言模型·云计算·aws·亚马逊云科技