如何计算张量流中RNN的困惑度

Posted

技术标签:

【中文标题】如何计算张量流中RNN的困惑度【英文标题】:How to calculate perplexity of RNN in tensorflow 【发布时间】:2017-06-12 09:17:59 【问题描述】:

我正在运行Word RNN张量流的RNN实现一词

如何计算RNN的perplexity。

以下是训练中的代码,显示每个 epoch 中的训练损失和其他内容:

for e in range(model.epoch_pointer.eval(), args.num_epochs):
        sess.run(tf.assign(model.lr, args.learning_rate * (args.decay_rate ** e)))
        data_loader.reset_batch_pointer()
        state = sess.run(model.initial_state)
        speed = 0
        if args.init_from is None:
            assign_op = model.batch_pointer.assign(0)
            sess.run(assign_op)
            assign_op = model.epoch_pointer.assign(e)
            sess.run(assign_op)
        if args.init_from is not None:
            data_loader.pointer = model.batch_pointer.eval()
            args.init_from = None
        for b in range(data_loader.pointer, data_loader.num_batches):
            start = time.time()
            x, y = data_loader.next_batch()
            feed = model.input_data: x, model.targets: y, model.initial_state: state,
                    model.batch_time: speed
            summary, train_loss, state, _, _ = sess.run([merged, model.cost, model.final_state,
                                                         model.train_op, model.inc_batch_pointer_op], feed)
            train_writer.add_summary(summary, e * data_loader.num_batches + b)
            speed = time.time() - start
            if (e * data_loader.num_batches + b) % args.batch_size == 0:
                print("/ (epoch ), train_loss = :.3f, time/batch = :.3f" \
                    .format(e * data_loader.num_batches + b,
                            args.num_epochs * data_loader.num_batches,
                            e, train_loss, speed))
            if (e * data_loader.num_batches + b) % args.save_every == 0 \
                    or (e==args.num_epochs-1 and b == data_loader.num_batches-1): # save for the last result
                checkpoint_path = os.path.join(args.save_dir, 'model.ckpt')
                saver.save(sess, checkpoint_path, global_step = e * data_loader.num_batches + b)
                print("model saved to ".format(checkpoint_path))
    train_writer.close()

【问题讨论】:

【参考方案1】:

您引用的项目使用sequence_to_sequence_loss_by_example,它返回交叉熵损失。因此,为了计算训练困惑度,您只需要像 here 解释的那样对损失求幂。

train_perplexity = tf.exp(train_loss)

我们必须使用 e 而不是 2 作为基数,因为 TensorFlow 使用自然对数 (TF Documentation) 测量交叉熵损失。谢谢@Matthias Arro 和@Colin Skow 的提示。

详细说明

当我们开发基于 Q 的编码方案时,两个概率分布 P 和 Q 的交叉熵告诉我们对 P 的事件进行编码所需的最小平均比特数。因此,P 是真实分布,我们通常不知道。我们希望找到一个尽可能接近 P 的 Q,这样我们就可以开发一个好的编码方案,每个事件的比特数尽可能少。

我不应该说位,因为如果我们在交叉熵的计算中使用以 2 为底,我们只能使用位作为度量。但是 TensorFlow 使用自然对数,所以让我们测量 nats 中的交叉熵。

假设我们有一个糟糕的语言模型,它说词汇表中的每个标记(字符/单词)都同样可能成为下一个标记。对于 1000 个标记的词汇表,此模型将具有 log(1000) = 6.9 nats 的交叉熵。在预测下一个token的时候,每一步都要在1000个token之间统一选择。

更好的语言模型将确定更接近 P 的概率分布 Q。因此,交叉熵较低 - 我们可能会得到 3.9 nats 的交叉熵。如果我们现在想测量困惑度,我们只需对交叉熵取幂:

exp(3.9) = 49.4

因此,在我们计算损失的样本上,好的模型就像它必须在大约 50 个标记中统一且独立地选择一样令人困惑。

【讨论】:

在我的情况下,火车损失为 6.3,所以您是说火车困惑度为 2^6 = 64? @ShanKhan 是的。您的模型对训练数据感到困惑,就好像它必须在每个单词的 64 个选项之间随机选择一样。 我相信“指数”是指 e (e^x) 的指数,而不是 2 的幂。根据我的研究,正确的计算是:train_perplexity = tf.exp(train_loss)【参考方案2】:

这取决于您的损失函数是否为您提供了以 2 为底或以 e 为底的数据的对数似然。该模型使用 legacy_seq2seq.sequence_loss_by_example,它使用 TensorFlow 的二元交叉熵,appears to use logs of base e。因此,即使我们处理的是离散概率分布(文本),我们也应该用 e 取幂,即按照 Colin Skow 的建议使用 tf.exp(train_loss)。

【讨论】:

以上是关于如何计算张量流中RNN的困惑度的主要内容,如果未能解决你的问题,请参考以下文章

张量流中的最小 RNN 示例

在张量流中连接两个 RNN 状态

张量流中的“tf.contrib.rnn.DropoutWrapper”到底是做啥的? (三题)

如何在张量流中用张量B指定的权重计算张量A的加权平均值?

根据张量流中给定的序列长度数组对 3D 张量进行切片

有没有办法在张量流中剪辑中间爆炸梯度