CoolFace
Datasetpublic

NagaYu/saccade-egomotion-bench

Saccade ego-motion benchmark The stream, the raw decision signals, and the per-frame measurements behind Saccade β€” an always-on edge VLM that re-encodes only the image patches whose change ego-motion cannot explain. This dataset exists so the central claim can be checked without running our code. πŸ’» Code: https://github.com/NagaYu/saccade πŸ€– Model: https://huggingface.co/NagaYu/saccade-predictor πŸš€ Demo: https://huggingface.co/spaces/NagaYu/saccade The claim, in… See the full description on the dataset page: https://huggingface.co/datasets/NagaYu/saccade-egomotion-bench.

sourceHugging Facemitupdated 18d agoView on Hugging Face
0likes167downloads
Dataset Card

Saccade ego-motion benchmark

The stream, the raw decision signals, and the per-frame measurements behind **Saccade** β€” an always-on edge VLM that re-encodes only the image patches whose change ego-motion cannot explain.

This dataset exists so the central claim can be checked without running our code.

  • β€”πŸ’» Code: https://github.com/NagaYu/saccade
  • β€”πŸ€– Model: https://huggingface.co/NagaYu/saccade-predictor
  • β€”πŸš€ Demo: https://huggingface.co/spaces/NagaYu/saccade

The claim, in one number

On the segments with predictable camera motion (walk + turn), at an identical threshold Ο„ = 0.06:

Decision rulePatches it must re-encode
Same-position residual (what temporal-similarity skipping thresholds)47.4 %
Motion-compensated residual (what Saccade thresholds)0.3 %

Same frames, same threshold β€” only the reference frame differs. A moving camera changes almost every pixel, so frame-differencing cannot thin the workload during steady motion; subtract the ego-motion first and a static world's residual collapses to nearly nothing.

Verify it yourself in four lines:

python
from datasets import load_dataset
import numpy as np

sig = load_dataset("NagaYu/saccade-egomotion-bench", "signals", split="train").to_pandas()
walk = sig[sig.segment.isin(["walk", "turn"])]
print((np.stack(walk.residual_same_position)        > 0.06).mean())  # ~0.474
print((np.stack(walk.residual_motion_compensated)   > 0.06).mean())  # ~0.003

Configs

frames β€” the stream itself (144 rows)

The scripted ego-motion video, so another method can be benchmarked on the exact same input.

ColumnTypeDescription
indexint32frame index
imageImage224Γ—224 RGB frame
segmentstringregime: static, walk, turn, event
ego_motion_mag_meanfloat32mean optical-flow magnitude (patch units)
ego_motion_mag_medianfloat32median flow magnitude β€” the robust ego-motion estimate (a single moving object must not read as camera motion)

signals β€” the two competing decision signals (143 rows)

The direct evidence. Per frame, the per-patch residual map under both rules.

ColumnTypeDescription
index, segmentint32/stringas above
residual_same_positionfloat32[196]per-patch residual vs the co-located previous patch
residual_motion_compensatedfloat32[196]per-patch residual vs the motion-warped previous frame
encode_frac_same_positionfloat32fraction above Ο„=0.06 under the first rule
encode_frac_motion_compensatedfloat32fraction above Ο„=0.06 under the second

Residuals are mean absolute pixel differences in [0,1] on a 14Γ—14 patch grid (row-major; reshape(14, 14) to get a map).

measurements β€” per-frame energy and quality (432 rows = 144 Γ— 3 conditions)

ColumnTypeDescription
indexint64frame index
conditionstringFull, TemporalSim or Saccade
n_encoded, encoded_fractionint/floatpatches actually re-encoded
fidelityfloatcosine of the reconstructed patch-token map vs the Full encoder
frame_flops, frame_joules, cum_joulesfloatanalytic energy model
processedboolFalse = frame dropped entirely (anytime degraded output)
taufloatthreshold in force (the budget controller adapts it)
budget_okboolwhether cum_J ≀ BΒ·t + Eβ‚€ still held

Headline (steady-state, excluding 6 warm-up frames, budget 20 mW):

Conditionre-encodedfidelityenergyruntime @10 kJ
Full100 %1.0001.264 J30.3 h
TemporalSim33.9 %0.97230.430 J89.1 h
Saccade20.7 %0.97390.263 J145.8 h

How the stream was made

Deterministically generated (saccade.stream.synthetic_walking_stream, seed 0): a window panning over a large static textured canvas, scripted into four regimes β€”

  • β€”static β€” camera still, world still (both methods should skip; fair region)
  • β€”walk β€” smooth translation across a static world (predictable ego-motion)
  • β€”turn β€” faster translation plus mild rotation (harder ego-motion)
  • β€”event β€” camera still, an independently moving object crosses (genuine change; every method must spend here)

Limitations β€” please read

  • β€”This is synthetic video, not natural footage. It is a controlled apparatus for the steady-motion regime, chosen so the result is exactly reproducible. It is deliberately not evidence about natural scenes with parallax, motion blur, rolling shutter, exposure changes or non-rigid motion. Treat conclusions as being about the mechanism, not about wearable cameras in the wild.
  • β€”fidelity is patch-token cosine similarity against a Full encoder β€” a proxy for downstream task quality, not a task metric like VQA accuracy.
  • β€”Energy is an analytic FLOP model (FLOPs Γ— 1 pJ/FLOP), not a power-meter measurement. Relative comparisons and the budget guarantee are sound; absolute Joules are model-dependent.
  • β€”measurements uses the SyntheticBackbone (a frozen random ViT-S/16-class patch encoder), chosen because each patch embedding is genuinely independent so subset encoding realizes real savings. Numbers on a real ViT differ; see the repo for DINOv2-small results.

Reproduce

bash
git clone https://github.com/NagaYu/saccade && cd saccade
pip install -r requirements.txt
python hf/export_dataset.py     # rebuilds every config from scratch

License

MIT