Rea*_*lar 7 python machine-learning neural-network pytorch
我在询问NLLLoss损失函数的C 类。
该文件指出:
负对数似然损失。用 C 类训练分类问题很有用。
基本上在那之后的一切都取决于你是否知道 C 类是什么,我以为我知道 C 类是什么,但文档对我来说没有多大意义。特别是当它描述 的预期输入时(N, C) where C = number of classes。这就是我感到困惑的地方,因为我认为 C 类仅指输出。我的理解是,C 类是一个热门的分类向量。我经常在教程中发现NLLLoss经常与 a 配对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])))
Run Code Online (Sandbox Code Playgroud)
以上在最后一行引发了以下错误:
ValueError:预期有 2 个或更多维度(得到 1 个)
我们可以忽略错误,因为显然我不明白我在做什么。在这里,我将解释我对上述源代码的意图。
input = torch.randn(5, requires_grad=True)
Run Code Online (Sandbox Code Playgroud)
随机一维数组与一个[1, 0, 0]用于训练的热向量配对。我正在尝试对一个十进制数的热向量进行二进制位处理。
m = nn.LogSoftmax(dim=0)
Run Code Online (Sandbox Code Playgroud)
的文档LogSoftmax说输出将与输入具有相同的形状,但我只看到了 的示例,LogSoftmax(dim=1)因此我一直在努力使其工作,因为我找不到相关示例。
print(loss(output, torch.tensor([1, 0, 0])))
Run Code Online (Sandbox Code Playgroud)
所以现在我有了神经网络的输出,我想知道我的分类损失 [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)
Run Code Online (Sandbox Code Playgroud)
同样,我们必须dim=1在LogSoftmax这让我困惑了,因为看的input数据。这是一个3x5张量,我迷路了。
这是该NLLLoss函数的第一个输入的文档:
输入:(N, C)(N,C) 其中 C = 类数
输入按类别数分组?
所以张量输入的每一行都与每个训练张量的元素吗?
如果我更改输入张量的第二维,则不会有任何问题,我不明白发生了什么。
input = torch.randn(3, 100, requires_grad=True)
# 3 x 100 still works?
Run Code Online (Sandbox Code Playgroud)
所以我不明白这里的 C 类是什么,我认为 C 类是一种分类(如标签)并且仅对 NN 的输出有意义。
我希望你理解我的困惑,因为神经网络输入的形状不应该独立于用于分类的一个热向量的形状吗?
代码示例和文档都说输入的形状是由分类数量定义的,我真的不明白为什么。
我试图研究文档和教程以了解我所缺少的东西,但是在几天无法通过这一点之后,我决定提出这个问题。它一直令人谦卑,因为我认为这将是更容易学习的事情之一。
基本上你缺少一个概念batch。
长话短说,损失的每个输入(以及通过网络的输入)都需要batch维度(即使用了多少个样本)。
一步步分解:
每个步骤都会对每个步骤进行比较,以使其更加清晰(文档在上面,您的示例在下面)
input = torch.randn(3, 5, requires_grad=True)
input = torch.randn(5, requires_grad=True)
Run Code Online (Sandbox Code Playgroud)
在第一种情况(文档)中,5创建具有特征的输入并3使用样本。在您的情况下,只有batch尺寸(5样本),您没有所需的功能。如果您想要一个5具有功能的样本,您应该这样做:
input = torch.randn(5, requires_grad=True)
Run Code Online (Sandbox Code Playgroud)
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])
Run Code Online (Sandbox Code Playgroud)
我想,您也想将 one-hot 向量作为目标传递。PyTorch 不会以这种方式工作,因为它的内存效率低下(当您可以精确定位类时,为什么将所有内容存储为 one-hot 编码,在您的情况下它会是0)。
只有神经网络的输出是一种热编码,以便通过所有输出节点反向传播误差,目标不需要它。
您torch.nn.LogSoftmax 根本不应该使用此任务。只需用作torch.nn.Linear最后一层并torch.nn.CrossEntropyLoss与您的目标一起使用。
我同意您的观点,即文档nn.NLLLoss()远非理想,但我认为我们可以在这里澄清您的问题,首先,通过澄清“类”通常在机器学习上下文中用作“类别”的同义词。
因此,当 PyTorch 谈论C类时,它实际上指的是您尝试训练网络的不同类别的数量。因此,在分类神经网络尝试对“猫”和“狗”进行分类的经典示例中,C = 2因为它要么是猫,要么是狗。
特别是对于这个分类问题,它还认为我们的类别数组只有一个真值(一张图片不能同时描绘猫和狗,但总是只能其中之一),这就是为什么我们可以方便地指示图像的索引对应的类别(假设这0表示一只猫和1一只狗)。现在,我们可以简单地将网络输出与我们想要的类别进行比较。
但是,为了使其发挥作用,我们还需要清楚这些损失值(在我们的网络输出中)所引用的内容,因为我们的网络通常会通过 softmax 对不同的输出神经元进行预测,这意味着我们通常有更多比单个值。幸运的是,PyTorch 会nn.NLLLoss自动为您完成此操作。
上面的示例实际上LogSoftmax只产生一个输出值,这是本示例的关键情况。这样,您基本上只能指示某些东西是否存在/不存在,但在分类示例中使用没有多大意义,在回归情况下更是如此(但这将需要完全不同的首先是损失函数)。
最后但并非最不重要的一点是,您还应该考虑这样一个事实:我们通常将 2D 张量作为输入,因为批处理(多个样本的同时计算)通常被认为是匹配性能的必要步骤。即使您选择批量大小为 1,这仍然要求您的输入尺寸为(batch_size, input_dimensions),因此输出张量的形状为(batch_size, number_of_categories)。
这解释了为什么您在网上找到的大多数示例都执行 over LogSoftmax(),dim=1因为这是“分布内轴”,而不是批处理轴(这将是dim=0)。
如果您只是想解决问题,最简单的方法是将随机张量扩展一个附加维度 ( torch.randn([1, 5], requires_grad=True)),然后仅与输出张量中的一个值进行比较 ( print(loss(output, torch.tensor([1])))
| 归档时间: |
|
| 查看次数: |
4248 次 |
| 最近记录: |