File size: 4,483 Bytes
975dbdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import sys
import time
import torch
from sentence_transformers import SentenceTransformer
import pandas as pd

# ── 1. Path setup (same pattern as run_ppo-2.py) ────────────────────────────
ROOT = os.path.dirname(__file__)
if ROOT not in sys.path:
    sys.path.insert(0, ROOT)

from model import RouterNetwork
from grpo_trainer import simulate_rag_pipeline   # reuse your existing tool caller

# ── 2. Config ────────────────────────────────────────────────────────────────
CHECKPOINT  = os.path.join(ROOT, "adapters/router_grpo_epoch_16.pt")   # ← change epoch here
EMBED_MODEL = "all-MiniLM-L6-v2"
DEVICE      = "cuda" if torch.cuda.is_available() else "cpu"

ACTION_NAMES = {
    0: "Guidelines  (academic rules / visa / scholarships)",
    1: "Web-Search   (news / announcements)",
    2: "CBNU Database (courses / departments / contacts)",
}

# ── 3. Load embedder + model ─────────────────────────────────────────────────
embedder  = SentenceTransformer(EMBED_MODEL)
embed_dim = embedder.get_sentence_embedding_dimension()
model     = RouterNetwork(embedding_dim=embed_dim, num_classes=3).to(DEVICE)

# Load checkpoint (supports both raw state_dict and wrapped dict)
sd = torch.load(CHECKPOINT, map_location="cpu")
if isinstance(sd, dict) and "model_state_dict" in sd:
    model.load_state_dict(sd["model_state_dict"], strict=False)
else:
    model.load_state_dict(sd, strict=False)

model.eval()
print(f"βœ…  Loaded checkpoint: {CHECKPOINT}")
print(f"    Device: {DEVICE}\n")

# ── 4. Single-query inference function ───────────────────────────────────────
def route_query(query: str, call_tool: bool = True):
    """
    Route one query through the loaded GRPO checkpoint.

    Args:
        query     : The user question string.
        call_tool : If True, also calls simulate_rag_pipeline and prints the answer.
                    Set False for routing-only / fast testing.

    Returns:
        action_idx (int), action_name (str), context (str), answer (str)
    """
    # Embed
    with torch.no_grad():
        emb = embedder.encode(query, convert_to_tensor=True).to(DEVICE)
        action, log_prob, _ = model.get_action(emb)
        action_idx = int(action.item())

    action_name = ACTION_NAMES[action_idx]
    print(f"Query   : {query}")
    print(f"β†’ Routed to Action {action_idx}: {action_name}")
    print(f"  log_prob = {log_prob.item():.4f}")

    context, answer = "", ""
    if call_tool:
        print("  Calling tool …")
        context, answer = simulate_rag_pipeline(query, action_idx)
        print(f"  Answer  : {answer[:300]}")

    return action_idx, action_name, context, answer


# ── 5. Main: test with one or more queries ───────────────────────────────────
if __name__ == "__main__":
    test_queries = [
        "What are the graduation requirements for international students?",
        "How do I register for courses next semester?",
        "What is the latest news from CBNU?",
    ]
    test_queries = [
        "2ν•™κΈ° κ°œκ°•μΌμ€?",
        "μ•Œλ°”ν•˜κ³  싢은데 μ–΄λ–€ 쑰건이 ν•„μš”ν•œκ°€?",
        "μ•„λ₯΄λ°”μ΄νŠΈ ν•˜λ €λŠ”λ° 쑰건은?",
        "μ‹œκ°„μ œ μ·¨μ—… 방법은?",
        "κ±΄κ°•λ³΄ν—˜ μ–΄λ–»κ²Œ κ°€μž…ν•΄?",
        "성적확인 기간은?"
    ]
    
    eval_df = pd.read_csv('ko_eval_queries.csv')
    test_queries = eval_df['question'].tolist()
    results = []
    for idx, row in eval_df.iterrows():
        q = row.get('question')
        ground = row.get('action_label')
        start = time.perf_counter()
        pred_idx, pred_name, context, answer = route_query(q, call_tool=False)
        end = time.perf_counter()
        elapsed = end - start
        results.append({
            'question': q,
            'ground_truth': ground,
            'predicted_label': pred_idx,
            'time_took': elapsed,
        })
        
        
    out_df = pd.DataFrame(results)
    out_df.to_csv('ko_eval_with_timing_results_epoch_16.csv', index=False)
    print(f"Wrote results to eval_with_timing_results.csv ({len(out_df)} rows)")