mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-08 10:32:00 +00:00
Fix GROOT relative action padding and RTC leftovers
This commit is contained in:
@@ -73,6 +73,7 @@ class GrootPolicy(PreTrainedPolicy):
|
||||
# Initialize GR00T model using ported components
|
||||
self._groot_model = self._create_groot_model()
|
||||
self._action_queue_steps = self._resolve_action_queue_steps()
|
||||
self._warned_native_relative_rtc_prefix_disabled = False
|
||||
|
||||
self.reset()
|
||||
|
||||
@@ -306,6 +307,17 @@ class GrootPolicy(PreTrainedPolicy):
|
||||
) -> tuple[dict[str, Tensor], dict[str, object] | None]:
|
||||
if prev_chunk_left_over is None:
|
||||
return inputs, None
|
||||
if getattr(self.config, "use_relative_actions", False):
|
||||
# Generic RTC only provides normalized leftovers from the previous chunk. For
|
||||
# native relative-action N1.7 checkpoints those rows are tied to the old
|
||||
# observation state and old per-horizon stats row, so using them as the next
|
||||
# prefix can push the policy in the wrong direction. Run without native RTC
|
||||
# overlap guidance until a GROOT-specific RTC path can pass re-anchored
|
||||
# absolute leftovers through.
|
||||
if not getattr(self, "_warned_native_relative_rtc_prefix_disabled", False):
|
||||
logger.info("Disabling native GR00T RTC prefix for relative-action policy")
|
||||
self._warned_native_relative_rtc_prefix_disabled = True
|
||||
return inputs, None
|
||||
if not isinstance(prev_chunk_left_over, torch.Tensor):
|
||||
raise TypeError("prev_chunk_left_over must be a torch.Tensor for GR00T N1.7 RTC.")
|
||||
if prev_chunk_left_over.numel() == 0:
|
||||
|
||||
@@ -588,6 +588,9 @@ def _slice_stats_entry(stats: dict[str, Any], indices: list[int]) -> dict[str, A
|
||||
max_index = max(indices)
|
||||
sliced: dict[str, Any] = {}
|
||||
for stat_name, value in stats.items():
|
||||
if stat_name == "count":
|
||||
sliced[stat_name] = torch.as_tensor(value).flatten().tolist()
|
||||
continue
|
||||
tensor = torch.as_tensor(value, dtype=torch.float32)
|
||||
if tensor.ndim >= 2:
|
||||
if tensor.shape[-1] <= max_index:
|
||||
@@ -1537,13 +1540,34 @@ class GrootN17PackInputsStep(ProcessorStep):
|
||||
)
|
||||
action = torch.cat([action, pad], dim=1)
|
||||
horizon = self.action_horizon
|
||||
if valid_horizon < horizon:
|
||||
horizon_valid = torch.zeros(bsz, horizon, dtype=torch.bool, device=action.device)
|
||||
horizon_valid[:, :valid_horizon] = True
|
||||
action_is_pad = comp.get(f"{ACTION}_is_pad")
|
||||
if action_is_pad is None:
|
||||
action_is_pad = comp.get("action_horizon_is_pad")
|
||||
if action_is_pad is not None:
|
||||
action_pad = torch.as_tensor(action_is_pad, dtype=torch.bool, device=action.device)
|
||||
if action_pad.ndim == 1:
|
||||
if bsz == 1 and action_pad.numel() == horizon:
|
||||
action_pad = action_pad.unsqueeze(0)
|
||||
elif horizon == 1 and action_pad.numel() == bsz:
|
||||
action_pad = action_pad.view(bsz, 1)
|
||||
if action_pad.ndim != 2 or action_pad.shape[0] != bsz:
|
||||
raise ValueError(
|
||||
"action_is_pad must have shape (B, T) matching the action batch; "
|
||||
f"got {tuple(action_pad.shape)} for action {tuple(action.shape)}."
|
||||
)
|
||||
pad_horizon = min(horizon, action_pad.shape[1])
|
||||
horizon_valid[:, :pad_horizon] &= ~action_pad[:, :pad_horizon]
|
||||
|
||||
if valid_horizon < horizon or action_is_pad is not None:
|
||||
action = action.clone()
|
||||
action[:, valid_horizon:, :] = 0
|
||||
action = action * horizon_valid.unsqueeze(-1).to(dtype=action.dtype)
|
||||
action_mask = torch.zeros(
|
||||
bsz, horizon, self.max_action_dim, dtype=torch.float32, device=action.device
|
||||
)
|
||||
action_mask[:, :valid_horizon, :valid_dim] = 1.0
|
||||
action_mask[:, :, :valid_dim] = horizon_valid.unsqueeze(-1).to(dtype=action_mask.dtype)
|
||||
transition[TransitionKey.ACTION] = action
|
||||
comp["action_mask"] = action_mask
|
||||
|
||||
|
||||
Reference in New Issue
Block a user