可学习位置嵌入的本质?嵌入可以更好地改善结果吗?

问题描述 投票:0回答:2

我最近正在阅读huggingface项目的bert源代码。我注意到所谓的“可学习位置编码”在实现时似乎指的是特定的 nn.Parameter 层。

def __init__(self):
    super()
    positional_encoding = nn.Parameter()
def forward(self, x):
    x += positional_encoding

↑ 可能是这种感觉,然后进行了可学习的位置编码。不管是不是这么简单,我不确定我理解是否正确,我想请教有经验的人。

此外,我注意到一个经典的 bert 结构,其位置实际上仅在初始输入时编码一次。这是否意味着后续的 bert 层,对于彼此来说,失去了捕获位置信息的能力?

BertModel(
  (embeddings): BertEmbeddings(
    (word_embeddings): Embedding(30522, 768, padding_idx=0)
    (position_embeddings): Embedding(512, 768)
    (token_type_embeddings): Embedding(2, 768)
    (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
    (dropout): Dropout(p=0.1, inplace=False)
  )
  (encoder): BertEncoder(
    (layer): ModuleList(
      (0): BertLayer(...)
      ...
  (pooler): BertPooler(...)

如果在下一个 BERT 层之前对上一层的结果进行重新位置编码,我会得到更好的结果吗?

deep-learning pytorch bert-language-model transformer-model
2个回答
7
投票

位置嵌入的目的是什么?

在 Transformer(包括 BERT)中,不同 token 之间的唯一交互是通过自注意力层完成的。如果仔细观察这些层实现的数学运算,您会注意到这些层是排列等变:即表示
“我确实喜欢编码”

“我喜欢编码吗”
是相同的,因为两个句子中的单词(=标记)是相同的,只是它们的顺序不同。
正如您所看到的,这种“排列等方差”在许多情况下并不是所需的属性。
为了打破这种对称性/等变性,我们可以简单地“编码”句子中每个单词/标记的实际位置。例如:
“I_1 do_2 like_3 编码_4”
不再与
相同 “Do_1 I_2 like_3编码_4”

这就是位置编码/嵌入的目的——使自注意力层对标记的顺序敏感。

现在回答你的问题:

  1. 可学习的位置编码确实是通过一个简单的
    nn.Parameter
    来实现的。位置编码只是添加到每个标记的“代码”,标记其在序列中的位置。因此,它所需要的只是一个与输入序列大小相同的张量,每个位置具有不同的值。
  2. 在 Transformer 架构中引入一次位置编码就足够了吗? 是的!由于 Transformer 堆叠了多个自注意力层,因此在处理开始时添加一次位置嵌入就足够了。位置信息被“融合”到每个标记学习的语义表示中。
    在这项工作中可以找到 Vision Transformers (ViT) 中这种效果的良好可视化:
    Shir Amir、Yossi Gandelsman、Shai Bagon 和 Tali Dekel 深度 ViT 特征作为密集视觉描述符 (arXiv 2021)。
    秒后。 3.1 和图3 它们展示了位置信息如何主导早期层的标记表示,但当您深入转换器时,语义信息就会占据主导地位。

0
投票

@Shai的回答相当精彩。我也有同样的疑问,这个答案对我帮助很大。我想添加关于该主题的另一篇好论文,它提供了对位置编码的深入见解:视觉变换器的条件位置编码(arXiv 2021)。

在第 4.2 节中,表 2 CPVT-Ti plus 显示出比 CPVT-Ti 更好的性能。 CPVT-Ti plus 为第一个第五个编码器插入了 pos 嵌入(而不是仅为 CPVT-Ti 的第一个编码器)。因此,它表明您的猜测是“如果在下一个 BERT 层之前对上一层的结果进行重新位置编码,我会得到更好的结果吗?”可能是对的。

© www.soinside.com 2019 - 2024. All rights reserved.