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)") |