11

为了清楚起见,我指的是用于文档分类的分层注意网络中描述的类型的“自我注意”,并在许多地方实现,例如: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(.)?(另外,这并不能解释性能提升......)

4

2 回答 2

5

好问题!我相信您的担忧是有效的,填充编码器输出的零注意力分数确实会影响注意力。但是,您必须牢记以下几个方面:

  • 有不同的分数函数,tf-rnn-attention中的一个使用简单的线性 + tanh + 线性变换。但即使是这个分数函数也可以学习输出负分数。如果您查看代码并想象inputs由零组成,v则由于偏差,向量不一定为零,并且点积u_omega可以将其进一步提升为低负数(换句话说,具有非线性的简单NN可以使两者都为正和负面预测)。低负分不会淡化 softmax 中的高分。

  • 由于分桶技术,一个桶内的序列通常具有大致相同的长度,因此不太可能有一半的输入序列用零填充。当然,它并不能解决任何问题,它只是意味着在实际应用中,填充的负面影响自然是有限的。

  • 您最后提到了它,但我也想强调一下:最终的参与输出是编码器输出的加权和,即相对值实际上很重要。以您自己的示例并在这种情况下计算加权和:

    • 第一个是0.2 * o1 + 0.23 * o2(其余为零)
    • 第二个是0.48 * o1 + 0.52 * o2(其余的也是零)


    是的,第二个向量的幅度要大两倍,这不是关键问题,因为它会进入线性层。但相对关注o2度仅比掩蔽时高 7%。

    这意味着即使注意力权重在学习忽略零输出方面做得不好,对输出向量的最终影响仍然足以让解码器考虑正确的输出,在这种情况下专注于o2

希望这能让您相信重新规范化并不那么重要,但如果实际应用可能会加快学习速度。

于 2018-04-17T21:25:09.650 回答
4

BERT 实现应用填充掩码来计算注意力分数。将 0 添加到非填充注意力分数,并将 -10000 添加到填充注意力分数。e^-10000 对于其他注意力得分值来说非常小。

attention_score = [0.1, 0.2, 0, 0, 0]
mask = [0, 0, -10000, -10000] # -10000 is a large negative value 
attention_score += mask
weights = softmax(attention_score)
于 2019-04-15T21:29:51.397 回答