我正在研究对数损失和交叉熵,发现计算它们似乎有两种方法,基于以下方程。
第一种方法是如下所示。
import numpy as npfrom sklearn.metrics import log_lossdef cross_entropy(predictions, targets): N = predictions.shape[0] ce = -np.sum(targets * np.log(predictions)) / N return cepredictions = np.array([[0.25,0.25,0.25,0.25], [0.01,0.01,0.01,0.97]])targets = np.array([[1,0,0,0], [0,0,0,1]])x = cross_entropy(predictions, targets)print(log_loss(targets, predictions), 'our_answer:', ans)
前述程序的输出是 0.7083767843022996 our_answer: 0.71355817782
,几乎相同。所以这不是问题所在。
上述实现是上述方程的中间部分。
第二种方法是基于上述方程的右侧部分。
res = 0for act_row, pred_row in zip(targets, np.array(predictions)): for class_act, class_pred in zip(act_row, pred_row): res += - class_act * np.log(class_pred) - (1-class_act) * np.log(1-class_pred)print(res/len(targets))
输出是 1.1549753967602232
,与之前的并不完全相同。
我还尝试了使用NumPy的相同实现,但也未能成功。我做错了什么?
附注:我还很好奇,-y log (y_hat)
看起来与 - sigma(p_i * log( q_i))
相同,那么为什么会有 -(1-y) log(1-y_hat)
部分。显然我误解了如何计算 -y log (y_hat)
。
回答:
我无法重现您在第一部分报告的结果差异(您还提到了一个ans
变量,看起来您没有定义它,我猜它应该是x
):
import numpy as npfrom sklearn.metrics import log_lossdef cross_entropy(predictions, targets): N = predictions.shape[0] ce = -np.sum(targets * np.log(predictions)) / N return cepredictions = np.array([[0.25,0.25,0.25,0.25], [0.01,0.01,0.01,0.97]])targets = np.array([[1,0,0,0], [0,0,0,1]])
结果如下:
cross_entropy(predictions, targets)# 0.7083767843022996log_loss(targets, predictions)# 0.7083767843022996log_loss(targets, predictions) == cross_entropy(predictions, targets)# True
您的cross_entropy
函数看起来运行正常。
关于第二部分:
显然我误解了如何计算
-y log (y_hat)
。
确实,仔细阅读您链接的fast.ai wiki后,您会发现方程的右侧部分仅适用于二元分类(其中y
和1-y
中总有一个为零),而这里的情况不是这样——您有一个4类多项分类。因此,正确的表述是
res = 0for act_row, pred_row in zip(targets, np.array(predictions)): for class_act, class_pred in zip(act_row, pred_row): res += - class_act * np.log(class_pred)
即丢弃(1-class_act) * np.log(1-class_pred)
的减法部分。
结果如下:
res/len(targets)# 0.7083767843022996res/len(targets) == log_loss(targets, predictions)# True
在更一般的层面上(对数损失和二元分类的准确性机制),您可能会发现这个回答有用。