Skip to main content

all-MiniLM-L6-v2

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. 推荐资源