File size: 7,489 Bytes
07f059a | 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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | from __future__ import annotations
"""
๊ฒฐํฉ(bundle-v3) ๋๊ท๋ชจ ๋๋ค ์คํธ๋ ์ค ์๋ฎฌ๋ ์ด์
โ ์๋ ๋ณํ ์ ์ ์ฑยท์ด์ ์ผ์ด์ค ํ์ง.
- ์ค๋ฌธ: ๋ฌด์์ N_SURVEY๊ฑด (์ ์ 1,870๋ง์ ๋ถ๊ฐ โ ๋๊ท๋ชจ ์ํ)
- ํ๋: N_SESS ์ธ์
ร ์ธ์
๋น ์ต๋ MAX_ACT ํด๋ฆญ (ํด๋ฆญ ๊ธฐ๋ฐ ์๋์ฐ ๊ฐ์ )
- ์งํ๋ฐ๋ /tmp/cs_sim_progress.txt ์ in-place ๊ธฐ๋ก (tail -f ๋ก ๊ด๋)
- ์์ฝ์ stdout, ์์ธ๋ /tmp/cs_sim_report.json
ํ์ง ์ด์:
E1 ๋ฒ์/NaN (scoreโ[0,1])
E2 ๋ฒ์ฉ intent(AI์ถ์ฒ๋ฅ) top-5 ๋์ถ
E3 ์์ ๋์ (top-1๊ณผ ๋๋ฅ ์ด top-5 ๋ด 3๊ฐ ์ด์)
E4 ํ๋ ๋ฌด๋ฐ์ (ํด๋ฆญ entity์ ์ ํธ intent๊ฐ top-10์๋ ๋ชป ๋ฆ)
E5 stuck (top-1์ด โฅSTUCK_N ์ฐ์ ๊ณ ์ )
+ ๋ถํฌ ๊ฑด์ ์ฑ(top-1 ๋ค์์ฑ/HHI), entity๋ณ ๋ฐ์๋ฅ
"""
import json, random, sys, time
from collections import Counter, defaultdict
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 # noqa: E402
SID = "bundle-v3"
N_SURVEY = 30_000
N_SESS = 8_000
MAX_ACT = 30
STUCK_N = 15
GENERIC = set() # bundle: ๋ฒ์ฉ intent ์์ (E2 N/A)
PROG = "/tmp/bundle_sim_progress.txt"
REPORT = "/tmp/bundle_sim_report.json"
tax = config.get_taxonomy(SID)["intents"]
NM = {i["id"]: i["name"] for i in tax}
SURVEY = config.get_survey(SID)["questions"]
OPTS = {q["id"]: [o["code"] for o in q["options"]] for q in SURVEY}
SIG = config.get_behavior_signals(SID)
# ํ๋ ํธ๋ฆฌ
_bc = config.get_behaviors(SID)
STEP1 = [(b["event_type"], b["entity"], b["id"]) for b in _bc["step1"]["behaviors"]]
STEP2 = {}
for parent, items in _bc["step2"]["by_parent"].items():
STEP2[parent] = [(b["event_type"], b["entity"], b["id"]) for b in items]
def _bar(frac, label):
n = int(frac * 30)
with open(PROG, "w") as f:
f.write(f"[{'#'*n}{'.'*(30-n)}] {frac*100:5.1f}% {label}")
def _rand_survey(rng):
return {q: rng.choice(OPTS[q]) for q in OPTS}
def _top(scores, k):
return sorted(scores, key=lambda s: s.final_score, reverse=True)[:k]
def _check_common(scores, anom, tag):
# E1 ๋ฒ์/NaN
for s in scores:
v = s.final_score
if v != v or v < -1e-9 or v > 1.0001:
anom["E1"].append((tag, s.intent_id, v)); break
top = _top(scores, 5)
top_ids = [s.intent_id for s in top]
# E2 ๋ฒ์ฉ ๋์ถ
g = GENERIC & set(top_ids)
if g:
anom["E2"].append((tag, list(g)))
# E3 ์์ ๋์
tv = round(top[0].final_score, 2)
tie = sum(1 for s in top if round(s.final_score, 2) == tv)
if tie >= 3:
anom["E3"].append((tag, tv, tie, top_ids[:tie]))
return top_ids
def run():
ext = get_extractor()
rng = random.Random(20240601)
t0 = time.time()
anom = defaultdict(list)
# ์ค๋ฌธ sweep
top1_survey = Counter()
for i in range(N_SURVEY):
a = _rand_survey(rng)
try:
_, sc = infer_batch(a, SID)
except Exception as e:
anom["E1"].append(("survey", "EXCEPTION", str(e)[:80])); continue
top_ids = _check_common(sc, anom, "survey")
top1_survey[top_ids[0]] += 1
if i % 500 == 0:
_bar(i / (N_SURVEY + N_SESS), f"์ค๋ฌธ {i:,}/{N_SURVEY:,}")
# ํ๋ sweep
ent_rise = defaultdict(lambda: [0, 0]) # entity โ [์ ํธ์์น, ์๋]
stuck_runs = []
top1_beh = Counter()
for j in range(N_SESS):
a = _rand_survey(rng)
sess = f"__st_{j}"
ext.reset(sess)
cur_parent = None
last_top1 = None; run_len = 0; max_run = 0
n_act = rng.randint(5, MAX_ACT)
for _ in range(n_act):
# ํธ๋ฆฌ ๋ค๋น๊ฒ์ด์
r = rng.random()
if cur_parent is None or r < 0.35:
et, en, bid = rng.choice(STEP1); cur_parent = bid
elif r < 0.5 and cur_parent:
cur_parent = None; ext.add_event(sess, "navigate_back", "back_to_step1"); continue
else:
items = STEP2.get(cur_parent) or STEP1
et, en, bid = rng.choice(items)
ext.add_event(sess, et, en)
try:
_, sc = infer_with_behavior(a, sess, SID)
except Exception as e:
anom["E1"].append((f"beh_{j}", "EXCEPTION", str(e)[:80])); break
top_ids = _check_common(sc, anom, f"beh_{j}")
# E4 ๋ฐ์์ฑ (์ ํธ entity๊ฐ top-10์)
targets = SIG.get(en, [])
if targets:
ent_rise[en][1] += 1
if set(targets) & set([s.intent_id for s in _top(sc, 10)]):
ent_rise[en][0] += 1
# E5 stuck
if top_ids[0] == last_top1:
run_len += 1; max_run = max(max_run, run_len)
else:
last_top1 = top_ids[0]; run_len = 1
top1_beh[top_ids[0]] += 1
if max_run >= STUCK_N:
stuck_runs.append((f"beh_{j}", last_top1, max_run))
ext.reset(sess)
if j % 150 == 0:
_bar((N_SURVEY + j) / (N_SURVEY + N_SESS), f"ํ๋ {j:,}/{N_SESS:,}")
_bar(1.0, "์๋ฃ")
dt = time.time() - t0
# โโ ์ง๊ณ/์์ฝ โโ
n_surv_top1 = sum(top1_survey.values())
hhi = sum((c / n_surv_top1) ** 2 for c in top1_survey.values()) if n_surv_top1 else 0
low_ent = {e: f"{v[0]}/{v[1]}={v[0]/v[1]*100:.0f}%" for e, v in ent_rise.items() if v[1] and v[0]/v[1] < 0.9}
summary = {
"elapsed_sec": round(dt, 1),
"n_survey": N_SURVEY, "n_sess": N_SESS, "max_act": MAX_ACT,
"E1_range_nan": len(anom["E1"]),
"E2_generic_leak": len(anom["E2"]),
"E3_top_tie(>=3)": len(anom["E3"]),
"E5_stuck(>=%d)" % STUCK_N: len(stuck_runs),
"survey_top1_distinct": len(top1_survey),
"survey_top1_HHI": round(hhi, 4),
"survey_top1_top8": [(NM[i][:14], f"{c/n_surv_top1*100:.1f}%") for i, c in top1_survey.most_common(8)],
"entity_low_responsiveness(<90%)": low_ent,
"stuck_samples": stuck_runs[:10],
"E1_samples": anom["E1"][:5],
"E2_samples": anom["E2"][:5],
"E3_samples": anom["E3"][:5],
}
json.dump({"summary": summary,
"anom_E1": anom["E1"][:200], "anom_E2": anom["E2"][:200],
"anom_E3": anom["E3"][:200], "stuck": stuck_runs[:200]},
open(REPORT, "w"), ensure_ascii=False, indent=1)
print("=" * 64)
print(f"๊ฒฐํฉ ์คํธ๋ ์ค ์๋ฎฌ ์๋ฃ โ {dt/60:.1f}๋ถ (์ค๋ฌธ {N_SURVEY:,} + ํ๋ {N_SESS:,}รโค{MAX_ACT})")
print("=" * 64)
print(f" [E1] ๋ฒ์/NaN/์์ธ : {len(anom['E1'])} ๊ฑด")
print(f" [E2] ๋ฒ์ฉ intent ๋์ถ : {len(anom['E2'])} ๊ฑด")
print(f" [E3] ์์ ๋์ (โฅ3) : {len(anom['E3'])} ๊ฑด")
print(f" [E5] stuck(top1 โฅ{STUCK_N}์ฐ์): {len(stuck_runs)} ์ธ์
")
print(f" ์ค๋ฌธ top-1 ๋ค์์ฑ: {len(top1_survey)}์ข
, HHI={hhi:.3f}")
print(f" ์ค๋ฌธ top-1 ์ต๋น: " + ", ".join(f"{NM[i][:10]} {c/n_surv_top1*100:.0f}%" for i, c in top1_survey.most_common(5)))
print(f" ํ๋ ๋ฐ์๋ฅ <90% entity: {low_ent if low_ent else '์์ โ'}")
if stuck_runs:
print(" stuck ์ํ:", [(s[1], s[2]) for s in stuck_runs[:5]])
print(f"\n์์ธ ๋ฆฌํฌํธ: {REPORT}")
if __name__ == "__main__":
run()
|