关于计算中的一个代码段 log_sum_exp

regarding one code segment in computing log_sum_exp

在此tutorial on using Pytorch to implement BiLSTM-CRF中,作者实现了以下功能。具体来说,我不是很明白max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1])到底想干什么?,或者它对应的是什么数学公式?

# Compute log sum exp in a numerically stable way for the forward algorithm
def log_sum_exp(vec):
    max_score = vec[0, argmax(vec)]
    max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1])
    return max_score + \
        torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))

查看代码,vec 的形状似乎是 (1, n)
现在我们可以逐行执行代码了:

max_score = vec[0, argmax(vec)]

在位置 0, argmax(v) 中使用 vec 只是一种获取 vec 最大值的奇特方法。所以,max_score 是(顾名思义)vec.

的最大值
max_score_broadcast = max_score.view(1, -1).expand(1, vec.size()[1])

接下来,我们要从 vec 的每个元素中减去 max_score。 为此,代码创建了一个 shapevec 相同的向量,所有元素都等于 max_score.
首先,使用 view command, then the expanded 2d vector is "stretched" to have length n using the expand 命令将 max_score 重塑为具有两个维度。

最后,稳健地计算对数和 exp:

 return max_score + \
        torch.log(torch.sum(torch.exp(vec - max_score_broadcast)))

这个计算的有效性可以在这张图中看到:

背后的道理是exp(x)可以"explode"换取x > 0,所以为了数值稳定,最好在之前减去最大值[= =58=] 服用 exp.


作为旁注,我认为利用 broadcasting 进行相同计算的更优雅的方法是

max_score, _ = vec.max(dim=1, keepdim=True)  # take max along second dimension
lse = max_score + torch.log(torch.sum(torch.exp(vec - max_score), dim=1))
return lse

另请注意,log sum exp 已由 pytorch 实现:torch.logsumexp