如何在 PyTorch 中并行化 GloVe 反向查找?

数据挖掘 词嵌入 火炬 平行线
2022-02-20 12:18:01

我觉得我在这里遗漏了一些明显的东西,因为我找不到任何关于这个的讨论。我想对单词生成网络的 GloVe 嵌入进行大量反向查找(最近邻距离搜索)。我目前只是在 cpu 上遍历词汇表。我已经使用进程池加快了速度,如下面的片段所示,但对于大型词汇来说仍然非常慢。

有没有办法使用 cuda 将其移至 GPU?我还读到有一种方法可以将这种事情变成一个大矩阵运算......任何参考都将不胜感激。谢谢!

glove = torchtext.vocab.GloVe(name='6B', dim=wordDim)

def closest(vec):
    dists = [(w, torch.dist(vec, glove.vectors[glove.stoi[w]] for w in glove.itos]
    return sorted(dists, key=lambda t: t[1])[0]

output = # word vectors…
# using a process pool to parallelize the lookup
pool=ProcessPoolExecutor(max_workers=8)
predictedWords = [w for w in list(pool.map(closestWord, output)]
1个回答

使用列表推导等以 Python 方式处理这些类型的问题通常不是很有效。整个过程可以通过一些矩阵数学来完成,这将大大加快(并且能够使用 PyTorch 在 GPU 上计算)。使用torch.dist默认值p=2将计算两个张量之间的欧几里得距离,定义为

euclidean distance=d(v,w)=d(vdwd)2

通过在整个词向量矩阵上广播查询词,您可以在 PyTorch 中对词汇中的每个词有效地执行此操作:

def closest(vec):
    dists = torch.sqrt(((glove.vectors - vec) ** 2).sum(dim=1))
    return dists.argmin() # or glove.itos[dists.argmin()] if you want a string output

但是,通常人们使用余弦相似度来寻找最接近的词向量,而不是欧几里得距离。这是向量之间夹角的余弦值,可以计算为

Cosine similarity=vwvw

可以类似地在 PyTorch 中实现如下:

glove_lengths = torch.sqrt((glove.vectors ** 2).sum(dim=1))

def closest_cosine(vec):
    numerator = (glove.vectors * vec).sum(dim=1)
    denominator = glove_lengths * torch.sqrt((vec ** 2).sum())
    similarities = numerator / denominator
    return glove.itos[similarities.argmax()]

请注意,我们移动了这里是函数之外的方程的一部分,因此我们不必在每次想要运行它时重新计算每个手套向量的长度。v