fix(reranker): score HuggingFace reranker with sigmoid, not min-max (#5715)
This commit is contained in:
@@ -59,6 +59,26 @@ class HuggingFaceReranker(BaseReranker):
|
||||
self.model.to(self.device)
|
||||
self.model.eval()
|
||||
|
||||
@staticmethod
|
||||
def _normalize_scores(scores: List[float]) -> List[float]:
|
||||
"""Map raw cross-encoder logits into the [0, 1] range via a sigmoid.
|
||||
|
||||
Cross-encoder rerankers (e.g. ``BAAI/bge-reranker-*``) emit unbounded
|
||||
logits; the documented way to obtain an interpretable [0, 1] relevance
|
||||
score is a per-document sigmoid (``1 / (1 + e^-x)``), which preserves the
|
||||
ranking order.
|
||||
|
||||
This replaces the previous min-max scaling, which produced *set-relative*
|
||||
scores: the lowest-ranked document was always forced to 0.0, and a single
|
||||
document (or any set of tied scores) collapsed to 0.0 — wrongly reporting
|
||||
a result as completely irrelevant. Sigmoid scores each document on its own
|
||||
merit, so those cases are handled naturally.
|
||||
"""
|
||||
if not scores:
|
||||
return []
|
||||
arr = np.asarray(scores, dtype=float)
|
||||
return (1.0 / (1.0 + np.exp(-arr))).tolist()
|
||||
|
||||
def rerank(self, query: str, documents: List[Dict[str, Any]], top_k: int = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Rerank documents using HuggingFace cross-encoder model.
|
||||
@@ -118,9 +138,7 @@ class HuggingFaceReranker(BaseReranker):
|
||||
|
||||
# Normalize scores if requested
|
||||
if self.config.normalize:
|
||||
scores = np.array(scores)
|
||||
scores = (scores - scores.min()) / (scores.max() - scores.min() + 1e-8)
|
||||
scores = scores.tolist()
|
||||
scores = self._normalize_scores(scores)
|
||||
|
||||
# Combine documents with scores
|
||||
doc_score_pairs = list(zip(documents, scores))
|
||||
|
||||
Reference in New Issue
Block a user