decompress / engine /viz.py
squaredcuber's picture
Deploy Decompress MiniCPM demo
bcbb8c5 verified
Raw
History Blame Contribute Delete
3.35 kB
from __future__ import annotations
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from engine.controller import Action, ControllerConfig, WhenToSpeakController
from engine.traces import SignalTrace, surprising_claim_trace
ROOT = Path(__file__).resolve().parents[1]
DEFAULT_OUTPUT = ROOT / "eval" / "controller_timeline.png"
ACTION_COLORS = {
Action.BACKCHANNEL: "tab:blue",
Action.TAKE_FLOOR: "tab:green",
Action.INTERRUPT: "tab:red",
}
def render_timeline(
trace: SignalTrace | None = None,
output_path: str | Path = DEFAULT_OUTPUT,
config: ControllerConfig | None = None,
) -> Path:
trace = trace or surprising_claim_trace()
controller = WhenToSpeakController(trace.agent_ids, config=config)
ticks = [controller.tick(step.signals_by_agent, floor_holder=step.floor_holder) for step in trace.steps]
steps = [tick.step for tick in ticks]
primary = trace.agent_ids[0]
surprise = [step.signals_by_agent[primary].surprise for step in trace.steps]
readiness = [step.signals_by_agent[primary].readiness for step in trace.steps]
p_end = [step.signals_by_agent[primary].p_end for step in trace.steps]
change = [tick.decisions[primary].change_score for tick in ticks]
fig, axes = plt.subplots(4, 1, figsize=(10, 8), sharex=True)
fig.suptitle(f"WhenToSpeak controller timeline: {trace.name}", fontsize=13)
axes[0].plot(steps, surprise, marker="o", color="tab:orange", label="surprise/NLL")
axes[0].set_ylabel("surprise")
axes[0].legend(loc="upper right")
axes[1].plot(steps, change, marker="o", color="tab:purple", label="change score")
axes[1].set_ylabel("change")
axes[1].legend(loc="upper right")
axes[2].plot(steps, readiness, marker="o", color="tab:green", label="readiness")
axes[2].plot(steps, p_end, marker=".", linestyle="--", color="tab:gray", label="p_end")
axes[2].set_ylabel("probability")
axes[2].set_ylim(-0.05, 1.05)
axes[2].legend(loc="upper right")
for agent_id in trace.agent_ids:
urges = [tick.decisions[agent_id].urge for tick in ticks]
axes[3].plot(steps, urges, marker="o", label=f"{agent_id} urge")
axes[3].axhline(controller.config.tau, color="black", linestyle="--", linewidth=1, label="tau")
axes[3].set_ylabel("urge")
axes[3].set_xlabel("step")
axes[3].legend(loc="upper right")
for tick in ticks:
for agent_id, decision in tick.decisions.items():
if decision.action == Action.SILENT:
continue
color = ACTION_COLORS[decision.action]
axes[3].scatter([tick.step], [decision.urge], color=color, s=90, zorder=5)
axes[3].annotate(
decision.action.value,
(tick.step, decision.urge),
textcoords="offset points",
xytext=(0, 8),
ha="center",
fontsize=8,
color=color,
)
for axis in axes:
axis.grid(True, alpha=0.25)
output = Path(output_path)
output.parent.mkdir(parents=True, exist_ok=True)
fig.tight_layout()
fig.savefig(output, dpi=160)
plt.close(fig)
return output
def main() -> None:
output = render_timeline()
print(f"Wrote {output}")
if __name__ == "__main__":
main()