Pytorch 中是否有一种方法可以以可以反向传播的方式计算唯一值的数量?

jwe*_*324 5 counting backpropagation pytorch

给定以下张量(这是网络的结果 [注意 grad_fn]):

tensor([121., 241., 125.,   1., 108., 238., 125., 121.,  13., 117., 121., 229.,
        161.,  13.,   0., 202., 161., 121., 121.,   0., 121., 121., 242., 125.],
       grad_fn=<MvBackward>)
Run Code Online (Sandbox Code Playgroud)

我们将定义为:

tensor([121., 241., 125.,   1., 108., 238., 125., 121.,  13., 117., 121., 229.,
        161.,  13.,   0., 202., 161., 121., 121.,   0., 121., 121., 242., 125.],
       grad_fn=<MvBackward>)
Run Code Online (Sandbox Code Playgroud)

我想定义一个计算每个值出现次数的操作,该操作将输出以下张量:

tensor([2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
        0, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
        0, 1, 1])
Run Code Online (Sandbox Code Playgroud)

即有 2 个零、1 个一、2 个十三等……可能值的总数设置在上游,但在本例中为 243

到目前为止,我已经尝试了以下方法,它们成功地产生了所需的张量,但这样做的方式不允许计算梯度通过网络返回:

尝试 1

xx = torch.tensor([121., 241., 125.,   1., 108., 238., 125., 121.,  13., 117., 121., 229.,
        161.,  13.,   0., 202., 161., 121., 121.,   0., 121., 121., 242., 125.]).requires_grad_(True)
Run Code Online (Sandbox Code Playgroud)

尝试 2

tensor([2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
        0, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
        0, 1, 1])
Run Code Online (Sandbox Code Playgroud)

编辑:添加尝试

尝试 3

-- 没想到这会支持道具,但我想无论如何我都会尝试一下

tt = []
for i in range(243):
    tt.append((xx == i).unsqueeze(0))
torch.cat(tt,dim=0).sum(dim=1)
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏

编辑:根据要求,最终目标如下:

我正在使用一种技术来计算两个时间序列之间的结构相似性。一个是真实的,另一个是生成的。本文概述了该技术(https://link.springer.com/chapter/10.1007/978-3-642-02279-1_33),其中将时间序列转换为代码字序列以及代码字的分布(类似于NLP中使用Bag of Words的方式)用于表示时间序列。当两个信号分布相似时,两个系列被认为是相似的。这就是计数统计张量的用途。

所希望的是能够构建一个消耗该张量并测量真实信号和生成信号之间距离的损失函数(直接时域数据上的欧几里德范数效果不佳,这种方法声称效果更好),以便它可以适当地更新生成器。

Jul*_*laz 8

我会用unique方法来做到这一点(仅计算出现次数):

在此输入图像描述

如果你想统计出现次数,你必须添加参数return_counts=True

在此输入图像描述

我是在1.3.1版本中做到的

在此输入图像描述

这是计算出现次数的快速方法,但是是不可微分的操作,因此,不推荐使用这种方法(无论如何我已经描述了计算出现次数的方法)。为了执行你想要的操作,我认为你应该通过可微函数(softmax是最常用的)将输入转换为分布,然后使用某种方法来测量分布(输出和目标)之间的距离,例如交叉熵、KL(kullback-liebler)、JS 或 wasserstein。


Szy*_*zke 4

您将无法像unique简单的不可微分操作那样做到这一点。

此外,只有floating点张量可以具有梯度,因为它仅针对实数域定义,而不是针对整数。

尽管如此,可能还有另一种可微分的方法来实现您想要实现的目标,但这是一个不同的问题。