You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mistral模型对不同输入生成相同嵌入的问题排查

问题:预训练LLM生成文本嵌入始终一致的异常排查

使用预训练的Mistral-7B-Instruct-v0.2模型生成输入文本的嵌入时出现异常:无论输入文本如何不同,输出的嵌入完全一致。相关代码及输出如下:

代码

from transformers import pipeline, AutoTokenizer, AutoModel
import numpy as np
import torch  # 原代码遗漏torch导入,运行会报错

PRETRAIN_MODEL = 'mistralai/Mistral-7B-Instruct-v0.2'
tokenizer = AutoTokenizer.from_pretrained(PRETRAIN_MODEL)
model = AutoModel.from_pretrained(PRETRAIN_MODEL)

def generate_embedding(document):
    inputs = tokenizer(document, return_tensors='pt')
    print("Tokenized inputs:", inputs)
    with torch.no_grad():
        outputs = model(**inputs)
    embedding = outputs.last_hidden_state[0, 0, :].numpy()
    print("Generated embedding:", embedding)
    return embedding

text1 = "this is a test"
text2 = "this is another test"
text3 = "there are other tests"

embedding1 = generate_embedding(text1)
embedding2 = generate_embedding(text2)
embedding3 = generate_embedding(text3)

are_equal = np.array_equal(embedding1, embedding2) and np.array_equal(embedding2, embedding3)

if are_equal:
    print("The embeddings are the same.")
else:
    print("The embeddings are not the same.")

输出结果

Tokenized inputs: {'input_ids': tensor([[   1,  456,  349,  264, 1369]]), 'attention_mask': tensor([[1, 1, 1, 1, 1]])}
Generated embedding: [-1.7762679  1.9293272 -2.2413437 ...  2.6379988 -3.104867   4.806004 ]
Tokenized inputs: {'input_ids': tensor([[   1,  456,  349, 1698, 1369]]), 'attention_mask': tensor([[1, 1, 1, 1, 1]])}
Generated embedding: [-1.7762679  1.9293272 -2.2413437 ...  2.6379988 -3.104867   4.806004 ]
Tokenized inputs: {'input_ids': tensor([[   1,  736,  460,  799, 8079]]), 'attention_mask': tensor([[1, 1, 1, 1, 1]])}
Generated embedding: [-1.7762679  1.9293272 -2.2413437 ...  2.6379988 -3.104867   4.806004 ]
The embeddings are the same.

问题原因

你取嵌入的位置是outputs.last_hidden_state[0, 0, :],也就是序列第一个token(,即bos token)的隐藏状态。对于Mistral这类大语言模型,bos token作为句子的起始标记,其隐藏状态不会随输入文本内容变化,因此不同文本生成的嵌入完全一致。

解决方法

方案1:取序列最后一个有效token的嵌入

直接取序列末尾的token隐藏状态(适用于无padding的短文本):

def generate_embedding(document):
    inputs = tokenizer(document, return_tensors='pt')
    with torch.no_grad():
        outputs = model(**inputs)
    # 取最后一个token的嵌入
    embedding = outputs.last_hidden_state[0, -1, :].numpy()
    return embedding

方案2:对所有token做平均池化(推荐)

基于attention mask忽略padding部分,对所有token的隐藏状态做平均,得到更具代表性的文本嵌入:

def generate_embedding(document):
    inputs = tokenizer(document, return_tensors='pt')
    with torch.no_grad():
        outputs = model(**inputs)
    
    # 基于attention mask计算平均池化嵌入
    mask = inputs['attention_mask'].unsqueeze(-1).expand(outputs.last_hidden_state.shape)
    masked_embeddings = outputs.last_hidden_state * mask
    summed_embeddings = torch.sum(masked_embeddings, dim=1)
    # 避免除以0,加极小值
    token_counts = torch.clamp(mask.sum(dim=1), min=1e-9)
    embedding = (summed_embeddings / token_counts).squeeze(0).numpy()
    return embedding

补充说明

如果是专门用于文本嵌入任务的场景,建议使用sentence-transformers系列模型,这类模型针对嵌入任务做了优化,池化方式更合理。但针对当前使用的Mistral模型,上述两种方法可以解决嵌入一致的问题。

内容的提问来源于stack exchange,提问作者Howie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:28:11