【问题标题】:Is there a method in Pytorch to count the number of unique values in a way that can be back propagated?Pytorch 中是否有一种方法可以以可以反向传播的方式计算唯一值的数量?
【发布时间】:2020-02-24 04:22:30
【问题描述】:

给定以下张量(这是网络的结果 [注意 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>)

我们将定义为:

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)

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

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])

即有 2 个零,1 个 1,2 个 13,等等……可能值的总数是在上游设置的,但在这个例子中是 243

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

尝试 1

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

尝试 2

tvtensor = torch.tensor([i for i in range(243)]).unsqueeze(1).repeat(1,xx.shape[0]).float().requires_grad_(True)
(xx==tvtensor).sum(dim=1)

编辑:添加尝试

尝试 3

-- 真的没想到这会支持,但我还是想试试看

ll = torch.zeros((1,243))
for x in xx:
    ll[0,x.long()] += 1

感谢任何帮助

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

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

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

【问题讨论】:

    标签: pytorch counting backpropagation


    【解决方案1】:

    您将无法这样做,因为unique 只是不可微分的操作。

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

    不过,可能还有另一种可区分的方式来实现您想要实现的目标,但这是一个不同的问题。

    【讨论】:

    • 好的,这解释了为什么这些尝试不起作用,因为它们使用比较运算符,因为它们生成整数,它们不会有 grad_fn?有没有一种您能想到的可微分方法可能会产生等效的结果?
    • 这取决于您的最终目标是什么(我想它没有采用唯一值)。如上所述,可以组合可微分函数以获得您所追求的近似值。但通常情况下,这不是必需的,您可能会以某种方式摆脱不可微分。请描述您的最终目标,我们或许可以提供帮助。
    【解决方案2】:

    “uniquify”操作是不可微分的,但可能有一些方法可以解决这个问题,例如,通过编写自定义运算符,或通过巧妙组合可微分运算符。

    但是,您需要问自己这个问题:您期望这种操作的梯度是多少?或者,在更高的层面上,您想通过此操作实现什么目标?

    【讨论】:

    • 输出是生成模型的一部分,我上面显示的张量是操作的结果,它是生成信号的编码版本。计数统计表示生成的信号中不同代码的出现次数,并且在此框架中代表信号的质量。因此,我正在寻找的梯度将与张量中每个值的出现次数的变化有关。
    • 我不确定我是否理解您的用例,但它看起来不像具有明确定义的渐变。您所描述的只是差异,即离散情况下的衍生物,我认为传统 DL 库提供的那种技术无法优化这一点。
    • 我猜您正试图约束模型以生成一定数量的特定信号。在这种情况下,您可能想要探索一些受控生成模型。我不是这方面的专家,但一般的想法可能是将分类器附加到输出,并要求它对特定信号的出现次数进行分类,然后根据预测添加惩罚项。
    【解决方案3】:

    我会使用unique 方法(仅计算出现次数):

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

    我是在 1.3.1 版本中做到的

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

    【讨论】:

    • 唯一是不可微分的操作,不能反向传播
    • @FiRas 你的权利,这可能是一个不完整的答案。我修好了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 2018-02-11
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多