为了清楚起见,我指的是用于文档分类的分层注意网络中描述的类型的“自我注意”,并在许多地方实现,例如:here。我指的不是编码器-解码器模型(即 Bahdanau)中使用的 seq2seq 类型的注意力,尽管我的问题也可能适用于此......我只是不太熟悉它。
Self-attention 基本上只是计算 RNN 隐藏状态的加权平均值(均值池的泛化,即未加权平均值)。当同一批次中有可变长度序列时,通常会将它们补零到批次中最长序列的长度(如果使用动态 RNN)。当为每个序列计算注意力权重时,最后一步是 softmax,因此注意力权重总和为 1。
然而,在我看到的每一个注意力实现中,都没有注意掩盖或取消零填充对注意力权重的影响。这对我来说似乎是错误的,但我担心我可能遗漏了一些东西,因为似乎没有其他人对此感到困扰。
例如,考虑一个长度为 2、零填充到长度 5 的序列。最终,这导致注意力权重被计算为类似的 0 填充向量的 softmax,例如:
权重 = softmax([0.1, 0.2, 0, 0, 0]) = [0.20, 0.23, 0.19, 0.19, 0.19]
并且因为 exp(0)=1,零填充实际上“淡化”了注意力权重。这可以很容易地修复,在 softmax 操作之后,通过将权重与二进制掩码相乘,即
掩码 = [1, 1, 0, 0, 0]
然后将权重重新归一化,使其总和为 1。这将导致:
权重 = [0.48, 0.52, 0, 0, 0]
当我这样做时,我几乎总是看到性能提升(在我的模型的准确性方面——我正在做文档分类/回归)。那么为什么没有人这样做呢?
有一段时间我认为,也许所有重要的是注意力权重的相对值(即比率),因为梯度无论如何都不会通过零填充。但是,如果归一化无关紧要,我们为什么要使用 softmax,而不是仅仅使用 exp(.)?(另外,这并不能解释性能提升......)