请问下:该模型返回的张量不是定长的

#16
by Ark0810 - opened

我看到该模型返回的张量会根据词的数量返回(n,768)那么这种不定长向量会影响余弦相似度的计算吗,对向量检索的准确率有没有影响,是否需要padding 0

Moka HR SaSS org

不会呀,只会返回定长的向量,如果是一个 batch , 就是 batch_size * 768 的向量。如果你那边的代码返回的是不定长的,可以把代码贴一下,我看看是怎么回事。

加载模型

tokenizer = AutoTokenizer.from_pretrained("moka-ai/m3e-base")
model = AutoModel.from_pretrained("moka-ai/m3e-base")

# 定义文本
text = "你好"

# 转成tensor输入
inputs = tokenizer(text, return_tensors="pt")
input_ids = inputs["input_ids"]
attention_mask = inputs["attention_mask"]
token_type_ids = inputs["token_type_ids"]

# 模型推理
with torch.no_grad():
    outputs = model(input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)

# 获取向量表示
embeddings = outputs.last_hidden_state[0]
res = embeddings.numpy()
print(res)

hi,似乎不应该直接使用 last_hidden_state,借助sentence transformer包可以更方便地得到pooling后的embedding

可以给个python示例吗

就是直接使用 sentence-transformers 这个 Python 包,以下是一个示例,更多功能可以查阅相关文档

from sentence_transformers import SentenceTransformer

model = SentenceTransformer('moka-ai/m3e-base')

# str -> tensor
text = 'hello world'
embedding = model.encode(text)
print(embedding.shape)

# a list of strings -> a list of tensors
texts = ['hello world', 'test embeddings']
embeddings = model.encode(texts)
for e in embeddings:
    print(e.shape)
This comment has been hidden

OK 多谢了, 我查到同样可以这样pooling

import torch
pooler = torch.mean(outputs.last_hidden_state, 1)

可以的,m3e 模型使用的方法是将所有 token embedding 向量作平均,在 sentence-transformers 这个包里可以找到相关源码,是使用 pytorch 实现的

代码来自 https://github.com/UKPLab/sentence-transformers/blob/179b659621c680371394d507683b25ba7faa0dd8/sentence_transformers/models/Pooling.py#L98-L113

        if self.pooling_mode_mean_tokens or self.pooling_mode_mean_sqrt_len_tokens:
            input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
            sum_embeddings = torch.sum(token_embeddings * input_mask_expanded, 1)

            #If tokens are weighted (by WordWeights layer), feature 'token_weights_sum' will be present
            if 'token_weights_sum' in features:
                sum_mask = features['token_weights_sum'].unsqueeze(-1).expand(sum_embeddings.size())
            else:
                sum_mask = input_mask_expanded.sum(1)

            sum_mask = torch.clamp(sum_mask, min=1e-9)

            if self.pooling_mode_mean_tokens:
                output_vectors.append(sum_embeddings / sum_mask)
            if self.pooling_mode_mean_sqrt_len_tokens:
                output_vectors.append(sum_embeddings / torch.sqrt(sum_mask))

这上面的 token_embeddings 实际上就是 last_hidden_state (对于 Bert 这种模型,它输出的 last_hidden_state 就是每个输入 token 对应的向量表示),上面这段代码实际上就是根据 mask 把所有向量求和再除以长度

直接求平均的话,可能会有产生偏差,如果多个句子同时进去,tokenizer 会把所有序列 pad 到一个固定长度,然后用 attention mask 告诉模型那些 pad tokens 不参与计算,如果直接求平均,会把那些 pad tokens 算进去的

Moka HR SaSS org

感谢 @habaneraa 的解释,全面且正确。👍

Ark0810 changed discussion status to closed

Sign up or log in to comment