我想从转换器模型中获得短文本嵌入,所以我测试了 3 种计算方法。所有 3 个案例都使用 Huggingface Hub 的模型。
inputs = tokenizer(text, padding=True, return_tensors="pt")
def embedding_1(text):
inputs = tokenizer(text, padding=True, return_tensors="pt")
outputs = model(**inputs)
output_tensors = outputs[1]
output_numpy = output_tensors.detach().numpy()
return output_numpy
def embedding_2(text):
model_output = model(**inputs)
token_embeddings = model_output[0]
input_mask_expanded = inputs['attention_mask'].unsqueeze(-1).expand(token_embeddings.size()).float()
return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
两种方法都使用中国模式:
tokenizer = BertTokenizer.from_pretrained("hfl/chinese-roberta-wwm-ext")
model = BertModel.from_pretrained("hfl/chinese-roberta-wwm-ext")
第三种方法直接使用句子转换器模型(https://www.sbert.net/):
def embedding_3(text):
model = SentenceTransformer('sentence-transformers/distiluse-base-multilingual-cased')
embedding = model.encode(text)
return embedding
现在我测试了'这个好'和其他几个句子的相似度,结果如下(基于cosine_similarity):
simi 1: 这个好 | 这个非常好: tensor([0.9844])
simi 2: 这个好 | 这个非常好: tensor([0.8641])
simi 3: 这个好 | 这个非常好: tensor([[0.8629]])
simi 1: 这个好 | 这个非常不好: tensor([0.9840])
simi 2: 这个好 | 这个非常不好: tensor([0.8403])
simi 3: 这个好 | 这个非常不好: tensor([[0.5878]])
simi 1: 这个好 | 他很傻: tensor([0.9737])
simi 2: 这个好 | 他很傻: tensor([0.7483])
simi 3: 这个好 | 他很傻: tensor([[0.3601]])
simi 1: 这个好 | 中国人民解放军: tensor([0.9171])
simi 2: 这个好 | 中国人民解放军: tensor([0.5162])
simi 3: 这个好 | 中国人民解放军: tensor([[0.0597]])
很明显,这 3 种方法产生了非常不同的相似度分数,第 3 种方法似乎是最好的。如果它们略有不同,那是可以理解的。如果它们如此不同,应该使用哪一个?
我喜欢第三种方法的结果,但是在测试这几句话时,它在 CPU 和 GPU 机器上都非常慢。其他2个要快得多。