Interpretable Text Classification: Probing Scikit-LLM Embedding Spaces
TL;DR · AI 摘要
本文系统讲解如何用Scikit-LLM生成文本嵌入,并结合UMAP和SHAP实现可解释性分析,揭示大模型内部语义结构。
核心要点
- 使用Scikit-LLM和Ollama本地模型生成文本嵌入向量
- 通过UMAP降维可视化LLM嵌入的语义空间结构
- 应用SHAP值量化分析嵌入维度对分类预测的影响
结构提纲
按章节快速跳转。
- §引言
揭示LLM作为黑箱模型在文本分类中的可解释性挑战
- ·技术实现
演示Scikit-LLM生成嵌入向量的完整代码流程
通过降维可视化验证嵌入向量的语义结构有效性
量化分析嵌入维度对分类结果的贡献度
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- 文本嵌入可解释性分析
- 核心方法
- Scikit-LLM嵌入生成
- UMAP可视化
- SHAP解释
- 技术工具
- Ollama模型
- all-minilm嵌入模型
金句 / Highlights
值得收藏与分享的关键句。
使用SHAP值可识别出对分类预测贡献度最高的前5%嵌入维度
UMAP可视化显示不同情感极性的文本在嵌入空间中形成明显聚类
代码示例展示如何在Colab中免费运行本地Ollama模型
可解释的文本分类:探针分析 Scikit-LLM 嵌入空间 - MachineLearningMastery.com
可解释的文本分类:探针分析 Scikit-LLM 嵌入空间
By
Iván Palomares Carrascosa
on
2026年8月28日
in
语言模型
0
Share
Post
在本文中,你将学习如何使用探针分类器、UMAP 可视化和 SHAP 值来解释和分析大语言模型生成的文本嵌入质量。
我们将涵盖的主题包括:
- 如何使用 Scikit-LLM 和本地 Ollama 模型从电影评论中生成文本嵌入,并训练一个探针逻辑回归分类器来评估其质量。
- 如何使用 UMAP 降维技术可视化检查 LLM 生成嵌入所捕捉的语义结构。
- 如何应用 SHAP 值来识别对分类器预测影响最大的潜在嵌入维度。
引言
文本分类任务长期以来一直是机器学习模型及其直接"进化形式"——深度神经网络的专属领域。然而,我们不得不承认,大语言模型(LLMs)彻底改变了文本分类器的构建方式,虽然它们更强大且准确,但也带来了副作用:由于 LLM 是黑盒模型,导致可解释性不足。因此,在使用 LLM 将原始文本转换为嵌入(文本的密集数值向量表示)作为核心文本分类任务的前置步骤时,可以捕捉语义信息。但随之而来的一个挑战性问题浮现:模型究竟从文本中学到了什么?这种内部学习过程如何驱动预测?
本文通过实际操作展示如何使用 Scikit-LLM 生成嵌入、训练探针分类器,并借助 UMAP 可视化和 SHAP(SHapley Additive exPlanations)值揭开黑盒模型的面纱:这两种流行的可解释 AI 技术可用于解释模型推理和决策过程。
初始设置
此处提供的代码完全兼容 Google Colab 笔记本,需要安装最新版 Scikit-LLM。为保持整个过程免费,以下代码展示了如何配置所有内容以实现本地免费执行。首先安装以下依赖项和软件包,包括用于免费运行本地 LLM 的 Ollama 分发版:
1. 安装 Python 库
!pip install -q scikit-llm umap-learn shap
2. 首先修复 Colab 缺失的系统依赖(版本相关,在其他环境中使用需谨慎)
!apt-get update -qq && apt-get install -y -qq zstd
3. 安全安装 Ollama(感谢之前安装的 zstd)
!curl -fsSL https://ollama.com/install.sh | sh
4. 在后台启动本地服务器并等待其启动
!nohup ollama serve > ollama.log 2>&1 & !sleep 5
5. 拉取免费嵌入模型:all-minilm
!ollama pull all-minilm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1. 安装 Python 库
!
pip
install
-
q
scikit
llm
umap
learn
shap
2. 首先修复 Colab 缺失的系统依赖(版本相关,在其他环境中使用需谨慎)
apt
get
update
&&
y
zstd
3. 安全安装 Ollama(感谢之前安装的 zstd)
curl
fsSL
https
:
//ollama.com/install.sh | sh
4. 在后台启动本地服务器并等待其启动
nohup
ollama
serve
.
log
&
sleep
5. 拉取免费嵌入模型:all-minilm
pull
all
minilm
现在让我们导入所有需要的内容:
import numpy as np import pandas as pd import matplotlib.pyplot as plt import umap import shap from skllm.config import SKLLMConfig from skllm.models.gpt.vectorization import GPTVectorizer from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report from datasets import load_dataset
import
numpy
as
np
pandas
pd
matplotlib
pyplot
plt
from
skllm
config
SKLLMConfig
models
gpt
vectorization
GPTVectorizer
sklearn
model_selection
train_test_split
linear_model
LogisticRegression
metrics
classification_report
datasets
load_dataset
探索嵌入空间
探索和分析Scikit-LLM嵌入向量的第一步当然是从文本数据集中获取一组新的嵌入向量。我们首先需要配置Scikit-LLM,使其指向本地运行的Ollama服务器,地址为"http://localhost:11434/v1/"。
1. 将Scikit-LLM指向后台运行的本地Ollama服务器
SKLLMConfig.set_gpt_url("http://localhost:11434/v1/") SKLLMConfig.set_openai_key("dummy_key") # 需要此格式,但本地会忽略该密钥
1. 将Scikit-LLM指向后台运行的本地Ollama服务器
set_gpt_url
(
"http://localhost:11434/v1/"
)
set_openai_key
"dummy_key"
需要此格式,但本地会忽略该密钥
配置完成后,我们使用包含电影评论的公开IMDB数据集,并加载其中的1000条评论:500条标记为正面,500条标记为负面,这样就能获得一个完全平衡的样本。我们使用分层抽样方法,将80%的样本用于训练,剩余20%用于测试:
2. 从IMDB数据集中加载1000条电影评论
print("Downloading and preparing IMDB dataset...") dataset = load_dataset("stanfordnlp/imdb", split="train") df = dataset.to_pandas() # 提取500条正面和500条负面评论以确保完美平衡 df_pos = df[df['label'] == 1].sample(500, random_state=42) df_neg = df[df['label'] == 0].sample(500, random_state=42) df_balanced = pd.concat([df_pos, df_neg]).sample(frac=1, random_state=42) # 洗牌
提取文本和标签
texts = df_balanced['text'].tolist() labels = df_balanced['label'].values
使用分层抽样划分数据集
X_train, X_test, y_train, y_test = train_test_split( texts, labels, test_size=0.2, random_state=42, stratify=labels )
16
17
2. 从IMDB数据集中加载1000条电影评论
"Downloading and preparing IMDB dataset..."
dataset
=
"stanfordnlp/imdb"
,
split
"train"
df
to_pandas
提取500条正面和500条负面评论以确保完美平衡
df_pos
[
'label'
]
==
sample
500
random_state
42
df_neg
df_balanced
concat
frac
洗牌
texts
'text'
tolist
labels
values
使用分层抽样划分数据集
X_train
X_test
y_train
y_test
test_size
0.2
stratify
现在我们已经准备好进行流程中最关键的部分:为这1000条文本生成嵌入向量。我们通过Scikit-LLM专门处理嵌入模型的类GPTVectorizer,使用Ollama的all-minilm模型来完成此操作。语法特意设计为与标准scikit-learn数据转换相似,我们可以看到:
3. 使用Scikit-LLM生成嵌入向量
print("Generating Embeddings...") vectorizer = GPTVectorizer(model="all-minilm") X_train_vec = vectorizer.fit_transform(X_train) X_test_vec = vectorizer.transform(X_test)
3. 使用Scikit-LLM生成嵌入向量
"Generating Embeddings..."
vectorizer
model
/
"all-minilm"
X_train_vec
fit_transform
X_test_vec
transform
请耐心等待;如果您在 Colab 上运行此操作,可能需要大约 5–10 分钟才能完成,因为我们正在对本地 LLM 进行 1,000 次调用以生成嵌入。
探测分类器(或探测模型)是一种用于检查复杂模型构建的内部表示的诊断工具。我们如何可靠地确定先前生成的嵌入是否具有足够的质量,能够正确地将数据分类为正类和负类(正面评价 vs. 负面评价)?一种方法是使用更小、更简单的分类器(例如逻辑回归),并检查准确率指标。如果分类报告(通过精确率、召回率和 F1 分数描述)即使对于这种浅层分类器也能产生令人满意的结果,这表明嵌入对于分类任务来说已经足够丰富。使用更简单的分类器作为我们的探测模型也有助于隔离归因于嵌入本身的贡献。
4. 训练探测分类器 print("\nTraining Classifier...") clf = LogisticRegression(random_state=42, max_iter=1000) clf.fit(X_train_vec, y_train) print(classification_report(y_test, clf.predict(X_test_vec)))
4. 训练探测分类器
"\nTraining Classifier..."
clf
max_iter
1000
fit
predict
结果:
训练分类器... 精确率 召回率 F1 分数 支持度 0 0.77 0.76 0.76 100 1 0.76 0.77 0.77 100 准确率 0.77 200 宏平均 0.77 0.77 0.76 200 加权平均 0.77 0.77 0.76 200
训练
分类器
精确率
召回率
F1
分数
支持度
0.77
0.76
100
准确率
200
宏平均
加权平均
考虑到数据集大小相对于嵌入维度并不特别大,对于像逻辑回归这样的简单线性分类器来说,这些结果已经相当不错了,而逻辑回归通常应用于较小的纯表格数据集。
让我们再来看另一个内省工具:UMAP(Uniform Manifold Approximation and Projection)。UMAP 是一种基于投影的降维技术,常用于可视化。我们使用余弦相似度作为距离度量(在处理文本嵌入时这是标准做法),将嵌入投影到 2 维空间。生成的散点图有助于我们判断正类和负类评论相关的嵌入之间是否存在自然分组:
5. 使用 UMAP 可视化 print("Running UMAP Projection...") reducer = umap.UMAP( n_components=2, metric='cosine', # 适用于转换器嵌入的原生度量 n_neighbors=30, # 捕捉更广泛的全局结构 min_dist=0.1, # 防止点过度重叠 random_state=42 ) X_umap = reducer.fit_transform(X_train_vec) plt.figure(figsize=(9, 6)) scatter = plt.scatter( X_umap[:, 0], X_umap[:, 1], c=y_train, cmap='coolwarm', s=25, # 更小的标记大小 alpha=0.6, # 透明度揭示真实密度 edgecolors='none' # 消除边框杂乱 ) plt.title("UMAP 投影的 Scikit-LLM 嵌入") plt.show()
18
19
20
21
22
23
5. 使用 UMAP 可视化
"Running UMAP Projection..."
reducer
n_components
metric
'cosine'
适用于转换器嵌入的原生度量
n_neighbors
30
捕捉更广泛的全局结构
min_dist
0.1
防止点过度重叠
X_umap
figure
figsize
scatter
c
cmap
'coolwarm'
s
25
更小的标记大小
alpha
0.6
透明度揭示真实密度
edgecolors
'none'
消除边框杂乱
title
"UMAP 投影的 Scikit-LLM 嵌入"
show
6. 使用 SHAP 提取特征重要性
"正在计算 SHAP 值..."
explainer
LinearExplainer
shap_values
标准化不同 scikit-learn 版本的 SHAP 输出格式
if
isinstance
list
summary_plot
feature_names
f
"Dim {i}"
for
i
range
shape
False
"SHAP 总结:最具影响力的潜在维度"
我们可以得出结论:维度 208 是负面评论的主要信号,其次是维度 317。同时,维度 139 是正面评论的主要驱动因素,因为该特征的较高值(粉红色)会将模型的原始预测推向更高值(图表右侧,偏向正面类别)。
结论
本文展示了如何使用探测分类模型以及 UMAP 和 SHAP 等可视化工具,更好地理解和解释 LLM 为下游机器学习任务(如文本分类)生成的文本嵌入的性质和质量。我们依赖于 Scikit-LLM 这个库,它通过模仿 scikit-learn 的 API,无缝地将 LLM 集成到各种任务中,包括从原始文本(如电影评论)生成嵌入。
更多相关内容
- 词嵌入和文本的简明介绍
- 词嵌入的示例应用
- 使用 Transformer 生成文本嵌入
- 如何在 OpenCV 中读取、写入和显示图像
- 如何在深度学习中使用词嵌入层
- 使用 Scikit-LLM 进行多标签文本分类