pytorch的嵌入层内部发生了什么“确切”的变化?

时间:2019-11-05 20:01:07

标签: pytorch embedding

通过多次搜索和 pytorch 文档本身,我可以弄清楚在嵌入层内部有一个查找表,用于存储嵌入向量。我无法理解的是:

  1. 在这一层的训练期间究竟发生了什么?
  2. 什么是权重以及如何计算这些权重的梯度?
  3. 我的直觉是,至少应该有一个带有一些参数的函数,该函数会生成查找表的键。如果是这样,那是什么功能?

在此方面的任何帮助将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:3)

这是一个非常好的问题! PyTorch的嵌入层(Tensorflow也是如此)用作查找表,只是为每个输入(索引)检索嵌入。考虑以下情况,您有一个句子,其中每个单词都被标记。因此,句子中的每个单词都用唯一的整数(索引)表示。如果索引(单词)的列表为[1, 5, 9],并且您想使用50维向量(嵌入)对每个单词进行编码,则可以执行以下操作:

# The list of tokens
tokens = torch.tensor([0,5,9], dtype=torch.long)
# Define an embedding layer, where you know upfront that in total you
# have 10 distinct words, and you want each word to be encoded with
# a 50 dimensional vector
embedding = torch.nn.Embedding(num_embeddings=10, embedding_dim=50)
# Obtain the embeddings for each of the words in the sentence
embedded_words = embedding(tokens)

现在,回答您的问题:

  1. 在前进过程中,将以与Numpy的索引工作类似的方式获得句子中每个标记的值。因为在后端,这是一个微分运算,所以在反向遍历(训练)期间,Pytorch将为每个嵌入计算梯度并相应地重新调整它们。

  2. 权重是嵌入本身。这就是嵌入矩阵的好处。词嵌入矩阵实际上是权重矩阵,将在训练过程中学习。

  3. 本身没有实际功能。如上所述,该句子已经被标记化了(每个单词都由一个唯一的整数表示),我们可以为句子中的每个标记获得嵌入。

最后,正如我多次提到带有索引的示例一样,让我们​​尝试一下。

# Let us assume that we have a pre-trained embedding matrix
pretrained_embeddings = torch.rand(10, 50)
# We can initialize our embedding module from the embedding matrix
embedding = torch.nn.Embedding.from_pretrained(pretrained_embeddings)
# Some tokens
tokens = torch.tensor([0,5,9], dtype=torch.long)

# Token embeddings from the lookup table
lookup_embeddings = embedding(tokens)
# Token embeddings obtained with indexing
indexing_embeddings = pretrained_embeddings[tokens]
# Voila! They are the same
np.testing.assert_array_equal(lookup_embeddings.numpy(), indexing_embeddings.numpy())

答案 1 :(得分:0)

nn.Embedding层可以用作查找表。这意味着,如果您有n个元素的字典,则在创建嵌入时可以通过id调用每个元素。

在这种情况下,字典的大小为num_embeddings,而embedding_dim为1。

在这种情况下,您没有什么要学习的。您可能会说,您只是为字典的元素建立索引,或者对它们进行编码。因此,在这种情况下,无需进行前向通过分析。

如果您使用过Word2vec之类的单词嵌入,则可能已经使用过。

另一方面,您可以将嵌入层用于分类变量(一般情况下具有此功能)。在其中,您可以将嵌入维度embedding_dim设置为您可能拥有的类别数。

在这种情况下,您将从随机初始化的嵌入层开始,然后学习向前的类别(功能)。