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

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 解码器层总结¶

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

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

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

相关文章:

  • 2024 年度学习总结
  • Axios 封装:处理重复调用与内容覆盖问题
  • 【日志篇】(7.6) ❀ 01. 在macOS下刷新FortiAnalyzer固件 ❀ FortiAnalyzer 日志分析
  • 【Leetcode 每日一题】2239. 找到最接近 0 的数字
  • 二十三种设计模式-装饰器模式
  • [手机Linux] 七,NextCloud优化设置
  • 阳振坤:AI 大模型的基础是数据,AI越发达,数据库价值越大
  • 基于SpringBoot的健身房管理系统【源码+文档+部署讲解】
  • 百度飞桨基与UIE结合Doccano的微调来训练自己的数据格式以满足复杂生产环境的数据识别的需要
  • 你了解什么是股指期货贴水套利吗?
  • 网络编程 | UDP组播通信
  • 【useReducer Hook】集中式管理组件复杂状态
  • CSS笔记基础篇02——浮动、标准流、定位、CSS精灵、字体图标
  • 实测点云标注工具
  • linux 安装mysql5.6
  • OpenCV相机标定与3D重建(63)校正图像的畸变函数undistort()的使用
  • Linux高级--3.3.1 C++ spdlog 开源异步日志方案
  • Kotlin Bytedeco OpenCV 图像图像50 仿射变换 图像缩放
  • 实现二叉树_堆
  • 【Mac】ComfyUI 部署
  • 算法题目总结-链表
  • 【Maui】视图界面与数据模型绑定
  • django应急物资管理系统
  • 基于FPGA的BPSK+costas环实现,包含testbench,分析不同信噪比对costas环性能影响
  • 英文隐私政策翻译
  • 【vitePress】基于github快速添加评论功能(giscus)