YohanAcxias commited on
Commit
025c7ea
·
verified ·
1 Parent(s): d70f155

Update handler.py

Browse files
Files changed (1) hide show
  1. handler.py +67 -41
handler.py CHANGED
@@ -335,73 +335,99 @@ class EndpointHandler:
335
  weights: Tuple[float, float, float, float] = (1.0, 0.6, 0.8, 0.5),
336
  rerank_topn: int = 40,
337
  debug_topn: int = 10,
 
338
  ) -> Dict[str, Any]:
339
  w_sup, w_seg, w_cat, w_rerank = weights
340
-
341
- # maps
342
- sup_map = {x["s4_code"]: float(x["score"]) for x in sup}
343
- seg_map = defaultdict(float)
344
- cat_map = defaultdict(float)
345
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  # candidate texts for rerank (prefer cleaned)
347
  text_map = {}
348
-
349
  for x in seg:
350
- code = x["s4_code"]
351
- seg_map[code] = max(seg_map[code], float(x.get("score_01", 0.0)))
352
  txt = x.get("label_text_clean") or x.get("label_text") or code
353
  text_map[code] = txt
354
-
355
  for x in cat:
356
- code = x["s4_code"]
357
- cat_map[code] = max(cat_map[code], float(x.get("score_01", 0.0)))
358
  txt = x.get("label_text_clean") or x.get("label_text") or code
359
- # keep existing if seg provided (often better), else catalog
360
  text_map.setdefault(code, txt)
361
-
362
- candidates = set(sup_map.keys()) | set(seg_map.keys()) | set(cat_map.keys())
363
  if not candidates:
364
  return {"prediction": None, "method": "no_candidates", "fused_topk": []}
365
-
366
  fused = []
367
  for code in candidates:
368
- s_sup = sup_map.get(code, 0.0)
369
- s_seg = seg_map.get(code, 0.0)
370
- s_cat = cat_map.get(code, 0.0)
371
-
372
- base = (w_sup * s_sup) + (w_seg * s_seg) + (w_cat * s_cat)
373
- fused.append(
374
- {
375
- "s4_code": code,
376
- "score": float(base),
377
- "components": {"sup": float(s_sup), "seg": float(s_seg), "cat": float(s_cat)},
378
- "text_for_rerank": text_map.get(code, code),
379
- }
380
  )
381
-
 
 
 
 
 
 
 
 
 
 
 
 
382
  fused.sort(key=lambda x: x["score"], reverse=True)
383
-
384
- # semantic query cleaning also for rerank query side
385
  rerank_query = self._make_semantic_query(raw_query) or raw_query.replace("\n", " ").replace("\r", " ")
386
  rerank_query = re.sub(r"\s+", " ", rerank_query).strip()
387
-
388
  if use_rerank and self.reranker is not None and fused:
389
  topn = fused[: min(rerank_topn, len(fused))]
390
  pairs = [[rerank_query, c["text_for_rerank"]] for c in topn]
 
391
  rr_raw = self.reranker.predict(pairs).tolist()
392
- rr_01 = minmax_norm([float(v) for v in rr_raw])
393
-
394
- for c, rraw, r01 in zip(topn, rr_raw, rr_01):
395
- c["rerank_raw"] = float(rraw)
396
- c["rerank_01"] = float(r01)
397
- c["score"] = float(c["score"] + w_rerank * float(r01))
398
-
 
 
 
 
 
399
  fused[: len(topn)] = topn
400
  fused.sort(key=lambda x: x["score"], reverse=True)
401
-
402
  return {
403
  "prediction": fused[0],
404
- "method": "fused_score",
405
  "fused_topk": fused[:debug_topn],
406
  }
407
 
 
335
  weights: Tuple[float, float, float, float] = (1.0, 0.6, 0.8, 0.5),
336
  rerank_topn: int = 40,
337
  debug_topn: int = 10,
338
+ rrf_k: int = 60, # bigger = ranks matter a bit less
339
  ) -> Dict[str, Any]:
340
  w_sup, w_seg, w_cat, w_rerank = weights
341
+
342
+ def rrf(rank: Optional[int]) -> float:
343
+ # rank is 1-based. Missing => 0 contribution
344
+ if rank is None:
345
+ return 0.0
346
+ return 1.0 / (rrf_k + rank)
347
+
348
+ def build_rank_map(items: List[Dict[str, Any]], code_key="s4_code") -> Dict[str, int]:
349
+ # assumes items already ordered best->worst
350
+ out = {}
351
+ r = 1
352
+ for x in items:
353
+ code = str(x.get(code_key))
354
+ if code and code not in out:
355
+ out[code] = r
356
+ r += 1
357
+ return out
358
+
359
+ # --- build rank maps (order matters) ---
360
+ sup_rank = build_rank_map(sup)
361
+
362
+ # seg/cat are already in FAISS best->worst order
363
+ seg_rank = build_rank_map(seg)
364
+ cat_rank = build_rank_map(cat)
365
+
366
  # candidate texts for rerank (prefer cleaned)
367
  text_map = {}
 
368
  for x in seg:
369
+ code = str(x["s4_code"])
 
370
  txt = x.get("label_text_clean") or x.get("label_text") or code
371
  text_map[code] = txt
 
372
  for x in cat:
373
+ code = str(x["s4_code"])
 
374
  txt = x.get("label_text_clean") or x.get("label_text") or code
 
375
  text_map.setdefault(code, txt)
376
+
377
+ candidates = set(sup_rank.keys()) | set(seg_rank.keys()) | set(cat_rank.keys())
378
  if not candidates:
379
  return {"prediction": None, "method": "no_candidates", "fused_topk": []}
380
+
381
  fused = []
382
  for code in candidates:
383
+ # rank-based fusion (scale-free)
384
+ score = (
385
+ w_sup * rrf(sup_rank.get(code))
386
+ + w_seg * rrf(seg_rank.get(code))
387
+ + w_cat * rrf(cat_rank.get(code))
 
 
 
 
 
 
 
388
  )
389
+
390
+ fused.append({
391
+ "s4_code": code,
392
+ "score": float(score),
393
+ "components": {
394
+ # keep some debug info (ranks + raw supervised prob if exists)
395
+ "sup_rank": sup_rank.get(code),
396
+ "seg_rank": seg_rank.get(code),
397
+ "cat_rank": cat_rank.get(code),
398
+ },
399
+ "text_for_rerank": text_map.get(code, code),
400
+ })
401
+
402
  fused.sort(key=lambda x: x["score"], reverse=True)
403
+
404
+ # --- optional rerank: use rank, NOT minmax ---
405
  rerank_query = self._make_semantic_query(raw_query) or raw_query.replace("\n", " ").replace("\r", " ")
406
  rerank_query = re.sub(r"\s+", " ", rerank_query).strip()
407
+
408
  if use_rerank and self.reranker is not None and fused:
409
  topn = fused[: min(rerank_topn, len(fused))]
410
  pairs = [[rerank_query, c["text_for_rerank"]] for c in topn]
411
+
412
  rr_raw = self.reranker.predict(pairs).tolist()
413
+
414
+ # rank reranker outputs (best = rank 1)
415
+ order = np.argsort(-np.array(rr_raw))
416
+ rr_rank_map = {}
417
+ for r, idx in enumerate(order, start=1):
418
+ rr_rank_map[idx] = r
419
+
420
+ for i, c in enumerate(topn):
421
+ c["rerank_raw"] = float(rr_raw[i])
422
+ c["rerank_rank"] = rr_rank_map[i]
423
+ c["score"] = float(c["score"] + w_rerank * rrf(c["rerank_rank"]))
424
+
425
  fused[: len(topn)] = topn
426
  fused.sort(key=lambda x: x["score"], reverse=True)
427
+
428
  return {
429
  "prediction": fused[0],
430
+ "method": "fused_rrf_rank",
431
  "fused_topk": fused[:debug_topn],
432
  }
433