1. 什么是 all-MiniLM-L6-v2? #
all-MiniLM-L6-v2 是 Sentence Transformers 库中最受欢迎的轻量级句子嵌入模型之一,由微软研究院开发。它可以将任意长度的文本(句子、段落)转换为固定长度的数值向量(嵌入向量),这些向量能够捕捉文本的语义信息。
核心特点:
- 轻量高效:参数量仅约 2270 万,模型文件大小约 90MB
- 速度快:在普通 CPU 上也能快速运行,GPU 上速度更快
- 通用性强:在多种自然语言处理任务上表现良好
- 易于使用:开箱即用,API 简单直观
主要用途:
- 计算文本之间的语义相似度
- 语义搜索和检索
- 文本聚类和分类
- 智能文档分块
- 问答系统和推荐系统
为什么选择这个模型?
- 在性能和速度之间取得了很好的平衡
- 适合大多数应用场景,不需要针对特定任务进行微调
- 资源消耗低,适合在普通硬件上运行
- 社区支持好,文档和示例丰富
2. 前置知识补充 #
在深入学习之前,我们先了解一些基础概念,这些知识会帮助你更好地理解模型的工作原理。
2.1 什么是文本嵌入(Embedding)? #
文本嵌入是将文本转换为数值向量的过程。这些向量是数字数组,能够表示文本的语义信息。
简单理解:
- 就像给每个文本分配一个"身份证号码"
- 相似的文本会有相似的"号码"
- 计算机可以通过比较这些"号码"来判断文本是否相似
示例:
# 文本嵌入的简单示例
文本1: "我喜欢编程"
嵌入1: [0.1, 0.5, 0.3, ..., 0.8] # 384 个数字
文本2: "我爱写代码"
嵌入2: [0.12, 0.48, 0.31, ..., 0.79] # 384 个数字
# 两个嵌入向量很相似,说明文本语义相似2.2 什么是句子嵌入(Sentence Embedding)? #
句子嵌入是专门为句子或短文本设计的嵌入方法。与词嵌入(Word Embedding)不同,句子嵌入能够理解整个句子的语义,而不仅仅是单个词语。
区别:
- 词嵌入:每个词有一个向量,如 "苹果" → [0.2, 0.5, ...]
- 句子嵌入:整个句子有一个向量,如 "我喜欢吃苹果" → [0.1, 0.3, ...]
优势:
- 能够理解句子的整体含义
- 考虑词语之间的上下文关系
- 更适合语义相似度计算
2.3 什么是知识蒸馏(Knowledge Distillation)? #
知识蒸馏是一种模型压缩技术,通过让小型模型(学生)学习大型模型(教师)的知识,在保持性能的同时大幅减小模型尺寸。
类比理解:
- 就像学生向老师学习知识
- 老师(大模型)知识丰富但体积大、速度慢
- 学生(小模型)体积小、速度快,但学到了老师的核心知识
过程:
大型教师模型(BERT-base,12层,768维,110M参数)
↓ 知识蒸馏
小型学生模型(MiniLM,6层,384维,22.7M参数)好处:
- 模型体积减小约 80%
- 推理速度提升 3-5 倍
- 性能损失很小(通常 < 5%)
2.4 什么是余弦相似度(Cosine Similarity)? #
余弦相似度是衡量两个向量相似程度的方法,取值范围通常是 -1 到 1,值越大表示越相似。
简单理解:
- 就像比较两个箭头的方向
- 方向相同(相似度高)→ 值接近 1
- 方向相反(相似度低)→ 值接近 -1
- 方向垂直(不相关)→ 值接近 0
计算公式:
相似度 = (向量A · 向量B) / (|向量A| × |向量B|)实际应用:
- 相似度 > 0.8:文本非常相似
- 相似度 0.5-0.8:文本有一定相关性
- 相似度 < 0.5:文本不太相关
3. 安装和基本使用 #
在开始使用 all-MiniLM-L6-v2 之前,需要先安装必要的库。
3.1 安装 Sentence Transformers #
Sentence Transformers 是使用该模型的主要库。
Windows 系统安装 #
在 Windows PowerShell 或命令提示符中执行:
# 升级 pip 到最新版本(推荐)
python -m pip install --upgrade pip
# 安装 sentence-transformers 库
python -m pip install sentence-transformers
# 如果需要使用 GPU 加速,还需要安装 PyTorch(可选)
# 访问 https://pytorch.org/ 获取适合你系统的安装命令注意事项:
- 如果系统中有多个 Python 版本,可能需要使用
python3代替python - 如果遇到权限问题,可以添加
--user参数
macOS 系统安装 #
在 macOS 终端中执行:
# 升级 pip 到最新版本(推荐)
python3 -m pip install --upgrade pip
# 安装 sentence-transformers 库
python3 -m pip install sentence-transformers注意事项:
- macOS 系统通常需要使用
python3命令 - 如果提示找不到
python3,可能需要先安装 Python
3.2 验证安装 #
安装完成后,可以通过以下代码验证是否安装成功:
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 尝试加载模型(首次运行会自动下载模型文件)
try:
model = SentenceTransformer("all-MiniLM-L6-v2")
print("安装成功!模型已加载。")
except Exception as e:
print(f"安装或加载模型时出错:{e}")3.3 第一个示例:将文本转换为向量 #
让我们从一个最简单的例子开始,了解如何使用模型将文本转换为向量。
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 加载 all-MiniLM-L6-v2 模型
# 首次运行时会自动从网络下载模型文件(约 90MB)
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备要转换的文本(可以是单个句子或句子列表)
text = "我喜欢编程和机器学习"
# 使用 encode 方法将文本转换为向量
# 返回一个 numpy 数组,包含 384 个数字
embedding = model.encode(text)
# 打印结果
print(f"文本:{text}")
print(f"嵌入向量维度:{embedding.shape}")
print(f"嵌入向量前 10 个值:{embedding[:10]}")
print(f"向量长度(L2 范数):{embedding.sum()**0.5:.4f}")运行说明:
- 保存代码为
first_example.py - 在终端运行:
python first_example.py(Windows)或python3 first_example.py(macOS) - 首次运行会自动下载模型,需要一些时间
- 后续运行会直接使用已下载的模型
输出说明:
embedding.shape应该是(384,),表示一个包含 384 个数字的向量- 向量已经过 L2 归一化,长度约为 1.0
4. 模型基本信息 #
了解模型的基本参数和特性,有助于更好地使用它。
4.1 模型规格 #
技术参数:
- 模型名称:all-MiniLM-L6-v2
- 参数量:约 22.7M(2270 万)
- 模型文件大小:约 90MB
- 输出维度:384 维
- 最大序列长度:256 tokens(约 200-300 个中文字符)
- 架构:基于 MiniLM 的蒸馏版本,6 层 Transformer
性能指标:
- 推理速度:CPU 上约 100-200 句子/秒,GPU 上更快
- 内存占用:约 200-300MB(加载模型后)
- 准确度:在语义相似度任务上表现优秀
4.2 模型架构说明 #
模型内部结构可以简单理解为:
输入文本
↓
文本分词(Tokenization)
↓
词嵌入层(将词转换为向量)
↓
6 层 Transformer 编码器(理解语义)
↓
平均池化层(合并所有词的向量)
↓
L2 归一化层(标准化向量长度)
↓
输出:384 维归一化向量各组件作用:
- Transformer 编码器:理解文本的语义信息
- 平均池化:将多个词的向量合并成一个句子向量
- L2 归一化:标准化向量,使余弦相似度计算更准确
4.3 查看模型详细信息 #
下面的代码可以查看模型的详细结构:
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 打印模型信息
print("模型信息:")
print(f"模型名称:{model.get_sentence_embedding_dimension()} 维")
print(f"最大序列长度:{model.max_seq_length} tokens")
# 查看模型结构(可选,输出较详细)
# print("\n模型结构:")
# print(model)5. 实际应用示例 #
本节提供多个实际应用场景的完整示例,帮助你理解如何在实际项目中使用模型。
5.1 示例 1:计算文本相似度 #
计算两个或多个文本之间的语义相似度是最常见的应用。
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 导入余弦相似度计算函数
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备要比较的文本
sentences = [
"狗在公园里跑步",
"一只犬在草地上奔跑",
"今天天气很好",
"苹果公司发布新产品"
]
# 将所有文本转换为向量
# encode 方法可以接受单个字符串或字符串列表
embeddings = model.encode(sentences)
# 计算相似度矩阵
# cosine_similarity 会计算所有文本对之间的相似度
similarity_matrix = cosine_similarity(embeddings)
# 打印结果
print("文本列表:")
for i, sentence in enumerate(sentences):
print(f"{i+1}. {sentence}")
print("\n相似度矩阵(值越大越相似,范围 0-1):")
print(similarity_matrix)
# 详细分析
print("\n详细分析:")
print(f"文本 1 和文本 2 的相似度:{similarity_matrix[0][1]:.4f}")
print("(这两句意思相同,相似度应该很高)")
print(f"\n文本 1 和文本 3 的相似度:{similarity_matrix[0][2]:.4f}")
print("(这两句意思不同,相似度应该较低)")运行说明:
- 需要安装 scikit-learn:
pip install scikit-learn(Windows)或pip3 install scikit-learn(macOS) - 运行后会看到相似度矩阵,对角线上的值都是 1.0(自己和自己最相似)
5.2 示例 2:语义搜索 #
在文档库中搜索与查询最相似的文档。
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 导入余弦相似度计算函数
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备文档库(实际应用中可能从文件读取)
documents = [
"Python 是一种高级编程语言,广泛用于数据科学和机器学习。",
"机器学习是人工智能的一个分支,让计算机能够从数据中学习。",
"深度学习使用神经网络来模拟人脑的工作方式。",
"自然语言处理帮助计算机理解和生成人类语言。",
"数据科学结合统计学和编程来分析数据。"
]
# 将文档库转换为向量
document_embeddings = model.encode(documents)
# 用户查询
query = "我想学习人工智能相关的技术"
# 将查询转换为向量
query_embedding = model.encode([query])
# 计算查询与所有文档的相似度
# cosine_similarity 返回一个矩阵,我们只需要第一行(查询与所有文档的相似度)
similarities = cosine_similarity(query_embedding, document_embeddings)[0]
# 找到最相似的文档
# argsort 返回按相似度排序的索引,[::-1] 表示降序排列
most_similar_idx = np.argsort(similarities)[::-1]
# 打印结果
print(f"查询:{query}\n")
print("搜索结果(按相似度排序):\n")
# 显示前 3 个最相似的文档
for i, idx in enumerate(most_similar_idx[:3], 1):
print(f"{i}. 相似度:{similarities[idx]:.4f}")
print(f" 文档:{documents[idx]}\n")运行说明:
- 运行后会显示与查询最相似的文档
- 可以修改查询文本,观察搜索结果的变化
5.3 示例 3:批量处理文本 #
当需要处理大量文本时,批量处理可以提高效率。
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
import time
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备大量文本(实际应用中可能从文件读取)
sentences = [
"这是第一个句子。",
"这是第二个句子。",
"这是第三个句子。"
] * 100 # 创建 300 个句子用于测试
print(f"准备处理 {len(sentences)} 个句子\n")
# 记录开始时间
start_time = time.time()
# 批量编码文本
# batch_size 参数控制每次处理的句子数量,可以根据内存情况调整
embeddings = model.encode(sentences, batch_size=32, show_progress_bar=True)
# 记录结束时间
end_time = time.time()
# 打印结果
print(f"\n处理完成!")
print(f"总耗时:{end_time - start_time:.2f} 秒")
print(f"平均每个句子:{(end_time - start_time) / len(sentences) * 1000:.2f} 毫秒")
print(f"嵌入向量形状:{embeddings.shape}")
print(f"单个向量维度:{embeddings[0].shape}")运行说明:
batch_size参数可以根据你的内存情况调整- 如果内存充足,可以增大
batch_size以提高速度 - 如果内存不足,减小
batch_size
5.4 示例 4:处理长文本 #
模型的最大序列长度是 256 tokens,对于超长文本需要先分割。
# 导入 SentenceTransformer 类
from sentence_transformers import SentenceTransformer
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备一个较长的文本
long_text = """
人工智能是计算机科学的一个分支。它试图理解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。
机器学习是人工智能的一个子领域。它使计算机能够在没有明确编程的情况下学习和改进。机器学习算法通过分析大量数据来识别模式,并基于这些模式做出预测或决策。
深度学习是机器学习的一个子集。它使用神经网络来模拟人脑的工作方式。深度学习在图像识别、自然语言处理等领域取得了突破性进展。
自然语言处理是人工智能的另一个重要分支。它帮助计算机理解、解释和生成人类语言。现代自然语言处理系统广泛应用于机器翻译、聊天机器人、文本分析等领域。
"""
# 方法 1:直接编码(会自动截断超长文本)
# 注意:如果文本超过 256 tokens,模型会自动截断,可能会丢失信息
embedding1 = model.encode(long_text)
print(f"方法 1 - 直接编码向量维度:{embedding1.shape}")
# 方法 2:分割后编码(推荐)
# 按段落分割文本
paragraphs = [p.strip() for p in long_text.split("\n\n") if p.strip()]
# 将每个段落转换为向量
paragraph_embeddings = model.encode(paragraphs)
# 计算所有段落向量的平均值作为整个文档的向量
# 这是一种简单的方法,也可以使用其他方法(如加权平均)
document_embedding = paragraph_embeddings.mean(axis=0)
print(f"\n方法 2 - 分割后编码:")
print(f"段落数量:{len(paragraphs)}")
print(f"每个段落向量维度:{paragraph_embeddings[0].shape}")
print(f"文档向量维度:{document_embedding.shape}")
# 显示段落内容
print("\n段落内容:")
for i, para in enumerate(paragraphs, 1):
print(f"{i}. {para[:50]}...")运行说明:
- 对于超长文本,推荐使用方法 2(分割后编码)
- 可以根据需要选择分割方式(按段落、按句子等)
6. 性能特点 #
了解模型的性能特点,有助于判断它是否适合你的应用场景。
6.1 计算效率测试 #
下面的代码可以测试模型在你的机器上的性能:
# 导入必要的库
from sentence_transformers import SentenceTransformer
import time
import numpy as np
# 加载模型
print("正在加载模型...")
model = SentenceTransformer("all-MiniLM-L6-v2")
print("模型加载完成!\n")
# 准备测试数据
test_sentences = ["这是一个测试句子。"] * 100
# 测试单次编码速度
print("性能测试:")
print(f"测试句子数量:{len(test_sentences)}")
# 预热(第一次运行可能较慢)
_ = model.encode(test_sentences[:10])
# 测试批量编码
start_time = time.time()
embeddings = model.encode(test_sentences, batch_size=32)
end_time = time.time()
# 计算性能指标
total_time = end_time - start_time
sentences_per_second = len(test_sentences) / total_time
time_per_sentence = total_time / len(test_sentences) * 1000
# 打印结果
print(f"总耗时:{total_time:.2f} 秒")
print(f"处理速度:{sentences_per_second:.1f} 句子/秒")
print(f"平均每个句子:{time_per_sentence:.2f} 毫秒")
print(f"嵌入向量维度:{embeddings[0].shape}")
print(f"向量数据类型:{embeddings.dtype}")
print(f"单个向量大小:{embeddings[0].nbytes} 字节")6.2 与其他模型对比 #
all-MiniLM-L6-v2 在性能和速度之间取得了很好的平衡:
| 模型 | 参数量 | 输出维度 | 速度 | 内存占用 | 适用场景 | ||--|-||-|-| | all-MiniLM-L6-v2 | 22.7M | 384 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 大多数应用 | | all-mpnet-base-v2 | 109M | 768 | ⭐⭐⭐ | ⭐⭐⭐ | 需要更高精度 | | BERT-base | 110M | 768 | ⭐⭐ | ⭐⭐ | 研究用途 |
选择建议:
- 大多数应用:选择
all-MiniLM-L6-v2,平衡了速度和性能 - 需要更高精度:选择
all-mpnet-base-v2,但速度较慢 - 资源受限:选择
all-MiniLM-L6-v2,资源消耗低
6.3 语义表示能力测试 #
下面的代码可以测试模型的语义理解能力:
# 导入必要的库
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备测试文本对
# 每组包含两个文本,第一组应该相似,第二组应该不相似
test_pairs = [
# 相似文本对
("我喜欢编程", "我爱写代码"),
("今天天气很好", "今天是个好天气"),
("机器学习很有趣", "我对机器学习很感兴趣"),
# 不相似文本对
("我喜欢编程", "今天天气很好"),
("机器学习很有趣", "苹果公司发布新产品"),
("Python 是一种编程语言", "我喜欢吃苹果")
]
# 测试每组文本对的相似度
print("语义相似度测试:\n")
for i, (text1, text2) in enumerate(test_pairs, 1):
# 将两个文本转换为向量
embeddings = model.encode([text1, text2])
# 计算相似度
similarity = cosine_similarity([embeddings[0]], [embeddings[1]])[0][0]
# 判断是否相似(阈值 0.7)
is_similar = "✓ 相似" if similarity > 0.7 else "✗ 不相似"
print(f"测试 {i}:")
print(f" 文本1:{text1}")
print(f" 文本2:{text2}")
print(f" 相似度:{similarity:.4f} {is_similar}\n")7. 优势和局限性 #
了解模型的优势和局限性,有助于做出正确的使用决策。
7.1 优势 #
1. 轻量高效
- 模型文件仅约 90MB,下载和加载速度快
- 参数量小,内存占用低(约 200-300MB)
- 适合在普通硬件上运行,不需要高端 GPU
2. 速度快
- CPU 上也能快速处理(100-200 句子/秒)
- GPU 上速度更快(可达 1000+ 句子/秒)
- 适合实时应用场景
3. 通用性强
- 在多种任务上表现良好(相似度、搜索、聚类等)
- 不需要针对特定任务进行微调
- 开箱即用,上手简单
4. 质量稳定
- 语义表示一致性高
- 相似文本的向量确实相似
- 经过大规模数据训练,可靠性高
5. 易于使用
- API 简单直观,几行代码就能使用
- 文档和示例丰富
- 社区支持好
7.2 局限性 #
1. 序列长度限制
- 最大支持 256 tokens(约 200-300 个中文字符)
- 超长文本需要先分割
- 可能丢失长距离依赖关系
解决方案:
- 对于长文档,先分割成段落或句子
- 分别编码每个片段
- 使用平均或其他方法合并向量
2. 专业领域效果
- 在通用领域表现好
- 在特定专业领域(如医学、法律)可能不如领域专用模型
- 对专业术语的理解可能不够深入
解决方案:
- 对于专业领域,考虑使用领域专用模型
- 或者使用通用模型 + 领域数据微调
3. 多语言支持
- 主要针对英语优化
- 其他语言(如中文)效果也不错,但可能略逊于英语
- 对于某些小众语言支持可能不够好
解决方案:
- 对于中文,可以使用
paraphrase-multilingual-MiniLM-L12-v2 - 对于其他语言,查找相应的多语言模型
4. 细微语义差异
- 对明显的语义差异识别准确
- 对非常细微的语义差异可能不够敏感
- 在某些需要极高精度的场景可能不够
解决方案:
- 对于高精度需求,使用更大的模型
- 或者使用多个模型集成的方法
8. 使用建议和最佳实践 #
根据实际应用经验,以下是一些使用建议和最佳实践。
8.1 批量处理优化 #
批量处理可以显著提高效率,特别是在处理大量文本时。
# 导入必要的库
from sentence_transformers import SentenceTransformer
import time
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备大量文本
sentences = ["这是测试句子。"] * 1000
# 方法 1:逐个处理(不推荐,速度慢)
print("方法 1:逐个处理")
start_time = time.time()
embeddings1 = []
for sentence in sentences[:100]: # 只处理前 100 个作为示例
embedding = model.encode(sentence)
embeddings1.append(embedding)
time1 = time.time() - start_time
print(f"耗时:{time1:.2f} 秒\n")
# 方法 2:批量处理(推荐,速度快)
print("方法 2:批量处理")
start_time = time.time()
# batch_size 可以根据内存情况调整,32 是一个常用的值
embeddings2 = model.encode(sentences[:100], batch_size=32)
time2 = time.time() - start_time
print(f"耗时:{time2:.2f} 秒")
print(f"速度提升:{time1 / time2:.1f} 倍")建议:
- 总是使用批量处理,不要逐个处理
batch_size可以根据内存情况调整(16、32、64 等)- 如果内存充足,增大
batch_size可以提高速度
8.2 相似度阈值选择 #
不同的应用场景需要不同的相似度阈值。
# 导入必要的库
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备测试文本
query = "我想学习机器学习"
documents = [
"机器学习是人工智能的一个分支",
"深度学习使用神经网络",
"今天天气很好",
"机器学习算法可以从数据中学习模式"
]
# 编码文本
query_embedding = model.encode([query])
doc_embeddings = model.encode(documents)
# 计算相似度
similarities = cosine_similarity(query_embedding, doc_embeddings)[0]
# 不同阈值的结果
thresholds = {
"严格匹配": 0.9, # 只返回非常相似的结果
"一般相似": 0.7, # 返回有一定相关性的结果
"宽松匹配": 0.5 # 返回所有可能相关的结果
}
print(f"查询:{query}\n")
for threshold_name, threshold_value in thresholds.items():
print(f"{threshold_name}(阈值 {threshold_value}):")
matches = []
for i, (doc, sim) in enumerate(zip(documents, similarities)):
if sim >= threshold_value:
matches.append((i, doc, sim))
if matches:
for idx, doc, sim in matches:
print(f" - [{idx+1}] 相似度 {sim:.4f}: {doc}")
else:
print(" (无匹配结果)")
print()阈值选择建议:
- 严格匹配(0.9+):用于精确查找、去重等场景
- 一般相似(0.7-0.9):用于搜索、推荐等场景
- 宽松匹配(0.5-0.7):用于探索性搜索、聚类等场景
8.3 处理长文本的最佳实践 #
对于超过模型限制的长文本,需要先分割再处理。
# 导入必要的库
from sentence_transformers import SentenceTransformer
import numpy as np
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备长文本
long_document = """
人工智能是计算机科学的一个分支。它试图理解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器。
机器学习是人工智能的一个子领域。它使计算机能够在没有明确编程的情况下学习和改进。机器学习算法通过分析大量数据来识别模式,并基于这些模式做出预测或决策。
深度学习是机器学习的一个子集。它使用神经网络来模拟人脑的工作方式。深度学习在图像识别、自然语言处理等领域取得了突破性进展。
自然语言处理是人工智能的另一个重要分支。它帮助计算机理解、解释和生成人类语言。现代自然语言处理系统广泛应用于机器翻译、聊天机器人、文本分析等领域。
"""
# 方法 1:按段落分割(推荐用于文档)
def encode_long_text_by_paragraphs(text, model):
"""按段落分割长文本并编码"""
# 按双换行符分割段落
paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
# 编码每个段落
paragraph_embeddings = model.encode(paragraphs)
# 计算平均向量作为文档向量
document_embedding = paragraph_embeddings.mean(axis=0)
return document_embedding, paragraph_embeddings
# 方法 2:按固定长度分割
def encode_long_text_by_chunks(text, model, chunk_size=200):
"""按固定长度分割长文本并编码"""
# 简单的字符级分割(实际应用中可以使用更智能的分割方法)
chunks = []
for i in range(0, len(text), chunk_size):
chunk = text[i:i+chunk_size]
if chunk.strip():
chunks.append(chunk)
# 编码每个块
chunk_embeddings = model.encode(chunks)
# 计算平均向量
document_embedding = chunk_embeddings.mean(axis=0)
return document_embedding, chunk_embeddings
# 使用方法 1
doc_embedding, para_embeddings = encode_long_text_by_paragraphs(long_document, model)
print("方法 1:按段落分割")
print(f"段落数量:{len(para_embeddings)}")
print(f"文档向量维度:{doc_embedding.shape}")
print(f"每个段落向量维度:{para_embeddings[0].shape}\n")
# 使用方法 2
doc_embedding2, chunk_embeddings = encode_long_text_by_chunks(long_document, model, chunk_size=150)
print("方法 2:按固定长度分割")
print(f"块数量:{len(chunk_embeddings)}")
print(f"文档向量维度:{doc_embedding2.shape}")建议:
- 对于结构化文档(如文章),按段落分割效果更好
- 对于非结构化文本,按固定长度分割更简单
- 可以根据具体需求选择合适的分割方法
8.4 保存和加载嵌入向量 #
对于大量文本,可以预先计算并保存嵌入向量,避免重复计算。
# 导入必要的库
from sentence_transformers import SentenceTransformer
import numpy as np
import pickle
import os
# 加载模型
model = SentenceTransformer("all-MiniLM-L6-v2")
# 准备文本数据
documents = [
"这是第一个文档",
"这是第二个文档",
"这是第三个文档"
]
# 计算嵌入向量
embeddings = model.encode(documents)
# 保存嵌入向量和对应的文本
# 方法 1:使用 pickle(简单但文件较大)
save_data = {
"documents": documents,
"embeddings": embeddings
}
with open("embeddings.pkl", "wb") as f:
pickle.dump(save_data, f)
print("嵌入向量已保存到 embeddings.pkl")
# 加载嵌入向量
with open("embeddings.pkl", "rb") as f:
loaded_data = pickle.load(f)
print(f"\n加载成功!")
print(f"文档数量:{len(loaded_data['documents'])}")
print(f"嵌入向量形状:{loaded_data['embeddings'].shape}")
# 方法 2:使用 numpy(更节省空间)
np.save("embeddings.npy", embeddings)
np.save("documents.npy", np.array(documents, dtype=object))
print("\n使用 numpy 格式保存(更节省空间)")
print("嵌入向量已保存到 embeddings.npy")
print("文档已保存到 documents.npy")
# 加载 numpy 格式
loaded_embeddings = np.load("embeddings.npy", allow_pickle=True)
loaded_documents = np.load("documents.npy", allow_pickle=True)
print(f"\n加载成功!")
print(f"文档数量:{len(loaded_documents)}")
print(f"嵌入向量形状:{loaded_embeddings.shape}")建议:
- 对于大量文本,预先计算并保存嵌入向量
- 使用 numpy 格式更节省空间
- 定期更新嵌入向量(如果文本发生变化)
9. 常见问题解答 #
在使用模型的过程中,可能会遇到一些问题。本节列出常见问题及解决方法。
问题 1:首次运行很慢 #
问题描述: 第一次运行代码时,需要很长时间才能开始。
原因:
- 首次运行需要从网络下载模型文件(约 90MB)
- 下载速度取决于网络连接
解决方案:
- 耐心等待首次下载完成
- 下载完成后,模型会缓存在本地,后续运行会很快
- 可以手动下载模型文件到本地
问题 2:内存不足 #
问题描述: 处理大量文本时,出现内存不足的错误。
原因:
- 批量处理的
batch_size设置太大 - 同时处理太多文本
解决方案:
- 减小
batch_size(如从 32 改为 16 或 8) - 分批处理文本,不要一次性处理所有文本
- 处理完一批后释放内存
问题 3:文本被截断 #
问题描述: 长文本的嵌入结果不准确。
原因:
- 文本超过模型的最大序列长度(256 tokens)
- 模型自动截断,丢失了部分信息
解决方案:
- 参考第 8.3 节,先分割长文本再处理
- 按段落或句子分割,分别编码后合并
问题 4:相似度计算不准确 #
问题描述: 明显相似的文本,相似度却很低。
原因:
- 文本确实不相似(需要仔细检查)
- 模型对某些特定领域理解不够
- 文本格式问题(如包含特殊字符)
解决方案:
- 检查文本内容,确认是否真的相似
- 对于专业领域,考虑使用领域专用模型
- 清理文本格式,去除无关字符
问题 5:GPU 未使用 #
问题描述: 有 GPU 但模型仍然使用 CPU,速度很慢。
原因:
- PyTorch 未正确安装 GPU 版本
- GPU 驱动未安装或版本不匹配
解决方案:
- 检查 PyTorch 是否支持 GPU:
import torch; print(torch.cuda.is_available()) - 如果返回
False,需要安装 GPU 版本的 PyTorch - 访问 https://pytorch.org/ 获取安装命令
10. 推荐资源 #
- 官方文档: https://www.sbert.net/
- GitHub 仓库: https://github.com/UKPLab/sentence-transformers
- 模型卡片: https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
- 示例代码: 官方文档中有大量示例