Spaces:
Sleeping
Sleeping
File size: 9,382 Bytes
cb330aa | 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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | """
SYNAPSE-X scripts/inference.py
================================
Multi-task inference script used for benchmarking and the report.py helper.
Runs all four tasks and writes inference_results.json.
This is the SCRIPTS version (benchmarking helper). The official hackathon
submission entrypoint is the root-level inference.py.
"""
import json
import os
import re
import sys
import time
from pathlib import Path
from typing import List, Optional
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
try:
from openai import OpenAI
_OPENAI_AVAILABLE = True
except ImportError:
OpenAI = None
_OPENAI_AVAILABLE = False
from agents.baseline import select_action as select_baseline_action
from env.environment import SynapseXEnvironment
from env.grader import TASK_REGISTRY, TASK_SEEDS, grade
from env.models import Action, ActionPayload, Observation
API_BASE_URL = os.environ.get("API_BASE_URL", "https://router.huggingface.co/v1")
MODEL_NAME = os.environ.get("MODEL_NAME", "meta-llama/Meta-Llama-3-8B-Instruct")
HF_TOKEN = os.environ.get("HF_TOKEN", "")
LOCAL_IMAGE_NAME = os.environ.get("LOCAL_IMAGE_NAME", "synapse-x")
MAX_STEPS = 20
TEMPERATURE = 0.0
INFERENCE_MODE = os.environ.get("INFERENCE_MODE", "auto").lower()
TASK_NAMES = tuple(TASK_REGISTRY.keys())
USE_LLM = bool(HF_TOKEN) and INFERENCE_MODE not in {"baseline", "offline"} and _OPENAI_AVAILABLE
SYSTEM_PROMPT = (
"You are an expert task scheduler inside the SYNAPSE-X decision environment.\n\n"
"You receive a JSON observation with pending tasks, current time, and resources.\n"
"Respond with ONLY a single valid JSON action object.\n"
'Format: {"action_type": "execute"|"delay"|"reallocate", "task_id": <int>}\n'
)
FALLBACK_ACTION: ActionPayload = {"action_type": "delay", "task_id": 0}
BENCHMARK = "synapse-x"
def _write(line: str) -> None:
sys.stdout.write(f"{line}\n")
sys.stdout.flush()
def _bool(v: bool) -> str:
return str(bool(v)).lower()
def _compact(v: object) -> str:
return json.dumps(v, separators=(",", ":"), ensure_ascii=True)
def _safe_error(err: Optional[str]) -> str:
if not err:
return "null"
return _compact(str(err).replace("\n", " ").strip())
def log_start(task: str, env: str, model: str) -> None:
_write(f"[START] task={task} env={env} model={model}")
def log_step(step: int, action: ActionPayload, reward: float, done: bool, error: Optional[str]) -> None:
_write(
f"[STEP] step={step} action={_compact(action)} reward={reward:.2f} "
f"done={_bool(done)} error={_safe_error(error)}"
)
def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> None:
rewards_text = ",".join(f"{r:.2f}" for r in rewards)
_write(f"[END] success={_bool(success)} steps={steps} score={score:.3f} rewards={rewards_text}")
def _obs_to_prompt(obs: Observation) -> str:
return json.dumps(
{
"time": obs.time,
"resources": obs.resources,
"tasks": [
{
"id": t.id, "name": t.name, "priority": t.priority,
"risk": t.risk, "uncertainty": t.uncertainty,
"deadline": t.deadline, "future_risk": t.future_risk,
"deadline_pressure": t.deadline_pressure,
"resources_required": t.resources_required,
"completed": t.completed, "failed": t.failed,
}
for t in obs.tasks
],
},
indent=2,
)
def _parse_action(text: str) -> ActionPayload:
m = re.search(r"\{.*?\}", text, re.DOTALL)
if m:
try:
return json.loads(m.group())
except json.JSONDecodeError:
pass
try:
return json.loads(text.strip())
except json.JSONDecodeError:
return FALLBACK_ACTION.copy()
def _coerce_action(raw: ActionPayload) -> Action:
try:
return Action(**raw)
except Exception:
return Action(**FALLBACK_ACTION)
def _baseline(obs: Observation) -> Action:
try:
return select_baseline_action(obs)
except Exception:
return Action(**FALLBACK_ACTION)
def _call_llm(client, obs: Observation) -> ActionPayload:
completion = client.chat.completions.create(
model=MODEL_NAME,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": _obs_to_prompt(obs)},
],
temperature=TEMPERATURE,
max_tokens=64,
stream=False,
)
return _parse_action((completion.choices[0].message.content or "").strip())
def run_baseline_episode(task_name: str, seed: int = 42, verbose: bool = True) -> tuple:
env = SynapseXEnvironment(task_config=TASK_REGISTRY[task_name], seed=seed)
obs = env.reset()
actions: List[ActionPayload] = []
traces: list = []
for step in range(MAX_STEPS):
if obs.episode_done:
break
action = _baseline(obs)
actions.append(action.model_dump())
result = env.step(action)
traces.append({"step": step + 1, "reward": result.reward, "done": result.done, "info": result.info})
if verbose:
err = (result.info or {}).get("error") or None
log_step(step + 1, action.model_dump(), float(result.reward), bool(result.done), err)
obs = result.observation
if result.done:
break
return actions, traces
def run_llm_episode(client, task_name: str, seed: int = 42, verbose: bool = True) -> tuple:
env = SynapseXEnvironment(task_config=TASK_REGISTRY[task_name], seed=seed)
obs = env.reset()
actions: List[ActionPayload] = []
traces: list = []
for step in range(MAX_STEPS):
if obs.episode_done:
break
try:
raw = _call_llm(client, obs)
except Exception as exc:
print(f"[DEBUG] LLM error step {step+1}: {exc}", file=sys.stderr)
raw = _baseline(obs).model_dump()
action = _coerce_action(raw)
actions.append(action.model_dump())
result = env.step(action)
traces.append({"step": step + 1, "reward": result.reward, "done": result.done, "info": result.info})
if verbose:
err = ((result.info or {}).get("error") or None)
log_step(step + 1, action.model_dump(), float(result.reward), bool(result.done), err)
obs = result.observation
if result.done:
break
return actions, traces
def run_episode(task_name: str, seed: int = 42, verbose: bool = False) -> float:
"""Run one episode and return the grader score. Used by report.py."""
use_baseline = not USE_LLM
if use_baseline:
actions, _ = run_baseline_episode(task_name, seed=seed, verbose=verbose)
else:
try:
client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
actions, _ = run_llm_episode(client, task_name, seed=seed, verbose=verbose)
except Exception:
actions, _ = run_baseline_episode(task_name, seed=seed, verbose=verbose)
return grade(task_name, actions).score
def main() -> None:
use_baseline = not USE_LLM
runtime_model = MODEL_NAME if not use_baseline else "baseline-fallback"
client = None
if not use_baseline:
try:
client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
except Exception as exc:
print(f"[DEBUG] Client init failed: {exc}", file=sys.stderr)
use_baseline = True
all_scores: dict = {}
per_task: dict = {}
started_at = time.perf_counter()
for task_name in TASK_NAMES:
seed = TASK_SEEDS.get(task_name, 42)
log_start(task=task_name, env=BENCHMARK, model=runtime_model)
if use_baseline or client is None:
actions, traces = run_baseline_episode(task_name, seed=seed, verbose=True)
else:
actions, traces = run_llm_episode(client, task_name, seed=seed, verbose=True)
result = grade(task_name, actions)
all_scores[task_name] = result.score
per_task[task_name] = {
"score": result.score,
"completion_rate": result.completion_rate,
"efficiency": result.efficiency,
"reward_score": result.reward_score,
"details": result.details,
"actions": actions,
"step_trace": traces,
}
log_end(
success=result.score >= 0.5,
steps=len(actions),
score=float(result.score),
rewards=[float(t["reward"]) for t in traces],
)
average = sum(all_scores.values()) / len(all_scores)
output = {
"model": runtime_model,
"mode": "llm" if not use_baseline else "baseline-fallback",
"api_base_url": API_BASE_URL,
"local_image_name": LOCAL_IMAGE_NAME,
"elapsed_seconds": round(time.perf_counter() - started_at, 4),
"average_score": round(average, 4),
"scores": all_scores,
"tasks": per_task,
}
with open(PROJECT_ROOT / "inference_results.json", "w", encoding="utf-8") as fh:
json.dump(output, fh, indent=2)
if __name__ == "__main__":
main()
|