Tensorflow 在解码过程中,不同的桶在第一时间步给出不同的输出

Tensorflow 在解码过程中,不同的桶在第一时间步给出不同的输出,tensorflow,Tensorflow,背景 我正在尝试构建一个聊天机器人,通过阅读以下内容,对tensorflow Sequence2Sequence API有一个基本的了解: 我还阅读了有关神经翻译、编码/解码过程中的注意机制等方面的相关论文 RNN翻译代码取自此处: http@s://github.com/tensorflow/models/blob/master/tutorials/rnn/translate/seq2seq_model.py 扣带/注意机制代码从这里选取: http@s://github.com/tenso

背景

我正在尝试构建一个聊天机器人,通过阅读以下内容,对tensorflow Sequence2Sequence API有一个基本的了解:

我还阅读了有关神经翻译、编码/解码过程中的注意机制等方面的相关论文

RNN翻译代码取自此处: http@s://github.com/tensorflow/models/blob/master/tutorials/rnn/translate/seq2seq_model.py

扣带/注意机制代码从这里选取: http@s://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/legacy_seq2seq/python/ops/seq2seq.py

在我的训练期间(注意机制,GRU细胞),我给我的水桶打成[(2,2),(4,4),(6,6),(,8,8),(10,10)]

问题

在解码过程中,如果我在同一个输入上强制一个bucket_索引,我在第一个时间步得到完全不同的输出。例如:

输入:你好吗? 桶指数:1

输出:NAME UNK NAME

输入:你好吗? 桶指数:2

输出:将Hi名称添加到

观察结果

我可以使用波束搜索修复每个时间步的错误输出。然而,为什么我在解码的第一个时间步得到不同的单词作为输出?较小的桶输出不应该是较大桶输出的子集吗

我试着在网上搜索,到处都提到参数在不同的存储桶中共享。铲斗用于训练效率,而不是模型调整。我还验证了我的可训练参数在所有铲斗中都是通用的

我能看到的不同存储桶的编码器输入之间的最大区别是在一开始就有额外的填充。我们正在对编码的_状态执行注意机制,并且在训练期间已经学习了这些编码状态的softmax权重。因此,在解码的第一时间步中,这些额外填充输入的softmax权重是否会导致足够的差异,从而导致不同的输出

有没有其他人也遇到过上述问题?如果您能帮助解决上述错误,我们将不胜感激

我在这里还打开了一个问题,因为我不确定这是一个bug(github上的文件)还是我的错误理解(Stackoverflow):

我不确定你是否找到了答案。我想对此发表评论,以防其他人对此有想法

我相信这是预期的行为。如果您在TensorFlow中检查model_与_bucket函数的源代码实现,您将大致看到以下代码行:

for j, bucket in enumerate(buckets):
    with variable_scope.variable_scope(
        variable_scope.get_variable_scope(), reuse=True if j > 0 else None):
        bucket_outputs, _ = seq2seq(encoder_inputs[:bucket[0]],
                                    decoder_inputs[:bucket[1]])
        outputs.append(bucket_outputs)
如果您使用5个bucket,那么上面的输出列表将包含5个子列表。在每个of子列表中,它包含每个bucket的解码器_输出。该输出将被返回,并将用于培训和预测。您可以看到,不同存储桶中的每个解码器输出(单数形式)通常是不同的,因为它们经过训练以生成与不同存储桶的不同目标匹配的输出(尽管不同存储桶中的变量被重复使用)

你可以做的一个有趣的测试是:在你的训练集中添加一对问题短而答案长的(确保你的模型足够大,可以记住几乎所有的训练样本)。这意味着,这一对将在训练中使用较大的桶,但在预测中使用较小的桶。您还需要一种机制以字符串格式键入pad令牌,例如pad。训练模型后,执行此类预测测试。输入原始答案,你很可能会得到完全不同/毫无意义的答案。但是,您可以输入问题,然后再输入一些pad,直到输入的句子足够长,以便可以选择所需的bucket。然后,你很可能会在新的训练组合中得到相同的准确答案


希望这个解释有意义。

另一个有趣的测试是在问题的开始句子中添加填充来创建训练数据。例如:1)你好吗?很好,谢谢。2) 帕德你好吗?很好,谢谢。3) pad pad你好吗?伟大的你呢?你可以看到,所有这些都可以训练成准确的记忆。现在你知道不同水桶之间的区别并不是因为它们可以有不同的重量,而是不同的填充顺序。而且,如果你使用GRUCell,你可能可以从不同的水桶中得到非常接近的答案。虽然有时小水桶可能不会切割你训练答案的最后一部分(看起来随机切割一些部分)。它还可以填充解码器的长度,而不输出eos令牌。