如何将预训练模型的Tensor嵌入降维至三维坐标?TSNE报错解决
问题解决与方案梳理
先解决报错:perplexity must be less than n_samples
这个错误逻辑很直接:你设置的perplexity=50必须小于样本总数,但你的代码里只输入了1个词,样本数远小于50,必然报错。
- 如果你要做词对比可视化,至少要准备多个待对比的词(比如10个以上),再把
perplexity设成样本数的1/5到1/10左右(比如20个样本就设perplexity=3-4);单个样本没法做t-SNE,它的作用是展示多个样本的空间分布。
你的代码里还有几个明显错误
- 变量名混乱:你定义了
result = auto_model(**batch_dict),但后面调用了outputs.last_hidden_state,应该改成result.last_hidden_state; text_list未定义:需要把所有待对比的词放进这个列表,比如text_list = ["Slartibartfast", "Ford Prefect", "Arthur Dent"];- 嵌入提取逻辑错误:
embeddings = outputs.last_hidden_state[:, 0][:768]完全不对,[:,0]是取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token的嵌入,形状是[样本数, 768],后面加[:768]会错误截断样本维度,正确写法是embeddings = result.last_hidden_state[:, 0],得到每个样本的<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token嵌入。
修正后的基础代码示例:
from sklearn.manifold import TSNE from transformers import AutoModel, AutoTokenizer import torch import matplotlib.pyplot as plt # 待对比的词列表(至少多个) text_list = ["Slartibartfast", "Ford Prefect", "Arthur Dent", "Zaphod Beeblebrox", "Marvin"] # 模型初始化 model_name = 'Alibaba-NLP/gte-multilingual-base' tokenizer = AutoTokenizer.from_pretrained(model_name) auto_model = AutoModel.from_pretrained(model_name, trust_remote_code=True) # 生成嵌入(加torch.no_grad()节省显存) batch_dict = tokenizer(text_list, padding=True, truncation=True, return_tensors='pt') with torch.no_grad(): result = auto_model(**batch_dict) # 取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token嵌入作为词的表征 embeddings = result.last_hidden_state[:, 0] # t-SNE降维:perplexity设为小于样本数,这里5个样本设为2 tsne = TSNE(n_components=3, learning_rate='auto', init='random', perplexity=2) embeddings_3d = tsne.fit_transform(embeddings.detach().numpy()) # 3D可视化 fig = plt.figure() ax = fig.add_subplot(projection='3d') for i, word in enumerate(text_list): ax.scatter(embeddings_3d[i,0], embeddings_3d[i,1], embeddings_3d[i,2], label=word) ax.legend() plt.show()
关于Skip Gram与可行性的疑问
- 不需要专门生成Skip Gram:Skip Gram是Word2Vec的训练架构,你用的GTE属于BERT类预训练模型,本身就能输出高质量的词/句子嵌入,直接用这些嵌入做t-SNE降维可视化,就能实现“在平面/三维空间找相似词”的目的——相似的词会在空间中聚集,效果逻辑和Skip Gram可视化一致。
- 用预训练模型做这件事完全可行:只要正确提取词嵌入(如果是多字词,BERT会拆分成子词,你可以取子词嵌入的均值/最大值来代表整个词的嵌入,而非只用<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]> token),再通过t-SNE/UMAP等降维算法转到2/3维,就能直观看到词的相似性,避免两两计算相似度的指数级复杂度。
多字词嵌入提取示例:
def get_word_embedding(text, tokenizer, model): inputs = tokenizer(text, return_tensors='pt', add_special_tokens=True) with torch.no_grad(): outputs = model(**inputs) # 去掉<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>和</s> token,取子词嵌入的均值 subword_embeddings = outputs.last_hidden_state[:, 1:-1, :] word_embedding = subword_embeddings.mean(dim=1) return word_embedding # 批量处理生成所有词的嵌入 embeddings = torch.cat([get_word_embedding(word, tokenizer, auto_model) for word in text_list], dim=0)
内容的提问来源于stack exchange,提问作者linkey apiacess
相关产品推荐
相关产品推荐

