【问题标题】:PyTorch / Gensim - How to load pre-trained word embeddingsPyTorch / Gensim - 如何加载预训练的词嵌入
【发布时间】:2018-04-07 18:21:06
【问题描述】:

我想将使用 gensim 预训练的 word2vec 嵌入加载到 PyTorch 嵌入层中。

所以我的问题是,如何让 gensim 加载的嵌入权重到 PyTorch 嵌入层中。

提前致谢!

【问题讨论】:

    标签: python neural-network pytorch gensim embedding


    【解决方案1】:

    我只是想报告我关于使用 PyTorch 加载 gensim 嵌入的发现。


    • PyTorch 0.4.0 及更高版本的解决方案:

    v0.4.0 有一个新功能from_pretrained(),它使加载嵌入非常舒适。 这是文档中的一个示例。

    import torch
    import torch.nn as nn
    
    # FloatTensor containing pretrained weights
    weight = torch.FloatTensor([[1, 2.3, 3], [4, 5.1, 6.3]])
    embedding = nn.Embedding.from_pretrained(weight)
    # Get embeddings for index 1
    input = torch.LongTensor([1])
    embedding(input)
    

    gensim 的权重可以通过以下方式轻松获得:

    import gensim
    model = gensim.models.KeyedVectors.load_word2vec_format('path/to/file')
    weights = torch.FloatTensor(model.vectors) # formerly syn0, which is soon deprecated
    

    正如@Guglie 所说:在较新的 gensim 版本中,权重可以通过model.wv 获得:

    weights = model.wv
    

    • PyTorch 版本0.3.1 及更早版本的解决方案:

    我使用的是0.3.1 版本,而from_pretrained() 在此版本中不可用。

    因此我创建了自己的from_pretrained,因此我也可以将它与0.3.1 一起使用。

    PyTorch 版本0.3.1 或更低版本的from_pretrained 代码:

    def from_pretrained(embeddings, freeze=True):
        assert embeddings.dim() == 2, \
             'Embeddings parameter is expected to be 2-dimensional'
        rows, cols = embeddings.shape
        embedding = torch.nn.Embedding(num_embeddings=rows, embedding_dim=cols)
        embedding.weight = torch.nn.Parameter(embeddings)
        embedding.weight.requires_grad = not freeze
        return embedding
    

    然后可以像这样加载嵌入:

    embedding = from_pretrained(weights)
    

    我希望这对某人有所帮助。

    【讨论】:

    • 之后模型的输入是什么?是文本本身还是文本的 1-hot 编码?
    • PyTorch 没有使用 one-hot 编码,您可以只使用整数 ids / token ids 来访问各自的嵌入:torch.LongTensor([1]) 或序列:torch.LongTensor(any_sequence) resp。 torch.LongTensor([1, 2, 5, 9, 12, 92, 7])。作为输出,您将获得相应的嵌入。
    • @blue-phoenox 请问您如何获得整数/令牌 ID?
    • @Jinglesting 这不是一个通用的答案,可能会导致性能下降,因为预训练的嵌入可能使用与您在应用程序中使用的不同的索引。
    • 带有较新版本的 gensim 向量在 model.wv.vectors
    【解决方案2】:

    我认为这很容易。只需将嵌入权重从 gensim 复制到 PyTorch embedding layer 中的相应权重即可。

    您需要确保两件事是正确的:首先是权重形状必须正确,其次是权重必须转换为 PyTorch FloatTensor 类型。

    【讨论】:

    • 不知道构造函数里有_weight参数,我试试看-谢谢!
    【解决方案3】:

    我有同样的问题,除了我使用带有 pytorch 的 torchtext 库,因为它有助于填充、批处理和其他事情。这是我用torchtext 0.3.0加载预训练嵌入并将它们传递给pytorch 0.4.1所做的(pytorch部分使用blue-phoenox提到的方法):

    import torch
    import torch.nn as nn
    import torchtext.data as data
    import torchtext.vocab as vocab
    
    # use torchtext to define the dataset field containing text
    text_field = data.Field(sequential=True)
    
    # load your dataset using torchtext, e.g.
    dataset = data.Dataset(examples=..., fields=[('text', text_field), ...])
    
    # build vocabulary
    text_field.build_vocab(dataset)
    
    # I use embeddings created with
    # model = gensim.models.Word2Vec(...)
    # model.wv.save_word2vec_format(path_to_embeddings_file)
    
    # load embeddings using torchtext
    vectors = vocab.Vectors(path_to_embeddings_file) # file created by gensim
    text_field.vocab.set_vectors(vectors.stoi, vectors.vectors, vectors.dim)
    
    # when defining your network you can then use the method mentioned by blue-phoenox
    embedding = nn.Embedding.from_pretrained(torch.FloatTensor(text_field.vocab.vectors))
    
    # pass data to the layer
    dataset_iter = data.Iterator(dataset, ...)
    for batch in dataset_iter:
        ...
        embedding(batch.text)
    

    【讨论】:

      【解决方案4】:
      from gensim.models import Word2Vec
      
      model = Word2Vec(reviews,size=100, window=5, min_count=5, workers=4)
      #gensim model created
      
      import torch
      
      weights = torch.FloatTensor(model.wv.vectors)
      embedding = nn.Embedding.from_pretrained(weights)
      

      【讨论】:

      • 感谢您的回复。我已经查看了 gensim 以检查您的方法。看看这里的 gensim 页面:radimrehurek.com/gensim/models/word2vec.html#usage-examples 它说Word2Vec 模型仅用于训练词向量,因为这种格式比KeyedVectors 慢得多。完成训练后,通常将它们保存到 KeyedVectors 模型中。该模型专门用于保存预训练的向量“导致对象更小更快”,比Word2Vec 模型。你可以那样做,但我认为这样使用没有任何好处。
      • 谢谢,@blue-phoenox 我读过我在假设嵌入是立即创建和使用而不是从文件加载的情况下编写此代码。
      • 你当然可以这样做。但这意味着每次你开始训练过程时,你也会训练嵌入。这只是浪费了计算,而不是真正的 pre-trained 嵌入的想法。当我创建模型时,我通常会多次运行它们,并且在我开始模型的训练过程时,我不想每次都再次训练我的预训练嵌入。
      • 主要强调的是火炬部分,因此,我让读者处理 gensim 模型和加载,在某些情况下,开发人员可以在创建后立即使用 gensim 模型
      • 我只是指出,在这个用例中,向量并没有真正预训练。在您的代码示例中,它不加载预训练的向量,而是训练新的词向量。我只是想知道是否还有其他用例,因此我在问。
      【解决方案5】:

      有类似的问题:“在使用 gensim 以 binary 格式训练和保存嵌入后,我如何将它们加载到 torchtext?”

      我刚刚将文件保存为 txt 格式,然后按照超棒的 tutorial 加载自定义词嵌入。

      def convert_bin_emb_txt(out_path,emb_file):
          txt_name = basename(emb_file).split(".")[0] +".txt"
          emb_txt_file = os.path.join(out_path,txt_name)
          emb_model = KeyedVectors.load_word2vec_format(emb_file,binary=True)
          emb_model.save_word2vec_format(emb_txt_file,binary=False)
          return emb_txt_file
      
      emb_txt_file = convert_bin_emb_txt(out_path,emb_bin_file)
      custom_embeddings = vocab.Vectors(name=emb_txt_file,
                                        cache='custom_embeddings',
                                        unk_init=torch.Tensor.normal_)
      
      TEXT.build_vocab(train_data,
                       max_size=MAX_VOCAB_SIZE,
                       vectors=custom_embeddings,
                       unk_init=torch.Tensor.normal_)
      

      测试:PyTorch:1.2.0 和 TorchText:0.4.0。

      我添加了这个答案,因为对于接受的答案,我不确定如何遵循链接的 tutorial 并使用正态分布初始化所有不在嵌入中的单词以及如何使向量和等于零。

      【讨论】:

        【解决方案6】:

        我自己在理解文档方面遇到了很多问题,而且周围没有那么多好的例子。希望这个例子可以帮助其他人。这是一个简单的分类器,它采用matrix_embeddings 中的预训练嵌入。通过将 requires_grad 设置为 false,我们确保不会更改它们。

        class InferClassifier(nn.Module):
          def __init__(self, input_dim, n_classes, matrix_embeddings):
            """initializes a 2 layer MLP for classification.
            There are no non-linearities in the original code, Katia instructed us 
            to use tanh instead"""
        
            super(InferClassifier, self).__init__()
        
            #dimensionalities
            self.input_dim = input_dim
            self.n_classes = n_classes
            self.hidden_dim = 512
        
            #embedding
            self.embeddings = nn.Embedding.from_pretrained(matrix_embeddings)
            self.embeddings.requires_grad = False
        
            #creates a MLP
            self.classifier = nn.Sequential(
                    nn.Linear(self.input_dim, self.hidden_dim),
                    nn.Tanh(), #not present in the original code.
                    nn.Linear(self.hidden_dim, self.n_classes))
        
          def forward(self, sentence):
            """forward pass of the classifier
            I am not sure it is necessary to make this explicit."""
        
            #get the embeddings for the inputs
            u = self.embeddings(sentence)
        
            #forward to the classifier
            return self.classifier(x)
        

        sentence 是一个以matrix_embeddings 为索引而不是单词的向量。

        【讨论】:

        • 你的意思是self.classifier(u)?
        猜你喜欢
        • 1970-01-01
        • 2019-12-30
        • 2019-03-02
        • 2019-10-27
        • 2018-10-30
        • 1970-01-01
        • 1970-01-01
        • 2021-07-16
        相关资源
        最近更新 更多