使用预训练词嵌入 - 如何为未知/ OOV 令牌创建向量?
Using pre-trained word embeddings - how to create vector for unknown / OOV Token?
我不想将 pre-trained embeddings 添加到模型中。但似乎没有 词汇外 (OOV) 标记响应。不存在未见单词的向量。
那么我能做些什么来处理我遇到的 OOV-tokens?我有一些想法,但其中 none 个似乎非常好:
我可以为此令牌创建一个随机向量,但理想情况下我希望该向量在现有模型的 逻辑 内。如果我只是随机创建它,恐怕向量会不小心与 'the'、'for'、'that' 等非常频繁的词非常相似等等,这不是我的本意。
或者我应该只用纯零初始化向量吗?
另一个想法是对其他现有向量的令牌进行平均。但是对什么向量进行平均呢?所有?这个好像也不是很有定论
我也想过尝试训练这个向量。但是,如果我想在训练期间冻结其余的嵌入,这就不太方便了。
(欢迎提供通用解决方案,但我想补充一点,我正在使用 PyTorch - 以防万一 PyTorch 已经为这个问题提供了一个方便的解决方案。)
那么创建这样一个向量的好简单策略是什么?
您可以通过多种方式处理它。我不认为我可以引用关于哪个效果更好的参考文献。
不可训练的选项:
- 作为嵌入的随机向量
- 您可以对 OOV 使用全零向量。
- 您可以使用所有嵌入向量的平均值,这样可以避免偏离实际分布的风险。
- 此外,嵌入通常带有在训练期间学习的“未知”向量,您可以使用它。
可训练选项:
您可以为 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
用法:
model = Embeddings_new(10,20000)
out = model.forward(torch.tensor([-1,-1, 100, 1, 0]))
# dummy loss
loss = torch.sum(a**2)
loss.backward()
我不想将 pre-trained embeddings 添加到模型中。但似乎没有 词汇外 (OOV) 标记响应。不存在未见单词的向量。
那么我能做些什么来处理我遇到的 OOV-tokens?我有一些想法,但其中 none 个似乎非常好:
我可以为此令牌创建一个随机向量,但理想情况下我希望该向量在现有模型的 逻辑 内。如果我只是随机创建它,恐怕向量会不小心与 'the'、'for'、'that' 等非常频繁的词非常相似等等,这不是我的本意。
或者我应该只用纯零初始化向量吗?
另一个想法是对其他现有向量的令牌进行平均。但是对什么向量进行平均呢?所有?这个好像也不是很有定论
我也想过尝试训练这个向量。但是,如果我想在训练期间冻结其余的嵌入,这就不太方便了。
(欢迎提供通用解决方案,但我想补充一点,我正在使用 PyTorch - 以防万一 PyTorch 已经为这个问题提供了一个方便的解决方案。)
那么创建这样一个向量的好简单策略是什么?
您可以通过多种方式处理它。我不认为我可以引用关于哪个效果更好的参考文献。
不可训练的选项:
- 作为嵌入的随机向量
- 您可以对 OOV 使用全零向量。
- 您可以使用所有嵌入向量的平均值,这样可以避免偏离实际分布的风险。
- 此外,嵌入通常带有在训练期间学习的“未知”向量,您可以使用它。
可训练选项:
您可以为 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
用法:
model = Embeddings_new(10,20000)
out = model.forward(torch.tensor([-1,-1, 100, 1, 0]))
# dummy loss
loss = torch.sum(a**2)
loss.backward()