1
Fork 0

feat: adapted simulate to trained config

This commit is contained in:
Jona Reynaert 2026-04-22 18:47:35 +02:00
parent c4447976ab
commit 395b04d9a8
4 changed files with 334 additions and 30 deletions

View file

@ -1,18 +1,19 @@
from dataclasses import dataclass
from typing import Optional
from brittle_star_project.environment.env_types import Backend
@dataclass
class SimulationSettings:
"""Settings for the simulation script."""
model_path: Optional[str] = None
model_type: str = "random"
backend: Backend = Backend.MJC
# Script behavior
headless: bool = False
# If None, viewer mode runs until window closed or target reached.
max_steps: Optional[int] = None
# Optional: point to a Hydra config.yaml from a training run (e.g. runs/.../.hydra/config.yaml).
# When set, the simulation script can override
# morphology/arena/environment/architecture to match.
trained_config_path: Optional[str] = None

View file

@ -6,6 +6,7 @@ This logger ensures all experimental data is preserved by writing to:
3. stdout (for real-time monitoring)
"""
from enum import Enum
import logging
import yaml
import sys
@ -25,6 +26,33 @@ _active_logger: Optional[Any] = None
_proxy_instance: Optional["LoggerProxy"] = None
def _sanitize_for_yaml(obj: Any) -> Any:
"""Convert non-primitive values into YAML-safe structures.
In particular, avoids PyYAML serializing Enums as
``!!python/object/apply:...`` which OmegaConf will not load.
"""
if isinstance(obj, Enum):
return obj.name
if isinstance(obj, Path):
return str(obj)
if isinstance(obj, (np.generic, jnp.ndarray)):
try:
return obj.item()
except Exception:
pass
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, dict):
return {str(k): _sanitize_for_yaml(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_sanitize_for_yaml(v) for v in obj]
if isinstance(obj, tuple):
return [_sanitize_for_yaml(v) for v in obj]
return obj
def get_logger() -> "LoggerProxy":
"""Retrieve the global LoggerProxy.
@ -216,7 +244,13 @@ class UnifiedLogger:
"""Save configuration to disk."""
try:
with open(self.config_file, "w") as f:
yaml.dump(self.full_config, f, default_flow_style=False, indent=2, sort_keys=False)
yaml.safe_dump(
_sanitize_for_yaml(self.full_config),
f,
default_flow_style=False,
indent=2,
sort_keys=False,
)
self.info(f"Config saved to {self.config_file}")
except Exception as e:
self.error(f"Error saving config: {e}")
@ -296,7 +330,12 @@ class UnifiedLogger:
else:
serializable_metric[k] = v
f.write("---\n")
yaml.dump(serializable_metric, f, default_flow_style=False)
yaml.safe_dump(
_sanitize_for_yaml(serializable_metric),
f,
default_flow_style=False,
sort_keys=False,
)
self.metrics_buffer.clear()
except Exception as e:
self.error(f"Error flushing metrics: {e}")
@ -321,7 +360,13 @@ class UnifiedLogger:
if metadata:
metadata_path = self.checkpoints_dir / f"{prefix}_step_{step}_metadata.yaml"
with open(metadata_path, "w") as f:
yaml.dump(metadata, f, default_flow_style=False)
yaml.safe_dump(
_sanitize_for_yaml(metadata),
f,
default_flow_style=False,
indent=2,
sort_keys=False,
)
self.info(f"Checkpoint saved: {checkpoint_path}")
@ -357,7 +402,13 @@ class UnifiedLogger:
if metadata:
metadata_path = self.run_dir / "final_model_metadata.yaml"
with open(metadata_path, "w") as f:
yaml.dump(metadata, f, default_flow_style=False)
yaml.safe_dump(
_sanitize_for_yaml(metadata),
f,
default_flow_style=False,
indent=2,
sort_keys=False,
)
self.info(f"Final model saved: {final_model_path}")