机器学习中的交叉熵介绍

交叉熵是机器学习中常用的损失函数。

交叉熵是信息论领域的一种度量,建立在熵的基础上,通常计算两个概率分布之间的差异。它与计算两个概率分布之间的相对熵的KL散度密切相关,但又不同于KL散度,而可以认为交叉熵计算的是分布之间的总熵。

交叉熵也与逻辑损失相关,并经常与之混淆,称为原木损失。虽然这两个度量来自不同的来源,但当用作分类模型的损失函数时,这两个度量计算的数量相同,并且可以互换使用。

在本教程中,你将发现机器学习的交叉熵。

完成本教程后,你将了解:

  • 如何从头开始并使用标准机器学习库计算交叉熵。
  • 在对Logistic回归和人工神经网络等分类模型进行优化时,交叉熵可以作为损失函数。
  • 交叉熵不同于KL散度,但可以使用KL散度计算,并且与对数损失不同,但在用作损失函数时计算相同的量。

教程概述

本教程分为五个部分;它们是:

  • 什么是交叉熵?
  • 交叉熵与KL散度。
  • 如何计算交叉熵。
    • 两个离散概率分布。
    • 计算分布之间的交叉熵。
    • 计算分布与其自身之间的交叉熵。
    • 利用KL散度计算交叉熵。
  • 作为损失函数的交叉熵。
    • 计算类别标签的熵。
    • 计算类标签与概率之间的交叉熵。
    • 利用KERAS计算交叉熵。
    • 预测概率的交叉熵直觉。
  • 交叉熵与对数损失。
    • 对数损失是负的对数可能性。
    • 对数损失和交叉熵计算相同。

什么是交叉熵?

交叉熵是对给定随机变量或事件集的两个概率分布之间差异的度量。

你可能还记得,信息量化了编码和传输事件所需的位数。低概率事件有更多的信息,高概率事件有更少的信息。

熵是从概率分布中传输随机选择的事件所需的位数。倾斜分布具有较低的熵,而事件概率相等的分布具有较大的熵。

在信息论中,我们喜欢描述事件的“惊喜”。小概率事件更令人惊讶,因此拥有更多的信息量。然而,事件概率相等的概率分布更令人惊讶,并且具有更大的熵。

  • 不对称的概率分布(不足为奇):低熵。
  • 均衡概率分布(令人惊讶):高熵。

可以计算X个离散状态中具有x组离散状态的随机变量的熵,其概率P(X)如下:

  • H(X) = – sum x in X P(x) * log(P(x))。

如果你想了解更多关于计算事件信息和分发信息熵的信息,请参阅本教程:

交叉熵建立在信息论中的熵概念之上,并与另一个分布相比,计算表示或传输来自一个分布的平均事件所需的位数。

…交叉熵是当我们使用模型q…时,对来自具有分布p的源的数据进行编码所需的平均比特数。

如果我们考虑目标或基本概率分布P和目标分布Q的近似值,则来自P的Q的交叉熵是使用Q而不是P来表示事件的附加位的数目。

两个概率分布(例如来自P的Q)之间的交叉熵可以形式地表示为:

  • H(P, Q)

其中H()是交叉熵函数,P可以是目标分布,Q是目标分布的近似。

交叉熵可以使用来自P和Q的事件的概率来计算,如下所示:

  • H(P, Q) = – sum x in X P(x) * log(Q(x))

其中P(X)是事件x在P中的概率,Q(X)是事件x在Q中的概率,log是以2为底的对数,这意味着结果以位为单位。如果改用以e为底的对数或自然对数,则结果将具有称为NAT的单位。

这种计算是针对离散概率分布的,尽管可以使用跨事件的积分而不是总和对连续的概率分布使用类似的计算。

结果将是以位为单位测量的正数,并且如果两个概率分布相同,则结果将等于分布的熵。

注意:这个符号看起来很像联合概率,或者更具体地说,P和Q之间的联合熵。这是有误导性的,因为我们用交叉熵对概率分布之间的差异进行评分。然而,联合熵是一个不同的概念,它使用相同的符号,而不是计算两个(或更多)随机变量的不确定性。

交叉熵与KL散度

交叉熵不是KL散度。

交叉熵与散度度量有关,例如Kullback-Leibler或KL散度,它量化了一种分布与另一种分布的不同程度。

具体地说,KL散度测量的量与交叉熵非常相似。它测量用Q而不是P来表示消息所需的平均额外比特数,而不是总比特数。

换句话说,由于我们使用分布q而不是真实分布p来编码数据,因此KL发散度是编码数据所需的平均额外比特数。

因此,KL发散通常被称为“相对熵”。

  • 交叉熵:表示来自Q而不是P的事件的平均总位数。
  • 相对熵(KL发散):表示来自Q而不是P的事件的平均额外位数。

KL散度可以被计算为每个事件在P中的概率的负和乘以Q中的事件的概率对P中的事件的概率的对数。通常,对数基-2使得结果以位来测量。

  • KL(P || Q) = – sum x in X P(x) * log(Q(x) / P(x))

总和中的值是给定事件的散度。

因此,我们可以通过将分布的熵加上由KL散度计算的附加熵来计算交叉熵。考虑到这两种计算的定义,这是直观的;例如:

  • H(P, Q) = H(P) + KL(P || Q)

其中H(P,Q)是Q与P的交叉熵,H(P)是P的熵,KL(P||Q)是Q与P的发散度。

可以将概率分布的熵计算为每个事件的概率乘以该事件的概率的对数的负和,其中log是以2为底的,以确保结果是以位为单位的。

  • H(P) = – sum x on X p(x) * log(p(x))

与KL发散一样,交叉熵不是对称的,这意味着:

  • H(P, Q) != H(Q, P)

正如我们稍后将看到的,当交叉熵和KL散度被用作优化分类预测模型的损失函数时,它们计算的量是相同的。正是在这样的背景下,有时你可能会看到交叉熵和KL散度是一样的。

有关KL分歧的更多详细信息,请参见教程:

如何计算交叉熵

在这一部分中,我们将用一个小例子来进行交叉熵的具体计算。

两个离散概率分布

考虑一个随机变量,它有三个离散事件作为不同的颜色:红色、绿色和蓝色。

对于此变量,我们可能有两种不同的概率分布;例如:

...
# define distributions
events = ['red', 'green', 'blue']
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]

我们可以绘制这些概率的条形图,以将它们直接作为概率直方图进行比较。

下面列出了完整的示例。

# plot of distributions
from matplotlib import pyplot
# define distributions
events = ['red', 'green', 'blue']
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
print('P=%.3f Q=%.3f' % (sum(p), sum(q)))
# plot first distribution
pyplot.subplot(2,1,1)
pyplot.bar(events, p)
# plot second distribution
pyplot.subplot(2,1,2)
pyplot.bar(events, q)
# show the plot
pyplot.show()

运行该示例将为每个概率分布创建一个直方图,从而允许直接比较每个事件的概率。

我们可以看到,实际上分布是不同的。

同一随机变量两种不同概率分布的直方图

计算分布之间的交叉熵

接下来,我们可以开发一个函数来计算两个分布之间的交叉熵。

我们将使用log base-2来确保结果具有以位为单位的单位。

# calculate cross entropy
def cross_entropy(p, q):
	return -sum([p[i]*log2(q[i]) for i in range(len(p))])

然后我们可以使用这个函数来计算P与Q的交叉熵,以及与P相反的Q与P的交叉熵。

...
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)
# calculate cross entropy H(Q, P)
ce_qp = cross_entropy(q, p)
print('H(Q, P): %.3f bits' % ce_qp)

将这些结合在一起,完整的示例如下所示。

# example of calculating cross entropy
from math import log2

# calculate cross entropy
def cross_entropy(p, q):
	return -sum([p[i]*log2(q[i]) for i in range(len(p))])

# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)
# calculate cross entropy H(Q, P)
ce_qp = cross_entropy(q, p)
print('H(Q, P): %.3f bits' % ce_qp)

运行该示例首先从P计算出Q的交叉熵略高于3位,然后从Q计算出P的交叉熵略低于3位。

H(P, Q): 3.288 bits
H(Q, P): 2.906 bits

计算分布与其自身之间的交叉熵

如果两个概率分布相同,则它们之间的交叉熵就是分布的熵。

我们可以通过计算P对P和Q对Q的交叉熵来证明这一点。

下面列出了完整的示例。

# example of calculating cross entropy for identical distributions
from math import log2

# calculate cross entropy
def cross_entropy(p, q):
	return -sum([p[i]*log2(q[i]) for i in range(len(p))])

# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate cross entropy H(P, P)
ce_pp = cross_entropy(p, p)
print('H(P, P): %.3f bits' % ce_pp)
# calculate cross entropy H(Q, Q)
ce_qq = cross_entropy(q, q)
print('H(Q, Q): %.3f bits' % ce_qq)

运行该示例首先计算Q与Q的交叉熵,该交叉熵被计算为Q的熵,以及P与P的交叉熵,该交叉熵被计算为P的熵。

H(P, P): 1.361 bits
H(Q, Q): 0.884 bits

利用KL散度计算交叉熵

我们也可以使用KL散度来计算交叉熵。

用KL发散度计算的交叉熵应该是相同的,并且计算分布之间的KL发散度也可能是有趣的,以查看相对熵或所需的附加位,而不是由交叉熵计算的总位数。

首先,我们可以使用log base-2定义一个函数来计算分布之间的KL散度,以确保结果也是以位为单位的。

# calculate the kl divergence KL(P || Q)
def kl_divergence(p, q):
	return sum(p[i] * log2(p[i]/q[i]) for i in range(len(p)))

接下来,我们可以定义一个函数来计算给定概率分布的熵。

# calculate entropy H(P)
def entropy(p):
	return -sum([p[i] * log2(p[i]) for i in range(len(p))])

最后,我们可以使用entropy()和kl_divergence()函数来计算交叉熵。

# calculate cross entropy H(P, Q)
def cross_entropy(p, q):
	return entropy(p) + kl_divergence(p, q)

为了简单起见,我们可以将H(P, Q) 的交叉熵与KL散度KL(P || Q)和熵H(P)进行比较。

下面列出了完整的示例。

# example of calculating cross entropy with kl divergence
from math import log2

# calculate the kl divergence KL(P || Q)
def kl_divergence(p, q):
	return sum(p[i] * log2(p[i]/q[i]) for i in range(len(p)))

# calculate entropy H(P)
def entropy(p):
	return -sum([p[i] * log2(p[i]) for i in range(len(p))])

# calculate cross entropy H(P, Q)
def cross_entropy(p, q):
	return entropy(p) + kl_divergence(p, q)

# define data
p = [0.10, 0.40, 0.50]
q = [0.80, 0.15, 0.05]
# calculate H(P)
en_p = entropy(p)
print('H(P): %.3f bits' % en_p)
# calculate kl divergence KL(P || Q)
kl_pq = kl_divergence(p, q)
print('KL(P || Q): %.3f bits' % kl_pq)
# calculate cross entropy H(P, Q)
ce_pq = cross_entropy(p, q)
print('H(P, Q): %.3f bits' % ce_pq)

运行该示例,我们可以看到3.288比特的交叉熵分数由P 1.361的熵和由KL散度计算的附加1.927比特组成。

这是一个很有用的例子,清楚地说明了这三种计算之间的关系。

H(P): 1.361 bits
KL(P || Q): 1.927 bits
H(P, Q): 3.288 bits

作为损失函数的交叉熵

交叉熵在优化分类模型时被广泛用作损失函数。

你可能会遇到的两个示例包括Logistic回归算法(线性分类算法)和可用于分类任务的人工神经网络。

…对于分类问题,使用交叉熵误差函数而不是平方和会导致更快的训练以及改进的泛化。

分类问题是涉及一个或多个输入变量和类别标签预测的问题。

对于输出变量只有两个标签的分类任务被称为二进制分类问题,而那些具有两个以上标签的问题被称为分类或多类分类问题。

  • 二分分类:为给定的例子预测两个类别标签中的一个的任务。
  • 多类别分类:为给定的例子预测两个以上类别标签中的一个的任务。

我们可以看到,交叉熵的思想对于分类模型的优化是有用的。

每个示例都有一个概率为1.0的已知类标签,所有其他标签的概率为0.0。模型可以估计示例属于每个类别标签的概率。然后可以使用交叉熵来计算两个概率分布之间的差异。

因此,我们可以将一个示例的分类映射到具有如下概率分布的随机变量的概念上:

随机变量:我们需要预测类标签的示例。
事件:可以预测的每个类别标签。
在分类任务中,我们知道输入的目标概率分布P为分类标签0或1,分别被解释为“不可能”或“确定”的概率。这些概率一点也不令人惊讶,因此它们没有信息含量或零熵。

我们的模型寻求近似目标概率分布Q。

在分类语言中,这些是实际和预测的概率,或y和yhat。

  • 预期概率(y):数据集中示例的每个类标签的已知概率(P)。
  • 预测概率(yhat):每个类别的概率标记由模型(Q)预测的示例。

因此,例如,我们可以使用上述交叉熵计算来估计单个预测的交叉熵。

H(P, Q) = – sum x in X P(x) * log(Q(x))

其中,X中的每个x是可以分配给该示例的类别标签,对于已知标签,P(X)将为1,对于所有其他标签,P(X)将为0。

二进制分类任务中单个示例的交叉熵可以通过如下展开求和运算来表示:

H(P, Q) = – (P(class0) * log(Q(class0)) + P(class1) * log(Q(class1)))

你可能会在教科书中看到这种计算交叉熵的形式。

如果只有两个类别标签,则将概率建模为正类别标签的伯努利分布。这意味着1类的概率是由模型直接预测的,0类的概率是1减去预测的概率,例如:

  • Predicted P(class0) = 1 – yhat
  • Predicted P(class1) = yhat

当计算分类任务的交叉熵时,使用以e为底的或自然对数。这意味着单元以NAT为单位,而不是以位为单位。

我们通常对最小化整个训练数据集上模型的交叉熵感兴趣。这是通过计算所有训练样本的平均交叉熵来计算的。

计算类别标签的熵

回想一下,当两个分布相同时,它们之间的交叉熵等于概率分布的熵。

在为分类任务准备数据时,使用值0和1对类标签进行编码。

例如,如果一个分类问题有三个类别,而一个示例有第一个类别的标签,那么概率分布将是[1,0,0]。如果示例有第二个类的标签,则两个事件的概率分布为[0,1,0]。这称为一次热编码。

这个概率分布没有信息,因为结果是确定的。我们了解这个班级。因此,这个变量的熵为零。

这是一个重要的概念,我们可以用一个示例来演示它。

假设有一个有3个类别的分类问题,我们每个类别都有一个例子。我们可以将每个示例表示为离散的概率分布,该示例所属的类的概率为1.0,所有其他类的概率为0.0。

我们可以计算跨“事件”的每个“变量”的概率分布的熵。

下面列出了完整的示例。

# entropy of examples from a classification task with 3 classes
from math import log2
from numpy import asarray

# calculate entropy
def entropy(p):
	return -sum([p[i] * log2(p[i]) for i in range(len(p))])

# class 1
p = asarray([1,0,0]) + 1e-15
print(entropy(p))
# class 2
p = asarray([0,1,0]) + 1e-15
print(entropy(p))
# class 3
p = asarray([0,0,1]) + 1e-15
print(entropy(p))

运行该示例将计算每个随机变量的熵。

我们可以看到,在每种情况下,熵都是0.0(实际上是一个非常接近于零的数字)。

请注意,我们必须向0.0值添加一个非常小的值,以避免log()爆炸,因为我们无法计算0.0的log。

9.805612959471341e-14
9.805612959471341e-14
9.805612959471341e-14

因此,已知类别标签的熵始终为0.0。

这意味着对于类别标签具有相同概率分布的两个分布(实数分布和预测分布)的交叉熵也将始终为0.0。

回想一下,当在训练数据集上使用交叉熵评估模型时,我们对数据集中所有示例的交叉熵进行平均。

因此,当训练模型时交叉熵为0.0表示预测的类概率与训练数据集中的概率相同,例如零损失。

我们可以像损失函数而不是交叉熵一样容易地最小化KL发散。

回想一下,KL发散是传输一个变量与另一个变量相比所需的额外比特。它是没有类标签熵的交叉熵,我们知道无论如何它都会是零。

因此,最小化分类任务的KL发散度和交叉熵是相同的。

最小化这种KL发散恰好对应于最小化分布之间的交叉熵。

在实践中,交叉熵损失为0.0通常表示模型已过度拟合训练数据集,但这是另一回事。

计算类标签与概率之间的交叉熵。

使用交叉熵进行分类通常会根据类的数量给出不同的具体名称,这反映了分类任务的名称;例如:

  • 二元交叉熵:作为二元分类任务损失函数的交叉熵。
  • 分类交叉熵:交叉熵作为多类分类任务的损失函数。

结合实例,可以将交叉熵作为损失函数加以具体应用。

考虑一个具有以下10个实际类别标签(P)和预测类别标签(Q)的两类分类任务。

...
# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]

我们可以枚举这些概率,并使用上一节中开发的交叉熵函数(使用log()(自然对数)而不是log2())来计算每个概率的交叉熵。

# calculate cross entropy
def cross_entropy(p, q):
	return -sum([p[i]*log(q[i]) for i in range(len(p))])

对于每个实际和预测的概率,我们必须将预测转换为每个事件的概率分布,在本例中,类{0, 1}减去类0的概率和类1的概率。

然后,我们可以计算交叉熵,并对所有示例重复此过程。

...
# calculate cross entropy for each example
results = list()
for i in range(len(p)):
	# create the distribution for each event {0, 1}
	expected = [1.0 - p[i], p[i]]
	predicted = [1.0 - q[i], q[i]]
	# calculate cross entropy for the two events
	ce = cross_entropy(expected, predicted)
	print('>[y=%.1f, yhat=%.1f] ce: %.3f nats' % (p[i], q[i], ce))
	results.append(ce)

最后,我们可以计算数据集上的平均交叉熵,并将其报告为数据集上模型的交叉熵损失。

...
# calculate the average cross entropy
mean_ce = mean(results)
print('Average Cross Entropy: %.3f nats' % mean_ce)

将这些结合在一起,完整的示例如下所示。

# calculate cross entropy for classification problem
from math import log
from numpy import mean

# calculate cross entropy
def cross_entropy(p, q):
	return -sum([p[i]*log(q[i]) for i in range(len(p))])

# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]
# calculate cross entropy for each example
results = list()
for i in range(len(p)):
	# create the distribution for each event {0, 1}
	expected = [1.0 - p[i], p[i]]
	predicted = [1.0 - q[i], q[i]]
	# calculate cross entropy for the two events
	ce = cross_entropy(expected, predicted)
	print('>[y=%.1f, yhat=%.1f] ce: %.3f nats' % (p[i], q[i], ce))
	results.append(ce)

# calculate the average cross entropy
mean_ce = mean(results)
print('Average Cross Entropy: %.3f nats' % mean_ce)

运行该示例将打印每个示例的实际和预测概率以及NAT中的交叉熵。

报告所有示例的最终平均交叉熵损失,在本例中为0.247 nats。

>[y=1.0, yhat=0.8] ce: 0.223 nats
>[y=1.0, yhat=0.9] ce: 0.105 nats
>[y=1.0, yhat=0.9] ce: 0.105 nats
>[y=1.0, yhat=0.6] ce: 0.511 nats
>[y=1.0, yhat=0.8] ce: 0.223 nats
>[y=0.0, yhat=0.1] ce: 0.105 nats
>[y=0.0, yhat=0.4] ce: 0.511 nats
>[y=0.0, yhat=0.2] ce: 0.223 nats
>[y=0.0, yhat=0.1] ce: 0.105 nats
>[y=0.0, yhat=0.3] ce: 0.357 nats
Average Cross Entropy: 0.247 nats

这就是在交叉熵损失函数下优化Logistic回归模型或神经网络模型时如何计算交叉熵损失。

利用Keras计算交叉熵

我们可以使用Keras深度学习API中的binary_crossentropy()函数来计算我们的小数据集的交叉熵损失,从而确认相同的计算结果。

下面列出了完整的示例。

注意:此示例假设你安装了Keras库(例如2.3版或更高版本),并配置了后端库,如TensorFlow(2.0版或更高版本)。如果没有,你可以跳过运行此示例。

# calculate cross entropy with keras
from numpy import asarray
from keras import backend
from keras.losses import binary_crossentropy
# prepare classification data
p = asarray([1, 1, 1, 1, 1, 0, 0, 0, 0, 0])
q = asarray([0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3])
# convert to keras variables
y_true = backend.variable(p)
y_pred = backend.variable(q)
# calculate the average cross-entropy
mean_ce = backend.eval(binary_crossentropy(y_true, y_pred))
print('Average Cross Entropy: %.3f nats' % mean_ce)

运行该示例,我们可以看到报告的平均交叉熵损失为0.247 nats。

这证实了交叉熵的人工计算是正确的。

Average Cross Entropy: 0.247 nats

预测概率的交叉熵直觉

我们可以进一步发展预测类概率的交叉熵的直觉。

例如,假设平均交叉熵损失为0.0是一个完美的模型,那么大于零的平均交叉熵值到底意味着什么呢?

我们可以探讨这个问题,这不是一个二分类问题,其中类标记为0和1。这是一个离散的概率分布,有两个事件,一个事件有一定的概率,另一个事件有不可能的概率。

然后,我们可以为不同的“预测”概率分布计算交叉熵,这些概率分布从目标分布的完美匹配过渡到完全相反的概率分布。

我们预计,随着预测的概率分布进一步偏离目标分布,计算出的交叉熵将会增加。

下面的示例实现了这一点,并将预测概率分布的交叉熵结果与两个事件的目标[0, 1]相比较,就像我们将在二进制分类任务中看到的交叉熵一样。

# cross-entropy for predicted probability distribution vs label
from math import log
from matplotlib import pyplot

# calculate cross-entropy
def cross_entropy(p, q, ets=1e-15):
	return -sum([p[i]*log(q[i]+ets) for i in range(len(p))])

# define the target distribution for two events
target = [0.0, 1.0]
# define probabilities for the first event
probs = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]
# create probability distributions for the two events
dists = [[1.0 - p, p] for p in probs]
# calculate cross-entropy for each distribution
ents = [cross_entropy(target, d) for d in dists]
# plot probability distribution vs cross-entropy
pyplot.plot([1-p for p in probs], ents, marker='.')
pyplot.title('Probability Distribution vs Cross-Entropy')
pyplot.xticks([1-p for p in probs], ['[%.1f,%.1f]'%(d[0],d[1]) for d in dists], rotation=70)
pyplot.subplots_adjust(bottom=0.2)
pyplot.xlabel('Probability Distribution')
pyplot.ylabel('Cross-Entropy (nats)')
pyplot.show()

运行该示例将计算每个概率分布的交叉熵分数,然后将结果绘制为折线图。

我们可以看到,正如预期的那样,当预测的概率分布与目标分布匹配时,交叉熵从0.0(最左边的点)开始,然后随着预测的概率分布的偏离而稳步增加。

当预测的概率分布与目标分布正好相反,即与目标的[1, 0]相比,[0, 1]时,我们还可以看到交叉熵的戏剧性飞跃。

二分类任务概率分布与交叉熵的直线图

我们不会有一个模型来预测一个二进制分类任务中所有情况的完全相反的概率分布。

因此,我们可以删除此案例并重新计算绘图。

下面列出了代码的更新版本。

# cross-entropy for predicted probability distribution vs label
from math import log
from matplotlib import pyplot

# calculate cross-entropy
def cross_entropy(p, q, ets=1e-15):
	return -sum([p[i]*log(q[i]+ets) for i in range(len(p))])

# define the target distribution for two events
target = [0.0, 1.0]
# define probabilities for the first event
probs = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]
# create probability distributions for the two events
dists = [[1.0 - p, p] for p in probs]
# calculate cross-entropy for each distribution
ents = [cross_entropy(target, d) for d in dists]
# plot probability distribution vs cross-entropy
pyplot.plot([1-p for p in probs], ents, marker='.')
pyplot.title('Probability Distribution vs Cross-Entropy')
pyplot.xticks([1-p for p in probs], ['[%.1f,%.1f]'%(d[0],d[1]) for d in dists], rotation=70)
pyplot.subplots_adjust(bottom=0.2)
pyplot.xlabel('Probability Distribution')
pyplot.ylabel('Cross-Entropy (nats)')
pyplot.show()

运行该示例可以更好地了解概率分布中的发散度与计算出的交叉熵之间的关系。

我们可以看到一种超线性关系,其中预测的概率分布与目标的偏差越大,交叉熵的增加就越大。

去掉极值情况下二分类任务概率分布与交叉熵的直线图

这样的曲线图可以用作解释为二进制分类数据集的模型报告的平均交叉熵的指南。

例如,你可以使用这些交叉熵值来解释KERAS为二进制分类任务上的神经网络模型报告的平均交叉熵,或SCRICKIT-LEARN中使用对数损失度量评估的二进制分类模型。

你可以使用它来回答一般问题:

什么是好的交叉熵分数?

如果你在NAT中工作(通常是这样),并且平均交叉熵小于0.2,那么你就有了一个良好的开端,小于0.1或0.05就更好了。

另一方面,如果你的平均交叉熵大于0.2或0.3,你可能会有所改进,如果你的平均交叉熵大于1.0,则说明发生了一些事情,你对数据集中的许多示例的概率预测都很差。

我们可以将平均交叉熵的这些直觉总结如下:

  • 交叉熵=0.00:完全概率。
  • 交叉熵<0.02:概率很大。
  • 交叉熵<0.05:在正确的轨道上。
  • 交叉熵<0.20:很好。
  • 交叉熵>0.30:不是很好。
  • 交叉熵>1.00:可怕。
  • 交叉熵>2.00:有什么东西坏了。

在解释Logistic回归模型或人工神经网络模型的交叉熵(对数损失)时,此清单将提供有用的指导。

你还可以计算每个类的平均交叉熵分数,并帮助梳理出你的模型中哪些类具有良好的概率,哪些类可能会出错。

交叉熵与对数损失

交叉熵不是对数损失,但当用作分类问题的损失函数时,它们计算的量是相同的。

对数损失是负的对数可能性。

Logistic损失是指通常用于优化Logistic回归模型的损失函数。

它也可以被称为对数损失(这是令人困惑的)或简单的原木损失。

许多模型是在称为最大似然估计(MLE)的概率框架下进行优化的,该框架涉及找到一组最能解释观测数据的参数。

这涉及选择定义一组观测(数据)被给定模型参数的可能性的似然函数。当使用对数似然函数(这是常见的)时,它通常被称为优化模型的对数似然。由于在实践中最小化函数比最大化函数更常见,因此通过在前面添加负号来反转对数似然函数。这将其转换为负对数似然函数或简称为NLL。

在推导伯努利概率分布函数(两类)的最大似然估计框架下的对数似然函数时,计算结果如下:

negative log-likelihood(P, Q) = -(P(class0) * log(Q(class0)) + P(class1) * log(Q(class1)))

这个量可以通过计算似然函数的对数的平均值来对所有训练示例进行平均。

二分类问题的负对数似然通常被缩短为简单的“对数损失”,作为Logistic回归的损失函数。

log loss = negative log-likelihood, under a Bernoulli probability distribution

我们可以看到,负对数似然与用于伯努利概率分布函数(两个事件或类)的交叉熵的计算相同。事实上,Multinoulli分布(多类分类)的负对数似然也与交叉熵的计算相匹配。

有关原木丢失和负对数可能性的更多信息,请参阅教程:

对数损失和交叉熵计算相同。

对于分类问题,“对数损失”、“交叉熵”和“负对数似然”可以互换使用。

更一般地,术语“交叉熵”和“负对数似然”在分类模型的损失函数的上下文中可互换使用。

Logistic回归的负对数似然率由[…]给出。这也称为交叉熵误差函数。

因此,计算对数损失与计算伯努利概率分布的交叉熵给出的量是相同的。我们可以通过使用scikit-learn API中的log_loss()函数计算日志损失来确认这一点。

计算上一节中同一组实际和预测概率的平均原木损失应与计算平均交叉熵的结果相同。

下面列出了完整的示例。

# calculate log loss for classification problem with scikit-learn
from sklearn.metrics import log_loss
from numpy import asarray
# define classification data
p = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
q = [0.8, 0.9, 0.9, 0.6, 0.8, 0.1, 0.4, 0.2, 0.1, 0.3]
# define data as expected, e.g. probability for each event {0, 1}
y_true = asarray([[1-v, v] for v in p])
y_pred = asarray([[1-v, v] for v in q])
# calculate the average log loss
ll = log_loss(y_true, y_pred)
print('Average Log Loss: %.3f' % ll)

运行该示例得到的预期结果是0.247的对数损失,这与使用平均交叉熵计算时的0.247 nats相匹配。

Average Log Loss: 0.247

这并不意味着对数损失计算交叉熵或交叉熵计算日志损失。

相反,它们是从不同的研究领域得出的不同的量,在计算分类任务的损失函数的条件下,导致等价的计算和结果。具体地说,交叉熵损失函数等价于Bernoulli或Multinoulli概率分布下的最大似然函数。

这证明了最大似然估计的研究与离散概率分布的信息论之间的联系。

它并不局限于离散的概率分布,这一事实让许多第一次听到它的从业者感到惊讶。

具体地说,在最大似然估计框架下优化的线性回归假设目标变量的高斯连续概率分布,并且涉及最小化均方误差函数。这相当于具有高斯概率分布的随机变量的交叉熵。

任何由负对数似然组成的损失都是由训练集定义的经验分布和由模型定义的概率分布之间的交叉熵。例如,均方误差是经验分布和高斯模型之间的交叉熵。

这有点令人兴奋,来自于连续随机变量的微分熵领域。

这意味着如果你计算覆盖相同事件(具有相同平均值和标准差)的两个高斯随机变量之间的均方误差,那么你就是在计算变量之间的交叉熵。

这也意味着,如果你使用均方误差损失来优化你的神经网络模型以解决回归问题,那么你实际上就是在使用交叉熵损失。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

教程

书籍

API接口

文章

摘要

在本教程中,您发现了机器学习的交叉熵。

具体地说,您了解到:

  • 如何从头开始并使用标准机器学习库计算交叉熵。
  • 在对Logistic回归和人工神经网络等分类模型进行优化时,交叉熵可以作为损失函数。
  • 交叉熵不同于KL散度,但可以使用KL散度计算,并且与对数损失不同,但在用作损失函数时计算相同的量。

00

Python

发表评论

邮箱地址不会被公开。 必填项已用*标注

什么阻碍了你实现迈入机器学习领域的目标?

什么阻碍了你实现迈入机器学习领域的目标?

2020-04-22 机器学习

如果你在为进入机器学习领域而挣扎,感觉到有什么东西阻止了自己的开始,那么你应该看看这篇文章。 在这篇文章中,我们会讨论阻止进入机器学习领域的自我限制的信念,让你明白面临的问题。 几乎总是一种自我限制的信念阻碍了你们的进步。 也许你会在一个或多个这样的信念中看到自己。如果是这样的话, [......]

了解详情

R语言机器学习迷你课程

R语言机器学习迷你课程

2020-08-12 机器学习

在这个迷你课程中,你将发现如何开始,构建精确的模型,并自信地完成在14天内使用R预测建模机器学习项目。 这是一个重要而重要的文章。你可能想把它书签。 了解如何准备数据,拟合机器学习模型,并用我的新书评估他们在r上的预测,包括14步教程、3个项目和完整源代码。 我们开始吧。 [......]

了解详情

关于机器学习的几点思考

关于机器学习的几点思考

2020-04-26 机器学习

机器学习是一个大的、跨学科的研究领域。 你可以通过机器学习获得令人印象深刻的结果,并找到非常具有挑战性的问题的解决方案。但这只是更广泛的机器学习领域的一小部分,通常被称为预测建模或预测分析。 在这篇文章中,你将发现如何改变你对机器学习的思考方式,以便更好地为你提供机器学习实践者的服务。 [......]

了解详情

找到你的机器学习部落

找到你的机器学习部落

2020-04-26 机器学习

机器学习是一个充满算法和数据的迷人而强大的研究领域。 问题是,有这么多不同类型的人对机器学习感兴趣,每个人都有不同的需求。重要的是要了解你想要从机器学习中得到什么,并根据这些需求调整你的自学。 如果你不这样做,你很容易就会陷入困境,迷失方向,失去兴趣,得不到你想要的东西。 找到 [......]

了解详情

应用机器学习过程

应用机器学习过程

2020-04-26 机器学习

随着时间的推移,在处理应用机器学习问题时,你会开发出一种模式或流程,以快速获得良好的正常结果。 一旦开发完成,你就可以在一个又一个项目上反复使用此过程。你的流程越健壮、越发达,你就能越快地获得可靠的结果。 在这篇文章中,我想与你分享我解决机器学习问题的过程框架。 你可以将其用作下一 [......]

了解详情