Spaces:
Running
Running
Download kernel_env/server/kernel_env_environment.py from Shreyansh327/kernel-env: direct link, hf CLI and curl.
- Browser
- Download file 6.88 kB
-
https://huggingface.co/spaces/Shreyansh327/kernel-env/resolve/main/kernel_env/server/kernel_env_environment.py
- Command line
-
hf download hf://spaces/Shreyansh327/kernel-env/kernel_env/server/kernel_env_environment.py
-
curl -L -o kernel_env_environment.py https://huggingface.co/spaces/Shreyansh327/kernel-env/resolve/main/kernel_env/server/kernel_env_environment.py
6.88 kB
| # Copyright (c) Meta Platforms, Inc. and affiliates. | |
| # All rights reserved. | |
| # | |
| # This source code is licensed under the BSD-style license found in the | |
| # LICENSE file in the root directory of this source tree. | |
| """ | |
| Kernel Env Environment Implementation. | |
| reset() picks a KernelBench task and returns the prompt; each step() evaluates one ModelNew | |
| submission (static checks -> compile -> correctness on hidden seeds -> timing) and returns | |
| feedback the agent can use to refine. Episode ends after `max_turns` submissions. | |
| """ | |
| import asyncio | |
| import hashlib | |
| import json | |
| import logging | |
| import os | |
| import random | |
| import threading | |
| import time | |
| from typing import Any, Dict, Optional | |
| from uuid import uuid4 | |
| from openenv.core.env_server.interfaces import Environment | |
| try: | |
| from ..models import KernelAction, KernelObservation, KernelState | |
| from .evaluator import Evaluator, default_evaluator | |
| from .rubrics import kernel_rubric | |
| from .tasks import Task, build_prompt, load_tasks | |
| except ImportError: | |
| from models import KernelAction, KernelObservation, KernelState | |
| from server.evaluator import Evaluator, default_evaluator | |
| from server.rubrics import kernel_rubric | |
| from server.tasks import Task, build_prompt, load_tasks | |
| log = logging.getLogger(__name__) | |
| N_TRIALS = 5 | |
| SUSPICIOUS_SPEEDUP = 50.0 # flagged in state.history for manual review of possible reward hacks | |
| RESULT_FIELDS = ("stage", "feedback", "correct", "max_abs_err", "speedup", "t_ref_ms", "t_new_ms", | |
| "t_min_ms", "bound", "arithmetic_intensity", "roofline_frac", "ref_roofline_frac") | |
| _log_lock = threading.Lock() | |
| def emit(event: str, **fields: Any) -> None: | |
| """One JSON line per event on stdout (Modal / docker logs); also appended to $KERNEL_ENV_EVAL_LOG if set.""" | |
| line = json.dumps({"event": event, "ts": round(time.time(), 3), **fields}, default=str) | |
| print(line, flush=True) | |
| path = os.environ.get("KERNEL_ENV_EVAL_LOG") | |
| if path: | |
| with _log_lock, open(path, "a") as f: | |
| f.write(line + "\n") | |
| class KernelEnvironment(Environment[KernelAction, KernelObservation, KernelState]): | |
| """Multi-turn GPU kernel optimization over KernelBench tasks.""" | |
| # Episode state is per instance; GPU access is serialized by the shared Evaluator. | |
| SUPPORTS_CONCURRENT_SESSIONS: bool = True | |
| def __init__( | |
| self, | |
| evaluator: Optional[Evaluator] = None, | |
| tasks: Optional[Dict[str, Task]] = None, | |
| max_turns: Optional[int] = None, | |
| ): | |
| super().__init__(rubric=kernel_rubric()) | |
| self._evaluator = evaluator or default_evaluator() | |
| self._tasks = tasks if tasks is not None else load_tasks() | |
| self.max_turns = max_turns or int(os.environ.get("KERNEL_ENV_MAX_TURNS", "4")) | |
| self._state = KernelState(episode_id=str(uuid4())) | |
| self._task: Optional[Task] = None | |
| self._rng = random.Random() | |
| def reset( | |
| self, | |
| seed: Optional[int] = None, | |
| episode_id: Optional[str] = None, | |
| task_id: Optional[str] = None, | |
| split: str = "train", | |
| language: str = "triton", | |
| **kwargs: Any, | |
| ) -> KernelObservation: | |
| """Start an episode on `task_id`, or a seeded random task from `split` ("train"/"eval").""" | |
| self._reset_rubric() | |
| self._rng = random.Random(seed) | |
| if task_id is None: | |
| pool = sorted(t for t, task in self._tasks.items() if task.split == split) | |
| if not pool: | |
| raise ValueError(f"no tasks in split {split!r}") | |
| task_id = self._rng.choice(pool) | |
| if task_id not in self._tasks: | |
| raise ValueError(f"unknown task_id {task_id!r}") | |
| self._task = self._tasks[task_id] | |
| self._state = KernelState( | |
| episode_id=episode_id or str(uuid4()), task_id=task_id, level=self._task.level | |
| ) | |
| emit("reset", episode_id=self._state.episode_id, task_id=task_id, split=split, seed=seed) | |
| return KernelObservation( | |
| task_id=task_id, | |
| problem=build_prompt(self._task, language, self.max_turns), | |
| max_turns=self.max_turns, | |
| done=False, | |
| reward=0.0, | |
| ) | |
| def step(self, action: KernelAction, timeout_s: Optional[float] = None, **kwargs: Any) -> KernelObservation: # type: ignore[override] | |
| if self._task is None: | |
| raise RuntimeError("call reset() before step()") | |
| if self._state.step_count >= self.max_turns: | |
| raise RuntimeError("episode is done; call reset()") | |
| self._state.step_count += 1 | |
| # hidden per-step input seeds: outputs can't be memorized across turns | |
| seeds = [self._rng.randrange(2**31) for _ in range(N_TRIALS)] | |
| res = self._evaluator.evaluate(self._task.src, action.code, action.language, seeds, task_id=self._task.task_id) | |
| obs = KernelObservation( | |
| task_id=self._task.task_id, | |
| turn=self._state.step_count, | |
| max_turns=self.max_turns, | |
| done=self._state.step_count >= self.max_turns, | |
| **{k: res[k] for k in RESULT_FIELDS if res.get(k) is not None}, | |
| ) | |
| obs.reward = self._apply_rubric(action, obs) | |
| entry = { | |
| "turn": obs.turn, "stage": obs.stage, "speedup": obs.speedup, "reward": obs.reward, | |
| "roofline_frac": obs.roofline_frac, "roofline_violation": bool(res.get("roofline_violation")), | |
| "gpu_id": res.get("gpu_id"), "queue_wait_s": res.get("queue_wait_s"), "eval_s": res.get("eval_s"), | |
| "code_sha": hashlib.sha1(action.code.encode()).hexdigest()[:12], | |
| "phases": res.get("phases"), # worker seconds per phase: inputs, JIT, correctness, bench, lock wait | |
| } | |
| if obs.correct and (obs.speedup or 0) > SUSPICIOUS_SPEEDUP: | |
| entry["suspicious"] = True | |
| log.warning("suspicious speedup %.1fx on %s (episode %s)", obs.speedup, obs.task_id, self._state.episode_id) | |
| self._state.history.append(entry) | |
| emit( | |
| "step", episode_id=self._state.episode_id, task_id=obs.task_id, **entry, | |
| t_ref_ms=obs.t_ref_ms, t_new_ms=obs.t_new_ms, t_min_ms=obs.t_min_ms, bound=obs.bound, | |
| ref_roofline_frac=obs.ref_roofline_frac, max_abs_err=obs.max_abs_err, | |
| gpu=res.get("gpu"), feedback_head=obs.feedback[:200], | |
| ) | |
| if obs.correct: | |
| self._state.best_speedup = max(self._state.best_speedup, obs.speedup or 0.0) | |
| return obs | |
| async def step_async(self, action: KernelAction, timeout_s: Optional[float] = None, **kwargs: Any) -> KernelObservation: # type: ignore[override] | |
| # evaluation blocks for seconds; keep the server event loop free for other sessions | |
| return await asyncio.to_thread(self.step, action, timeout_s, **kwargs) | |
| def state(self) -> KernelState: | |
| return self._state | |