某些(所有?)库不通过 log1p(x) = log(1 + x) 实现 log_softmax 是有原因的吗?

Is there a reason some (all?) libraries don't implement log_softmax via log1p(x) = log(1 + x)?

提问人:Jason Gross 提问时间:11/14/2023 最后编辑:Jason Gross 更新时间:11/15/2023 访问量:76

问:

据我了解,PyTorch 实现为 ,以增加数值稳定性。(例如,请参阅此处。但是,当最大值远大于其余值时(float32 大约大 16,float64 大约 36),则返回最大值,此时它可以给出更精确的答案。log_softmax(x)x - x.max() - (x - x.max()).exp().sum().log()log_softmax0

从数字上看,我们有

>>> eps = torch.tensor(torch.finfo(torch.float32).eps)
>>> -torch.tensor([1-(2*eps).log(), 0]).log_softmax(dim=0)
tensor([1.1921e-07, 1.6249e+01])
>>> -torch.tensor([1-eps.log(), 0]).log_softmax(dim=0)
tensor([-0.0000, 16.9424])

(对于 float16,这是 7.2e-4。

据我了解,并使用某种多项式(?)级数扩展在引擎盖下实现。(参见,例如,这个答案)1.19e-7 是 float32 在 1 附近的最低精度单位,但 float32 可以表示小到通常 (, ) 或大约 1.18e-45 () 不正常的值。因此,在更高的精度方面有很大的空间,这可以通过具有诸如 which is 但精度更高的函数来实现,以及 which is 但对 的微小值具有更高的精度。然后我们可以实现为logexptorch.finfo(torch.float32).smallest_normal2**-126 = 2**-(2**7 - 2)2**-126 * 2**-23expm1(x)exp(x) - 1log1p(x)log(1 + x)xlog_softmax(x)

maxi = x.argmax()
xoffset = x - x[maxi]
xoffsetexp = xoffset.exp()
# xoffsetexp[maxi] is currently about 1
xoffsetexp[maxi] = 0
xoffsetexp_sum_m1 = xoffsetexp.sum()
return xoffset - xoffsetexp_sum_m1.log1p()

例如,在某些情况下,这可能使模型训练不会像以前那样早地被浮点误差所支配。

是否有任何库以这种方式实现log_softmax?是否有理由避免以这种方式实施log_softmax

Python TensorFlow Pytorch 数值方法

评论

1赞 Tangentially Perpendicular 11/14/2023
“有没有讨论......” - 不在 Stack Overflow 上。这是一个问答网站。“Do any libraries...”属于推荐请求,这在这里特别偏离了主题。
1赞 Jason Gross 11/15/2023
我不是在要求推荐请求,我是在要求了解现有的技术水平。我已将“有没有讨论......”到“有理由避免以这种方式实施吗?我正在寻找诸如“是的,这是一种常见的实现模式,只是 pytorch 没有这样做”或“这本教科书/文章/无论给出这样那样的原因,为什么实现这种方式是一个坏主意”或“民间智慧认为这是对无关紧要的极端情况的优化”或“可能只是以前没有人想到这一点”log_softmaxlog_softmax
0赞 Martin Brown 12/1/2023
我认为当有更准确的数字替代方案可用但未在特定库中使用时,这是一个公平的问题。我无法回答OP的问题。我能想到的唯一原因是,也许他们发现,在实践中,提前截断到零实际上比向前传播微小值更有效。值得一试,看看建议的替代方案是否有任何性能改进。

答: 暂无答案