当前位置:   article > 正文

transformer--解码器_transformer解码器

transformer解码器

编码器中实现了编码器的各种组件,其实解码器中使用的也是这些组件,如下图:

解码器组成部分:

  1. 由N个解码器层堆叠而成
  2. 每个解码器层由三个子层连接结构组成
  3. 第一个子层连接结构包括一个多头自注意力子层和规范化层以及一个残差连接
  4. 第二个子层连接结构包括一个多头注意力子层和规范化层以及一个残差连接
  5. 第三个子层连接结构包括一个前馈全连接子层和规范化层以及一个残差连接 

解码器层code

  1. # 解码器层的类实现
  2. class DecoderLayer(nn.Module):
  3. def __init__(self, size, self_attn, src_attn, feed_forward,dropout) -> None:
  4. """
  5. size : 词嵌入维度
  6. self_attn:多头自注意对象,需要Q=K=V
  7. src_attn:多头注意力对象,这里Q!=K=V
  8. feed_forward: 前馈全连接层对象
  9. """
  10. super(DecoderLayer,self).__init__()
  11. self.size = size
  12. self.self_attn = self_attn
  13. self.src_attn = src_attn
  14. self.feed_forward = feed_forward
  15. # 根据论文图使用clones克隆三个子层对象
  16. self.sublayer = clones(SublayerConnection(size,dropout), 3)
  17. def forward(self, x, memory, source_mask, target_mask):
  18. """
  19. x : 上一层的输入
  20. memory: 来自编码器层的语义存储变量
  21. source_mask: 源码数据掩码张量,针对就是输入到解码器的数据
  22. target_mask: 目标数据掩码张量,针对解码器最后生成的数据,一个一个的推理生成的词
  23. """
  24. m = memory
  25. # 将x传入第一个子层结构,第一个子层结构输入分别是x和self_attn函数,因为是自注意力机制,所以Q=K=V=x
  26. # 最后一个参数是目标数据掩码张量,这时要对目标数据进行掩码,因为此时模型可能还没有生成任何目标数据,
  27. # 比如在解码器准备生成第一个字符或词汇时,我们其实已经传入第一个字符以便计算损失
  28. # 但是我们不希望在生成第一个字符时模型能利用这个信息,因为我们会将其遮掩,同样生成第二个字符或词汇时
  29. # 模型只能使用第一个字符或词汇信息,第二个字符以及以后得信息都不允许被模型使用
  30. x = self.sublayer[0](x, lambda x: self.self_attn(x,x,x,target_mask))
  31. # 紧接着第一层的输出进入第二个子层,这个子层是常规的注意力机制,但是q是输入x;k、v是编码层输出memory
  32. # 同样也传入source_mask, 但是进行源数据遮掩的原因并非是抑制信息泄露,而是遮蔽掉对结果没有意义的的字符而产生的注意力
  33. # 以此提升模型的效果和训练速度,这样就完成第二个子层的处理
  34. x = self.sublayer[1](x, lambda x: self.src_attn(x,m,m,source_mask))
  35. # 最后一个子层就是前馈全连接子层,经过他的处理后就可以返回结果,这就是解码器层的结构
  36. return self.sublayer[2](x,self.feed_forward)

测试代码全放到最后

测试结果:

  1. embr.shape = torch.Size([2, 4, 512])
  2. pe_result.shape = torch.Size([2, 4, 512])
  3. en_result.shape : torch.Size([2, 4, 512])
  4. en_result : tensor([[[-1.0392, -1.2399, -0.0508, ..., -0.0731, 0.0161, 0.1734],
  5. [ 0.4218, -0.8372, 0.0657, ..., 1.1024, -0.0273, 0.0458],
  6. [ 1.1038, 0.7187, -0.4767, ..., 0.0396, 0.4021, -0.2545],
  7. [-0.4050, 0.2746, 0.2608, ..., -0.0969, 0.1556, 0.7639]],
  8. [[ 1.1785, 0.7174, -0.4660, ..., -0.7642, 0.2084, -0.2262],
  9. [-0.2988, 0.7209, 0.1552, ..., -0.4515, 0.2163, -0.5891],
  10. [-0.6027, -0.3825, -0.2690, ..., 2.3163, 0.3059, -1.7363],
  11. [-0.5485, -1.7348, 0.5710, ..., -1.8011, -3.2616, 0.6475]]],
  12. grad_fn=<AddBackward0>)
  13. dl_result.shape = torch.Size([2, 4, 512])
  14. dl_result = tensor([[[-23.0521, -28.3426, -0.5458, ..., -6.1061, -0.1419, 5.0221],
  15. [ 11.1962, -23.1371, -0.3318, ..., 24.4704, -0.2596, 0.3329],
  16. [ 22.7772, 15.4876, -13.8883, ..., -0.7536, 6.2517, -6.4530],
  17. [ -8.6034, 5.9488, 4.5170, ..., -1.7604, 3.1385, 18.6994]],
  18. [[ 20.9259, 18.1934, -13.7914, ..., -18.0120, 0.2210, -6.3908],
  19. [ -9.2162, 19.0768, -0.3693, ..., -11.8371, 5.5636, -15.0215],
  20. [-14.9818, -8.8418, -8.3098, ..., 61.9500, 3.2425, -43.5170],
  21. [-16.1407, -38.8550, 10.6465, ..., -44.7966, -83.8235, 12.7915]]],
  22. grad_fn=<AddBackward0>)

解码器

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

  1. # 解码器
  2. class Decoder(nn.Module):
  3. def __init__(self,layer,N) -> None:
  4. """ layer: 解码器层, N:解码器层的个数"""
  5. super(Decoder,self).__init__()
  6. self.layers = clones(layer,N)
  7. self.norm = LayerNorm(layer.size)
  8. def forward(self, x, memory,source_mask, target_mask):
  9. # x:目标数据的嵌入表示
  10. # memory:编码器的输出
  11. # source_mask: 源数据的掩码张量
  12. # target_mask: 目标数据的掩码张量
  13. for layre in self.layers:
  14. x = layer(x,memory,source_mask,target_mask)
  15. return self.norm(x)

测试代码放到最后代码

结果:

  1. de_result.shape : torch.Size([2, 4, 512])
  2. de_result : tensor([[[-0.0569, 0.3506, -0.4071, ..., -1.0797, 0.4819, 1.5599],
  3. [ 0.2342, 0.0497, 0.8868, ..., 1.8162, 0.1724, -0.0384],
  4. [-0.0438, -0.8501, 1.2952, ..., 0.5489, 0.1530, 1.2819],
  5. [-2.7741, 0.4939, 1.5461, ..., -0.7539, 0.6964, -0.4137]],
  6. [[ 1.1773, -0.7767, 1.2400, ..., 0.4109, -0.0105, 1.3137],
  7. [ 0.0067, -0.5182, 0.1695, ..., -1.0328, -1.6252, 1.3039],
  8. [-0.8350, -0.8536, -0.4261, ..., -1.2965, 0.1531, 0.2299],
  9. [-0.2015, 0.5470, -0.9219, ..., -0.1534, 1.3922, -0.2488]]],
  10. grad_fn=<AddBackward0>)

输出部分

线性层的作用:

通过对上一步的线性变化得到指定维度的输出,也就是转换维度的作用,

softmax层的作用:

使最后一维的向量中的数字缩放到0-1的概率值域内,并满足他们的和为1 

 code

  1. # 输出
  2. class Generator(nn.Module):
  3. def __init__(self,d_mode, vocab_size) -> None:
  4. """
  5. d_mode: 词嵌入
  6. vocab_size: 词表大小
  7. """
  8. super(Generator,self).__init__()
  9. self.project = nn.Linear(d_mode, vocab_size)
  10. def forward(self, x):
  11. return F.log_softmax(self.project(x),dim=-1)

输出:

  1. gen_result.shape : torch.Size([2, 4, 1000])
  2. gen_result: tensor([[[-7.3236, -6.3419, -6.6023, ..., -6.8704, -6.2303, -6.9161],
  3. [-7.3549, -7.2196, -8.2483, ..., -6.5249, -6.9905, -6.4151],
  4. [-6.7272, -6.5778, -7.1534, ..., -6.3917, -7.4114, -6.7917],
  5. [-6.7106, -7.3387, -7.4814, ..., -6.7696, -6.8284, -7.5407]],
  6. [[-7.0403, -6.6602, -6.6994, ..., -6.5930, -7.5068, -7.0125],
  7. [-6.4951, -7.2265, -7.4753, ..., -7.0645, -7.2771, -7.2495],
  8. [-7.5860, -7.3894, -8.1477, ..., -6.7407, -6.4232, -8.4255],
  9. [-7.4713, -6.9773, -7.0890, ..., -7.6705, -7.1161, -7.3006]]],
  10. grad_fn=<LogSoftmaxBackward0>)

测试代码 

  1. import numpy as np
  2. import torch
  3. import torch.nn.functional as F
  4. import torch.nn as nn
  5. import matplotlib.pyplot as plt
  6. import math
  7. import copy
  8. from inputs import Embeddings,PositionalEncoding
  9. from encode import subsequent_mask,attention,clones,MultiHeadedAttention,PositionwiseFeedForward,LayerNorm,SublayerConnection,Encoder,EncoderLayer
  10. # encode 代码在前面几节
  11. # 解码器层的类实现
  12. class DecoderLayer(nn.Module):
  13. def __init__(self, size, self_attn, src_attn, feed_forward,dropout) -> None:
  14. """
  15. size : 词嵌入维度
  16. self_attn:多头自注意对象,需要Q=K=V
  17. src_attn:多头注意力对象,这里Q!=K=V
  18. feed_forward: 前馈全连接层对象
  19. """
  20. super(DecoderLayer,self).__init__()
  21. self.size = size
  22. self.self_attn = self_attn
  23. self.src_attn = src_attn
  24. self.feed_forward = feed_forward
  25. # 根据论文图使用clones克隆三个子层对象
  26. self.sublayer = clones(SublayerConnection(size,dropout), 3)
  27. def forward(self, x, memory, source_mask, target_mask):
  28. """
  29. x : 上一层的输入
  30. memory: 来自编码器层的语义存储变量
  31. source_mask: 源码数据掩码张量,针对就是输入到解码器的数据
  32. target_mask: 目标数据掩码张量,针对解码器最后生成的数据,一个一个的推理生成的词
  33. """
  34. m = memory
  35. # 将x传入第一个子层结构,第一个子层结构输入分别是x和self_attn函数,因为是自注意力机制,所以Q=K=V=x
  36. # 最后一个参数是目标数据掩码张量,这时要对目标数据进行掩码,因为此时模型可能还没有生成任何目标数据,
  37. # 比如在解码器准备生成第一个字符或词汇时,我们其实已经传入第一个字符以便计算损失
  38. # 但是我们不希望在生成第一个字符时模型能利用这个信息,因为我们会将其遮掩,同样生成第二个字符或词汇时
  39. # 模型只能使用第一个字符或词汇信息,第二个字符以及以后得信息都不允许被模型使用
  40. x = self.sublayer[0](x, lambda x: self.self_attn(x,x,x,target_mask))
  41. # 紧接着第一层的输出进入第二个子层,这个子层是常规的注意力机制,但是q是输入x;k、v是编码层输出memory
  42. # 同样也传入source_mask, 但是进行源数据遮掩的原因并非是抑制信息泄露,而是遮蔽掉对结果没有意义的的字符而产生的注意力
  43. # 以此提升模型的效果和训练速度,这样就完成第二个子层的处理
  44. x = self.sublayer[1](x, lambda x: self.src_attn(x,m,m,source_mask))
  45. # 最后一个子层就是前馈全连接子层,经过他的处理后就可以返回结果,这就是解码器层的结构
  46. return self.sublayer[2](x,self.feed_forward)
  47. # 解码器
  48. class Decoder(nn.Module):
  49. def __init__(self,layer,N) -> None:
  50. """ layer: 解码器层, N:解码器层的个数"""
  51. super(Decoder,self).__init__()
  52. self.layers = clones(layer,N)
  53. self.norm = LayerNorm(layer.size)
  54. def forward(self, x, memory,source_mask, target_mask):
  55. # x:目标数据的嵌入表示
  56. # memory:编码器的输出
  57. # source_mask: 源数据的掩码张量
  58. # target_mask: 目标数据的掩码张量
  59. for layre in self.layers:
  60. x = layer(x,memory,source_mask,target_mask)
  61. return self.norm(x)
  62. # 输出
  63. class Generator(nn.Module):
  64. def __init__(self,d_mode, vocab_size) -> None:
  65. """
  66. d_mode: 词嵌入
  67. vocab_size: 词表大小
  68. """
  69. super(Generator,self).__init__()
  70. self.project = nn.Linear(d_mode, vocab_size)
  71. def forward(self, x):
  72. return F.log_softmax(self.project(x),dim=-1)
  73. if __name__ == "__main__":
  74. # 词嵌入
  75. dim = 512
  76. vocab =1000
  77. emb = Embeddings(dim,vocab)
  78. x = torch.LongTensor([[100,2,321,508],[321,234,456,324]])
  79. embr =emb(x)
  80. print("embr.shape = ",embr.shape)
  81. # 位置编码
  82. pe = PositionalEncoding(dim,0.1) # 位置向量的维度是20,dropout是0
  83. pe_result = pe(embr)
  84. print("pe_result.shape = ",pe_result.shape)
  85. # 编码器测试
  86. size = 512
  87. dropout=0.2
  88. head=8
  89. d_model=512
  90. d_ff = 64
  91. c = copy.deepcopy
  92. x = pe_result
  93. self_attn = MultiHeadedAttention(head,d_model,dropout)
  94. ff = PositionwiseFeedForward(d_model,d_ff,dropout)
  95. # 编码器层不是共享的,因此需要深度拷贝
  96. layer= EncoderLayer(size,c(self_attn),c(ff),dropout)
  97. N=8
  98. mask = torch.zeros(8,4,4)
  99. en = Encoder(layer,N)
  100. en_result = en(x,mask)
  101. print("en_result.shape : ",en_result.shape)
  102. print("en_result : ",en_result)
  103. # 解码器层测试
  104. size = 512
  105. dropout=0.2
  106. head=8
  107. d_model=512
  108. d_ff = 64
  109. self_attn = src_attn = MultiHeadedAttention(head,d_model,dropout)
  110. ff = PositionwiseFeedForward(d_model,d_ff,dropout)
  111. x = pe_result
  112. mask = torch.zeros(8,4,4)
  113. source_mask = target_mask = mask
  114. memory = en_result
  115. dl = DecoderLayer(size,self_attn,src_attn,ff,dropout)
  116. dl_result = dl(x,memory,source_mask,target_mask)
  117. print("dl_result.shape = ", dl_result.shape)
  118. print("dl_result = ", dl_result)
  119. # 解码器测试
  120. size = 512
  121. dropout=0.2
  122. head=8
  123. d_model=512
  124. d_ff = 64
  125. memory = en_result
  126. c = copy.deepcopy
  127. x = pe_result
  128. self_attn = MultiHeadedAttention(head,d_model,dropout)
  129. ff = PositionwiseFeedForward(d_model,d_ff,dropout)
  130. # 编码器层不是共享的,因此需要深度拷贝
  131. layer= DecoderLayer(size,c(self_attn),c(self_attn),c(ff),dropout)
  132. N=8
  133. mask = torch.zeros(8,4,4)
  134. source_mask = target_mask = mask
  135. de = Decoder(layer,N)
  136. de_result = de(x,memory,source_mask, target_mask)
  137. print("de_result.shape : ",de_result.shape)
  138. print("de_result : ",de_result)
  139. # 输出测试
  140. d_model = 512
  141. vocab =1000
  142. x = de_result
  143. gen = Generator(d_mode=d_model,vocab_size=vocab)
  144. gen_result = gen(x)
  145. print("gen_result.shape :", gen_result.shape)
  146. print("gen_result: ", gen_result)
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/372617
推荐阅读
相关标签
  

闽ICP备14008679号