【问题标题】:What are C classes for a NLLLoss loss function in Pytorch?Pytorch 中 NLLLoss 损失函数的 C 类是什么?
【发布时间】:2020-04-30 06:07:51
【问题描述】:

我在询问关于 NLLLoss 损失函数的 C 类。

文档说明:

负对数似然损失。用 C 类训练分类问题很有用。

基本上,在那之后的一切都取决于您知道什么是 C 类,我以为我知道什么是 C 类,但文档对我来说没有多大意义。特别是当它描述(N, C) where C = number of classes 的预期输入时。这就是我感到困惑的地方,因为我认为 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:预期 2 个或更多维度(得到 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])))

所以现在我有了 NN 的输出,我想知道我的分类 [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,这让我很困惑,因为请查看 input 数据。这是一个 3x5 张量,我迷路了。

这是NLLLoss 函数的第一个输入的文档:

输入:(N, C)(N,C) 其中 C = 类数

输入按类数分组

那么张量输入的每一都与训练张量的每一元素相关联?

如果我改变输入张量的第二个维度,那么什么都不会发生,我不明白发生了什么。

input = torch.randn(3, 100, requires_grad=True)
# 3 x 100 still works?

所以我不明白这里的 C 类是什么,我认为 C 类是一种分类(如标签),仅对 NN 的输出有意义。

我希望你能理解我的困惑,因为神经网络的输入形状不应该独立于用于分类的一个热向量的形状吗?

代码示例和文档都说输入的形状是由分类数定义的,我不太明白为什么。

我试图研究文档和教程以了解我所缺少的内容,但在几天无法超越这一点后,我决定问这个问题。这让我感到羞愧,因为我认为这将是更容易学习的事情之一。

【问题讨论】:

    标签: python machine-learning neural-network pytorch


    【解决方案1】:

    基本上您缺少batch 的概念。

    长话短说,损失的每个输入(以及通过网络的输入)都需要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,因此是 @987654332 @ 很好)。

    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 与您的目标一起使用。

    【讨论】:

      【解决方案2】:

      我同意您的观点,nn.NLLLoss() 的文档远非理想,但我认为我们可以在这里澄清您的问题,首先,通过澄清“类”通常用作机器中“类别”的同义词学习环境。

      因此,当 PyTorch 谈论 C 类时,它实际上是指不同类别的数量,您正在尝试训练您的网络。 因此,在分类神经网络试图在“猫”和“狗”之间进行分类的经典示例中,C = 2,因为它不是猫就是狗。

      特别是对于这个分类问题,它还认为我们在我们的类别数组上只有一个一个真值(一张图片不能同时描绘猫和狗,但总是只有一个),这就是为什么我们可以通过索引方便地指示图像的相应类别(假设0 表示猫,1 表示狗)。现在,我们可以简单地将网络输出与我们想要的类别进行比较。

      但是,为了使它起作用,我们还需要清楚这些损失值所引用的内容(在我们的网络输出中),因为我们的网络通常会通过 softmax 对不同的输出神经元进行预测 /em>,意思是我们通常有多个值。幸运的是,PyTorch 的 nn.NLLLoss 会自动为您执行此操作。

      您上面的带有LogSoftmax 的示例实际上只产生一个输出值,这是本示例的关键情况。这样,您基本上只能指示某物是否存在/不存在,但在分类示例中使用没有多大意义,在回归案例中更是如此(但这需要完全不同的损失函数)。

      最后但同样重要的是,您还应该考虑我们通常将 2D 张量作为输入这一事实,因为批处理(多个样本的同时计算)通常被认为是匹配性能的必要步骤。即使您选择批量大小为 1,这仍然需要您的输入是维度 (batch_size, input_dimensions),因此您的输出张量的形状是 (batch_size, number_of_categories)

      这解释了为什么您在网上找到的大多数示例都执行 LogSoftmax() 而不是 dim=1,因为这是“分布中轴”,而不是批处理轴(应该是 dim=0)。

      如果您只是想解决问题,最简单的方法是将随机张量扩展一个额外的维度 (torch.randn([1, 5], requires_grad=True)),然后仅比较输出张量中的一个值 (print(loss(output, torch.tensor([1])))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 2017-06-18
        • 2019-03-16
        • 2019-08-19
        • 2021-11-18
        • 2020-05-24
        • 2018-02-26
        相关资源
        最近更新 更多