使用预先训练的词嵌入 - 如何为未知/OOV 令牌创建向量?

blu*_*nox 4 nlp neural-network deep-learning word-embedding pytorch

我不想将预先训练的嵌入添加到模型中。但看起来并没有词汇外(OOV)标记。不存在未见单词的向量。

那么我该如何处理遇到的OOV 代币呢?我有一些想法,但似乎都不是很好:

  • 我可以为此标记创建一个随机向量,但理想情况下我希望该向量位于现有模型的逻辑范围内。如果我只是随机创建它,我担心向量可能会意外地与非常频繁的单词(如“the”、“for”、“that”等)非常相似,这不是我的意图。

  • 或者我应该用普通的零来初始化向量?

  • 另一个想法是将令牌与其他现有向量进行平均。但是对什么向量进行平均呢?所有?这似乎也不是很有结论。

  • 我也想过尝试训练这个向量。然而,如果我想在训练期间冻结其余的嵌入,这并不是很方便。

(通用解决方案值得赞赏,但我想补充一点,我正在使用 PyTorch - 以防万一 PyTorch 已经为这个问题提供了一个方便的解决方案。)

那么创建这样一个向量的良好且简单的策略是什么?

Uma*_*pta 5

您可以通过多种方式来处理它。我不认为我可以引用关于哪种效果更好的参考资料。

不可训练选项

  1. 随机向量作为嵌入
  2. 您可以对 OOV 使用全零向量。
  3. 您可以使用所有嵌入向量的平均值,这样就可以避免偏离实际分布的风险。
  4. 此外,嵌入通常带有在训练过程中学习到的“unk”向量,您可以使用它。

可培训选项

您可以为 OOV 声明一个单独的嵌入向量,并使其可训练,同时保持其他嵌入固定。您可能必须为此重写嵌入查找的前向方法。您可以声明一个新的可训练对象Variable,并在前向传递中使用该向量作为 OOV 的嵌入,而不是进行查找。


针对OP的评论:

我不确定这三种不可训练的方法中哪一种效果更好,我也不确定是否有一些关于这方面的工作。但方法 4) 应该效果更好。

对于可训练选项,您可以创建一个新的嵌入层,如下所示。

class Embeddings_new(torch.nn.Module): 
    def __init__(self, dim, vocab): 
        super().__init__() 
        self.embedding = torch.nn.Embedding(vocab, dim) 
        self.embedding.weight.requires_grad = False
        # vector for oov 
        self.oov = torch.nn.Parameter(data=torch.rand(1,dim)) 
        self.oov_index = -1 
        self.dim = dim 

    def forward(self, arr): 
        N = arr.shape[0] 
        mask =  (arr==self.oov_index).long() 
        mask_ = mask.unsqueeze(dim=1).float() 
        embed =(1-mask_)*self.embedding((1-mask)*arr) + mask_*(self.oov.expand((N,self.dim))) 
        return embed 
Run Code Online (Sandbox Code Playgroud)

用法:

model = Embeddings_new(10,20000)    
out = model.forward(torch.tensor([-1,-1, 100, 1, 0]))
# dummy loss
loss = torch.sum(a**2)
loss.backward()
Run Code Online (Sandbox Code Playgroud)