导航菜单

  • 1.vector
  • 2.milvus
  • 3.pymilvus
  • 4.rag
  • 5.rag_measure
  • 7.search
  • ragflow
  • heapq
  • HNSW
  • cosine_similarity
  • math
  • typing
  • etcd
  • minio
  • collections
  • jieba
  • random
  • beautifulsoup4
  • chromadb
  • sentence_transformers
  • numpy
  • lxml
  • openpyxl
  • PyMuPDF
  • python-docx
  • requests
  • python-pptx
  • text_splitter
  • all-MiniLM-L6-v2
  • openai
  • llm
  • BPETokenizer
  • Flask
  • RAGAS
  • BagofWords
  • langchain
  • Pydantic
  • abc
  • faiss
  • MMR
  • scikit-learn
  • 1. 什么是 all-MiniLM-L6-v2?
  • 2. 前置知识补充
    • 2.1 什么是文本嵌入(Embedding)?
    • 2.2 什么是句子嵌入(Sentence Embedding)?
    • 2.3 什么是知识蒸馏(Knowledge Distillation)?
    • 2.4 什么是余弦相似度(Cosine Similarity)?
  • 3. 安装和基本使用
    • 3.1 安装 Sentence Transformers
      • Windows 系统安装
      • macOS 系统安装
    • 3.2 验证安装
    • 3.3 第一个示例:将文本转换为向量
  • 4. 模型基本信息
    • 4.1 模型规格
    • 4.2 模型架构说明
    • 4.3 查看模型详细信息
  • 5. 实际应用示例
    • 5.1 示例 1:计算文本相似度
    • 5.2 示例 2:语义搜索
    • 5.3 示例 3:批量处理文本
    • 5.4 示例 4:处理长文本
  • 6. 性能特点
    • 6.1 计算效率测试
    • 6.2 与其他模型对比
    • 6.3 语义表示能力测试
  • 7. 优势和局限性
    • 7.1 优势
    • 7.2 局限性
  • 8. 使用建议和最佳实践
    • 8.1 批量处理优化
    • 8.2 相似度阈值选择
    • 8.3 处理长文本的最佳实践
    • 8.4 保存和加载嵌入向量
  • 9. 常见问题解答
    • 问题 1:首次运行很慢
    • 问题 2:内存不足
    • 问题 3:文本被截断
    • 问题 4:相似度计算不准确
    • 问题 5:GPU 未使用
  • 10. 推荐资源

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
  • 示例代码: 官方文档中有大量示例

访问验证

请输入访问令牌

Token不正确,请重新输入