【问题标题】:How to calculate geometric mean in a differentiable way?如何以可微分的方式计算几何平均值?
【发布时间】:2020-04-30 13:00:21
【问题描述】:

如何使用 Pytorch 计算沿维度的几何平均值?有些数字可能是负数。函数必须是可微的。

【问题讨论】:

    标签: pytorch


    【解决方案1】:

    几何平均值的已知(合理)数值稳定版本是:

    import torch
    
    def gmean(input_x, dim):
        log_x = torch.log(input_x)
        return torch.exp(torch.mean(log_x, dim=dim))
    
    x = torch.Tensor([2.0] * 1000).requires_grad_(True)
    print(gmean(x, dim=0))
    # tensor(2.0000, grad_fn=<ExpBackward>)
    

    这种实现可以在例如 SciPy (see here) 中找到,这是一个相当稳定的库。


    上面的实现不处理零和负数。有些人会争辩说,负数的几何平均数定义不明确,至少当并非所有负数都是负数时。

    【讨论】:

    • 这通过在日志空间计算解决了下溢问题,但不处理负值。 IE。如果 x 包含负值,则日志将计算为“nan”。我认为处理负值的唯一方法是将它们视为微小的正值(即 log(negative_something) = 巨大的负值)。
    • 要处理负值,您可以将 torch.log(input_x) 替换为 torch.log(torch.clamp(input_x, torch.finfo(torch.dtype(input_x)).tiny))
    • @BazyliDebowski gmean 实际上对于负值没有明确定义。一些人认为,当它们全部为负时,它是明确定义的。此实现也不处理 0,这会导致 0。大多数人会争辩说,仅对正数进行计算才有意义。
    • 我同意负值对 gmean 没有意义。话虽如此,这个问题确实明确指出某些值可能是负数,所以我试图解决这个问题。我不知道我之前评论中的解决方案是否可以区分……直觉上我认为不是,但我还没有解决。
    • @BazyliDebowski 哦,对负数的提及仍然存在......我记得当时所有这些都与 cmets 中的 OP 进行了讨论(因为 cmets 主要是对话式的,他们现在已删除)。无论如何,我会在我的答案中添加一个注释,因为我们的 cmets 也可能会被删除。我不会建议任何处理负数的具体方法(除非它们都是负数),除非我们想要支持复数。
    【解决方案2】:

    torch.prod() 帮助:

    import torch
    
    x = torch.FloatTensor(3).uniform_().requires_grad_(True)
    print(x)
    y = x.prod() ** (1.0/x.shape[0])
    print(y)
    y.backward()
    print(x.grad)
    
    # tensor([0.5692, 0.7495, 0.1702], requires_grad=True)
    # tensor(0.4172, grad_fn=<PowBackward0>)
    # tensor([0.2443, 0.1856, 0.8169])
    

    编辑:?怎么样

    y = (x.abs() ** (1.0/x.shape[0]) * x.sign() ).prod()
    

    【讨论】:

    • 如果你做x = torch.Tensor([2.0] * 1000).requires_grad_(True),当你做x.prod()时你会得到无穷大。我想要一个数值更稳定的方法。
    猜你喜欢
    • 2020-10-20
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    相关资源
    最近更新 更多