Spaces:
Runtime error
Runtime error
File size: 7,306 Bytes
0255d22 bff1b70 0255d22 bff1b70 0255d22 bff1b70 0255d22 bff1b70 0255d22 bff1b70 0255d22 | 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 | """
SemanticTransitionDataset β PyTorch-compatible dataset for MBRL research.
Loads trajectory JSONL files exported from CodeReviewEnv episodes and
provides (state, action, reward, next_state, done) transitions for
training Knowledge-Work World Models (KW-WM).
Usage:
from dataset import SemanticTransitionDataset
ds = SemanticTransitionDataset("trajectories/")
print(f"{len(ds)} transitions collected")
# Each item is a dict with keys:
# state_text: str β serialized observation (PR diff, context)
# action_text: str β serialized action (type + params)
# reward: float β grader reward for this transition
# next_state_text: str β serialized next observation
# done: bool β whether episode ended
# task: str β easy|medium|hard
# step: int β step number in episode
# For embedding-based world models:
from sentence_transformers import SentenceTransformer
encoder = SentenceTransformer("all-MiniLM-L6-v2")
s_enc = encoder.encode(ds[0]["state_text"])
# Train: MLP(s_enc, a_enc) β (s'_enc, r_pred)
Research context:
Standard MBRL benchmarks (Dreamer, MBPO, MuZero) assume vector state
spaces with physics-based transitions. Text-based world models (Li et al.,
2025) study synthetic text games; embodied SWMs (Berg et al., 2025) target
robotics. CodeReviewEnv enables training the first **Knowledge-Work World
Models (KW-WM)** β world models over structured professional text where
T(s,a)βs' depends on professional judgment rather than physics or game rules.
Open questions this dataset enables:
1. Does prediction error compound exponentially in knowledge-work spaces?
2. Does structured text provide natural error correction vs. continuous?
3. Can a KW-WM transfer across knowledge-work domains?
"""
import json
import os
from pathlib import Path
from typing import Any, Dict, List, Optional
class SemanticTransitionDataset:
"""
Loads trajectory JSONL files for training a Knowledge-Work World Model.
Compatible with PyTorch Dataset interface (implements __len__ and __getitem__).
Each trajectory file is a JSONL where each line is a transition dict.
Args:
trajectory_dir: Path to directory containing .jsonl trajectory files
task_filter: Optional β only load trajectories for this task (easy|medium|hard)
max_transitions: Optional β cap total transitions loaded (for memory)
"""
def __init__(
self,
trajectory_dir: str,
task_filter: Optional[str] = None,
max_transitions: Optional[int] = None,
):
self.trajectory_dir = Path(trajectory_dir)
self.transitions: List[Dict[str, Any]] = []
self._load(task_filter, max_transitions)
def _load(self, task_filter: Optional[str], max_transitions: Optional[int]) -> None:
"""Load all .jsonl files from the trajectory directory."""
if not self.trajectory_dir.exists():
return
for fpath in sorted(self.trajectory_dir.glob("*.jsonl")):
with open(fpath) as f:
for line in f:
line = line.strip()
if not line:
continue
try:
transition = json.loads(line)
except json.JSONDecodeError:
continue
# Apply task filter if specified
if task_filter and transition.get("task") != task_filter:
continue
self.transitions.append(transition)
if max_transitions and len(self.transitions) >= max_transitions:
return
def __len__(self) -> int:
return len(self.transitions)
def __getitem__(self, idx: int) -> Dict[str, Any]:
"""Return a single transition as a dict.
Keys:
state_text (str): Serialized observation text
action_text (str): Serialized action string
reward (float): Step reward
next_state_text (str): Serialized next observation
done (bool): Whether episode ended
task (str): Task difficulty level
step (int): Step number in episode
"""
t = self.transitions[idx]
return {
"state_text": t.get("state_text", json.dumps(t.get("state", {}))),
"action_text": t.get("action_text", json.dumps(t.get("action", {}))),
"reward": self._extract_reward(t),
"next_state_text": t.get("next_state_text", json.dumps(t.get("next_state", {}))),
"done": bool(t.get("done", False)),
"task": t.get("task", "unknown"),
"step": int(t.get("step", 0)),
}
@staticmethod
def _extract_reward(t: Dict) -> float:
"""Extract reward as float, handling dict or float formats."""
r = t.get("reward", 0.0)
if isinstance(r, dict):
return float(r.get("value", 0.0))
try:
return float(r)
except (TypeError, ValueError):
return 0.0
def get_episode(self, episode_id: str) -> List[Dict[str, Any]]:
"""Get all transitions from a specific episode."""
return [t for t in self.transitions if t.get("episode_id") == episode_id]
def get_episodes(self) -> List[str]:
"""Get all unique episode IDs."""
return list(set(t.get("episode_id", "unknown") for t in self.transitions))
def stats(self) -> Dict[str, Any]:
"""Summary statistics for the loaded dataset."""
episodes = self.get_episodes()
rewards = [self._extract_reward(t) for t in self.transitions]
tasks = {}
for t in self.transitions:
task = t.get("task", "unknown")
tasks[task] = tasks.get(task, 0) + 1
return {
"total_transitions": len(self.transitions),
"total_episodes": len(episodes),
"task_distribution": tasks,
"reward_mean": sum(rewards) / len(rewards) if rewards else 0.0,
"reward_min": min(rewards) if rewards else 0.0,
"reward_max": max(rewards) if rewards else 0.0,
}
def to_pytorch(self):
"""Convert to a PyTorch-compatible dataset (requires torch)."""
try:
import torch
from torch.utils.data import Dataset as TorchDataset
parent = self
class _TorchWrapper(TorchDataset):
def __len__(self):
return len(parent)
def __getitem__(self, idx):
item = parent[idx]
return {
"state_text": item["state_text"],
"action_text": item["action_text"],
"reward": torch.tensor(item["reward"], dtype=torch.float32),
"next_state_text": item["next_state_text"],
"done": torch.tensor(item["done"], dtype=torch.bool),
}
return _TorchWrapper()
except ImportError:
raise ImportError("PyTorch is required for to_pytorch(). Install with: pip install torch")
|