首页 > 解决方案 > Pytorch softmax 沿着不同的掩码,没有 for 循环

问题描述

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

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

玩具示例:

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 循环来节省时间。

标签: parallel-processingdeep-learningpytorchsoftmaxattention-model

解决方案


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

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

此外,您还可以在 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

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

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


推荐阅读