最近,我一直在尝试基于此article实施RNNLM。 有一个implementation有一些LSTM分解技巧,但与作者的原始实现类似。
1)将数据集拆分成文件,然后在列车时间对文件的行进行混洗,并在测试时按顺序进给。 (link):
# deterministic at test time, non deterministic at train time
if not self._deterministic:
random.shuffle(lines)
2)批次是连续形成的
*符号表示句子的开头\结尾。每个矩阵代表一个巴赫。 The code link。所以:
如果句子长于num_steps,则会在同一行的下一批次继续。
如果句子较短,则批次行将填充另一句话。
3)他们计算批次平均损失。 num_steps - LSTM的内存。 Code。
# loss_shape = [batch_size * num_steps]
# 1D tensor, reshaped 2d tensor with dims of [batch_size, num_steps]
loss = tf.reduce_mean(loss)
4)LSTM单元在每次训练迭代后正在更新,并在评估时被清零。
他们将其声明为局部变量declaration。
然后它在火车时刻updated。并且zeroed out在eval时间。
5)在评估时间,作者以这种方式计算困惑(the link):
for i, (x, y) in enumerate(data_iterator):
# get a batch
loss = sess.run(model.loss, {model.x: x, model.y: y})
loss_nom += loss
loss_den += 1
loss = loss_nom / loss_den
sys.stdout.write("%d: %.3f (%.3f) ... " % (i, loss, np.exp(loss)))
sys.stdout.flush()
sys.stdout.write("\n")
这意味着他们可以衡量批次平均困惑度。
话虽如此,我有两个主要问题。
LSTM单元格在每个句子后都没有被清零,所以它记忆了前一个句子。
在顶部的例子中,当神经网络正在处理批次№1时,单词“Half”的第2行,它会记住单词Music的上下文并开始\ end标记。 如果句子没有被洗牌并且它是真实的文本可能是有意义的,但是它们被洗牌并且彼此没有连接。
我实现了两种方法,无限批次给了很多更好的性能。
考虑到第一个问题,我不清楚当我们用这种方式衡量困惑时,我们可以真实地估计我们的模型有多好。 但句子平均困惑似乎更有效率。
如果我的逻辑存在缺陷,如果你指出这一点,我将不胜感激。