我正在从火炬中心加载一个语言模型(CamemBERT是一个基于法国 RoBERTa 的模型),并使用它嵌入了一些句子:
import torch
camembert = torch.hub.load('pytorch/fairseq', 'camembert.v0')
camembert.eval() # disable dropout (or leave in train mode to finetune)
def embed(sentence):
tokens = camembert.encode(sentence)
# Extract all layer's features (layer 0 is the embedding layer)
all_layers = camembert.extract_features(tokens, return_all_hiddens=True)
embeddings = all_layers[0]
return embeddings
# Here we see that the shape of the embedding vector depends on the number of tokens in the sentence
u = embed("Bonjour, ça va ?")
u.shape # torch.Size([1, 7, 768])
v = embed("Salut, comment vas-tu ?")
v.shape # torch.Size([1, 9, 768])
现在想象一下,我想计算cosine distance向量(在我们的例子中是张量)u和v:
cos = torch.nn.CosineSimilarity(dim=0)
cos(u, v) #will throw an error since the shape of `u` is different from the shape of `v``
我在问,无论令牌的数量如何,为了始终获得相同的句子嵌入形状,最好的方法是什么?
=>我正在考虑的第一个解决方案是计算mean on axis=1(句子中标记的平均嵌入),因为axis=0和axis=2始终具有相同的大小:
cos = torch.nn.CosineSimilarity(dim=1) #dim becomes 1 now
u = u.mean(axis=1)
v = v.mean(axis=1)
cos(u, v).detach().numpy().item() # works now and gives 0.7269
但是,我担心在计算平均值时会伤害嵌入!
=> 第二种解决方案是将较短的句子填充出来,这意味着:
- 给出一次嵌入的句子列表(而不是逐句嵌入)
- 查找具有最长标记的句子并将其嵌入,得到它的形状
S - 对于嵌入的其余句子,然后填充零以获得相同的形状
S(句子的其余维度为 0)
你觉得呢?你有没有什么想法?你会使用什么技术,为什么?