【问题标题】:Pytorch softmax along different masks without for loopPytorch softmax 沿着不同的掩码,没有 for 循环
【发布时间】:2019-01-21 05:46:34
【问题描述】:

假设我有一个向量 a ,索引向量 b 的长度相同。索引范围为0~N-1,对应N组。如何在没有 for 循环的情况下为每个组做 softmax?

我在这里做一些注意力操作。每个组的数字都不相同,因此我无法将a 重塑为矩阵并在标准Softmax() API 中使用dim

玩具示例:

a = torch.rand(10)
a: tensor([0.3376, 0.0557, 0.3016, 0.5550, 0.5814, 0.1306, 0.2697, 0.9989, 0.4917,
        0.6306])
b = torch.randint(0,3,(1,10), dtype=torch.int64)
b: tensor([[1, 2, 0, 2, 2, 0, 1, 1, 1, 1]])

我想做softmax之类的

for index in range(3):
    softmax(a[b == index])

但没有 for 循环以节省时间。

【问题讨论】:

  • 如果我错了,请纠正我,但是您要查找的不是softmax,而是元素均方误差,对吗?由于您对 softmax 的计算会假设 a 中沿主轴的值的总和为 1。
  • 感谢您的回复。 Acutally 我没有在这里计算损失。 b 中的索引更适合被视为组而不是类。我想要a 中属于同一索引的每个 scaler 的 softmax 概率,它们使用这些概率作为权重以供以后计算。因此,每个指数的输出总和为 1,在 N 组示例中,输出总和应为 N。

标签: parallel-processing deep-learning pytorch softmax attention-model


【解决方案1】:

也许这个答案必须根据对我的评论的潜在回应而略有改变,但我只是继续前进,并为Softmax 投入两分钱。

一般来说,softmax 的公式在PyTorch documentation 中有很好的解释,我们可以看到这是当前值的指数除以所有类的总和。
这样做的原因是基于概率论,可能有点超出我的舒适区,但本质上它可以帮助你保持一个相当简单的反向传播导数,当它与一种流行的损失策略结合使用时,称为“交叉熵损失” (CE) (参见 PyTorch 中的相应函数here

此外,您还可以在 CE 的描述中看到它自动组合两个函数,即 softmax 函数的(数值稳定)版本,以及负对数似然损失(NLLL )。

现在,回到您最初的问题,并希望解决您的问题:
为了这个问题 - 以及您提出问题的方式 - 您似乎正在使用流行的 MNIST 手写数字数据集,我们希望在其中预测您当前输入图像的一些值。

我还假设您的输出 a 将在某个时候成为神经网络层的输出。是否将其压缩到特定范围都没有关系(例如,通过应用某种形式的激活函数),因为 softmax 基本上是一种归一化。具体来说,如前所述,它将为我们提供所有预测值的某种形式的分布,并且在所有类中总和为 1。为此,我们可以简单地应用类似

soft_a = softmax(a, dim=0) # otherwise throws error if we don't specify axis
print(torch.sum(soft_a)) # should return "Tensor(1.)"

现在,如果我们假设您想要执行“经典”MNIST 示例,您可以使用argmax() 函数来预测您的系统认为哪个值是正确答案,并据此计算错误,例如, 使用 nn.NLLLoss() 函数。

如果您确实在预测单个输出中每个位置的值,那么您必须对此略有不同。
首先,softmax() 在这里不再有意义,因为您正在计算一个跨多个输出的概率分布,除非您相当确定它们的分布以一种非常具体的方式相互依赖,我认为这里不是这种情况。

另外,请记住,您正在寻求计算成对损失,即输出的每个索引的东西。为此特定目的想到的函数是nn.BCELoss(),它计算交叉熵的二值化(元素)版本。 为此,您可以简单地“支持”您的原始预测张量a,以及您的基本事实张量b。一个最小的示例如下所示:

bce = torch.nn.BCELoss(reduction="none") # to keep losses for each element separate
loss = bce(a,b) # returns tensor with respective pairwise loss

如果您对单个损失感兴趣,您显然可以使用 BCELossreduction 的不同参数,如文档中所述。 让我知道我是否可以为您澄清答案的某些部分。

编辑:这里要记住的其他内容:BCELoss() 要求您输入可能接近您想要预测的值的值。如果您首先将值输入到激活函数(例如 sigmoid 或 tanh)中,这尤其会成为一个问题,因为它们受区间限制,因此 永远不会达到您想要预测的值!

【讨论】:

  • 感谢您的回复,我在问题下方留下了评论。也许我应该更清楚地提出我的问题。顺便问一下,BCELoss()tget 不应该只有 0 或 1 吗?
猜你喜欢
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多