sentence-transformers 的 Natural Questions 模型:基于 nq-distilbert-base-v1 构建问答检索系统
sentence-transformers 的 Natural Questions 模型基于 nq-distilbert-base-v1 构建问答检索系统【免费下载链接】sentence-transformersState-of-the-Art Embeddings, Retrieval, and Reranking项目地址: https://gitcode.com/gh_mirrors/se/sentence-transformers本指南围绕 sentence-transformers 官方预训练模型nq-distilbert-base-v1展开介绍其背后的 Natural Questions 数据集、问答式question-answer检索的使用方法、段落编码格式标题 正文以及 MRR10 评估指标并结合仓库中的语义搜索示例与检索评估器源码说明如何在真实问答检索场景中落地。读完本文你将掌握用单个 Bi-Encoder 模型完成问题 → Wikipedia 段落检索的完整流程并理解其性能优势的度量方式。Natural Questions 数据集与模型定位nq-distilbert-base-v1是 sentence-transformers 基于Google 的 Natural Questions 数据集训练的双编码器Bi-Encoder模型。Natural Questions 数据集包含约 10 万条来自 Google 搜索的真实用户查询以及从 Wikipedia 中标注出的包含答案的相关段落。正因为训练数据来自真实搜索日志基于该数据集训练的模型在问题-答案检索question-answer retrieval这类非对称检索任务上表现良好——即查询是口语化的自然语言问题而检索目标是长篇知识段落。该模型的定位可见于仓库示例 semantic_search_wikipedia_qa.py 中的说明它专门针对 Natural Questions 数据集训练适用于问答检索在 semantic_search_nq_opensearch.py 中同样被明确描述为专门为 Natural Questions 数据集上的问答训练。基本用法一行代码加载模型按照 nq-v1.md 的用法说明加载与使用模型非常直接from sentence_transformers import SentenceTransformer model SentenceTransformer(sentence-transformers/nq-distilbert-base-v1) query_embedding model.encode(How many people live in London?) # The passages are encoded as [ [title1, text1], [title2, text2], ...] passage_embedding model.encode( [[London, London has 9,787,426 inhabitants at the 2011 census.]] ) print(Similarity:, model.similarity(query_embedding, passage_embedding))其中query_embedding与passage_embedding都是固定维度的稠密向量model.similarity(...)返回两批嵌入两两之间的相似度矩阵。查询向量形状为[embedding_dim]段落向量形状为[num_passages, embedding_dim]二者点积后得到[num_passages]的相似度分数。关键细节段落必须以标题 正文形式编码原文档特别强调了一个极易踩坑的细节编码段落时必须将 Wikipedia 文章标题与正文段落拼接在一起即传入形如[London, London has 9,787,426 inhabitants at the 2011 census.]的成对输入对应[[title1, text1], [title2, text2], ...]的列表。这一设计的原因在于Natural Questions 数据集中的答案段落天然带有来源文章标题训练时模型正是以标题 段落文本作为段落侧输入。因此推理阶段也必须保持同样的输入格式否则标题这一关键上下文信息缺失检索效果会明显下降。这一约定在仓库示例中得到了完整贯彻。在 semantic_search_wikipedia_qa.py 中Simple English Wikipedia 的每个段落都被组织为[data[title], paragraph]passages [] with gzip.open(wikipedia_filepath, rt, encodingutf8) as fIn: for line in fIn: data json.loads(line.strip()) for paragraph in data[paragraphs]: # We encode the passages as [title, text] passages.append([data[title], paragraph])实战基于 Simple English Wikipedia 的问答语义搜索仓库提供了开箱即用的端到端示例 semantic_search_wikipedia_qa.py展示完整的问答检索链路。由于完整英文 Wikipedia 体量过大示例选用约 17 万篇文章的 Simple English Wikipediasimplewiki-2020-11-01将文章切分为段落并与标题组合成[title, text]结构。整体流程如下加载 Bi-Encoder 模型sentence-transformers/nq-distilbert-base-v1下载并解析语料若本地无data/simplewiki-2020-11-01.jsonl.gz则自动下载逐行解析 JSON将每个段落组织为[title, paragraph]编码语料使用bi_encoder.encode(passages, convert_to_tensorTrue, show_progress_barTrue)预计算全部段落向量示例还提供了simplewiki-2020-11-01-nq-distilbert-base-v1.pt预计算嵌入文件可直接torch.load加载以跳过耗时的语料编码步骤交互式问答检索循环接收用户输入问题用semantic_search(question_embedding, corpus_embeddings, top_ktop_k)在全部段落嵌入中检索 top-5 命中并输出(score, [title, text])。semantic_search来自 sentence_transformers/util/init.py其核心是对语料嵌入与查询嵌入做批量内积排序。该示例完整演示了真实查询 → 语义检索 → 返回带标题段落的问答式检索闭环适合作为二次开发的基础模板。进阶与 OpenSearch 集成实现混合检索如果语料规模超出内存可容纳范围仓库在 semantic_search_nq_opensearch.py 中提供了基于 OpenSearch 的向量检索方案思路与内存版一致从sentence-transformers/natural-questions数据集加载 1 万个答案段落作为语料load_dataset用nq-distilbert-base-v1将段落编码为 768 维向量model.encode(corpus, batch_size32)在 OpenSearch 中创建含knn_vector维度 768、space_type: cosinesimil、HNSW 方法映射的索引将answer原文与answer_vector批量写入查询时既执行基于knn查询的语义检索也执行基于match查询的 BM25 关键词检索两种结果并排输出以便对比。该示例表明nq-distilbert-base-v1不仅可用于内存内语义搜索也能与主流向量数据库配合构建可横向扩展的问答检索服务。性能NQ dev 集上的 MRR10 对比原文档给出了模型在 Natural Questions 开发集small 子集上的 MRR10 评测结果ApproachMRR10 (NQ dev set small)nq-distilbert-base-v172.36Other modelsDPR58.96MRR10Mean Reciprocal Rank10是检索排序的标准指标对每个查询若第一个相关文档出现在第 k 位k ≤ 10则记分 1/k否则记 0最后对所有查询取平均。从结果看nq-distilbert-base-v1以 72.36 显著高于 DPRDense Passage Retrieval基线模型的 58.96体现了单模型双编码器在问答检索上的竞争力。仓库对 MRR 的计算有完整的源码实现可供参照。在 information_retrieval.py 的InformationRetrievalEvaluator.compute_metrics中检索器按分数降序排序每个查询的命中结果随后遍历 top-k 命中若命中corpus_id属于相关文档集合则累加1.0 / (rank 1)并跳出循环# MRRk for k_val in self.mrr_at_k: for rank, hit in enumerate(top_hits[0:k_val]): if hit[corpus_id] in query_relevant_docs: MRR[k_val] 1.0 / (rank 1) break最终MRR[k_val] / len(self.queries)对所有查询取平均。评估器默认mrr_at_k[10]information_retrieval.py且同时支持 Accuracyk、Precision/Recallk、NDCGk、MAPk 等多种指标可复用于自定义检索评测。相似度计算底层similarity 方法与余弦相似度model.similarity(...)的实现位于 sentence_transformer/model.py。SentenceTransformer通过similarity_fn_name属性默认cosine见 model.py确定相似度函数并在首次访问时惰性初始化。similarity接收两批嵌入返回形状为[num_embeddings_1, num_embeddings_2]的相似度矩阵def similarity(self, embeddings1, embeddings2): # Access similarity_fn_name to trigger lazy initialization of _similarity self.similarity_fn_name # noqa: B018 return self._similarity(embeddings1, embeddings2)除余弦相似度外还可通过similarity_fn_name切换为dot、euclidean、manhattan。需要说明的是对于nq-distilbert-base-v1这类基于 Natural Questions 训练的检索模型编码后的嵌入已做过归一化处理使用默认余弦相似度即可获得正确的排序效果。与其他预训练检索模型的关系DPR 模型文档 提供了另一类问答检索基线的用法DPR 采用双塔结构——question_encoder编码查询、ctx_encoder编码段落两塔不可互换段落侧同样需要标题信息但以London [SEP] London is the capital ...的显式[SEP]分隔格式输入且必须使用**点积dot-product**而非余弦相似度。对比之下nq-distilbert-base-v1的优势在于单一模型即可同时编码查询与段落输入格式统一段落为[title, text]列表并使用默认的余弦相似度工程实现更简洁。两者在 nq-v1.md 的 MRR10 对比中差距明显72.36 vs 58.96这也是推荐优先选用nq-distilbert-base-v1的依据。小结与适用场景nq-distilbert-base-v1是 sentence-transformers 生态中面向问答检索的成熟预训练模型。将其投入生产时需要牢记三个要点输入格式段落必须是[title, text]成对结构标题信息不可省略评估口径官方成绩基于 NQ dev 集的 MRR10可用 information_retrieval.py 中的InformationRetrievalEvaluator复现或扩展评估规模扩展小语料可直接在内存中执行semantic_search参考 semantic_search_wikipedia_qa.py大规模语料可借助 OpenSearch 等向量数据库落地参考 semantic_search_nq_opensearch.py。对于需要从真实自然语言问题中检索 Wikipedia 知识段落的场景该模型是开箱即用、效果经过验证的首选方案之一。【免费下载链接】sentence-transformersState-of-the-Art Embeddings, Retrieval, and Reranking项目地址: https://gitcode.com/gh_mirrors/se/sentence-transformers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考