指将一段文本从一种语言自动翻译到另一种语言
读取和预处理数据# 将一个序列中所有的词记录在all_tokens中以便之后构造词典,然后在该序列后面添加PAD直到序列
# 长度变为max_seq_len,然后将序列保存在all_seqs中
def process_one_seq(seq_tokens, all_tokens, all_seqs, max_seq_len):
all_tokens.extend(seq_tokens)
seq_tokens += [EOS] + [PAD] * (max_seq_len - len(seq_tokens) - 1)
all_seqs.append(seq_tokens)
# 使用所有的词来构造词典。并将所有序列中的词变换为词索引后构造NDArray实例
def build_data(all_tokens, all_seqs):
vocab = text.vocab.Vocabulary(collections.Counter(all_tokens),
reserved_tokens=[PAD, BOS, EOS])
indices = [vocab.to_indices(seq) for seq in all_seqs]
return vocab, nd.array(indices)
使用
def read_data(max_seq_len):
# in和out分别是input和output的缩写
in_tokens, out_tokens, in_seqs, out_seqs = [], [], [], []
#读取法语-英语数据集
with io.open('../data/fr-en-small.txt') as f: #
lines = f.readlines()
for line in lines:
#法语和英语之间用\t分割的
in_seq, out_seq = line.rstrip().split('\t')
#把法语和英语用空格分隔开
in_seq_tokens, out_seq_tokens = in_seq.split(' '), out_seq.split(' ')
if max(len(in_seq_tokens), len(out_seq_tokens)) > max_seq_len - 1:
continue # 如果加上EOS后长于max_seq_len,则忽略掉此样本
#预处理序列
process_one_seq(in_seq_tokens, in_tokens, in_seqs, max_seq_len)
process_one_seq(out_seq_tokens, out_tokens, out_seqs, max_seq_len)
#构造词典
in_vocab, in_data = build_data(in_tokens, in_seqs)
out_vocab, out_data = build_data(out_tokens, out_seqs)
return in_vocab, out_vocab, gdata.ArrayDataset(in_data, out_data)
含注意力机制的编码器—解码器
编码器:
将输入语言的词索引通过词嵌入层得到词的表征,然后输入到一个多层门控循环单元中。
class Encoder(nn.Block):
def __init__(self, vocab_size, embed_size, num_hiddens, num_layers,
drop_prob=0, **kwargs):
super(Encoder, self).__init__(**kwargs)
#嵌入层
self.embedding = nn.Embedding(vocab_size, embed_size)
#循环神经网络
self.rnn = rnn.GRU(num_hiddens, num_layers, dropout=drop_prob)
def forward(self, inputs, state):
# 输入形状是(批量大小, 时间步数)。将输出互换样本维和时间步维
embedding = self.embedding(inputs).swapaxes(0, 1)
return self.rnn(embedding, state)
def begin_state(self, *args, **kwargs):
return self.rnn.begin_state(*args, **kwargs)
注意力机制:
Dense的flatten选项
训练时的模型:
预测时的模型:
两个是不一样的!
由来 :翻译的过程像是解码器的每一时间步对输入序列中不同时间步的表征或编码信息分配不同的注意力一样。
以循环神经网络为例,注意力机制通过对编码器所有时间步的隐藏状态做加权平均来得到背景变量。解码器在每一时间步调整这些权重,即注意力权重,从而能够在不同时间步分别关注输入序列中的不同部分并编码进相应时间步的背景变量。(因人而异)
记ct′\boldsymbol{c}_{t'}ct′是解码器在时间步t′t't′的背景变量,那么解码器在该时间步的隐藏状态可以改写为
st′=g(yt′−1,ct′,st′−1).\boldsymbol{s}_{t'} = g(\boldsymbol{y}_{t'-1}, \boldsymbol{c}_{t'}, \boldsymbol{s}_{t'-1}).st′=g(yt′−1,ct′,st′−1).
难点在于:
计算背景变量首先,函数