在两阶段检索系统中,第一阶段的嵌入模型负责从庞大的数据集中快速检索出一组与查询相关的候选文档。嵌入模型通过将文档和查询转换为向量表示,计算它们之间的相似度,进而筛选出可能相关的文档。由于嵌入模型能够将复杂的文本信息压缩成固定长度的向量,因此这一过程非常高效,尤其适用于处理大规模数据集。
然而,嵌入模型在压缩文本信息时会丢失部分上下文信息,导致它的准确率不如重新排序器。为了解决这一问题,在第二阶段,我们使用重新排序器对嵌入模型筛选出的候选文档进行精细排序。重新排序器通常基于更加复杂的深度神经网络模型,能够更好地理解文档与查询之间的上下文关联,从而提供更高的排序精度。
为什么要使用重新排序器?
既然嵌入模型已经能够提供初步筛选结果,为什么还需要额外的重新排序器呢?答案在于准确性。嵌入模型在转换文本时不可避免地会丢失信息,尤其是在面对复杂的查询和文档时,它无法完全捕捉到两者之间的微妙差异。这是因为嵌入模型必须将文档的所有可能含义压缩为一个向量,而这个向量只能表达某种通用的平均含义,无法针对特定的查询做出精准的响应。
相比之下,重新排序器可以避免这种信息丢失。重新排序器直接处理查询和文档的原始信息,可以更精细地分析文档内容如何与查询相关联,从而提供更准确的排序结果。由于重新排序器是在收到用户查询后运行的,因此它可以结合查询的上下文对文档进行更为精准的分析,而不是依赖于嵌入模型的平均化表示。
Reranker与embedding模型的区别
尽管Reranker和Embedding模型都用于信息检索系统,它们的定位和功能却是不同的。
Embedding模型主要用于初步筛选文档。它将文本转换为向量表示,并计算这些向量之间的相似度,从而筛选出一组可能相关的候选文档。Embedding模型的优势在于它的计算效率高,适合处理大规模数据集。
Reranker则用于对Embedding模型筛选出的候选文档进行精细排序。Reranker通常基于复杂的深度神经网络,能够更好地理解文本的上下文和细微差异,从而提供更高的排序精度。
简单来说,Embedding模型负责“找出一批可能相关的候选文档”,而Reranker负责“在这些候选文档中找出最相关的,并将它们按相关性排序”。
Reranker能否直接用于检索?
理论上,Reranker可以直接用于检索,但在实际应用中并不常见。这是因为Reranker的计算复杂度较高,直接使用它对整个数据集进行排序会导致极高的计算成本,难以满足实时性要求。因此,通常我们会先用Embedding模型进行初步筛选,将文档集合缩小到一个合理的范围,然后再使用Reranker进行精细排序。
代码示例:使用Reranker对候选文档重新排序
以下是一个简单的Reranker实现示例(基于阿里魔塔开源的gte),展示了如何使用模型对候选文档进行重新排序。
import torch
import torch.nn.functional as F
from modelscope import AutoModelForSequenceClassification, AutoTokenizer
# 初始化模型和分词器
model_name_or_path = "iic/gte_passage-ranking_multilingual-base"
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
model = AutoModelForSequenceClassification.from_pretrained(model_name_or_path, trust_remote_code=True)
model.eval()
# 示例数据
query = "中国的首都在哪儿"
documents = [
"中国的首都在哪",
"北京。",
"上海是中国的一个主要城市。"
]
def reranker(query, documents):
with torch.no_grad():
# 创建 (query, document) 对
pairs = [[query, text] for text in documents]
# 对输入对进行分词
inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors='pt', max_length=8192)
# 通过模型计算得分
scores = model(**inputs, return_dict=True).logits.view(-1, ).float()
# 将得分转换为百分比形式的概率
probabilities = F.softmax(scores, dim=0) * 100
# 将文档与其对应的概率结合
ranked_results = list(zip(documents, probabilities.tolist()))
# 根据概率降序排序结果
ranked_results.sort(key=lambda x: x[1], reverse=True)
return ranked_results
# 运行 Reranker 并输出排序结果
ranked_documents = reranker(query, documents)
print(ranked_documents)
这段代码中,我把结果输出为根据rerank计算的相似度百分比,3条数据大约运行了1.2s,花费时间还是比较久的,结果如下:
[('中国的首都在哪', 90.24225616455078), ('北京。', 6.394253730773926), ('上海是中国的一个主要城市。', 3.363481044769287)]
结合Embedding模型和Reranker的优势,实现了效率和准确性的平衡。Embedding模型负责快速筛选候选文档,而Reranker则通过更细致的分析对这些文档进行精准排序,虽然其的计算开销较高,但它在提升排序准确性方面的作用不可忽视。