You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用Python将BERT/mBART生成的高维句嵌入可视化至2D或3D空间?

如何用Python将BERT/mBART生成的高维句嵌入可视化至2D或3D空间?

我太懂你用PCA跑出来聚类模糊的郁闷了!高维句嵌入里的语义关系大多是非线性的,PCA这种线性降维方法只能抓全局方差,对这种精细的语义聚类确实不太给力。下面我结合自己平时做NLP可视化的经验,给你一步步讲清楚怎么搞定这件事:

一、先搞懂:PCA、t-SNE、UMAP选哪个?

直接给结论:优先用UMAP,t-SNE作为备选,PCA可以彻底放弃(除非你只是想看全局方差分布,不是语义聚类)。

具体为啥:

  • PCA:线性降维,只保留方差最大的维度,完全忽略语义之间的非线性关联,像你遇到的情况,机器学习和动物类的句子可能方差差异不大,所以混在一起,根本分不出聚类。
  • t-SNE:擅长捕捉局部结构,能把相似的点聚得很密,但全局结构拉胯——比如本来机器学习类和动物类在高维空间里距离很远,但t-SNE可能把它们画得很近;而且计算速度慢,数据量一大就卡。
  • UMAP:兼顾局部和全局结构,既能把相似的句子聚成清晰的类,又能保持不同类之间的相对距离;计算速度比t-SNE快很多,对句嵌入这种数据适配性最好。

二、实操步骤:从降维到可视化

我就用你给的4个句子的例子来写代码,假设你已经拿到了embeddings(768维的数组,形状是(4,768))和sentences列表。

1. 先做降维:用UMAP

首先得安装UMAP,直接pip install umap-learn就行。然后代码如下:

import umap
import numpy as np

# 先对句嵌入做L2归一化(可选,但能让降维效果更稳定)
normalized_embeddings = embeddings / np.linalg.norm(embeddings, axis=1, keepdims=True)

# 初始化UMAP,参数可以根据数据调整
reducer = umap.UMAP(
    n_components=2,  # 降到2D,要3D就改成3
    n_neighbors=15,  # 控制局部/全局平衡,句嵌入一般选10-50,数据少的话选小一点
    min_dist=0.1,    # 控制聚类紧密程度,越小聚类越紧凑
    random_state=42  # 固定随机种子,结果可复现
)
reduced_embeddings = reducer.fit_transform(normalized_embeddings)

这里提一下,L2归一化不是必须的,但很多预训练模型的句嵌入做了归一化后,语义相似度的计算更稳定,降维后的聚类效果也会更好。

2. 静态可视化:用Matplotlib/Seaborn

如果只是要生成静态图,用Matplotlib就够了,能快速看到聚类效果:

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 8))
# 画散点
scatter = plt.scatter(reduced_embeddings[:, 0], reduced_embeddings[:, 1])
# 给每个点加标签
for i, sentence in enumerate(sentences):
    plt.annotate(sentence, (reduced_embeddings[i, 0], reduced_embeddings[i, 1]), 
                 fontsize=10, ha='center')
plt.title("Sentence Embeddings Visualization (UMAP)")
plt.show()

这样你就能看到,机器学习的两个句子会紧紧聚在一起,猫和狗的句子要么各自分开,要么聚成一个动物小簇,和机器学习的簇离得很远。

3. 交互式可视化:用Plotly(支持hover、缩放)

如果要做交互式的,比如鼠标hover显示完整句子、缩放拖拽,那Plotly是我最常用的工具,完全满足你的需求:

import plotly.express as px

# 把数据转成DataFrame方便Plotly处理
import pandas as pd
df = pd.DataFrame({
    'x': reduced_embeddings[:, 0],
    'y': reduced_embeddings[:, 1],
    'sentence': sentences
})

# 生成交互式散点图
fig = px.scatter(df, x='x', y='y', hover_name='sentence', 
                 title="Interactive Sentence Embeddings Visualization (UMAP)",
                 labels={'x': 'UMAP Dimension 1', 'y': 'UMAP Dimension 2'})
# 可以自定义点的大小、颜色
fig.update_traces(marker=dict(size=12, opacity=0.8))
fig.show()

运行后会弹出一个网页(或者在Jupyter里直接显示),你可以缩放、拖拽,鼠标放到点上就能看到完整的句子,完全不用担心标签重叠看不清的问题。

三、优化语义聚类的小技巧

如果用UMAP还是觉得聚类不够清晰,可以试试这些调参和预处理技巧:

  • 调整UMAP的核心参数
    • n_neighbors:如果你的数据集小(比如几十条),可以调到5-10,更关注局部聚类;如果数据量大(几百上千条),调到30-50,兼顾全局结构。
    • min_dist:如果想让聚类更紧凑,把这个值调小到0.01;如果想让不同簇之间的距离更大,调大到0.5试试。
  • 降维前做标准化:除了L2归一化,也可以用sklearn.preprocessing.StandardScaler把每个特征的均值拉到0,方差拉到1,对有些句嵌入数据集有帮助。
  • 如果用t-SNE,调perplexity:要是你非要用t-SNE,perplexity参数是关键,一般设置为数据集大小的1/5到1/10,比如你有4条数据,perplexity设为2-3,这样局部聚类会更准,但注意t-SNE的结果随机性很强,要固定random_state

四、预期效果验证

用上面的方法处理你给的4个句子,应该能得到这样的效果:

  • 「I love machine learning」和「Deep learning is amazing」会紧紧聚在同一个小簇里
  • 「The cat is sleeping」和「Dogs are very loyal」要么形成一个独立的动物小簇,要么各自分开,但肯定和机器学习的簇离得很远
  • 交互式图里,hover就能看到完整句子,缩放后细节也清晰

这样应该就能完美解决你的问题啦,要是还有细节调不好的地方,随时再问!

火山引擎 最新活动