使用 Milvus 和 Hugging Face 进行问答
基于语义搜索的问答系统通过在问题-答案对数据集中找到与给定查询问题最相似的问题来工作。一旦确定了最相似的问题,数据集中相应的答案被视为查询的答案。这种方法依赖于语义相似度度量来确定问题之间的相似性,并检索相关答案。
本教程展示了如何使用 Hugging Face 作为数据加载器和嵌入生成器,以进行数据处理,并使用 Milvus 作为语义搜索的向量数据库来构建问答系统。
开始之前
您需要确保已安装所有必需的依赖项:
pymilvus
:与由 Milvus 或 Zilliz Cloud 提供支持的向量数据库服务一起使用的 Python 包。datasets
、transformers
:Hugging Face 包,用于管理数据和利用模型。torch
:一个强大的库,提供高效的张量计算和深度学习工具。
$ pip install --upgrade pymilvus transformers datasets torch
如果您正在使用 Google Colab,在启用刚安装的依赖项时,您可能需要重新启动运行时。
准备数据
在本节中,我们将从 Hugging Face Datasets 中加载示例问题-答案对。作为演示,我们仅从 SQuAD 的验证集中获取部分数据。
from datasets import load_dataset
DATASET = "squad" # 来自 HuggingFace Datasets 的数据集名称
INSERT_RATIO = 0.001 # 要插入的示例数据集比例
data = load_dataset(DATASET, split="validation")
# 生成一个固定的子集。要生成一个随机子集,请删除 seed。
data = data.train_test_split(test_size=INSERT_RATIO, seed=42)["test"]
# 清理数据集中的数据结构。
data = data.map(
lambda val: {"answer": val["answers"]["text"][0]},
remove_columns=["id", "answers", "context"],
)
查看示例数据的摘要
print(data)
Dataset({
features: ['title', 'question', 'answer'],
num_rows: 11
})
为了为问题生成嵌入向量,您可以从Hugging Face Models中选择一个文本嵌入模型。在本教程中,我们将使用一个小型的句子嵌入模型 all-MiniLM-L6-v2 作为示例。
from transformers import AutoTokenizer, AutoModel
import torch
MODEL = (
"sentence-transformers/all-MiniLM-L6-v2" # 模型名称来自 HuggingFace Models
)
INFERENCE_BATCH_SIZE = 64 # 模型推断的批处理大小
# 从 HuggingFace Hub 加载分词器 和模型
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModel.from_pretrained(MODEL)
def encode_text(batch):
# 对句子进行分词
encoded_input = tokenizer(
batch["question"], padding=True, truncation=True, return_tensors="pt"
)
# 计算标记嵌入
with torch.no_grad():
model_output = model(**encoded_input)
# 执行池化
token_embeddings = model_output[0]
attention_mask = encoded_input["attention_mask"]
input_mask_expanded = (
attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
)
sentence_embeddings = torch.sum(
token_embeddings * input_mask_expanded, 1
) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
# 规范化嵌入
batch["question_embedding"] = torch.nn.functional.normalize(
sentence_embeddings, p=2, dim=1
)
return batch
data = data.map(encode_text, batched=True, batch_size=INFERENCE_BATCH_SIZE)
data_list = data.to_list()