feat(pipeline): sequential H-Net pipeline, flat stages instead of a nested trunk - #567
Draft
ElmoPA wants to merge 1 commit into
Draft
feat(pipeline): sequential H-Net pipeline, flat stages instead of a nested trunk#567ElmoPA wants to merge 1 commit into
ElmoPA wants to merge 1 commit into
Conversation
…ested trunk
Dissolves DualstreamTrunk (which nests level i.inner = level i+1 and recurses
mid-forward) into an explicit, flat stages list. Every stage declares `reads`
and `writes`, so the wiring is inspectable from the config alone rather than
implied by nesting.
stages_seq.py StreamTrunk, Framewise, Chunk, Dechunk, Apex, Mix, Rename,
ScheduledRatioLoss, ObsNoise, VisualEncode, ObsEmbed, Fuse,
TimePos -- the encoder is stages too, so obs routing is
visible instead of hidden inside an encoder module.
config_graph.py builds the routing graph by INSTANTIATING each stage and
reading its declared reads/writes (ground truth, not a yaml
parse), with a lint for dim/key mismatches and a 3D viewer.
Configs: 7 arms -- a baseline plus shared/separate encoder and attention-window
variants, on circle+small_circle and circle+u_socket.
Also carried over from the working stack, without which the above cannot run:
per-stream trunk options (multi_stream_trunk), route_on / separate_boundaries
on DualStreamRouter, SharedObsEncoders + DeriveVelocity (stages_io), StreamMLP
(stages_hnet), the hetero denoiser and per-embodiment codec (stages_flow), and
confidence_ssl.
Strictness: CondEncoderModule gains strict_keys and Theta/RotVec gain strict,
both default True. A mis-typed key was previously a silent no-op -- an encoder
would train on the remaining inputs (vision with no proprio) with no error, and
a rotvec transform would leave the angle un-encoded while downstream still
sliced for (cos, sin). Transforms and encoders see KEY_MAP ALIASES, not zarr
paths; get_rotvec_transform_list previously passed
"observations.pusher_cmd_pose", a zarr path that could never match.
Verified from this repo (not the working stack): all symbols import including
the pre-existing PadGripperZeros, strict=True raises and strict=False passes
through, and all 7 configs instantiate with a clean lint, producing node/edge
counts identical to the stack that is currently training them.
Contributor
Author
This was referenced Aug 12, 2026
This was referenced Aug 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Dissolves DualstreamTrunk (which nests level i.inner = level i+1 and recurses
mid-forward) into an explicit, flat stages list. Every stage declares
readsand
writes, so the wiring is inspectable from the config alone rather thanimplied by nesting.
stages_seq.py StreamTrunk, Framewise, Chunk, Dechunk, Apex, Mix, Rename,
ScheduledRatioLoss, ObsNoise, VisualEncode, ObsEmbed, Fuse,
TimePos -- the encoder is stages too, so obs routing is
visible instead of hidden inside an encoder module.
config_graph.py builds the routing graph by INSTANTIATING each stage and
reading its declared reads/writes (ground truth, not a yaml
parse), with a lint for dim/key mismatches and a 3D viewer.
Configs: 7 arms -- a baseline plus shared/separate encoder and attention-window
variants, on circle+small_circle and circle+u_socket.
Also carried over from the working stack, without which the above cannot run:
per-stream trunk options (multi_stream_trunk), route_on / separate_boundaries
on DualStreamRouter, SharedObsEncoders + DeriveVelocity (stages_io), StreamMLP
(stages_hnet), the hetero denoiser and per-embodiment codec (stages_flow), and
confidence_ssl.
Strictness: CondEncoderModule gains strict_keys and Theta/RotVec gain strict,
both default True. A mis-typed key was previously a silent no-op -- an encoder
would train on the remaining inputs (vision with no proprio) with no error, and
a rotvec transform would leave the angle un-encoded while downstream still
sliced for (cos, sin). Transforms and encoders see KEY_MAP ALIASES, not zarr
paths; get_rotvec_transform_list previously passed
"observations.pusher_cmd_pose", a zarr path that could never match.
Verified from this repo (not the working stack): all symbols import including
the pre-existing PadGripperZeros, strict=True raises and strict=False passes
through, and all 7 configs instantiate with a clean lint, producing node/edge
counts identical to the stack that is currently training them.