File size: 4,486 Bytes
e000be4
 
 
 
 
d504def
e000be4
 
d504def
 
e000be4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d504def
e000be4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from __future__ import annotations
"""
๊ฒฐํ•ฉ(bundle-v3) Intent ๋ถ„ํฌ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ (๋กœ์ง ๊ณ ๋„ํ™”์šฉ).

๊ฐ ํŽ˜๋ฅด์†Œ๋‚˜๊ฐ€ ์„ค๋ฌธ(๋Œ€ํ‘œ ๋‹ต๋ณ€)์— ์‘๋‹ตํ•˜๊ณ  ๋Œ€ํ‘œ ํ–‰๋™ ์‹œํ€€์Šค๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์„ ๋•Œ,
๊ธฐ๋Œ€ intent(expected_intents)๊ฐ€ ์ƒ์œ„ ๋ถ„ํฌ์— ๋œจ๋Š”์ง€ ์ ์ˆ˜ํ™”ํ•ด "๋‚ฉ๋“ ๊ฐ€๋Šฅํ•œ ๋ถ„ํฌ"์ธ์ง€ ํ‰๊ฐ€ํ•œ๋‹ค.

์ง€ํ‘œ:
  - cov@5 / cov@10 : expected_intents ์ค‘ final top-5/top-10์— ๋“  ๋น„์œจ
  - avg_rank       : expected_intents์˜ ํ‰๊ท  final ์ˆœ์œ„ (๋‚ฎ์„์ˆ˜๋ก ์ข‹์Œ)
  - ํŽ˜๋ฅด์†Œ๋‚˜๋ณ„ + ์ „์ฒด ํ‰๊ท 

์‹คํ–‰: python scripts/sim_bundle.py [--behavior]   (--behavior: ๋Œ€ํ‘œ ํ–‰๋™ ์‹œํ€€์Šค๊นŒ์ง€ ๋ฐ˜์˜)
"""
import argparse
import random
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

from core.engines import config                              # noqa: E402
from core.extractor import get_extractor                     # noqa: E402
from core.inference import infer_batch, infer_with_behavior, to_topn_with_others  # noqa: E402
from scripts.build_bundle_dataset import PERSONAS            # noqa: E402

SID = "bundle-v3"


def _sample_answers(answer_dist: dict, rng: random.Random) -> dict[str, str]:
    """answer_dist ๋ถ„ํฌ์—์„œ 1๋ช…์˜ ์‘๋‹ต์„ ์ƒ˜ํ”Œ๋ง (์‹ค์ œ ์‹œ์—ฐ์ž ์‘๋‹ต์„ ๋ชจ์‚ฌ)."""
    return {qid: rng.choices(list(d), weights=list(d.values()), k=1)[0]
            for qid, d in answer_dist.items()}


def _behavior_map() -> dict[str, tuple[str, str]]:
    """behavior_id โ†’ (event_type, entity). BACK/EXIT ํฌํ•จ."""
    bc = config.get_behaviors(SID)
    m: dict[str, tuple[str, str]] = {}
    for b in bc["step1"]["behaviors"]:
        m[b["id"]] = (b["event_type"], b["entity"])
    for items in bc["step2"]["by_parent"].values():
        for b in items:
            m[b["id"]] = (b["event_type"], b["entity"])
    for b in bc["step2"].get("common", []):
        m[b["id"]] = (b["event_type"], b["entity"])
    m.setdefault("BACK", ("navigate_back", "back_to_step1"))
    m.setdefault("EXIT", ("app_exit", "session_end"))
    return m


def _intent_names() -> dict[str, str]:
    return {i["id"]: i["name"] for i in config.get_taxonomy(SID)["intents"]}


def _rank_of(scores: list, intent_id: str) -> int:
    """final ์ˆœ์œ„(1-๊ธฐ๋ฐ˜). ์—†์œผ๋ฉด 999."""
    for s in scores:
        if s.intent_id == intent_id:
            return s.rank
    return 999


def run(use_behavior: bool, k: int = 40, seed: int = 7) -> None:
    """ํŽ˜๋ฅด์†Œ๋‚˜๋งˆ๋‹ค answer_dist์—์„œ k๋ช…์„ ์ƒ˜ํ”Œ๋งํ•ด cov@5/10ยทavg_rank ํ‰๊ท  (๋ถ„ํฌ ์ถฉ์‹ค)."""
    bmap = _behavior_map()
    ext = get_extractor()
    rng = random.Random(seed)

    p_cov5, p_cov10, rank_all = [], [], []
    for p in PERSONAS:
        expected = p["expected_intents"]
        c5s, c10s, rks = [], [], []
        for j in range(k):
            answers = _sample_answers(p["answer_dist"], rng)
            if use_behavior:
                seq = rng.choice(p["action_seqs"])
                sess = f"__sim__{p['id']}_{j}"
                ext.reset(sess)
                for bid in seq:
                    et, ent = bmap.get(bid, (None, None))
                    if et:
                        ext.add_event(sess, et, ent)
                _, scores = infer_with_behavior(answers, sess, SID)
                ext.reset(sess)
            else:
                _, scores = infer_batch(answers, SID)

            top_ids = [s.intent_id for s in sorted(scores, key=lambda s: s.final_score, reverse=True)]
            top5, top10 = set(top_ids[:5]), set(top_ids[:10])
            c5s.append(sum(1 for e in expected if e in top5) / len(expected))
            c10s.append(sum(1 for e in expected if e in top10) / len(expected))
            rks.extend(_rank_of(scores, e) for e in expected)

        cov5, cov10 = sum(c5s) / k, sum(c10s) / k
        p_cov5.append(cov5); p_cov10.append(cov10); rank_all.extend(rks)
        print(f"   {p['id']} {p['name'][:22]:22} cov@5={cov5:.2f} cov@10={cov10:.2f} "
              f"avg_rank={sum(rks)/len(rks):4.1f}")

    n = len(PERSONAS)
    print("=" * 64)
    print(f"  ์ „์ฒด ํ‰๊ท   cov@5={sum(p_cov5)/n:.3f}  cov@10={sum(p_cov10)/n:.3f}  "
          f"avg_rank={sum(rank_all)/len(rank_all):.1f}  ({'ํ–‰๋™๋ฐ˜์˜' if use_behavior else '์„ค๋ฌธ๋งŒ'}, k={k})")
    print("=" * 64)


if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--behavior", action="store_true", help="๋Œ€ํ‘œ ํ–‰๋™ ์‹œํ€€์Šค๊นŒ์ง€ ๋ฐ˜์˜")
    args = ap.parse_args()
    run(args.behavior)