如何在MNIST数据集上计算负对数似然率?

时间:2018-09-25 11:54:10

标签: python tensorflow machine-learning recurrent-neural-network mnist

NLL evaluations on MNIST test set.

该表来自Professor Forcing: A New Algorithm for Training Recurrent Networks纸。我找不到他们的代码来计算NLL。我想问一下这是否仅仅是二进制交叉熵。我可以使用Tensorflow tf.nn.sigmoid_cross_entropy_with_logits函数来计算它吗?

在“强迫教授”论文中,没有给出教师强迫的评估结果。我训练了一个简单的LSTM,并取得了80.394的NLL。我的最后一个问题是大约有80或70的可能性?

谢谢。

编辑(回答后)一些细节:基本上,我试图逐像素生成MNIST图像。我的模型为每个像素取值可以为0和1的二进制预测。logit和标签的尺寸均为[batch_size,28 * 28,1],其中28是MNIST图像的高度和宽度。

1 个答案:

答案 0 :(得分:0)

实际上,负对数似然度是对数损失或(二进制)分类问题的(二进制)交叉熵,但是由于MNIST是多类问题,因此在这里我们讨论分类交叉熵。通常是优选的,因为对数可能性本身为负,因此其负数将为正数;来自log_loss的scikit-learn文档(已添加重点):

  

对数损失,又称逻辑损失或交叉熵损失。

     

这是(多项式)逻辑回归中使用的损失函数   以及它的扩展,例如神经网络,定义为负数   给定概率分类器的真实标签的对数可能性   预测。仅为两个或多个标签定义对数丢失。对于   在{0,1}中具有真实标签yt并估计概率的单个样本   yt yt = 1,对数损失为

-log P(yt|yp) = -(yt log(yp) + (1 - yt) log(1 - yp))

不确定如何使用Tensorflow做到这一点;这是使用Keras的一种方法(为了使代码简洁明了,我在Keras MNIST CNN example的基础上构建,此处仅运行了2个时期,因为我们只对获取y_pred感兴趣,并且演示过程):

首先,这是Keras报告的 test 集的绝对交叉熵损失结果:

y_pred = model.predict(x_test)
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
# Test loss: 0.05165324027412571
# Test accuracy: 0.9834

现在,让我们看看我们如何才能“手动”获得此损失结果,以防万一我们有预测y_pred和真实标签y_test,而与所使用的任何特定模型无关。仅注意,当我们的预测和真实标签都进行一次热编码时,即:

y_pred[0]
# array([2.4637930e-07, 1.0927782e-07, 1.0026793e-06, 7.6613435e-07,
#        4.1209915e-09, 1.4566888e-08, 2.3195759e-10, 9.9999702e-01,
#        4.9344425e-08, 8.6051602e-07], dtype=float32)
y_test[0]
# array([0., 0., 0., 0., 0., 0., 0., 1., 0., 0.])

这是程序:

from keras import backend as K
import numpy as np

y_test = y_test.astype('float32') # necessary here, since y_pred comes in this type - check in your case with y_test.dtype and y_pred.dtype
y_test = K.constant(y_test)
y_pred = K.constant(y_pred)

g = K.categorical_crossentropy(target=y_test, output=y_pred)  # tensor
ce = K.eval(g)  # 'ce' for cross-entropy
ce.shape
# (10000,) # i.e. one loss quantity per sample

# sum up and divide with the no. of samples:
log_loss = np.sum(ce)/ce.shape[0]
log_loss
# 0.05165323486328125

您可以从视觉上验证,就所有实际目的而言,这等于上述Keras本身报告的损失(score[0]);确实:

np.isclose(log_loss, score[0])
# True

虽然不完全相等,这可能是由于两种方法的数值精度差异造成的:

log_loss == score[0]
# False

希望,您现在应该能够使用上述过程来获得在任何两套y_truey_pred之间进行一次热编码的日志丢失(例如,MNIST)...