Transfomer学习记录:解码器

83 阅读3分钟

解码器由N个解码器层堆叠⽽成:

  • 每个解码器层由三个⼦层连接结构组成
  • 第⼀个⼦层连接结构包括⼀个多头⾃注意⼒⼦层和规范化层以及⼀个残差连接
  • 第⼆个⼦层连接结构包括⼀个多头注意⼒⼦层和规范化层以及⼀个残差连接
  • 第三个⼦层连接结构包括⼀个前馈全连接⼦层和规范化层以及⼀个残差连接

解码器层:

解码器层的作⽤:

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

代码实现:

class DecoderLayer(nn.Module):
    def __init__(self, size, self_attn, src_attn, feed_forward, dropout):
        super(DecoderLayer, self).__init__()
        self.size = size
        self.self_attn = self_attn
        self.src_attn = src_attn
        self.feed_forward = feed_forward
        self.sublayer = clones(SublayerConnection(size, dropout), 3)
     def forward(self, x, memory, source_mask, target_mask):
         m = memory
         x = self.sublayer[0](x, lambda x: self.self_attn(x, x, x,target_mask))
         x = self.sublayer[1](x, lambda x: self.src_attn(x, m, m,source_mask))
         return self.sublayer[2](x, self.feed_forward)

代码解释:

  • 初始化函数的参数有5个, 分别是size,代表词嵌⼊的维度⼤⼩, 同时也代表解码器层的尺⼨,第⼆个是self_attn,多头⾃注意⼒对象,也就是说这个注意⼒机制需要Q=K=V,第三个是src_attn,多头注意⼒对象,这⾥Q!=K=V, 第四个是前馈全连接层对象,最后就是droupout置0⽐率。
  • 来⾃编码器层的语义存储变量mermory, 以及源数据掩码张量和⽬标数据掩码张量。
  • 将x传⼊第⼀个⼦层结构,第⼀个⼦层结构的输⼊分别是x和self-attn函数,因为是⾃注意⼒机制,所以Q,K,V都是x,最后⼀个参数是⽬标数据掩码张量,这时要对⽬标数据进⾏遮掩,因为此时模型可能还没有⽣成任何⽬标数据,⽐如在解码器准备⽣成第⼀个字符或词汇时,我们其实已经传⼊了第⼀个字符以便计算损失,但是我们不希望在⽣成第⼀个字符时模型能利⽤这个信息,因此我们会将其遮掩,同样⽣成第⼆个字符或词汇时,模型只能使⽤第⼀个字符或词汇信息,第⼆个字符以及之后的信息都不允许被模型使⽤。
  • 接着进⼊第⼆个⼦层,这个⼦层中常规的注意⼒机制,q是输⼊x; k,v是编码层输出memory,同样也传⼊source_mask,但是进⾏源数据遮掩的原因并⾮是抑制信息泄漏,⽽是遮蔽掉对结果没有意义的字符⽽产⽣的注意⼒值,以此提升模型效果和训练速度. 这样就完成了第⼆个⼦层的处理。
  • 最后⼀个⼦层就是前馈全连接⼦层,经过它的处理后就可以返回结果.这就是我们的解码器层结构。

解码器层

解码器的作⽤:

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

代码实现:

class Decoder(nn.Module):
    def __init__(self, layer, N):
    #初始化函数的参数有两个,第⼀个就是解码器层layer,第⼆个是解码器层的个数N.
        super(Decoder, self).__init__()
        # ⾸先使⽤clones⽅法克隆了N个layer,然后实例化了⼀个规范化层.
        # 因为数据⾛过了所有的解码器层后最后要做规范化处理.
        self.layers = clones(layer, N)
        self.norm = LayerNorm(layer.size)
    def forward(self, x, memory, source_mask, target_mask):
    #forward函数中的参数有4个,x代表⽬标数据的嵌⼊表示,memory是编码器层的输出
    #source_mask, target_mask代表源数据和⽬标数据的掩码张量
        for layer in self.layers:
            # 然后就是对每个层进⾏循环,当然这个循环就是变量x通过每⼀个层的处理,
            # 得出最后的结果,再进⾏⼀次规范化返回即可.
            x = layer(x, memory, source_mask, target_mask)
            return self.norm(x)

实例化参数:

# 分别是解码器层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 = 8
# 输⼊参数与解码器层的输⼊参数相同
x = pe_result
memory = en_result
mask = Variable(torch.zeros(8, 4, 4))
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)