【问题标题】:Embedding in pytorch嵌入pytorch
【发布时间】:2018-11-17 18:22:18
【问题描述】:

我在 Stackoverflow 上查看了 PyTorch 教程和与此类似的问题。

我感到困惑; pytorch (Embedding) 中的嵌入是否使相似的单词彼此更接近?我只需要给它所有的句子吗?或者它只是一个查找表,我需要对模型进行编码?

【问题讨论】:

    标签: python pytorch word-embedding


    【解决方案1】:

    您可以将nn.Embedding 视为一个查找表,其中键是词索引,值是对应的词向量。但是,在使用它之前,您应该指定查找表的大小,并自己初始化词向量。下面是一个演示这个的代码示例。

    import torch.nn as nn 
    
    # vocab_size is the number of words in your train, val and test set
    # vector_size is the dimension of the word vectors you are using
    embed = nn.Embedding(vocab_size, vector_size)
    
    # intialize the word vectors, pretrained_weights is a 
    # numpy array of size (vocab_size, vector_size) and 
    # pretrained_weights[i] retrieves the word vector of
    # i-th word in the vocabulary
    embed.weight.data.copy_(torch.fromnumpy(pretrained_weights))
    
    # Then turn the word index into actual word vector
    vocab = {"some": 0, "words": 1}
    word_indexes = [vocab[w] for w in ["some", "words"]] 
    word_vectors = embed(word_indexes)
    

    【讨论】:

    • 所以我仍然没有得到在整个训练过程中学习这些随机初始化嵌入的方法。这是一个简单的 CBOW 或 Skip-gram 程序还是其他什么?
    • 关键是 nn.Embedding 不关心你用来训练词嵌入的任何方法,它只是一个存储训练好的嵌入的“矩阵”。在使用 nn.Embedding 加载 Glove 或 FastText 等外部词嵌入时,这些外部词嵌入的职责是确定训练方法。
    • 如果您在训练时选择微调词向量,这些词向量将被视为模型参数并通过反向传播进行更新。
    • nn.Embedding 是可训练层吗?
    • 是的,nn.Embedding也是模型参数层,默认是可训练的,你也可以通过冻结其梯度使其不可训练。
    【解决方案2】:

    nn.Embedding 拥有一个维度为 (vocab_size, vector_size) 的张量,即词汇表的大小 x 每个向量嵌入的维度,以及一个进行查找的方法。

    当您创建嵌入层时,张量会随机初始化。只有当你训练它时,相似词之间的这种相似性才会出现。除非您使用之前训练的模型(例如 GloVe 或 Word2Vec)覆盖了嵌入的值,但那是另一回事了。

    所以,一旦你定义了嵌入层,并且定义和编码了词汇表(即为词汇表中的每个单词分配一个唯一编号),你就可以使用 nn.Embedding 类的实例来获取相应的嵌入。

    例如:

    import torch
    from torch import nn
    embedding = nn.Embedding(1000,128)
    embedding(torch.LongTensor([3,4]))
    

    将返回与您的词汇表中的单词 3 和 4 对应的嵌入向量。由于没有模型经过训练,它们将是随机的。

    【讨论】:

    • 例如,如果我有一个神经机器翻译模型并且我不使用预训练嵌入,那么嵌入层将随机初始化词向量并与翻译模型一起训练这些向量?
    • 没错,它们最初是随机的,并且是模型的可训练参数。
    • @Escachator 我明白了你解释的原理。我主要想知道在训练模型中学习的嵌入如何应用于测试数据。例如,我已经将大约 20,000 个单词转换为数字,并进行了嵌入。现在,在测试集中,如果我有 [3,2,5,4] 的序列,模型权重是否已经包含进行分解和执行嵌入的方法?我只是不确定背景中的数学。
    • @KanishkMair 测试集中的嵌入是固定的。没有分解或任何事情要做。 embedding(torch.LongTensor([3,2,5,4])) 将只返回词(或标记)3 和词 2 等在 [dim_embedding, 4] 的张量中的嵌入
    • @Escachator 你说,“因为没有模型被训练过,所以它们是随机的。”我认为在训练过程中,问题中所说的相似词在训练过程中会变得更接近。
    【解决方案3】:

    啊!我认为这部分仍然缺失。展示了当您设置嵌入层时,您会自动获得权重,您可以稍后更改 nn.Embedding.from_pretrained(weight)

    import torch
    import torch.nn as nn
    
    embedding = nn.Embedding(10, 4)
    print(type(embedding))
    print(embedding)
    
    t1 = embedding(torch.LongTensor([0,1,2,3,4,5,6,7,8,9])) # adding, 10 won't work
    print(t1.shape)
    print(t1)
    
    
    t2 = embedding(torch.LongTensor([1,2,3]))
    print(t2.shape)
    print(t2)
    
    #predefined weights
    weight = torch.FloatTensor([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])
    print(weight.shape)
    embedding = nn.Embedding.from_pretrained(weight)
    # get embeddings for ind 0 and 1
    embedding(torch.LongTensor([0, 1]))
    

    输出:

    <class 'torch.nn.modules.sparse.Embedding'>
    Embedding(10, 4)
    torch.Size([10, 4])
    tensor([[-0.7007,  0.0169, -0.9943, -0.6584],
            [-0.7390, -0.6449,  0.1481, -1.4454],
            [-0.1407, -0.1081,  0.6704, -0.9218],
            [-0.2738, -0.2832,  0.7743,  0.5836],
            [ 0.4950, -1.4879,  0.4768,  0.4148],
            [ 0.0826, -0.7024,  1.2711,  0.7964],
            [-2.0595,  2.1670, -0.1599,  2.1746],
            [-2.5193,  0.6946, -0.0624, -0.1500],
            [ 0.5307, -0.7593, -1.7844,  0.1132],
            [-0.0371, -0.5854, -1.0221,  2.3451]], grad_fn=<EmbeddingBackward>)
    torch.Size([3, 4])
    tensor([[-0.7390, -0.6449,  0.1481, -1.4454],
            [-0.1407, -0.1081,  0.6704, -0.9218],
            [-0.2738, -0.2832,  0.7743,  0.5836]], grad_fn=<EmbeddingBackward>)
    torch.Size([2, 3])
    
    tensor([[0.1000, 0.2000, 0.3000],
            [0.4000, 0.5000, 0.6000]])
    

    最后一部分是嵌入层的权重可以通过梯度下降来学习。

    【讨论】:

      【解决方案4】:

      torch.nn.Embedding 只是创建一个查找表,以获取给定单词索引的单词嵌入。

      from collections import Counter
      import torch.nn as nn
      
      # Let's say you have 2 sentences(lowercased, punctuations removed) :
      sentences = "i am new to PyTorch i am having fun"
      
      words = sentences.split(' ')
          
      vocab = Counter(words) # create a dictionary
      vocab = sorted(vocab, key=vocab.get, reverse=True)
      vocab_size = len(vocab)
      
      # map words to unique indices
      word2idx = {word: ind for ind, word in enumerate(vocab)} 
      
      # word2idx = {'i': 0, 'am': 1, 'new': 2, 'to': 3, 'pytorch': 4, 'having': 5, 'fun': 6}
      
      encoded_sentences = [word2idx[word] for word in words]
      
      # encoded_sentences = [0, 1, 2, 3, 4, 0, 1, 5, 6]
      
      # let's say you want embedding dimension to be 3
      emb_dim = 3 
      

      现在,嵌入层可以初始化为:

      emb_layer = nn.Embedding(vocab_size, emb_dim)
      word_vectors = emb_layer(torch.LongTensor(encoded_sentences))
      

      这会从标准正态分布(即 0 均值和单位方差)初始化嵌入。因此,这些词向量没有任何“相关性”的感觉。

      word_vectors 是大小为 (9,3) 的火炬张量。 (因为我们的数据中有 9 个单词)

      emb_layer 有一个称为 weight 的可训练参数,默认情况下,它被设置为被训练。您可以通过以下方式查看:

      emb_layer.weight.requires_grad
      

      返回。如果您不想在模型训练期间训练您的嵌入(例如,当您使用预训练嵌入时),您可以通过以下方式将它们设置为 False:

      emb_layer.weight.requires_grad = False
      

      如果您的词汇量为 10,000,并且您希望使用预训练的嵌入(dim 300)初始化嵌入,例如 Word2Vec,请执行以下操作:

      emb_layer = nn.Embedding(10000, 300)
      emb_layer.load_state_dict({'weight': torch.from_numpy(emb_mat)})
      

      这里,emb_mat 是一个大小为 (10,000, 300) 的 Numpy 矩阵,其中包含 300 维 Word2vec 词向量,用于词汇表中的 10,000 个词中的每一个。

      现在,嵌入层加载了 Word2Vec 单词表示。

      【讨论】:

        猜你喜欢
        • 2021-02-07
        • 2018-04-22
        • 1970-01-01
        • 2019-09-24
        • 2019-02-08
        • 2020-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多