refactor(runtime): remove gibberish filtering

This commit is contained in:
Pepijn
2026-07-15 15:55:26 +02:00
parent f76e6b0841
commit ad885c098d
4 changed files with 14 additions and 59 deletions
+1 -5
View File
@@ -1751,8 +1751,6 @@ class PI052Policy(PreTrainedPolicy):
return out
def _generate_low_level_subtask(self, obs_i: dict[str, Tensor], task: str, i: int) -> str:
from lerobot.runtime.adapter import looks_like_gibberish as _looks_like_gibberish # noqa: PLC0415
from .inference.pi052_adapter import _generate_with_policy # noqa: PLC0415
msg = ""
@@ -1767,7 +1765,7 @@ class PI052Policy(PreTrainedPolicy):
self.last_subtasks_raw[i] = msg or ""
# Feed the generated subtask verbatim, matching low-level training.
if msg and not _looks_like_gibberish(msg):
if msg:
subtask = " ".join(msg.strip().split())
self._last_good_subtasks[i] = subtask
self.last_subtasks[i] = subtask
@@ -1779,8 +1777,6 @@ class PI052Policy(PreTrainedPolicy):
debug = getattr(self, "_last_select_message_debug", "") or ""
if not task:
reason = "No task string was available in the batch."
elif msg:
reason = f"Rejected generated subtask: {msg!r}"
else:
reason = f"Empty generated subtask. {debug}".strip()
if self._last_good_subtasks[i]:
+4 -33
View File
@@ -43,11 +43,10 @@ class GenerationConfig:
@dataclass
class LanguageDiagnostics:
"""Runtime-panel rejection and repeat counters keyed by text kind."""
"""Runtime-panel generation counters keyed by text kind."""
last_raw: dict[str, str] = field(default_factory=dict)
empty: dict[str, int] = field(default_factory=dict)
gibberish: dict[str, int] = field(default_factory=dict)
repeat: int = 0
def _bump(self, table: dict[str, int], kind: str) -> int:
@@ -96,9 +95,9 @@ class BaseLanguageAdapter(ABC):
state.set_context("plan", plan, label="plan")
def plan_from_text(self, text: str) -> str:
"""Strip ``<say>`` speech markers and reject gibberish plans."""
"""Strip ``<say>`` speech markers from a generated plan."""
plan, _speech = split_plan_and_say(text)
return "" if looks_like_gibberish(plan) else plan
return plan
def _regenerate_context(self, observation: dict[str, Any] | None, state: RuntimeState) -> None:
"""Default hierarchy: regenerate the subtask, then memory when it changes.
@@ -127,7 +126,7 @@ class BaseLanguageAdapter(ABC):
def _generate_filtered(
self, kind: str, observation: dict[str, Any] | None, state: RuntimeState
) -> str | None:
"""Generate one ``kind``, record diagnostics, drop empty / gibberish output."""
"""Generate one ``kind``, record diagnostics, and drop empty output."""
text = self.generate_text(kind, observation, state)
self.diag.last_raw[kind] = text or ""
if not text:
@@ -135,11 +134,6 @@ class BaseLanguageAdapter(ABC):
if count == 1 or count % 5 == 0:
state.log(f" [info] {kind} gen returned empty (x{count})")
return None
if looks_like_gibberish(text):
count = self.diag._bump(self.diag.gibberish, kind)
if count == 1 or count % 30 == 0:
state.log(f" [info] {kind} gen rejected (gibberish x{count}): {text[:60]!r}")
return None
return text
@@ -159,29 +153,6 @@ class DirectTaskPolicyAdapter(BaseLanguageAdapter):
return ""
def looks_like_gibberish(text: str) -> bool:
"""Heuristic filter for malformed / collapsed LM-head output."""
if not text or not text.strip():
return True
stripped = text.strip()
alpha = sum(1 for c in stripped if c.isalpha())
if alpha < max(3, len(stripped) // 8):
return True
if stripped.startswith('":') and stripped.count('"') > stripped.count(" "):
return True
if len(set(stripped)) <= 2 and len(stripped) > 4:
return True
cleaned = stripped.replace("\n", " ").replace(":", " ")
for marker in ("Assistant", "User", "Ass "):
if marker in cleaned and len(cleaned.split()) < 4:
return True
tokens = [t for t in cleaned.split() if any(c.isalpha() for c in t)]
unique_alpha = {t.lower() for t in tokens}
if len(unique_alpha) < 3 and len(stripped) < 80:
return True
return len(tokens) >= 8 and len(unique_alpha) <= max(3, len(tokens) // 10)
def split_plan_and_say(text: str) -> tuple[str, str]:
"""Split ``plan <say>speech</say>`` into ``(plan, speech)``."""
if not text:
+4 -9
View File
@@ -660,24 +660,19 @@ def _make_state_panel_renderer(
dispatched = int(st.get("actions_dispatched") or 0)
console.print(f" [dim]queued actions: {queue_len} dispatched: {dispatched}[/]")
# Surface repeated or rejected generations as overfitting diagnostics.
# Surface repeated or empty generations as overfitting diagnostics.
diag = getattr(runtime.policy_adapter, "diag", None)
if diag is not None:
raw_subtask = diag.last_raw.get("subtask")
sub_rep = int(diag.repeat)
sub_gib = int(diag.gibberish.get("subtask", 0))
sub_empty = int(diag.empty.get("subtask", 0))
if raw_subtask is not None or sub_rep or sub_gib or sub_empty:
if raw_subtask is not None or sub_rep or sub_empty:
raw_display = (raw_subtask or "(empty)")[:80]
color = "yellow" if (sub_rep >= 3 or sub_gib >= 3 or sub_empty >= 3) else "dim"
color = "yellow" if (sub_rep >= 3 or sub_empty >= 3) else "dim"
console.print(
f" [{color}]subtask diag repeat:{sub_rep} "
f"gibberish:{sub_gib} empty:{sub_empty} "
f" [{color}]subtask diag repeat:{sub_rep} empty:{sub_empty} "
f"last_raw: {raw_display!r}[/]"
)
mem_gib = int(diag.gibberish.get("memory", 0))
if mem_gib:
console.print(f" [dim]gen rejects memory:{mem_gib}[/]")
console.rule(style="cyan")
# Show recent generation warnings and speech oldest-first.
if scrollback:
+5 -12
View File
@@ -17,7 +17,6 @@ from lerobot.runtime.adapter import (
BaseLanguageAdapter,
DirectTaskPolicyAdapter,
GenerationConfig,
looks_like_gibberish,
)
@@ -49,15 +48,15 @@ def test_cascade_sets_subtask_then_memory():
assert adapter.calls == ["subtask", "memory"]
def test_gibberish_subtask_is_rejected_and_counted():
adapter = ScriptedAdapter({"subtask": [":::: ::"], "memory": ["should not run"]})
def test_nonempty_generation_is_used_verbatim():
adapter = ScriptedAdapter({"subtask": [":::: ::"], "memory": ["memory"]})
state = RuntimeState(task="clean")
adapter.update_language_state(None, state)
assert "subtask" not in state.language_context
assert adapter.diag.gibberish.get("subtask") == 1
assert adapter.calls == ["subtask"] # memory never generated when subtask is rejected
assert state.language_context["subtask"] == ":::: ::"
assert state.language_context["memory"] == "memory"
assert adapter.calls == ["subtask", "memory"]
def test_throttle_regenerates_every_n_chunks():
@@ -87,12 +86,6 @@ def test_handle_interjection_sets_plan_and_strips_say():
assert state.language_context["plan"] == "turn to the left now"
def test_looks_like_gibberish_basic():
assert looks_like_gibberish("")
assert looks_like_gibberish(":::: ::")
assert not looks_like_gibberish("pick up the red cube")
def test_direct_task_adapter_delegates_action_chunk():
class Policy:
def predict_action_chunk(self, observation):