Machine Learning Mastery

Interpretable Text Classification: Probing Scikit-LLM Embedding Spaces

8.5内容质量

TL;DR · AI 摘要

本文系统讲解如何用Scikit-LLM生成文本嵌入,并结合UMAP和SHAP实现可解释性分析,揭示大模型内部语义结构。

核心要点

  • 使用Scikit-LLM和Ollama本地模型生成文本嵌入向量
  • 通过UMAP降维可视化LLM嵌入的语义空间结构
  • 应用SHAP值量化分析嵌入维度对分类预测的影响

结构提纲

按章节快速跳转。

  1. 揭示LLM作为黑箱模型在文本分类中的可解释性挑战

  2. 演示Scikit-LLM生成嵌入向量的完整代码流程

  3. UMAP分析

    通过降维可视化验证嵌入向量的语义结构有效性

  4. SHAP解释

    量化分析嵌入维度对分类结果的贡献度

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • 文本嵌入可解释性分析
    • 核心方法
      • Scikit-LLM嵌入生成
      • UMAP可视化
      • SHAP解释
    • 技术工具
      • Ollama模型
      • all-minilm嵌入模型

金句 / Highlights

值得收藏与分享的关键句。

#Scikit-LLM#UMAP#SHAP#NLP#可解释性AI
打开原文

可解释的文本分类:探针分析 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

qq

&&

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条电影评论

print

"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 进行多标签文本分类