为了处理这种长度可变的输入和输出, 可以设计一个包含两个主要组件的编码器-解码器(encoder-decoder)架构:
-
编码器(encoder):它接受一个长度可变的序列作为输入,并将其转换为具有固定形状的编码状态。
-
解码器(decoder):它将固定形状的编码状态映射到长度可变的序列。
9.6.1 编码器
编码器接口仅指定长度可变的序列作为编码器的输入 X。代码实现需要由继承这个Encoder基类的模型完成。
from torch import nn
#@save
class Encoder(nn.Module):
"""编码器-解码器架构的基本编码器接口"""
def __init__(self, **kwargs):
super(Encoder, self).__init__(**kwargs)
def forward(self, X, *args):
raise NotImplementedError
9.6.2 解码器
在下面的解码器接口中新增的 init_state 函数用于将编码器的输出(enc_outputs)转换为编码后的状态。
为了逐个地生成长度可变的词元序列,解码器在每个时间步都会将输入(例如:在前一时间步生成的词元)和编码后的状态映射成当前时间步的输出词元。
#@save
class Decoder(nn.Module):
"""编码器-解码器架构的基本解码器接口"""
def __init__(self, **kwargs):
super(Decoder, self).__init__(**kwargs)
def init_state(self, enc_outputs, *args):
raise NotImplementedError
def forward(self, X, state):
raise NotImplementedError
9.6.3 合并编码器和解码器
#@save
class EncoderDecoder(nn.Module):
"""编码器-解码器架构的基类"""
def __init__(self, encoder, decoder, **kwargs):
super(EncoderDecoder, self).__init__(**kwargs)
self.encoder = encoder
self.decoder = decoder
def forward(self, enc_X, dec_X, *args):
enc_outputs = self.encoder(enc_X, *args)
dec_state = self.decoder.init_state(enc_outputs, *args)
return self.decoder(dec_X, dec_state)
练习
(1)假设我们使用神经网络来实现“编码器-解码器”架构,那么编码器和解码器必须是同一类型的神经网络吗?
不需要吧,编码器解码器是抽象于神经网络的。
(2)除了机器翻译,还有其它可以适用于”编码器-解码器“架构的应用吗?
时序模型很多都需要的吧。