Spaces:
Sleeping
Sleeping
| """ | |
| src/evaluation/_bertscore.py | |
| BERTScore F1 ๊ณตํต ํฌํผ โ eval_worker_b / eval_e2e๊ฐ ๋ ๋ค ์ฌ์ฉ. | |
| BERTScore๋ BERT ์๋ฒ ๋ฉ ๊ธฐ๋ฐ ํ ํฐ ๋จ์ ์ ์ฌ๋ โ precision/recall/F1 ์ฐ์ถ. | |
| n-gram(BLEU/ROUGE)๊ณผ ๋ฌ๋ฆฌ ํจ๋ฌํ๋ ์ด์ฆ์ ๋์์ด๋ฅผ ๊ฐํ๊ฒ ์ก์์ฃผ๋ฏ๋ก ์ด๋ฉ์ผ | |
| ๋ต๋ณยทRAG ๋ต๋ณ์ฒ๋ผ ํํ์ด ๋ค์ํ ์ถ๋ ฅ์ ์ ํฉ. | |
| ์ฌ์ฉ: | |
| from src.evaluation._bertscore import compute_bertscore_f1 | |
| per_case, mean = compute_bertscore_f1( | |
| candidates=["the customer asked โฆ", โฆ], | |
| references=["the customer wants โฆ", โฆ], | |
| ) | |
| ์ค๊ณ: | |
| - ์ฒซ ํธ์ถ์์ ๋ชจ๋ธ์ ํ ๋ฒ๋ง ๋ก๋ (lazy + cache). | |
| - bert_score ๋ฏธ์ค์น / ๋ชจ๋ธ ๋ก๋ ์คํจ ์ graceful: per_case=[None,โฆ], mean=None์ ๋ฐํํ๊ณ | |
| ๋ก๊ทธ๋ง ๋จ๊ธด๋ค. ํธ์ถ์๋ ์ด ๊ฐ์ ๊ทธ๋๋ก ๋ฆฌํฌํธ์ None์ผ๋ก ํ๋ ค๋ณด๋ด๋ฉด ๋๋ค. | |
| - ๋น reference/candidate ์์ ์๋์ผ๋ก None ์ฒ๋ฆฌ (์๋ฏธ ๋น๊ต ๋ถ๊ฐ). | |
| - ๋ฉ๋ชจ๋ฆฌ ๋ถ๋ด ์ค์ด๋ ค๊ณ ํ ๋ฒ์ ๋ชจ๋ pair๋ฅผ ๋ฐฐ์น ํธ์ถ. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| from typing import Iterable, Optional | |
| logger = logging.getLogger(__name__) | |
| # bert_score ๋ชจ๋ธ์ ๋ฌด๊ฑฐ์ฐ๋ ์ธ์คํด์ค๋ฅผ ๋ชจ๋ ์บ์์ ๋ โ ๊ฐ์ ํ๋ก์ธ์ค ์์์ ์ฌ๋ฌ ๋ฒ | |
| # ํธ์ถ๋์ด๋ ํ ๋ฒ๋ง ๋ก๋ฉ๋๋๋ก. | |
| _MODEL_TYPE = "microsoft/deberta-xlarge-mnli" # bert_score ๊ถ์ฅ ์๋ฌธ ๋ชจ๋ธ. ์ ํ๋/์๋ ๊ท ํ | |
| _FALLBACK_MODEL = "roberta-large" # ์ ๋ชจ๋ธ ๋ก๋ ์คํจ ์ fallback | |
| _LANG = "en" | |
| def _try_import_bertscore(): | |
| """bert_score import๋ฅผ ์๋ํ๋ค. ์คํจ ์ None์ ๋ฐํํ๊ณ None์ ํธ์ถ์๊ฐ graceful ์ฒ๋ฆฌ.""" | |
| try: | |
| from bert_score import score as bs_score # type: ignore | |
| return bs_score | |
| except Exception as e: | |
| logger.warning( | |
| "[bertscore] bert_score ํจํค์ง๋ฅผ importํ ์ ์์ (%s). " | |
| "BERTScore ๋ฉํธ๋ฆญ์ None์ผ๋ก ์ฑ์์ง๋๋ค. " | |
| "ํ์ฑํํ๋ ค๋ฉด `pip install bert-score`.", | |
| e, | |
| ) | |
| return None | |
| def compute_bertscore_f1( | |
| candidates: Iterable[str], | |
| references: Iterable[str], | |
| *, | |
| model_type: Optional[str] = None, | |
| ) -> tuple[list[Optional[float]], Optional[float]]: | |
| """ํ๋ณด ํ ์คํธ์ ์ฐธ์กฐ ํ ์คํธ ์์ ๋ํด BERTScore F1์ ๊ณ์ฐํ๋ค. | |
| Args: | |
| candidates: ์์ฑ๋ ๋ต๋ณ ๋ฆฌ์คํธ (LLM ์ถ๋ ฅ) | |
| references: ์ ๋ต ํ ์คํธ ๋ฆฌ์คํธ (golden_response ๋๋ rag_evidence) | |
| model_type: ์ฌ์ฉ ๋ชจ๋ธ (๊ธฐ๋ณธ deberta-xlarge-mnli) | |
| Returns: | |
| (per_case_f1, mean_f1) | |
| per_case_f1: ์ผ์ด์ค๋ณ F1 (0.0~1.0). ๋น๊ต ๋ถ๊ฐํ ์ผ์ด์ค๋ None | |
| mean_f1 : ์ ํจ ์ผ์ด์ค๋ค์ ํ๊ท F1. ์ ํจ ์ผ์ด์ค๊ฐ 0๊ฐ๋ฉด None | |
| """ | |
| cand_list = list(candidates) | |
| ref_list = list(references) | |
| if len(cand_list) != len(ref_list): | |
| raise ValueError( | |
| f"candidates({len(cand_list)})์ references({len(ref_list)}) ๊ธธ์ด๊ฐ ๋ค๋ฆ ๋๋ค" | |
| ) | |
| n = len(cand_list) | |
| if n == 0: | |
| return [], None | |
| # ๋น ์์ ๋น๊ต ๋ถ๊ฐ โ ์ธ๋ฑ์ค ๋ณ๋ ๊ธฐ๋ก ํ ๋๋จธ์ง๋ง ๊ณ์ฐ | |
| valid_idx = [ | |
| i for i in range(n) | |
| if (cand_list[i] or "").strip() and (ref_list[i] or "").strip() | |
| ] | |
| if not valid_idx: | |
| logger.info("[bertscore] ์ ํจํ (cand, ref) ์์ด ์์ด ๊ณ์ฐ ์๋ต") | |
| return [None] * n, None | |
| bs_score = _try_import_bertscore() | |
| if bs_score is None: | |
| return [None] * n, None | |
| valid_cands = [cand_list[i] for i in valid_idx] | |
| valid_refs = [ref_list[i] for i in valid_idx] | |
| chosen_model = model_type or _MODEL_TYPE | |
| try: | |
| # bert_score.score๋ (P, R, F1) ํ ์๋ฅผ ๋ฐํ | |
| _P, _R, F1 = bs_score( | |
| valid_cands, valid_refs, | |
| model_type=chosen_model, | |
| lang=_LANG, | |
| verbose=False, | |
| rescale_with_baseline=False, | |
| ) | |
| except Exception as e: | |
| logger.warning( | |
| "[bertscore] ๋ชจ๋ธ %r ๋ก๋/์คํ ์คํจ (%s). %r๋ก ์ฌ์๋.", | |
| chosen_model, e, _FALLBACK_MODEL, | |
| ) | |
| try: | |
| _P, _R, F1 = bs_score( | |
| valid_cands, valid_refs, | |
| model_type=_FALLBACK_MODEL, | |
| lang=_LANG, | |
| verbose=False, | |
| rescale_with_baseline=False, | |
| ) | |
| except Exception as e2: | |
| logger.error("[bertscore] fallback ๋ชจ๋ธ๋ ์คํจ: %s. ๋ฉํธ๋ฆญ None.", e2) | |
| return [None] * n, None | |
| # ํ ์ โ float ๋ฆฌ์คํธ | |
| f1_vals = [float(v) for v in F1.tolist()] | |
| per_case: list[Optional[float]] = [None] * n | |
| for k, i in enumerate(valid_idx): | |
| per_case[i] = round(f1_vals[k], 4) | |
| mean = round(sum(f1_vals) / len(f1_vals), 4) if f1_vals else None | |
| logger.info( | |
| "[bertscore] mean F1 = %s over %d/%d valid pairs (model=%s)", | |
| mean, len(valid_idx), n, chosen_model, | |
| ) | |
| return per_case, mean | |