系列文章目录
文章目录
一、引言
正如我们在上一节中所讨论的, 机器翻译是序列转换模型的一个核心问题, 其输入和输出都是长度可变的序列。 为了处理这种类型的输入和输出, 我们可以设计一个包含两个主要组件的架构: 第一个组件是一个编码器(encoder): 它接受一个长度可变的序列作为输入, 并将其转换为具有固定形状的编码状态。 第二个组件是解码器(decoder): 它将固定形状的编码状态映射到长度可变的序列。 这被称为编码器-解码器 (encoder-decoder)架构, 如下图所示。
我们以英语到法语的机器翻译为例: 给定一个英文的输入序列:"They""are""watching""."。 首先,这种"编码器-解码器"架构将长度可变的输入序列编码成一个"状态", 然后对该状态进行解码, 一个词元接着一个词元地生成翻译后的序列作为输出: "Ils""regordent""."。 由于"编码器-解码器"架构是形成后续章节中不同序列转换模型的基础, 因此本节将把这个架构转换为接口方便后面的代码实现。
编码器
在编码器接口中,我们只指定长度可变的序列作为编码器的输入X
。任何继承这个Encoder
基类的模型将完成代码实现。
python
from torch import nn
class Encoder(nn.Module):
"""编码器-解码器架构的基本编码器接口"""
def __init__(self, **kwargs):
super(Encoder, self).__init__(**kwargs)
def forward(self, X, *args):
raise NotImplementedError
解码器
在下面的解码器接口中,我们新增一个init_state
函数,用于将编码器的输出(enc_outputs
)转换为编码后的状态。
注意,此步骤可能需要额外的输入,例如:输入序列的有效长度,
这在上一节中进行了解释。为了逐个地生成长度可变的词元序列,解码器在每个时间步都会将输入(例如:在前一时间步生成的词元)和编码后的状态映射成当前时间步的输出词元。
python
#@save
class Decoder(nn.Module):
"""编码器-解码器架构的基本解码器接口"""
def __init__(self, **kwargs):
# 调用父类 nn.Module 的构造函数进行初始化
super(Decoder, self).__init__(**kwargs)
def init_state(self, enc_outputs, *args):
# 初始化解码器状态,基于编码器的输出
# 该方法尚未实现,需在子类中具体定义
raise NotImplementedError
def forward(self, X, state):
# 定义解码器的前向传播过程
# 接受输入 X 和当前状态 state
# 该方法尚未实现,需在子类中具体定义
raise NotImplementedError
合并编码器和解码器
总而言之,"编码器-解码器"架构包含了一个编码器和一个解码器,并且还拥有可选的额外的参数。
在前向传播中,编码器的输出用于生成编码状态,这个状态又被解码器作为其输入的一部分。
python
#@save
class EncoderDecoder(nn.Module):
"""编码器-解码器架构的基类"""
def __init__(self, encoder, decoder, **kwargs):
# 调用父类 nn.Module 的构造函数进行初始化
super(EncoderDecoder, self).__init__(**kwargs)
# 保存传入的编码器和解码器对象
self.encoder = encoder
self.decoder = decoder
def forward(self, enc_X, dec_X, *args):
# 通过编码器处理输入 enc_X,获取编码器的输出
enc_outputs = self.encoder(enc_X, *args)
# 初始化解码器的状态,基于编码器的输出
dec_state = self.decoder.init_state(enc_outputs, *args)
# 使用解码器处理输入 dec_X 和初始化的状态,返回最终输出
return self.decoder(dec_X, dec_state)
"编码器-解码器"体系架构中的术语状态
会启发人们使用具有状态的神经网络来实现该架构。
在下一节中,我们将学习如何应用循环神经网络,
来设计基于"编码器-解码器"架构的序列转换模型。
小结
- "编码器-解码器"架构可以将长度可变的序列作为输入和输出,因此适用于机器翻译等序列转换问题。
- 编码器将长度可变的序列作为输入,并将其转换为具有固定形状的编码状态。
- 解码器将具有固定形状的编码状态映射为长度可变的序列。
练习
- 假设我们使用神经网络来实现"编码器-解码器"架构,那么编码器和解码器必须是同一类型的神经网络吗?
- 除了机器翻译,还有其它可以适用于"编码器-解码器"架构的应用吗?
答案
1. 编码器和解码器是否必须是同一类型的神经网络?
不,编码器和解码器不必是同一类型的神经网络。虽然它们通常在同一架构中协同工作,但可以使用不同类型的网络。例如:
- 编码器 可以是卷积神经网络(CNN),用于处理图像数据,而解码器可以是循环神经网络(RNN),用于生成序列数据。
- 在某些情况下,编码器和解码器也可以是同一类型的网络,例如都使用RNN,但它们的具体结构和参数可以不同。
2. 除了机器翻译,还有其它可以适用于"编码器-解码器"架构的应用吗?
是的,编码器-解码器架构适用于多种应用,除了机器翻译之外,还包括:
-
图像生成:
- 例如,图像到图像的转换(如从素描到真实图像)。
-
文本摘要:
- 自动生成文章的简要摘要。
-
语音识别:
- 将语音信号编码为文本。
-
对话系统:
- 生成对话回复,基于用户输入的上下文。
-
视频分析:
- 从视频中提取特征并生成描述或动作预测。
-
图像标注:
- 为图像生成描述性文本。
-
时间序列预测:
- 从历史数据预测未来的数值序列。
这些应用展示了编码器-解码器架构的灵活性和广泛适用性。