当目标不是单热时,如何计算 Pytorch 中 2 个张量之间的正确交叉熵?
How to calculate correct Cross Entropy between 2 tensors in Pytorch when target is not one-hot?
我对Pytorch中交叉熵的计算感到困惑。如果我想计算 2 个张量之间的交叉熵并且目标张量不是 one-hot 标签,我应该使用哪种损失?计算 2 个概率分布之间的交叉熵而不是预测结果和确定的 one-hot 标签是很常见的。
基本损失函数CrossEntropyLoss
强制目标作为索引整数,在这种情况下不符合条件。 BCELoss
似乎有效,但它给出了意想不到的结果。计算交叉熵的预期公式是
但是BCELoss
计算每个维度的BCE,表示为
-yi*log(pi)-(1-yi)*log(1-pi)
与第一个方程相比,-(1-yi)*log(1-pi)
项应该没有涉及。这是一个使用 BCELoss
的示例,我们可以看到第二项涉及每个维度的结果。这使得结果与正确的结果不同。
import torch.nn as nn
import torch
from math import log
a = torch.Tensor([0.1,0.2,0.7])
y = torch.Tensor([0.2,0.2,0.6])
L = nn.BCELoss(reduction='none')
y1 = -0.2 * log(0.1) - 0.8 * log(0.9)
print(L(a, y))
print(y1)
结果是
tensor([0.5448, 0.5004, 0.6956])
0.5448054311250702
如果我们将所有维度的结果相加,最终的交叉熵与预期的不对应。因为这些维度中的每一个都涉及 -(1-yi)*log(1-pi)
项。相比之下,Tensorflow 可以用 CategoricalCrossentropy
计算出正确的交叉熵值。这是具有相同设置的示例,我们可以看到交叉熵的计算方式与第一个公式相同。
import tensorflow as tf
from math import log
L = tf.losses.CategoricalCrossentropy()
a = tf.convert_to_tensor([0.1,0.2,0.7])
y = tf.convert_to_tensor([0.2,0.2,0.6])
y_ = -0.2* log(0.1) - 0.2 * log(0.2) - 0.6 * log(0.7)
print(L(y,a), y_)
tf.Tensor(0.9964096, shape=(), dtype=float32) 0.9964095674488687
在Pytorch中有没有函数可以像Tensorflow中的CategoricalCrossentropy
一样使用第一个公式计算出正确的交叉熵?
也许你应该试试 torch.nn.CrossEntropyLoss
函数
根本问题是您错误地使用了 BCELoss
函数。
交叉熵损失就是你想要的。它用于计算两个任意概率分布之间的损失。实际上,它的定义正是您提供的等式:
其中 p
是目标分布,q
是您的预测分布。有关详细信息,请参阅 。
在您提供行的示例中
y = tf.convert_to_tensor([0.2, 0.2, 0.6])
您正在隐式建模一个多 class class 化问题,其中目标 class 可以是三个 class 之一(该张量的长度) .更具体地说,该行表示对于这个数据实例,class 0 的概率为 0.2,class 1 的概率为 0.2,class 2 的概率为 0.6。
您遇到的问题是 PyTorch 的 BCELoss 计算 binary 交叉熵损失,其公式不同。二元交叉熵损失计算 class化问题的交叉熵,其中目标 class 只能是 0 或 1。
在二元交叉熵中,你只需要一个概率,例如0.2,表示实例为class1的概率为0.2。相应地,class0的概率为0.8。
如果您将相同的张量 [0.2, 0.2, 0.6]
赋予 BCELoss,则您正在对存在三个数据实例的情况进行建模,其中数据实例 0 成为 class 1 的概率为 0.2,数据实例 1 class 1 的概率为 0.2,数据实例 2 为 class 1 的概率为 0.6。
现在,回到你原来的问题:
If I want to calculate the cross entropy between 2 tensors and the target tensor is not a one-hot label, which loss should I use?
不幸的是,PyTorch 没有接受两个概率分布的交叉熵函数。看到这个问题:
https://discuss.pytorch.org/t/how-should-i-implement-cross-entropy-loss-with-continuous-target-outputs/10720
建议使用其方程定义来实现您自己的函数。这是有效的代码:
def cross_entropy(input, target):
return torch.mean(-torch.sum(target * torch.log(input), 1))
y = torch.Tensor([[0.2, 0.2, 0.6]])
yhat = torch.Tensor([[0.1, 0.2, 0.7]])
cross_entropy(yhat, y)
# tensor(0.9964)
它提供了您想要的答案。
更新: 从 1.10 版本开始,Pytorch 在 CrossEntropyLoss 中支持 class 概率目标,因此您现在可以简单地使用:
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(x, y)
其中 x
是输入,y
是目标。当 y
与 x
具有相同的形状时,它将被视为 class 概率。请注意,x
预计包含每个 class 的原始非标准化分数,而 y
预计包含每个 class 的概率(通常是 softmax 层的输出) .您可以在 docs.
中找到详细信息
我对Pytorch中交叉熵的计算感到困惑。如果我想计算 2 个张量之间的交叉熵并且目标张量不是 one-hot 标签,我应该使用哪种损失?计算 2 个概率分布之间的交叉熵而不是预测结果和确定的 one-hot 标签是很常见的。
基本损失函数CrossEntropyLoss
强制目标作为索引整数,在这种情况下不符合条件。 BCELoss
似乎有效,但它给出了意想不到的结果。计算交叉熵的预期公式是
但是BCELoss
计算每个维度的BCE,表示为
-yi*log(pi)-(1-yi)*log(1-pi)
与第一个方程相比,-(1-yi)*log(1-pi)
项应该没有涉及。这是一个使用 BCELoss
的示例,我们可以看到第二项涉及每个维度的结果。这使得结果与正确的结果不同。
import torch.nn as nn
import torch
from math import log
a = torch.Tensor([0.1,0.2,0.7])
y = torch.Tensor([0.2,0.2,0.6])
L = nn.BCELoss(reduction='none')
y1 = -0.2 * log(0.1) - 0.8 * log(0.9)
print(L(a, y))
print(y1)
结果是
tensor([0.5448, 0.5004, 0.6956])
0.5448054311250702
如果我们将所有维度的结果相加,最终的交叉熵与预期的不对应。因为这些维度中的每一个都涉及 -(1-yi)*log(1-pi)
项。相比之下,Tensorflow 可以用 CategoricalCrossentropy
计算出正确的交叉熵值。这是具有相同设置的示例,我们可以看到交叉熵的计算方式与第一个公式相同。
import tensorflow as tf
from math import log
L = tf.losses.CategoricalCrossentropy()
a = tf.convert_to_tensor([0.1,0.2,0.7])
y = tf.convert_to_tensor([0.2,0.2,0.6])
y_ = -0.2* log(0.1) - 0.2 * log(0.2) - 0.6 * log(0.7)
print(L(y,a), y_)
tf.Tensor(0.9964096, shape=(), dtype=float32) 0.9964095674488687
在Pytorch中有没有函数可以像Tensorflow中的CategoricalCrossentropy
一样使用第一个公式计算出正确的交叉熵?
也许你应该试试 torch.nn.CrossEntropyLoss
函数
根本问题是您错误地使用了 BCELoss
函数。
交叉熵损失就是你想要的。它用于计算两个任意概率分布之间的损失。实际上,它的定义正是您提供的等式:
其中 p
是目标分布,q
是您的预测分布。有关详细信息,请参阅
在您提供行的示例中
y = tf.convert_to_tensor([0.2, 0.2, 0.6])
您正在隐式建模一个多 class class 化问题,其中目标 class 可以是三个 class 之一(该张量的长度) .更具体地说,该行表示对于这个数据实例,class 0 的概率为 0.2,class 1 的概率为 0.2,class 2 的概率为 0.6。
您遇到的问题是 PyTorch 的 BCELoss 计算 binary 交叉熵损失,其公式不同。二元交叉熵损失计算 class化问题的交叉熵,其中目标 class 只能是 0 或 1。
在二元交叉熵中,你只需要一个概率,例如0.2,表示实例为class1的概率为0.2。相应地,class0的概率为0.8。
如果您将相同的张量 [0.2, 0.2, 0.6]
赋予 BCELoss,则您正在对存在三个数据实例的情况进行建模,其中数据实例 0 成为 class 1 的概率为 0.2,数据实例 1 class 1 的概率为 0.2,数据实例 2 为 class 1 的概率为 0.6。
现在,回到你原来的问题:
If I want to calculate the cross entropy between 2 tensors and the target tensor is not a one-hot label, which loss should I use?
不幸的是,PyTorch 没有接受两个概率分布的交叉熵函数。看到这个问题: https://discuss.pytorch.org/t/how-should-i-implement-cross-entropy-loss-with-continuous-target-outputs/10720
建议使用其方程定义来实现您自己的函数。这是有效的代码:
def cross_entropy(input, target):
return torch.mean(-torch.sum(target * torch.log(input), 1))
y = torch.Tensor([[0.2, 0.2, 0.6]])
yhat = torch.Tensor([[0.1, 0.2, 0.7]])
cross_entropy(yhat, y)
# tensor(0.9964)
它提供了您想要的答案。
更新: 从 1.10 版本开始,Pytorch 在 CrossEntropyLoss 中支持 class 概率目标,因此您现在可以简单地使用:
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(x, y)
其中 x
是输入,y
是目标。当 y
与 x
具有相同的形状时,它将被视为 class 概率。请注意,x
预计包含每个 class 的原始非标准化分数,而 y
预计包含每个 class 的概率(通常是 softmax 层的输出) .您可以在 docs.