refactor(unified_trainer): extract step merging into a shared backend-agnostic module#576
Open
listar2000 wants to merge 1 commit into
Open
refactor(unified_trainer): extract step merging into a shared backend-agnostic module#576listar2000 wants to merge 1 commit into
listar2000 wants to merge 1 commit into
Conversation
Both the Tinker and Verl transforms used to implement near-identical
cumulative-prefix step merging in backend-specific code, with the same
loop accessing slightly different fields. That made debugging or evolving
the merge in one backend require touching the other, and duplicated the
delta-extension logic.
This change pulls the merge into rllm/experimental/common/step_merge.py
behind a small typed protocol:
- MergedSegment is the post-merge intermediate (prompt_ids, response_ids,
plus per-flat-token mask/logprobs/advantages and an extras dict).
- merge_trajectory_steps() walks Trajectory.steps once and emits one
MergedSegment per cumulative-prefix run.
- TokenOps is a Protocol; DefaultTokenOps covers list[int] backends
(Verl) and lives in step_merge.py. Tinker ships its own
_TinkerTokenOps that handles EncodedTextChunk unwrapping and chunk
.length counting (typed against TinkerTokenInput).
- PerTokenExtras (router_replay) and per_segment_extras (multimodal
inputs) are the two extension hooks the existing backends needed.
Backend transforms are now thin Datum/DataProto adapters over
MergedSegment. Net diff in the existing files: -262 / +136 lines.
Tests: new tests/unified_trainer/test_step_merge.py covers both the
default int ops and a mock chunk-aware ops (single step, prefix merging,
prefix breaks, image-chunk equality, strict vs tolerant, per-token and
per-segment extras, length invariant). The Tinker test file drops the
TestIsPrefix and TestFlattenTokenInput classes (now subsumed) and keeps
the Datum-builder tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, reopen this pull request to trigger a review.
Collaborator
|
would like to see some e2e tests on this one to ensure no regression : ) |
Collaborator
Author
For sure. Would do the tests soon. |
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.
Summary
Both the Tinker and Verl transforms used to implement near-identical cumulative-prefix step merging in backend-specific code, with the same delta-extension loop accessing slightly different fields. This PR pulls the merge into one place behind a small typed protocol, and turns the backend transforms into thin Datum / DataProto adapters over a common
MergedSegment.What changed
New module
rllm/experimental/common/step_merge.py:MergedSegment— post-merge intermediate (prompt_ids,response_ids, plus per-flat-tokenresponse_mask/response_logprobs/response_advantagesand anextrasdict).merge_trajectory_steps(trajectory, *, token_ops, ...)— walksTrajectory.stepsonce and emits oneMergedSegmentper cumulative-prefix run.TokenOpsProtocol typed againstTokenInputfromrllm/experimental/rollout/types.py.DefaultTokenOpscoverslist[int]backends (Verl) and is the default; Tinker ships its own_TinkerTokenOpsthat handlesEncodedTextChunkunwrapping and chunk.lengthcounting.PerTokenExtras(Tinkerrouter_replay) andper_segment_extras(Verlmulti_modal_inputs) are the two extension hooks the existing backends needed.Backend transforms become thin adapters:
rllm/trainer/tinker/transform.py:trajectory_to_datumscalls the merge with_TINKER_OPS, then_segment_to_datumbuilds the TinkerDatum(concat prompt+response, prepend prompt-region zeros, right-shift).rllm/experimental/verl/transform.py:_process_trajectorycalls the merge with the default ops,pad_short_logprobs=True,skip_steps_without_model_output=True, then materialises tensors and feedsaccumulated.add_step.Net diff in existing files: -262 / +136 lines (~−40%).
Tests
New
tests/unified_trainer/test_step_merge.py(33 tests) covers the merge directly with both the default int ops and a mock chunk-awareTokenOpsmirroring what Tinker ships:ImageChunkequality on prefix matches and splits; delta_obs containing chunks expands the per-token arrays correctlyrequire_logprobs/require_advantage) vs tolerant (pad_short_logprobs, missing→zeros) modesskip_steps_without_model_outputfilterPerTokenExtras(routing matrices) with pad behavior over delta_obs and steps lacking the fieldper_segment_extras(multimodal) taken from each segment's first stepThe Tinker test file drops
TestIsPrefixandTestFlattenTokenInput(now subsumed bytest_step_merge.py) and keeps the Datum-builder tests; one assertion-message regex was relaxed to match the new wording.Test plan
./venv/bin/python -m pytest tests/unified_trainer/— 70 passed (33 step_merge + 9 tinker + 6 verl + 22 others)tests/suite (the same 13 pre-existing failures onmainreproduce, unrelated to this change)🤖 Generated with Claude Code