我正在询问 NLLLoss 的 C 类损失函数。
文档指出:
The negative log likelihood loss. It is useful to train a classification problem with C classes.
基本上,在那之后的一切都取决于您是否知道 C 类是什么,我以为我知道 C 类是什么,但文档对我来说没有多大意义。特别是当它描述 (N, C) 的预期输入(其中 C = 类数
)时。这就是我感到困惑的地方,因为我认为 C 类仅指输出。我的理解是,C 类是分类的热门向量之一。我经常在教程中发现 NLLLoss
通常与 LogSoftmax
配合使用来解决分类问题。
我希望在以下示例中使用 NLLLoss
:
# Some random training data
input = torch.randn(5, requires_grad=True)
print(input) # tensor([-1.3533, -1.3074, -1.7906, 0.3113, 0.7982], requires_grad=True)
# Build my NN (here it's just a LogSoftmax)
m = nn.LogSoftmax(dim=0)
# Train my NN with the data
output = m(input)
print(output) # tensor([-2.8079, -2.7619, -3.2451, -1.1432, -0.6564], grad_fn=<LogSoftmaxBackward>)
loss = nn.NLLLoss()
print(loss(output, torch.tensor([1, 0, 0])))
上面的最后一行引发了以下错误:
ValueError: Expected 2 or more dimensions (got 1)
我们可以忽略该错误,因为显然我不明白我在做什么。这里我解释一下我上面源码的意图。
input = torch.randn(5, requires_grad=True)
随机一维数组与 [1, 0, 0]
的一个热向量配对进行训练。我正在尝试对十进制数的一个热向量执行二进制位。
m = nn.LogSoftmax(dim=0)
LogSoftmax
的文档表示输出的形状与输入相同,但我只看到了 LogSoftmax(dim=1)
的示例,因此我一直在努力让这项工作发挥作用,因为我找不到相关的例子。
print(loss(output, torch.tensor([1, 0, 0])))
现在我有了神经网络的输出,我想知道分类[1, 0, 0]
的损失。在这个例子中,数据是什么并不重要。我只想要代表分类的一个热向量的损失。
此时,我在尝试解决与预期输出和输入结构相关的损失函数中的错误时陷入困境。我尝试在输出和输入上使用 view(...)
来修复形状,但这只会给我带来其他错误。
所以这又回到了我原来的问题,我将展示文档中的示例来解释我的困惑:
m = nn.LogSoftmax(dim=1)
loss = nn.NLLLoss()
input = torch.randn(3, 5, requires_grad=True)
train = torch.tensor([1, 0, 4])
print('input', input) # input tensor([[...],[...],[...]], requires_grad=True)
output = m(input)
print('train', output, train) # tensor([[...],[...],[...]],grad_fn=<LogSoftmaxBackward>) tensor([1, 0, 4])
x = loss(output, train)
同样,我们在 LogSoftmax
上有 dim=1
,这让我现在很困惑,因为看看输入
数据。这是一个 3x5
张量,我迷路了。
以下是有关 NLLLoss
函数第一个输入的文档:
Input: (N, C)(N,C) where C = number of classes
输入按类别数分组?
那么张量输入的每个行都与训练张量的每个元素相关联?
如果我更改输入张量的第二个维度,那么不会发生任何事情,而且我不明白发生了什么。
input = torch.randn(3, 100, requires_grad=True)
# 3 x 100 still works?
所以我不明白 C 类是什么,我认为 C 类是一个分类(如标签)并且仅对神经网络的输出有意义。
我希望您能理解我的困惑,因为神经网络的输入形状不应该独立于用于分类的一个热向量的形状吗?
代码示例和文档都说输入的形状是由分类数量定义的,我不太明白为什么。
我尝试研究文档和教程以了解我所缺少的内容,但经过几天无法解决这一问题后,我决定提出这个问题。这让我感到很谦卑,因为我认为这将是更容易学习的事情之一。
最佳答案
基本上,您缺少批处理
的概念。
长话短说,每个损失输入(以及通过网络传递的输入)都需要batch
维度(即使用了多少个样本)。
逐步分解:
您的示例与文档
每个步骤都会对每个步骤进行比较,以使其更加清晰(文档在上面,您的示例在下面)
输入
input = torch.randn(3, 5, requires_grad=True)
input = torch.randn(5, requires_grad=True)
在第一种情况(文档)中,创建具有 5
特征的输入并使用 3
样本。在您的情况下,只有batch
维度(5
样本),您没有所需的功能。如果您想要一个具有 5
功能的示例,您应该这样做:
input = torch.randn(5, requires_grad=True)
LogSoftmax
LogSoftmax
是跨特征维度完成的,您正在跨批处理进行。
m = nn.LogSoftmax(dim=1) # 应用于特征 m = nn.LogSoftmax(dim=0) # 批量应用
此操作通常没有意义,因为样本彼此独立。
目标
由于这是多类分类,并且向量中的每个元素代表一个样本,因此可以传递任意数量的数字(只要它小于特征数量,在文档示例中它是5
,因此 [0-4]
就可以了)。
train = torch.tensor([1, 0, 4])
train = torch.tensor([1, 0, 0])
我假设,您也想将 one-hot 向量作为目标传递。 PyTorch 不会以这种方式工作,因为它内存效率低(当您可以精确定位类时,为什么将所有内容存储为 one-hot 编码,在您的情况下它将是 0
)。
只有神经网络的输出是一个热编码,以便通过所有输出节点反向传播误差,目标不需要它。
决赛
您根本不应该使用torch.nn.LogSoftmax
来执行此任务。只需使用 torch.nn.Linear
作为最后一层,并使用 torch.nn.CrossEntropyLoss
与您的目标。
关于python - Pytorch 中 NLLLoss 损失函数的 C 类是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59718130/