Reject sequence packing under pipeline parallelism - #205
Open
timothyngo wants to merge 2 commits into
Open
timothyngo wants to merge 2 commits into
timothyngo wants to merge 2 commits into
Conversation
PipelineStageModule.forward receives only hidden states, and pipeline_step never read batch["doc_ids"], so `pp > 1` with `data.pack_sequences = true` trained with cross-document attention: packed documents attended across each other while the labels still masked the boundary positions. The loss looked correct while attention leaked, which is why it went unnoticed. JobConfig.validate now raises on the combination. Packing without PP and PP without packing are both unchanged, and no shipped config sets pack_sequences, so no existing run is affected.
_compute_packed_output carried a document counter in a Python for-loop over every token. It runs inside __getitem__, so it cost one interpreter iteration per token on every sample the loader yields -- seq_len iterations per sample, on the dataloader's critical path. doc_ids[i] is just the number of EOS tokens strictly before i, so a single np.cumsum over the shifted EOS mask replaces the loop. Behavior-preserving; TestComputePackedOutput pins the semantics and a new randomized test compares against the literal counter loop it replaces.
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
5 tasks
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
Two independent, self-contained commits on the sequence-packing path. Neither depends on FlexAttention; this is the first of three PRs (see Follow-ups).
pp > 1+data.pack_sequencesinJobConfig.validate.PipelineStageModule.forwardreceives only hidden states (pipeline_parallel.py:192, layer call at:216) andpipeline_stepnever readbatch["doc_ids"](loop.py:194-226), so the combination trained with cross-document attention. Packing's label half still worked — labels carry-100at boundaries from the dataset — so the loss looked correct while attention leaked, which is why it went unnoticed._compute_packed_output's doc-id assignment. It carried a counter in a Pythonforloop over every token, inside__getitem__—seq_leninterpreter iterations per sample, on the dataloader's critical path.doc_ids[i]is just the number of EOS tokens strictly beforei, so onenp.cumsumover the shifted EOS mask replaces it.Kept as separate commits so the refactor is not bundled with the bug fix.
Behavior change
The validation error is the only user-visible change. Packing without PP, and PP without packing, are both unchanged. No config in
configs/train/setspack_sequences, so no existing run is affected — the shipped PP configs (13b_32gpu_tp4_pp2.toml,29b_32gpu_tp4_pp2.toml,70b_32gpu_tp4_pp4.toml) all still load, whichtest_shipped_config_loadscovers.The vectorization is behavior-preserving:
TestComputePackedOutputpins the semantics, and a new randomized test compares against the literal counter loop it replaces. I verified that test has teeth by mutating the implementation off-by-one — it fails, along with three of the existing cases.Testing
uv run ruff check kempnerforge/ tests/passesuv run ruff format --checkpassesuv run pytest tests/unit/passes — 1808 passed, 13 skippedruff,ruff-format) passes on all changed filesuv run pyright kempnerforge/— 1 error, pre-existing and unrelated:video_io.py:94import "av" could not be resolved.avlives in the optionalvideodependency group, whichuv syncdoes not install by default. Zero errors in the files this PR touches.Not run: integration/distributed/e2e suites — this PR changes config validation and a numpy expression, touching no GPU or distributed code path.
One environment note for anyone reproducing on the cluster:
pytest --timeout=60from CONTRIBUTING.md gives spurious failures intests/unit/test_packing.pyon a cold NFS cache, becauseimport transformerswalks its wholemodels/tree and can exceed 60s on its own. Those tests pass with a larger timeout; nothing to do with this change.Follow-ups
model.attention_backend = "flex"), replacing the dense(B, 1, S, S)mask atattention.py:214-227that currently drops SDPA off FlashAttention whenever packing is on.Closes #204