[RTC] Real Time Chunking for Pi0, Smolvla, Pi0.5 (#1698)
* Add Real-Time Chunking (RTC) support for flow matching models
Implement Real-Time Chunking (RTC) for action chunking policies using flow
matching denoising. RTC enables smooth action transitions between consecutive
chunks by using prefix guidance during denoising.
Key features:
- RTCProcessor class with denoise_step method for RTC guidance
- Tracker system for debug tracking using time-based dictionary storage
- RTCDebugVisualizer with comprehensive visualization utilities
- Integration with SmolVLA policy for flow matching models
- Support for multiple prefix attention schedules (ZEROS, ONES, LINEAR, EXP)
- Configurable execution horizon and max guidance weight
- Example scripts for dataset evaluation and real-time control
Technical details:
- Uses autograd-based gradient computation for RTC corrections
- Time-based tracking eliminates duplicate step issues
- Proxy methods in RTCProcessor for cleaner API
- Full integration with LeRobot's policy and dataset systems
Files added/modified:
- src/lerobot/configs/types.py: Add RTCAttentionSchedule enum
- src/lerobot/policies/rtc/: Core RTC implementation
- configuration_rtc.py: RTC configuration
- modeling_rtc.py: RTCProcessor with denoise_step
- debug_handler.py: Tracker for debug information
- debug_visualizer.py: Visualization utilities
- src/lerobot/policies/smolvla/modeling_smolvla.py: RTC integration
- examples/rtc/: Example scripts and evaluation tools
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix rtc_config attribute access in SmolVLA
Use getattr() to safely check for rtc_config attribute existence
instead of direct attribute access. This fixes AttributeError when
loading policies without rtc_config in their config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix rtc_config attribute access in SmolVLA
* Add RTCConfig field to SmolVLAConfig
Add rtc_config as an optional field in SmolVLAConfig to properly
support Real-Time Chunking configuration. This replaces the previous
getattr() workarounds with direct attribute access, making the code
cleaner and more maintainable.
Changes:
- Import RTCConfig in configuration_smolvla.py
- Add rtc_config: RTCConfig | None = None field
- Revert getattr() calls to direct attribute access in modeling_smolvla.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor RTC enabled checks to use _rtc_enabled helper
Add _rtc_enabled() helper method in VLAFlowMatching class to simplify
and clean up RTC enabled checks throughout the code. This reduces
code duplication and improves readability.
Changes:
- Add _rtc_enabled() method in VLAFlowMatching
- Replace verbose rtc_config checks with _rtc_enabled() calls
- Maintain exact same functionality with cleaner code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Rename track_debug method to track
Simplify the method name from track_debug to just track for better
readability and consistency. The method already has clear documentation
about its debug tracking purpose.
Changes:
- Rename RTCProcessor.track_debug() to track()
- Update all call sites in modeling_smolvla.py and modeling_rtc.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Use output_dir for saving all evaluation images
Update eval_dataset.py to save all comparison images to the
configured output_dir instead of the current directory. This provides
better organization and allows users to specify where outputs should be
saved.
Changes:
- Add os import at top level
- Create output_dir at start of run_evaluation()
- Save all comparison images to output_dir
- Remove duplicate os imports
- Update init_rtc_processor() docstring to be more concise
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Use output_dir for saving all evaluation images
* Fix logging buffering and enable tracking when RTC config provided
- Add force=True to logging.basicConfig to override existing configuration
- Enable line buffering for stdout/stderr for real-time log output
- Modify init_rtc_processor to create processor when rtc_config exists
even if RTC is disabled, allowing tracking of denoising data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor SmolVLA plotting to use tracker data instead of local variables
Remove local tracking variables (correction, x1_t, error) from the
denoising loop and instead retrieve plotting data from the RTC tracker
after each denoise step. This makes the code cleaner and uses the
tracker as the single source of truth for debug/visualization data.
Changes:
- Remove initialization of correction, x1_t, error before denoising loop
- After each Euler step, retrieve most recent debug step from tracker
- Extract correction, x1_t, err from debug step for plotting
- Update tracking condition to use is_debug_enabled() method
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Move plotting logic from modeling_smolvla to eval_dataset script
Refactor to improve separation of concerns:
modeling_smolvla.py changes:
- Remove all plotting logic from sample_actions method
- Remove viz_xt_axs, viz_vt_axs, viz_x1t_axs parameters
- Remove matplotlib and RTCDebugVisualizer imports
- Remove viz_fig, viz_axs, denoise_step_counter instance variables
- Simplify denoising loop to only track data in rtc_processor
eval_dataset.py changes:
- Add _plot_denoising_steps_from_tracker helper method
- Retrieve debug steps from tracker after inference
- Plot x_t, v_t, x1_t, correction, and error from tracker data
- Enable debug tracking (cfg.rtc.debug = True) for visualization
- Remove viz axes parameters from predict_action_chunk calls
modeling_rtc.py changes:
- Remove v_t from track() call (handled by user change)
Benefits:
- Cleaner modeling code focused on inference
- Evaluation script owns all visualization logic
- Better separation of concerns
- Tracker is single source of truth for debug data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor plotting loging
* fixup! Refactor plotting loging
* Improve visualization: separate correction plot and fix axis scaling
Changes:
- Create separate figure for correction data instead of overlaying on v_t
- Add _rescale_axes helper method to properly scale all axes
- Add 10% margin to y-axis for better visualization
- Fix v_t chart vertical compression issue
Benefits:
- Clearer v_t plot without correction overlay
- Better axis scaling with proper margins
- Separate correction figure for focused analysis
- Improved readability of all denoising visualizations
Output files:
- denoising_xt_comparison.png (x_t trajectories)
- denoising_vt_comparison.png (v_t velocity - now cleaner)
- denoising_correction_comparison.png (NEW - separate corrections)
- denoising_x1t_comparison.png (x1_t state with error)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* Fix traacking
* Right kwargs for the policy
* Add tests for tracker
* Fix tests
* Drop not required methods
* Add torch compilation for eval_dataset
* delete policies
* Add matplotliv to dev
* fixup! Add matplotliv to dev
* Experiemnt with late detach
* Debug
* Fix compilation
* Add RTC to PI0
* Pi0
* Pi0 eval dataset
* fixup! Pi0 eval dataset
* Turn off compilation for pi0/pi05
* fixup! Turn off compilation for pi0/pi05
* fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* Add workable flow
* Small fixes
* Add more tests
* Add validatio at the end
* Update README
* Silent validation
* Fix tests
* Add tests for modeling_rtc
* Add tests for flow matching models with RTC
* fixup! Add tests for flow matching models with RTC
* fixup! fixup! Add tests for flow matching models with RTC
* Add one more test
* fixup! Add one more test
* Fix test to use _rtc_enabled() instead of is_rtc_enabled()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* fixup! fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* Add RTC initialization tests without config for PI0.5 and SmolVLA
Add test_pi05_rtc_initialization_without_rtc_config and
test_smolvla_rtc_initialization_without_rtc_config to verify that
policies can initialize without RTC config and that _rtc_enabled()
returns False in this case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix SmolVLA init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
* Fixup eval with real robot
* fixup! Fixup eval with real robot
* fixup! fixup! Fixup eval with real robot
* Extract simulator logic from eval_with real robot and add proper headers to files
* Update images
* Fix tests
* fixup! Fix tests
* add docs for rtc
* enhance doc and add images
* Fix instal instructions
---------
Co-authored-by: Ben Zhang <benzhangniu@gmail.com>
Co-authored-by: Alexander Soare <alexander.soare159@gmail.com>
Co-authored-by: Michel Aractingi <michel.aractingi@huggingface.co>
2025-11-19 17:19:48 +07:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
|
|
# Copyright 2025 The HuggingFace Inc. team. All rights reserved.
|
|
|
|
|
#
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
|
#
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
#
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Demo script showing how to use Real-Time Chunking (RTC) with action chunking policies on real robots.
|
|
|
|
|
|
|
|
|
|
This script demonstrates:
|
|
|
|
|
1. Creating a robot and policy (SmolVLA, Pi0, etc.) with RTC
|
|
|
|
|
2. Consuming actions from the policy while the robot executes
|
|
|
|
|
3. Periodically requesting new action chunks in the background using threads
|
|
|
|
|
4. Managing action buffers and timing for real-time operation
|
|
|
|
|
|
|
|
|
|
For simulation environments, see eval_with_simulation.py
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
# Run RTC with Real robot with RTC
|
|
|
|
|
uv run examples/rtc/eval_with_real_robot.py \
|
|
|
|
|
--policy.path=helper2424/smolvla_check_rtc_last3 \
|
|
|
|
|
--policy.device=mps \
|
|
|
|
|
--rtc.enabled=true \
|
|
|
|
|
--rtc.execution_horizon=20 \
|
|
|
|
|
--robot.type=so100_follower \
|
|
|
|
|
--robot.port=/dev/tty.usbmodem58FA0834591 \
|
|
|
|
|
--robot.id=so100_follower \
|
|
|
|
|
--robot.cameras="{ gripper: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
|
|
|
|
|
--task="Move green small object into the purple platform" \
|
|
|
|
|
--duration=120
|
|
|
|
|
|
|
|
|
|
# Run RTC with Real robot without RTC
|
|
|
|
|
uv run examples/rtc/eval_with_real_robot.py \
|
|
|
|
|
--policy.path=helper2424/smolvla_check_rtc_last3 \
|
|
|
|
|
--policy.device=mps \
|
|
|
|
|
--rtc.enabled=false \
|
|
|
|
|
--robot.type=so100_follower \
|
|
|
|
|
--robot.port=/dev/tty.usbmodem58FA0834591 \
|
|
|
|
|
--robot.id=so100_follower \
|
|
|
|
|
--robot.cameras="{ gripper: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}, front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
|
|
|
|
|
--task="Move green small object into the purple platform" \
|
|
|
|
|
--duration=120
|
|
|
|
|
|
|
|
|
|
# Run RTC with Real robot with pi0.5 policy
|
|
|
|
|
uv run examples/rtc/eval_with_real_robot.py \
|
|
|
|
|
--policy.path=helper2424/pi05_check_rtc \
|
|
|
|
|
--policy.device=mps \
|
|
|
|
|
--rtc.enabled=true \
|
|
|
|
|
--rtc.execution_horizon=20 \
|
|
|
|
|
--robot.type=so100_follower \
|
|
|
|
|
--robot.port=/dev/tty.usbmodem58FA0834591 \
|
|
|
|
|
--robot.id=so100_follower \
|
|
|
|
|
--robot.cameras="{ gripper: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, front: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
|
|
|
|
|
--task="Move green small object into the purple platform" \
|
|
|
|
|
--duration=120
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
import math
|
|
|
|
|
import sys
|
|
|
|
|
import time
|
|
|
|
|
import traceback
|
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
from threading import Event, Lock, Thread
|
|
|
|
|
|
|
|
|
|
import torch
|
|
|
|
|
from torch import Tensor
|
|
|
|
|
|
|
|
|
|
from lerobot.cameras.opencv.configuration_opencv import OpenCVCameraConfig # noqa: F401
|
|
|
|
|
from lerobot.cameras.realsense.configuration_realsense import RealSenseCameraConfig # noqa: F401
|
|
|
|
|
from lerobot.configs import parser
|
|
|
|
|
from lerobot.configs.policies import PreTrainedConfig
|
|
|
|
|
from lerobot.configs.types import RTCAttentionSchedule
|
|
|
|
|
from lerobot.datasets.utils import build_dataset_frame, hw_to_dataset_features
|
|
|
|
|
from lerobot.policies.factory import get_policy_class, make_pre_post_processors
|
|
|
|
|
from lerobot.policies.rtc.action_queue import ActionQueue
|
|
|
|
|
from lerobot.policies.rtc.configuration_rtc import RTCConfig
|
|
|
|
|
from lerobot.policies.rtc.latency_tracker import LatencyTracker
|
|
|
|
|
from lerobot.processor.factory import (
|
|
|
|
|
make_default_robot_action_processor,
|
|
|
|
|
make_default_robot_observation_processor,
|
|
|
|
|
)
|
|
|
|
|
from lerobot.rl.process import ProcessSignalHandler
|
|
|
|
|
from lerobot.robots import ( # noqa: F401
|
|
|
|
|
Robot,
|
|
|
|
|
RobotConfig,
|
2026-01-12 16:01:22 +01:00
|
|
|
bi_so_follower,
|
[RTC] Real Time Chunking for Pi0, Smolvla, Pi0.5 (#1698)
* Add Real-Time Chunking (RTC) support for flow matching models
Implement Real-Time Chunking (RTC) for action chunking policies using flow
matching denoising. RTC enables smooth action transitions between consecutive
chunks by using prefix guidance during denoising.
Key features:
- RTCProcessor class with denoise_step method for RTC guidance
- Tracker system for debug tracking using time-based dictionary storage
- RTCDebugVisualizer with comprehensive visualization utilities
- Integration with SmolVLA policy for flow matching models
- Support for multiple prefix attention schedules (ZEROS, ONES, LINEAR, EXP)
- Configurable execution horizon and max guidance weight
- Example scripts for dataset evaluation and real-time control
Technical details:
- Uses autograd-based gradient computation for RTC corrections
- Time-based tracking eliminates duplicate step issues
- Proxy methods in RTCProcessor for cleaner API
- Full integration with LeRobot's policy and dataset systems
Files added/modified:
- src/lerobot/configs/types.py: Add RTCAttentionSchedule enum
- src/lerobot/policies/rtc/: Core RTC implementation
- configuration_rtc.py: RTC configuration
- modeling_rtc.py: RTCProcessor with denoise_step
- debug_handler.py: Tracker for debug information
- debug_visualizer.py: Visualization utilities
- src/lerobot/policies/smolvla/modeling_smolvla.py: RTC integration
- examples/rtc/: Example scripts and evaluation tools
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix rtc_config attribute access in SmolVLA
Use getattr() to safely check for rtc_config attribute existence
instead of direct attribute access. This fixes AttributeError when
loading policies without rtc_config in their config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix rtc_config attribute access in SmolVLA
* Add RTCConfig field to SmolVLAConfig
Add rtc_config as an optional field in SmolVLAConfig to properly
support Real-Time Chunking configuration. This replaces the previous
getattr() workarounds with direct attribute access, making the code
cleaner and more maintainable.
Changes:
- Import RTCConfig in configuration_smolvla.py
- Add rtc_config: RTCConfig | None = None field
- Revert getattr() calls to direct attribute access in modeling_smolvla.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor RTC enabled checks to use _rtc_enabled helper
Add _rtc_enabled() helper method in VLAFlowMatching class to simplify
and clean up RTC enabled checks throughout the code. This reduces
code duplication and improves readability.
Changes:
- Add _rtc_enabled() method in VLAFlowMatching
- Replace verbose rtc_config checks with _rtc_enabled() calls
- Maintain exact same functionality with cleaner code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Rename track_debug method to track
Simplify the method name from track_debug to just track for better
readability and consistency. The method already has clear documentation
about its debug tracking purpose.
Changes:
- Rename RTCProcessor.track_debug() to track()
- Update all call sites in modeling_smolvla.py and modeling_rtc.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Use output_dir for saving all evaluation images
Update eval_dataset.py to save all comparison images to the
configured output_dir instead of the current directory. This provides
better organization and allows users to specify where outputs should be
saved.
Changes:
- Add os import at top level
- Create output_dir at start of run_evaluation()
- Save all comparison images to output_dir
- Remove duplicate os imports
- Update init_rtc_processor() docstring to be more concise
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Use output_dir for saving all evaluation images
* Fix logging buffering and enable tracking when RTC config provided
- Add force=True to logging.basicConfig to override existing configuration
- Enable line buffering for stdout/stderr for real-time log output
- Modify init_rtc_processor to create processor when rtc_config exists
even if RTC is disabled, allowing tracking of denoising data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor SmolVLA plotting to use tracker data instead of local variables
Remove local tracking variables (correction, x1_t, error) from the
denoising loop and instead retrieve plotting data from the RTC tracker
after each denoise step. This makes the code cleaner and uses the
tracker as the single source of truth for debug/visualization data.
Changes:
- Remove initialization of correction, x1_t, error before denoising loop
- After each Euler step, retrieve most recent debug step from tracker
- Extract correction, x1_t, err from debug step for plotting
- Update tracking condition to use is_debug_enabled() method
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Move plotting logic from modeling_smolvla to eval_dataset script
Refactor to improve separation of concerns:
modeling_smolvla.py changes:
- Remove all plotting logic from sample_actions method
- Remove viz_xt_axs, viz_vt_axs, viz_x1t_axs parameters
- Remove matplotlib and RTCDebugVisualizer imports
- Remove viz_fig, viz_axs, denoise_step_counter instance variables
- Simplify denoising loop to only track data in rtc_processor
eval_dataset.py changes:
- Add _plot_denoising_steps_from_tracker helper method
- Retrieve debug steps from tracker after inference
- Plot x_t, v_t, x1_t, correction, and error from tracker data
- Enable debug tracking (cfg.rtc.debug = True) for visualization
- Remove viz axes parameters from predict_action_chunk calls
modeling_rtc.py changes:
- Remove v_t from track() call (handled by user change)
Benefits:
- Cleaner modeling code focused on inference
- Evaluation script owns all visualization logic
- Better separation of concerns
- Tracker is single source of truth for debug data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor plotting loging
* fixup! Refactor plotting loging
* Improve visualization: separate correction plot and fix axis scaling
Changes:
- Create separate figure for correction data instead of overlaying on v_t
- Add _rescale_axes helper method to properly scale all axes
- Add 10% margin to y-axis for better visualization
- Fix v_t chart vertical compression issue
Benefits:
- Clearer v_t plot without correction overlay
- Better axis scaling with proper margins
- Separate correction figure for focused analysis
- Improved readability of all denoising visualizations
Output files:
- denoising_xt_comparison.png (x_t trajectories)
- denoising_vt_comparison.png (v_t velocity - now cleaner)
- denoising_correction_comparison.png (NEW - separate corrections)
- denoising_x1t_comparison.png (x1_t state with error)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* Fix traacking
* Right kwargs for the policy
* Add tests for tracker
* Fix tests
* Drop not required methods
* Add torch compilation for eval_dataset
* delete policies
* Add matplotliv to dev
* fixup! Add matplotliv to dev
* Experiemnt with late detach
* Debug
* Fix compilation
* Add RTC to PI0
* Pi0
* Pi0 eval dataset
* fixup! Pi0 eval dataset
* Turn off compilation for pi0/pi05
* fixup! Turn off compilation for pi0/pi05
* fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* Add workable flow
* Small fixes
* Add more tests
* Add validatio at the end
* Update README
* Silent validation
* Fix tests
* Add tests for modeling_rtc
* Add tests for flow matching models with RTC
* fixup! Add tests for flow matching models with RTC
* fixup! fixup! Add tests for flow matching models with RTC
* Add one more test
* fixup! Add one more test
* Fix test to use _rtc_enabled() instead of is_rtc_enabled()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* fixup! fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* Add RTC initialization tests without config for PI0.5 and SmolVLA
Add test_pi05_rtc_initialization_without_rtc_config and
test_smolvla_rtc_initialization_without_rtc_config to verify that
policies can initialize without RTC config and that _rtc_enabled()
returns False in this case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix SmolVLA init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
* Fixup eval with real robot
* fixup! Fixup eval with real robot
* fixup! fixup! Fixup eval with real robot
* Extract simulator logic from eval_with real robot and add proper headers to files
* Update images
* Fix tests
* fixup! Fix tests
* add docs for rtc
* enhance doc and add images
* Fix instal instructions
---------
Co-authored-by: Ben Zhang <benzhangniu@gmail.com>
Co-authored-by: Alexander Soare <alexander.soare159@gmail.com>
Co-authored-by: Michel Aractingi <michel.aractingi@huggingface.co>
2025-11-19 17:19:48 +07:00
|
|
|
koch_follower,
|
2026-01-08 13:04:30 +01:00
|
|
|
so_follower,
|
[RTC] Real Time Chunking for Pi0, Smolvla, Pi0.5 (#1698)
* Add Real-Time Chunking (RTC) support for flow matching models
Implement Real-Time Chunking (RTC) for action chunking policies using flow
matching denoising. RTC enables smooth action transitions between consecutive
chunks by using prefix guidance during denoising.
Key features:
- RTCProcessor class with denoise_step method for RTC guidance
- Tracker system for debug tracking using time-based dictionary storage
- RTCDebugVisualizer with comprehensive visualization utilities
- Integration with SmolVLA policy for flow matching models
- Support for multiple prefix attention schedules (ZEROS, ONES, LINEAR, EXP)
- Configurable execution horizon and max guidance weight
- Example scripts for dataset evaluation and real-time control
Technical details:
- Uses autograd-based gradient computation for RTC corrections
- Time-based tracking eliminates duplicate step issues
- Proxy methods in RTCProcessor for cleaner API
- Full integration with LeRobot's policy and dataset systems
Files added/modified:
- src/lerobot/configs/types.py: Add RTCAttentionSchedule enum
- src/lerobot/policies/rtc/: Core RTC implementation
- configuration_rtc.py: RTC configuration
- modeling_rtc.py: RTCProcessor with denoise_step
- debug_handler.py: Tracker for debug information
- debug_visualizer.py: Visualization utilities
- src/lerobot/policies/smolvla/modeling_smolvla.py: RTC integration
- examples/rtc/: Example scripts and evaluation tools
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix rtc_config attribute access in SmolVLA
Use getattr() to safely check for rtc_config attribute existence
instead of direct attribute access. This fixes AttributeError when
loading policies without rtc_config in their config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix rtc_config attribute access in SmolVLA
* Add RTCConfig field to SmolVLAConfig
Add rtc_config as an optional field in SmolVLAConfig to properly
support Real-Time Chunking configuration. This replaces the previous
getattr() workarounds with direct attribute access, making the code
cleaner and more maintainable.
Changes:
- Import RTCConfig in configuration_smolvla.py
- Add rtc_config: RTCConfig | None = None field
- Revert getattr() calls to direct attribute access in modeling_smolvla.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor RTC enabled checks to use _rtc_enabled helper
Add _rtc_enabled() helper method in VLAFlowMatching class to simplify
and clean up RTC enabled checks throughout the code. This reduces
code duplication and improves readability.
Changes:
- Add _rtc_enabled() method in VLAFlowMatching
- Replace verbose rtc_config checks with _rtc_enabled() calls
- Maintain exact same functionality with cleaner code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Rename track_debug method to track
Simplify the method name from track_debug to just track for better
readability and consistency. The method already has clear documentation
about its debug tracking purpose.
Changes:
- Rename RTCProcessor.track_debug() to track()
- Update all call sites in modeling_smolvla.py and modeling_rtc.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Use output_dir for saving all evaluation images
Update eval_dataset.py to save all comparison images to the
configured output_dir instead of the current directory. This provides
better organization and allows users to specify where outputs should be
saved.
Changes:
- Add os import at top level
- Create output_dir at start of run_evaluation()
- Save all comparison images to output_dir
- Remove duplicate os imports
- Update init_rtc_processor() docstring to be more concise
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Use output_dir for saving all evaluation images
* Fix logging buffering and enable tracking when RTC config provided
- Add force=True to logging.basicConfig to override existing configuration
- Enable line buffering for stdout/stderr for real-time log output
- Modify init_rtc_processor to create processor when rtc_config exists
even if RTC is disabled, allowing tracking of denoising data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor SmolVLA plotting to use tracker data instead of local variables
Remove local tracking variables (correction, x1_t, error) from the
denoising loop and instead retrieve plotting data from the RTC tracker
after each denoise step. This makes the code cleaner and uses the
tracker as the single source of truth for debug/visualization data.
Changes:
- Remove initialization of correction, x1_t, error before denoising loop
- After each Euler step, retrieve most recent debug step from tracker
- Extract correction, x1_t, err from debug step for plotting
- Update tracking condition to use is_debug_enabled() method
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Move plotting logic from modeling_smolvla to eval_dataset script
Refactor to improve separation of concerns:
modeling_smolvla.py changes:
- Remove all plotting logic from sample_actions method
- Remove viz_xt_axs, viz_vt_axs, viz_x1t_axs parameters
- Remove matplotlib and RTCDebugVisualizer imports
- Remove viz_fig, viz_axs, denoise_step_counter instance variables
- Simplify denoising loop to only track data in rtc_processor
eval_dataset.py changes:
- Add _plot_denoising_steps_from_tracker helper method
- Retrieve debug steps from tracker after inference
- Plot x_t, v_t, x1_t, correction, and error from tracker data
- Enable debug tracking (cfg.rtc.debug = True) for visualization
- Remove viz axes parameters from predict_action_chunk calls
modeling_rtc.py changes:
- Remove v_t from track() call (handled by user change)
Benefits:
- Cleaner modeling code focused on inference
- Evaluation script owns all visualization logic
- Better separation of concerns
- Tracker is single source of truth for debug data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor plotting loging
* fixup! Refactor plotting loging
* Improve visualization: separate correction plot and fix axis scaling
Changes:
- Create separate figure for correction data instead of overlaying on v_t
- Add _rescale_axes helper method to properly scale all axes
- Add 10% margin to y-axis for better visualization
- Fix v_t chart vertical compression issue
Benefits:
- Clearer v_t plot without correction overlay
- Better axis scaling with proper margins
- Separate correction figure for focused analysis
- Improved readability of all denoising visualizations
Output files:
- denoising_xt_comparison.png (x_t trajectories)
- denoising_vt_comparison.png (v_t velocity - now cleaner)
- denoising_correction_comparison.png (NEW - separate corrections)
- denoising_x1t_comparison.png (x1_t state with error)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* Fix traacking
* Right kwargs for the policy
* Add tests for tracker
* Fix tests
* Drop not required methods
* Add torch compilation for eval_dataset
* delete policies
* Add matplotliv to dev
* fixup! Add matplotliv to dev
* Experiemnt with late detach
* Debug
* Fix compilation
* Add RTC to PI0
* Pi0
* Pi0 eval dataset
* fixup! Pi0 eval dataset
* Turn off compilation for pi0/pi05
* fixup! Turn off compilation for pi0/pi05
* fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* Add workable flow
* Small fixes
* Add more tests
* Add validatio at the end
* Update README
* Silent validation
* Fix tests
* Add tests for modeling_rtc
* Add tests for flow matching models with RTC
* fixup! Add tests for flow matching models with RTC
* fixup! fixup! Add tests for flow matching models with RTC
* Add one more test
* fixup! Add one more test
* Fix test to use _rtc_enabled() instead of is_rtc_enabled()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* fixup! fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* Add RTC initialization tests without config for PI0.5 and SmolVLA
Add test_pi05_rtc_initialization_without_rtc_config and
test_smolvla_rtc_initialization_without_rtc_config to verify that
policies can initialize without RTC config and that _rtc_enabled()
returns False in this case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix SmolVLA init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
* Fixup eval with real robot
* fixup! Fixup eval with real robot
* fixup! fixup! Fixup eval with real robot
* Extract simulator logic from eval_with real robot and add proper headers to files
* Update images
* Fix tests
* fixup! Fix tests
* add docs for rtc
* enhance doc and add images
* Fix instal instructions
---------
Co-authored-by: Ben Zhang <benzhangniu@gmail.com>
Co-authored-by: Alexander Soare <alexander.soare159@gmail.com>
Co-authored-by: Michel Aractingi <michel.aractingi@huggingface.co>
2025-11-19 17:19:48 +07:00
|
|
|
)
|
|
|
|
|
from lerobot.robots.utils import make_robot_from_config
|
|
|
|
|
from lerobot.utils.constants import OBS_IMAGES
|
|
|
|
|
from lerobot.utils.hub import HubMixin
|
|
|
|
|
from lerobot.utils.utils import init_logging
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RobotWrapper:
|
|
|
|
|
def __init__(self, robot: Robot):
|
|
|
|
|
self.robot = robot
|
|
|
|
|
self.lock = Lock()
|
|
|
|
|
|
|
|
|
|
def get_observation(self) -> dict[str, Tensor]:
|
|
|
|
|
with self.lock:
|
|
|
|
|
return self.robot.get_observation()
|
|
|
|
|
|
|
|
|
|
def send_action(self, action: Tensor):
|
|
|
|
|
with self.lock:
|
|
|
|
|
self.robot.send_action(action)
|
|
|
|
|
|
|
|
|
|
def observation_features(self) -> list[str]:
|
|
|
|
|
with self.lock:
|
|
|
|
|
return self.robot.observation_features
|
|
|
|
|
|
|
|
|
|
def action_features(self) -> list[str]:
|
|
|
|
|
with self.lock:
|
|
|
|
|
return self.robot.action_features
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class RTCDemoConfig(HubMixin):
|
|
|
|
|
"""Configuration for RTC demo with action chunking policies and real robots."""
|
|
|
|
|
|
|
|
|
|
# Policy configuration
|
|
|
|
|
policy: PreTrainedConfig | None = None
|
|
|
|
|
|
|
|
|
|
# Robot configuration
|
|
|
|
|
robot: RobotConfig | None = None
|
|
|
|
|
|
|
|
|
|
# RTC configuration
|
|
|
|
|
rtc: RTCConfig = field(
|
|
|
|
|
default_factory=lambda: RTCConfig(
|
|
|
|
|
execution_horizon=10,
|
|
|
|
|
max_guidance_weight=1.0,
|
|
|
|
|
prefix_attention_schedule=RTCAttentionSchedule.EXP,
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Demo parameters
|
|
|
|
|
duration: float = 30.0 # Duration to run the demo (seconds)
|
|
|
|
|
fps: float = 10.0 # Action execution frequency (Hz)
|
|
|
|
|
|
|
|
|
|
# Compute device
|
|
|
|
|
device: str | None = None # Device to run on (cuda, cpu, auto)
|
|
|
|
|
|
|
|
|
|
# Get new actions horizon. The amount of executed steps after which will be requested new actions.
|
|
|
|
|
# It should be higher than inference delay + execution horizon.
|
|
|
|
|
action_queue_size_to_get_new_actions: int = 30
|
|
|
|
|
|
|
|
|
|
# Task to execute
|
|
|
|
|
task: str = field(default="", metadata={"help": "Task to execute"})
|
|
|
|
|
|
|
|
|
|
# Torch compile configuration
|
|
|
|
|
use_torch_compile: bool = field(
|
|
|
|
|
default=False,
|
|
|
|
|
metadata={"help": "Use torch.compile for faster inference (PyTorch 2.0+)"},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
torch_compile_backend: str = field(
|
|
|
|
|
default="inductor",
|
|
|
|
|
metadata={"help": "Backend for torch.compile (inductor, aot_eager, cudagraphs)"},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
torch_compile_mode: str = field(
|
|
|
|
|
default="default",
|
|
|
|
|
metadata={"help": "Compilation mode (default, reduce-overhead, max-autotune)"},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
torch_compile_disable_cudagraphs: bool = field(
|
|
|
|
|
default=True,
|
|
|
|
|
metadata={
|
|
|
|
|
"help": "Disable CUDA graphs in torch.compile. Required due to in-place tensor "
|
|
|
|
|
"operations in denoising loop (x_t += dt * v_t) which cause tensor aliasing issues."
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __post_init__(self):
|
|
|
|
|
# HACK: We parse again the cli args here to get the pretrained path if there was one.
|
|
|
|
|
policy_path = parser.get_path_arg("policy")
|
|
|
|
|
if policy_path:
|
|
|
|
|
cli_overrides = parser.get_cli_overrides("policy")
|
|
|
|
|
self.policy = PreTrainedConfig.from_pretrained(policy_path, cli_overrides=cli_overrides)
|
|
|
|
|
self.policy.pretrained_path = policy_path
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Policy path is required")
|
|
|
|
|
|
|
|
|
|
# Validate that robot configuration is provided
|
|
|
|
|
if self.robot is None:
|
|
|
|
|
raise ValueError("Robot configuration must be provided")
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def __get_path_fields__(cls) -> list[str]:
|
|
|
|
|
"""This enables the parser to load config from the policy using `--policy.path=local/dir`"""
|
|
|
|
|
return ["policy"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_image_key(k: str) -> bool:
|
|
|
|
|
return k.startswith(OBS_IMAGES)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_actions(
|
|
|
|
|
policy,
|
|
|
|
|
robot: RobotWrapper,
|
|
|
|
|
robot_observation_processor,
|
|
|
|
|
action_queue: ActionQueue,
|
|
|
|
|
shutdown_event: Event,
|
|
|
|
|
cfg: RTCDemoConfig,
|
|
|
|
|
):
|
|
|
|
|
"""Thread function to request action chunks from the policy.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
policy: The policy instance (SmolVLA, Pi0, etc.)
|
|
|
|
|
robot: The robot instance for getting observations
|
|
|
|
|
robot_observation_processor: Processor for raw robot observations
|
|
|
|
|
action_queue: Queue to put new action chunks
|
|
|
|
|
shutdown_event: Event to signal shutdown
|
|
|
|
|
cfg: Demo configuration
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
logger.info("[GET_ACTIONS] Starting get actions thread")
|
|
|
|
|
|
|
|
|
|
latency_tracker = LatencyTracker() # Track latency of action chunks
|
|
|
|
|
fps = cfg.fps
|
|
|
|
|
time_per_chunk = 1.0 / fps
|
|
|
|
|
|
|
|
|
|
dataset_features = hw_to_dataset_features(robot.observation_features(), "observation")
|
|
|
|
|
policy_device = policy.config.device
|
|
|
|
|
|
|
|
|
|
# Load preprocessor and postprocessor from pretrained files
|
|
|
|
|
# The stats are embedded in the processor .safetensors files
|
|
|
|
|
logger.info(f"[GET_ACTIONS] Loading preprocessor/postprocessor from {cfg.policy.pretrained_path}")
|
|
|
|
|
|
|
|
|
|
preprocessor, postprocessor = make_pre_post_processors(
|
|
|
|
|
policy_cfg=cfg.policy,
|
|
|
|
|
pretrained_path=cfg.policy.pretrained_path,
|
|
|
|
|
dataset_stats=None, # Will load from pretrained processor files
|
|
|
|
|
preprocessor_overrides={
|
|
|
|
|
"device_processor": {"device": cfg.policy.device},
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
logger.info("[GET_ACTIONS] Preprocessor/postprocessor loaded successfully with embedded stats")
|
|
|
|
|
|
|
|
|
|
get_actions_threshold = cfg.action_queue_size_to_get_new_actions
|
|
|
|
|
|
|
|
|
|
if not cfg.rtc.enabled:
|
|
|
|
|
get_actions_threshold = 0
|
|
|
|
|
|
|
|
|
|
while not shutdown_event.is_set():
|
|
|
|
|
if action_queue.qsize() <= get_actions_threshold:
|
|
|
|
|
current_time = time.perf_counter()
|
|
|
|
|
action_index_before_inference = action_queue.get_action_index()
|
|
|
|
|
prev_actions = action_queue.get_left_over()
|
|
|
|
|
|
|
|
|
|
inference_latency = latency_tracker.max()
|
|
|
|
|
inference_delay = math.ceil(inference_latency / time_per_chunk)
|
|
|
|
|
|
|
|
|
|
obs = robot.get_observation()
|
|
|
|
|
|
|
|
|
|
# Apply robot observation processor
|
|
|
|
|
obs_processed = robot_observation_processor(obs)
|
|
|
|
|
|
|
|
|
|
obs_with_policy_features = build_dataset_frame(
|
|
|
|
|
dataset_features, obs_processed, prefix="observation"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for name in obs_with_policy_features:
|
|
|
|
|
obs_with_policy_features[name] = torch.from_numpy(obs_with_policy_features[name])
|
|
|
|
|
if "image" in name:
|
|
|
|
|
obs_with_policy_features[name] = (
|
|
|
|
|
obs_with_policy_features[name].type(torch.float32) / 255
|
|
|
|
|
)
|
|
|
|
|
obs_with_policy_features[name] = (
|
|
|
|
|
obs_with_policy_features[name].permute(2, 0, 1).contiguous()
|
|
|
|
|
)
|
|
|
|
|
obs_with_policy_features[name] = obs_with_policy_features[name].unsqueeze(0)
|
|
|
|
|
obs_with_policy_features[name] = obs_with_policy_features[name].to(policy_device)
|
|
|
|
|
|
|
|
|
|
obs_with_policy_features["task"] = [cfg.task] # Task should be a list, not a string!
|
|
|
|
|
obs_with_policy_features["robot_type"] = (
|
|
|
|
|
robot.robot.name if hasattr(robot.robot, "name") else ""
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
preproceseded_obs = preprocessor(obs_with_policy_features)
|
|
|
|
|
|
|
|
|
|
# Generate actions WITH RTC
|
|
|
|
|
actions = policy.predict_action_chunk(
|
|
|
|
|
preproceseded_obs,
|
|
|
|
|
inference_delay=inference_delay,
|
|
|
|
|
prev_chunk_left_over=prev_actions,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Store original actions (before postprocessing) for RTC
|
|
|
|
|
original_actions = actions.squeeze(0).clone()
|
|
|
|
|
|
|
|
|
|
postprocessed_actions = postprocessor(actions)
|
|
|
|
|
|
|
|
|
|
postprocessed_actions = postprocessed_actions.squeeze(0)
|
|
|
|
|
|
|
|
|
|
new_latency = time.perf_counter() - current_time
|
|
|
|
|
new_delay = math.ceil(new_latency / time_per_chunk)
|
|
|
|
|
latency_tracker.add(new_latency)
|
|
|
|
|
|
|
|
|
|
if cfg.action_queue_size_to_get_new_actions < cfg.rtc.execution_horizon + new_delay:
|
|
|
|
|
logger.warning(
|
|
|
|
|
"[GET_ACTIONS] cfg.action_queue_size_to_get_new_actions Too small, It should be higher than inference delay + execution horizon."
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
action_queue.merge(
|
|
|
|
|
original_actions, postprocessed_actions, new_delay, action_index_before_inference
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
# Small sleep to prevent busy waiting
|
|
|
|
|
time.sleep(0.1)
|
|
|
|
|
|
|
|
|
|
logger.info("[GET_ACTIONS] get actions thread shutting down")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"[GET_ACTIONS] Fatal exception in get_actions thread: {e}")
|
|
|
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def actor_control(
|
|
|
|
|
robot: RobotWrapper,
|
|
|
|
|
robot_action_processor,
|
|
|
|
|
action_queue: ActionQueue,
|
|
|
|
|
shutdown_event: Event,
|
|
|
|
|
cfg: RTCDemoConfig,
|
|
|
|
|
):
|
|
|
|
|
"""Thread function to execute actions on the robot.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
robot: The robot instance
|
|
|
|
|
action_queue: Queue to get actions from
|
|
|
|
|
shutdown_event: Event to signal shutdown
|
|
|
|
|
cfg: Demo configuration
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
logger.info("[ACTOR] Starting actor thread")
|
|
|
|
|
|
|
|
|
|
action_count = 0
|
|
|
|
|
action_interval = 1.0 / cfg.fps
|
|
|
|
|
|
|
|
|
|
while not shutdown_event.is_set():
|
|
|
|
|
start_time = time.perf_counter()
|
|
|
|
|
|
|
|
|
|
# Try to get an action from the queue with timeout
|
|
|
|
|
action = action_queue.get()
|
|
|
|
|
|
|
|
|
|
if action is not None:
|
|
|
|
|
action = action.cpu()
|
|
|
|
|
action_dict = {key: action[i].item() for i, key in enumerate(robot.action_features())}
|
|
|
|
|
action_processed = robot_action_processor((action_dict, None))
|
|
|
|
|
robot.send_action(action_processed)
|
|
|
|
|
|
|
|
|
|
action_count += 1
|
|
|
|
|
|
|
|
|
|
dt_s = time.perf_counter() - start_time
|
|
|
|
|
time.sleep(max(0, (action_interval - dt_s) - 0.001))
|
|
|
|
|
|
|
|
|
|
logger.info(f"[ACTOR] Actor thread shutting down. Total actions executed: {action_count}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"[ACTOR] Fatal exception in actor_control thread: {e}")
|
|
|
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _apply_torch_compile(policy, cfg: RTCDemoConfig):
|
|
|
|
|
"""Apply torch.compile to the policy's predict_action_chunk method.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
policy: Policy instance to compile
|
|
|
|
|
cfg: Configuration containing torch compile settings
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Policy with compiled predict_action_chunk method
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# PI models handle their own compilation
|
|
|
|
|
if policy.type == "pi05" or policy.type == "pi0":
|
|
|
|
|
return policy
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Check if torch.compile is available (PyTorch 2.0+)
|
|
|
|
|
if not hasattr(torch, "compile"):
|
|
|
|
|
logger.warning(
|
|
|
|
|
f"torch.compile is not available. Requires PyTorch 2.0+. "
|
|
|
|
|
f"Current version: {torch.__version__}. Skipping compilation."
|
|
|
|
|
)
|
|
|
|
|
return policy
|
|
|
|
|
|
|
|
|
|
logger.info("Applying torch.compile to predict_action_chunk...")
|
|
|
|
|
logger.info(f" Backend: {cfg.torch_compile_backend}")
|
|
|
|
|
logger.info(f" Mode: {cfg.torch_compile_mode}")
|
|
|
|
|
logger.info(f" Disable CUDA graphs: {cfg.torch_compile_disable_cudagraphs}")
|
|
|
|
|
|
|
|
|
|
# Compile the predict_action_chunk method
|
|
|
|
|
# - CUDA graphs disabled to prevent tensor aliasing from in-place ops (x_t += dt * v_t)
|
|
|
|
|
compile_kwargs = {
|
|
|
|
|
"backend": cfg.torch_compile_backend,
|
|
|
|
|
"mode": cfg.torch_compile_mode,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Disable CUDA graphs if requested (prevents tensor aliasing issues)
|
|
|
|
|
if cfg.torch_compile_disable_cudagraphs:
|
|
|
|
|
compile_kwargs["options"] = {"triton.cudagraphs": False}
|
|
|
|
|
|
|
|
|
|
original_method = policy.predict_action_chunk
|
|
|
|
|
compiled_method = torch.compile(original_method, **compile_kwargs)
|
|
|
|
|
policy.predict_action_chunk = compiled_method
|
|
|
|
|
logger.info("✓ Successfully compiled predict_action_chunk")
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"Failed to apply torch.compile: {e}")
|
|
|
|
|
logger.warning("Continuing without torch.compile")
|
|
|
|
|
|
|
|
|
|
return policy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@parser.wrap()
|
|
|
|
|
def demo_cli(cfg: RTCDemoConfig):
|
|
|
|
|
"""Main entry point for RTC demo with draccus configuration."""
|
|
|
|
|
|
|
|
|
|
# Initialize logging
|
|
|
|
|
init_logging()
|
|
|
|
|
|
|
|
|
|
logger.info(f"Using device: {cfg.device}")
|
|
|
|
|
|
|
|
|
|
# Setup signal handler for graceful shutdown
|
|
|
|
|
signal_handler = ProcessSignalHandler(use_threads=True, display_pid=False)
|
|
|
|
|
shutdown_event = signal_handler.shutdown_event
|
|
|
|
|
|
|
|
|
|
policy = None
|
|
|
|
|
robot = None
|
|
|
|
|
get_actions_thread = None
|
|
|
|
|
actor_thread = None
|
|
|
|
|
|
|
|
|
|
policy_class = get_policy_class(cfg.policy.type)
|
|
|
|
|
|
|
|
|
|
# Load config and set compile_model for pi0/pi05 models
|
|
|
|
|
config = PreTrainedConfig.from_pretrained(cfg.policy.pretrained_path)
|
|
|
|
|
|
|
|
|
|
if cfg.policy.type == "pi05" or cfg.policy.type == "pi0":
|
|
|
|
|
config.compile_model = cfg.use_torch_compile
|
|
|
|
|
|
Add basic PEFT support to train script + record module (#1411)
* Add basic support for PEFT adapter methods
This changes adds support for training policies with much less parameters
by applying adapter methods such as LoRA on specific parts of the policies
and therefore possibly higher learning rates / batch sizes.
To make this as accessible as possible I thought it useful to provide
defaults for `target_modules` and `modules_to_save`. Currently only SmolVLA
has such defaults but when we agree that this change is useful I will set
out to generate more such defaults. While the user can override these
settings, they are expected to only change the peft_method, rank and init_type
parameters.
* Implement loading of PEFT adapters
Loading a PEFT adapter is currently done by initializing a policy with default config
and then applying the adapter on the resulting model. This has the obvious drawback
that any configurations done during training are not applied in the adapted model.
Currently the `use_peft` attribute of `PreTrainedConfig` is only set during loading
to signal the following code that it has to deal with a PEFT adapter. However
we could imagine a scenario where this is already set at training time and stored
alongside the adapter.
* Store policy config alongside PEFT checkpoint
Before this change the PEFT-wrapped policy did not save the policy's config
alongside the adapter config / weights which prevented us from changing the
policy config. Now the policy config is saved both in full training and PEFT
training.
This change makes loading the PEFT policy adapter much easier as well.
* Add default config for ACT
* Support targets like `all-linear`
* Formatting
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
* Fix failing tests
* Remove PEFT compatibility changes in config
We'll wait for the PEFT release that fixes this for good.
* Remove `use_peft` parameter from training script
Instead we make the PEFT config optional which has the same effect.
* Log adapter config to WandB
* Better documentation for CLI arguments
* Don't unload & merge the PEFT model
This can make things hard when using quantized layers (user expects quantized base layers with
unquantized adapters for example, merging defaults to upcast the layers leading to higher
memory).
* Correct way of identifying when to save config
* Add CLI end-to-end tests
Currently there don't seem to be any way to test the CLI commands.
Since this change mostly happens in those I thought it best to add
a way to test these commands end-to-end.
More integrated commands like `lerobot-record` need patching but
standalone commands like training seem to work fine.
* Update default targets
Removed ACT since it doesn't make sense to fine-tune ACT without having it pretrained beforehand.
SmolVLA and Pi0/0.5 are much more senseful targets.
* Clean up loading code
- Centralized instantiation of the PEFT wrapper in `make_policy` for inference
(e.g. in `lerobot-record`)
- Training a PEFT policy also sets `cfg.use_peft` so that all inference code loading
the policy can rely on that attribute to identify if PEFT loading is needed
- Modified RTC example to also include PEFT policies. Mostly because this is an example
I'm currently exploring.
* Make sure push_to_hub works
Since PEFT only wraps `push_to_hub` and not `push_model_to_hub`, the reference
to `self` in `policy.push_model_to_hub` is the unwrapped policy which, of course,
doesn't know anything about PEFT.
To make the upload process aware of PEFT, we pass the unwrapped policy down to
`push_model_to_hub` as a kwarg. This is not ideal but I think it is the best way
for now.
* formatting
* Warn when encountering from-scratch-training
* Revamp pretrained model loading
There were quite a few factors that convinced me that the status quo
is able to load pretrained models from the PEFT adapter config but
in fact that didn't work.
This commit fixes the following things:
- policies wrapped in PEFT will now have a `name_or_path` attribute
containing the name or path of the pretrained model we're fine-tuning
- we further assume that SmolVLA without `pretrained_path` and
`load_vlm_weights==False` must be an user-side error
- we assume that using PEFT on from-scratch-policies must be
an user-side-error
* Make it possible to unset policy features
This is necessary to train pre-trained policies on new datasets so that the
features are inferred from the new dataset and not from the pretrained
policy.
* Use correct loading for PEFT in RTC example
* Make it possible to use PeftModels in eval
* Add test checking that PEFT actually reduces params
* Adapt state/action projections instead of full-finetuning
There doesn't seem to be a benefit to fully fine-tune these layers
over just adapting them, so we do that instead.
* Disallow PEFT training on non-pretrained policies
At first I thought it would make sense to have this feature
in case you want to fine-tune a pre-trained section but in the
end it makes more trouble than it's worth.
It's still possible to allow this in the future when a concrete
need arises.
* Add basic documentation
* Formatting
* Add peft as extra dependency, mark tests
Fast tests currently fail because of the missing dependency.
* Fix pre-commit issues
* Add walx <> peft conflict for uv
* Exclude peft from pi install for now
---------
Co-authored-by: nemo <git@ningu.net>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Pepijn <138571049+pkooij@users.noreply.github.com>
2026-01-05 08:51:26 +01:00
|
|
|
if config.use_peft:
|
|
|
|
|
from peft import PeftConfig, PeftModel
|
|
|
|
|
|
|
|
|
|
peft_pretrained_path = cfg.policy.pretrained_path
|
|
|
|
|
peft_config = PeftConfig.from_pretrained(peft_pretrained_path)
|
|
|
|
|
|
|
|
|
|
policy = policy_class.from_pretrained(
|
|
|
|
|
pretrained_name_or_path=peft_config.base_model_name_or_path, config=config
|
|
|
|
|
)
|
|
|
|
|
policy = PeftModel.from_pretrained(policy, peft_pretrained_path, config=peft_config)
|
|
|
|
|
else:
|
|
|
|
|
policy = policy_class.from_pretrained(cfg.policy.pretrained_path, config=config)
|
[RTC] Real Time Chunking for Pi0, Smolvla, Pi0.5 (#1698)
* Add Real-Time Chunking (RTC) support for flow matching models
Implement Real-Time Chunking (RTC) for action chunking policies using flow
matching denoising. RTC enables smooth action transitions between consecutive
chunks by using prefix guidance during denoising.
Key features:
- RTCProcessor class with denoise_step method for RTC guidance
- Tracker system for debug tracking using time-based dictionary storage
- RTCDebugVisualizer with comprehensive visualization utilities
- Integration with SmolVLA policy for flow matching models
- Support for multiple prefix attention schedules (ZEROS, ONES, LINEAR, EXP)
- Configurable execution horizon and max guidance weight
- Example scripts for dataset evaluation and real-time control
Technical details:
- Uses autograd-based gradient computation for RTC corrections
- Time-based tracking eliminates duplicate step issues
- Proxy methods in RTCProcessor for cleaner API
- Full integration with LeRobot's policy and dataset systems
Files added/modified:
- src/lerobot/configs/types.py: Add RTCAttentionSchedule enum
- src/lerobot/policies/rtc/: Core RTC implementation
- configuration_rtc.py: RTC configuration
- modeling_rtc.py: RTCProcessor with denoise_step
- debug_handler.py: Tracker for debug information
- debug_visualizer.py: Visualization utilities
- src/lerobot/policies/smolvla/modeling_smolvla.py: RTC integration
- examples/rtc/: Example scripts and evaluation tools
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix rtc_config attribute access in SmolVLA
Use getattr() to safely check for rtc_config attribute existence
instead of direct attribute access. This fixes AttributeError when
loading policies without rtc_config in their config.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix rtc_config attribute access in SmolVLA
* Add RTCConfig field to SmolVLAConfig
Add rtc_config as an optional field in SmolVLAConfig to properly
support Real-Time Chunking configuration. This replaces the previous
getattr() workarounds with direct attribute access, making the code
cleaner and more maintainable.
Changes:
- Import RTCConfig in configuration_smolvla.py
- Add rtc_config: RTCConfig | None = None field
- Revert getattr() calls to direct attribute access in modeling_smolvla.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Refactor RTC enabled checks to use _rtc_enabled helper
Add _rtc_enabled() helper method in VLAFlowMatching class to simplify
and clean up RTC enabled checks throughout the code. This reduces
code duplication and improves readability.
Changes:
- Add _rtc_enabled() method in VLAFlowMatching
- Replace verbose rtc_config checks with _rtc_enabled() calls
- Maintain exact same functionality with cleaner code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Rename track_debug method to track
Simplify the method name from track_debug to just track for better
readability and consistency. The method already has clear documentation
about its debug tracking purpose.
Changes:
- Rename RTCProcessor.track_debug() to track()
- Update all call sites in modeling_smolvla.py and modeling_rtc.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Use output_dir for saving all evaluation images
Update eval_dataset.py to save all comparison images to the
configured output_dir instead of the current directory. This provides
better organization and allows users to specify where outputs should be
saved.
Changes:
- Add os import at top level
- Create output_dir at start of run_evaluation()
- Save all comparison images to output_dir
- Remove duplicate os imports
- Update init_rtc_processor() docstring to be more concise
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Use output_dir for saving all evaluation images
* Fix logging buffering and enable tracking when RTC config provided
- Add force=True to logging.basicConfig to override existing configuration
- Enable line buffering for stdout/stderr for real-time log output
- Modify init_rtc_processor to create processor when rtc_config exists
even if RTC is disabled, allowing tracking of denoising data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor SmolVLA plotting to use tracker data instead of local variables
Remove local tracking variables (correction, x1_t, error) from the
denoising loop and instead retrieve plotting data from the RTC tracker
after each denoise step. This makes the code cleaner and uses the
tracker as the single source of truth for debug/visualization data.
Changes:
- Remove initialization of correction, x1_t, error before denoising loop
- After each Euler step, retrieve most recent debug step from tracker
- Extract correction, x1_t, err from debug step for plotting
- Update tracking condition to use is_debug_enabled() method
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Move plotting logic from modeling_smolvla to eval_dataset script
Refactor to improve separation of concerns:
modeling_smolvla.py changes:
- Remove all plotting logic from sample_actions method
- Remove viz_xt_axs, viz_vt_axs, viz_x1t_axs parameters
- Remove matplotlib and RTCDebugVisualizer imports
- Remove viz_fig, viz_axs, denoise_step_counter instance variables
- Simplify denoising loop to only track data in rtc_processor
eval_dataset.py changes:
- Add _plot_denoising_steps_from_tracker helper method
- Retrieve debug steps from tracker after inference
- Plot x_t, v_t, x1_t, correction, and error from tracker data
- Enable debug tracking (cfg.rtc.debug = True) for visualization
- Remove viz axes parameters from predict_action_chunk calls
modeling_rtc.py changes:
- Remove v_t from track() call (handled by user change)
Benefits:
- Cleaner modeling code focused on inference
- Evaluation script owns all visualization logic
- Better separation of concerns
- Tracker is single source of truth for debug data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* Refactor plotting loging
* fixup! Refactor plotting loging
* Improve visualization: separate correction plot and fix axis scaling
Changes:
- Create separate figure for correction data instead of overlaying on v_t
- Add _rescale_axes helper method to properly scale all axes
- Add 10% margin to y-axis for better visualization
- Fix v_t chart vertical compression issue
Benefits:
- Clearer v_t plot without correction overlay
- Better axis scaling with proper margins
- Separate correction figure for focused analysis
- Improved readability of all denoising visualizations
Output files:
- denoising_xt_comparison.png (x_t trajectories)
- denoising_vt_comparison.png (v_t velocity - now cleaner)
- denoising_correction_comparison.png (NEW - separate corrections)
- denoising_x1t_comparison.png (x1_t state with error)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Alexander Soare <alexander.soare159@gmail.com>
* fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* fixup! fixup! fixup! Improve visualization: separate correction plot and fix axis scaling
* Fix traacking
* Right kwargs for the policy
* Add tests for tracker
* Fix tests
* Drop not required methods
* Add torch compilation for eval_dataset
* delete policies
* Add matplotliv to dev
* fixup! Add matplotliv to dev
* Experiemnt with late detach
* Debug
* Fix compilation
* Add RTC to PI0
* Pi0
* Pi0 eval dataset
* fixup! Pi0 eval dataset
* Turn off compilation for pi0/pi05
* fixup! Turn off compilation for pi0/pi05
* fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* fixup! fixup! fixup! fixup! fixup! Turn off compilation for pi0/pi05
* Add workable flow
* Small fixes
* Add more tests
* Add validatio at the end
* Update README
* Silent validation
* Fix tests
* Add tests for modeling_rtc
* Add tests for flow matching models with RTC
* fixup! Add tests for flow matching models with RTC
* fixup! fixup! Add tests for flow matching models with RTC
* Add one more test
* fixup! Add one more test
* Fix test to use _rtc_enabled() instead of is_rtc_enabled()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* fixup! fixup! Fix test to use _rtc_enabled() instead of is_rtc_enabled()
* Add RTC initialization tests without config for PI0.5 and SmolVLA
Add test_pi05_rtc_initialization_without_rtc_config and
test_smolvla_rtc_initialization_without_rtc_config to verify that
policies can initialize without RTC config and that _rtc_enabled()
returns False in this case.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix SmolVLA init_rtc_processor to use getattr instead of direct model access
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fixup! Fix PI0.5 RTC tests to use quantile stats (q01, q99) for normalization
* Fixup eval with real robot
* fixup! Fixup eval with real robot
* fixup! fixup! Fixup eval with real robot
* Extract simulator logic from eval_with real robot and add proper headers to files
* Update images
* Fix tests
* fixup! Fix tests
* add docs for rtc
* enhance doc and add images
* Fix instal instructions
---------
Co-authored-by: Ben Zhang <benzhangniu@gmail.com>
Co-authored-by: Alexander Soare <alexander.soare159@gmail.com>
Co-authored-by: Michel Aractingi <michel.aractingi@huggingface.co>
2025-11-19 17:19:48 +07:00
|
|
|
|
|
|
|
|
# Turn on RTC
|
|
|
|
|
policy.config.rtc_config = cfg.rtc
|
|
|
|
|
|
|
|
|
|
# Init RTC processort, as by default if RTC disabled in the config
|
|
|
|
|
# The processor won't be created
|
|
|
|
|
policy.init_rtc_processor()
|
|
|
|
|
|
|
|
|
|
assert policy.name in ["smolvla", "pi05", "pi0"], "Only smolvla, pi05, and pi0 are supported for RTC"
|
|
|
|
|
|
|
|
|
|
policy = policy.to(cfg.device)
|
|
|
|
|
policy.eval()
|
|
|
|
|
|
|
|
|
|
# Apply torch.compile to predict_action_chunk method if enabled
|
|
|
|
|
if cfg.use_torch_compile:
|
|
|
|
|
policy = _apply_torch_compile(policy, cfg)
|
|
|
|
|
|
|
|
|
|
# Create robot
|
|
|
|
|
logger.info(f"Initializing robot: {cfg.robot.type}")
|
|
|
|
|
robot = make_robot_from_config(cfg.robot)
|
|
|
|
|
robot.connect()
|
|
|
|
|
robot_wrapper = RobotWrapper(robot)
|
|
|
|
|
|
|
|
|
|
# Create robot observation processor
|
|
|
|
|
robot_observation_processor = make_default_robot_observation_processor()
|
|
|
|
|
robot_action_processor = make_default_robot_action_processor()
|
|
|
|
|
|
|
|
|
|
# Create action queue for communication between threads
|
|
|
|
|
action_queue = ActionQueue(cfg.rtc)
|
|
|
|
|
|
|
|
|
|
# Start chunk requester thread
|
|
|
|
|
get_actions_thread = Thread(
|
|
|
|
|
target=get_actions,
|
|
|
|
|
args=(policy, robot_wrapper, robot_observation_processor, action_queue, shutdown_event, cfg),
|
|
|
|
|
daemon=True,
|
|
|
|
|
name="GetActions",
|
|
|
|
|
)
|
|
|
|
|
get_actions_thread.start()
|
|
|
|
|
logger.info("Started get actions thread")
|
|
|
|
|
|
|
|
|
|
# Start action executor thread
|
|
|
|
|
actor_thread = Thread(
|
|
|
|
|
target=actor_control,
|
|
|
|
|
args=(robot_wrapper, robot_action_processor, action_queue, shutdown_event, cfg),
|
|
|
|
|
daemon=True,
|
|
|
|
|
name="Actor",
|
|
|
|
|
)
|
|
|
|
|
actor_thread.start()
|
|
|
|
|
logger.info("Started actor thread")
|
|
|
|
|
|
|
|
|
|
logger.info("Started stop by duration thread")
|
|
|
|
|
|
|
|
|
|
# Main thread monitors for duration or shutdown
|
|
|
|
|
logger.info(f"Running demo for {cfg.duration} seconds...")
|
|
|
|
|
start_time = time.time()
|
|
|
|
|
|
|
|
|
|
while not shutdown_event.is_set() and (time.time() - start_time) < cfg.duration:
|
|
|
|
|
time.sleep(10)
|
|
|
|
|
|
|
|
|
|
# Log queue status periodically
|
|
|
|
|
if int(time.time() - start_time) % 5 == 0:
|
|
|
|
|
logger.info(f"[MAIN] Action queue size: {action_queue.qsize()}")
|
|
|
|
|
|
|
|
|
|
if time.time() - start_time > cfg.duration:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
logger.info("Demo duration reached or shutdown requested")
|
|
|
|
|
|
|
|
|
|
# Signal shutdown
|
|
|
|
|
shutdown_event.set()
|
|
|
|
|
|
|
|
|
|
# Wait for threads to finish
|
|
|
|
|
if get_actions_thread and get_actions_thread.is_alive():
|
|
|
|
|
logger.info("Waiting for chunk requester thread to finish...")
|
|
|
|
|
get_actions_thread.join()
|
|
|
|
|
|
|
|
|
|
if actor_thread and actor_thread.is_alive():
|
|
|
|
|
logger.info("Waiting for action executor thread to finish...")
|
|
|
|
|
actor_thread.join()
|
|
|
|
|
|
|
|
|
|
# Cleanup robot
|
|
|
|
|
if robot:
|
|
|
|
|
robot.disconnect()
|
|
|
|
|
logger.info("Robot disconnected")
|
|
|
|
|
|
|
|
|
|
logger.info("Cleanup completed")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
demo_cli()
|
|
|
|
|
logging.info("RTC demo finished")
|