Skip to content

feat(trim): add motion trimming - find dead frames from proprioception - #39

Merged
ykdojo merged 8 commits into
mainfrom
motion-trim
Jul 31, 2026
Merged

feat(trim): add motion trimming - find dead frames from proprioception#39
ykdojo merged 8 commits into
mainfrom
motion-trim

Conversation

@ykdojo

@ykdojo ykdojo commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Finds the dead frames in an episode - operator setup before anything happens, the tail after the task is done - without decoding video. The robot's joint positions sit in parquet next to the mp4, so a still arm is a columnar scan away. On DROID that's 12 GB of proprioception against 400 GB of video.

Two outputs, for two kinds of consumer: a per-frame is_active flag (frame samplers - drops interior pauses too) and one contiguous window per episode from trim_windows (video slices). proprio/ is plain expressions, same shape as track_hands / score_rewards; trim/ takes a DataFrame and returns one.

On DROID 1.0.1 (4 shards, 4,391 episodes, 1.28M frames): 3.8% trimmed in the window view, 11.2% per-frame, reproducing the multibase prototype. Aborted takes where the arm never moves keep their full span, flagged never_active.

examples/trim/ is the committed executed walkthrough (one DROID shard streamed from Hugging Face), generated by the new daft-physical-ai trim CLI subcommand. 25 new tests, 103 passing.

Prototype, method writeup, and figures: Eventual-Inc/multibase#1169 (private).

ykdojo added 6 commits July 28, 2026 14:36
Two modules. proprio/ turns the robot's joint-state columns into a per-frame
motion signal: motion_scale measures the typical per-dim step in one pass,
motion_energy diffs each dim against its previous value inside the episode and
combines them as a normalized Euclidean norm, is_active thresholds that with a
run requirement so one noisy frame is not motion. All plain Daft expressions -
no UDF, no video decode.

trim/ reduces that to one contiguous window per episode. It takes a DataFrame
and returns a DataFrame, unlike the rest of the package, because a window is an
aggregation across an episode's rows rather than a per-row value. Aborted takes
where the arm never moves keep their full span and get a never_active flag.

The two views serve different consumers: frame samplers filter on is_active and
drop interior pauses too; video-slice consumers take the window, which has to
keep them to stay contiguous.

Validated on DROID 1.0.1 (4 shards, 4,391 episodes, 1.28M frames): 3.8% trimmed
in the window view, 11.2% per-frame, matching the multibase prototype. 25 new
tests, 103 passing overall.
daft-physical-ai trim scaffolds a motion-trimming demo (script + notebook +
markdown) from a TrimDemoConfig, mirroring hands and rewards. The committed
examples/trim/ is the executed default: one DROID shard streamed from Hugging
Face, 321,344 frames, 4.0% dropped in the window view and 11.2% in the
per-frame view. 12 new tests.
""[:1] in "[{" is True (empty string is a substring), so an empty cell
rendered as a stray backtick pair in the markdown table.
frames.show(5) after the build cell, so all three formats display what
one-row-per-frame actually looks like before the motion scoring.
The task column showed blank for episode 0 (~21% of DROID episodes have
no task label) and the trim workflow never uses it. Also drop the
score_rewards aside from the what-it-saves note.
@ykdojo
ykdojo marked this pull request as ready for review July 30, 2026 19:39
ty infers Expression == int as bool (daft doesn't type __eq__), so the
one live == comparison fails the style check; is_in is typed properly
and already used elsewhere in the package.
@ykdojo
ykdojo merged commit 444ed8d into main Jul 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant