变压器模型中位置编码的实现细节?

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

这个位置编码到底是怎么计算的呢?

我们假设一个机器翻译的场景,这些都是输入句子。

english_text = [this is good, this is bad]
german_text = [das ist gut, das ist schlecht]

现在我们的输入词汇大小为4,嵌入维度为4。

#words     #embeddings
this     - [0.5, 0.2, 0.3, 0.1]
is       - [0.1, 0.2, 0.5, 0.1]
good     - [0.9, 0.7, 0.9, 0.1]
bad      - [0.7, 0.3, 0.4, 0.1]

根据变换器文件,我们添加了 各字位编码词缀 然后将其传递给编码器,如下图所示。

attention is all you need

就论文而言,他们给出了这个公式来计算每个词的位置编码。attention paper

所以,我认为可以这样实现。

d_model = 4 # Embedding dimension

positional_embeddings = np.zeros((max_sentence_length, d_model))

max_sentence_length = 3 # as per my examples above

for position in range(maximum_sentence_length):
    for i in range(0, d_model, 2):
       positional_embeddings[position, i] = (
                                          sin(position / (10000 ** ( (2*i) / d_model) ) )
                                            )
       positional_embeddings[position, i + 1] = (
                                              cos(position / (10000 ** ( (2 * (i + 1) ) / d_model) ) )
                                                )

那么,新的嵌入向量将是

[[0.5, 0.2, 0.3, 0.1], 
 [0.1, 0.2, 0.5, 0.1], 
 [0.9, 0.7, 0.9, 0.1]] + positional_embeddings = NEW EMBEDDINGS

 ## shapes
  3 x 4                + 3 x 4                 = 3 x 4     

在实现中是这样计算的吗?如果我上面的伪实现有什么错误,请纠正我。

如果一切正确,那么 我有三个疑问 希望有人能清除他们。

1) 从上面的实现来看,我们对偶数位置使用sin公式,对奇数位置使用cos公式,但我不明白这背后的原因?我看到说是利用了循环的特性,但是不明白。

2) 选择 10000/(2i/d)10000/(2i+1/d) 作为公式中的缩放因子。

3)所有的句子都不会等于最大句子长度,所以我们可能要对句子进行填充,那么我们是否也要计算填充标记的位置编码。

encoding deep-learning nlp transformer attention-model
1个回答
1
投票

你的实现基本正确。典型的实现是预先计算嵌入矩阵,做一个不可训练的嵌入层,然后做一个范围的嵌入查找。例如参见 HuggingFace的变形金刚.

关于方程背后的直觉的一些提示在这些线程中。

但在我看来,几乎所有关于位置编码的决定都是经验性的选择。

所谓循环特性,他们IMHO指的是给定一个嵌入的维度,无论在序列中的哪个位置,具有恒定偏移量的位置之间的嵌入值的差异是相同的。对于这一点,只使用正弦或余弦可能就够了,但有些位置的法线会比其他位置大得多,因此它们交替使用正弦和余弦。

我认为缩放系数是根据经验估计的,可以覆盖通常的句子长度。

对于填充,你确实还要考虑填充位置的位置编码,但由于它们是预先计算的,这确实意味着更高的计算负荷,因为你无论如何都要得到填充符号的嵌入。

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