Skip to content

chore(trainer): unify context-parallel setup across models - #3533

Merged
garrett361 merged 3 commits into
mainfrom
feat/uniform-cp-setup
Sep 14, 2026
Merged

garrett361 merged 3 commits into
mainfrom
feat/uniform-cp-setup

Conversation

@garrett361

@garrett361 garrett361 commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Unifies all context parallel setup so that a single frozen CPContext dataclass is shared by all cp-aware modules, stored under a self.cp_contex: CPContext attr.

@garrett361
garrett361 marked this pull request as ready for review September 11, 2026 18:11
@garrett361
garrett361 requested review from S1ro1 and samsja September 11, 2026 18:12
Comment thread src/prime_rl/trainer/models/base.py Resolved
samsja
samsja previously approved these changes Sep 11, 2026

@samsja samsja left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

samsja
samsja previously approved these changes Sep 12, 2026
CP wiring had grown two trainer-side helpers calling the same method name at
different depths, a duplicated setup block in both trainers, and three attribute
spellings for the same three values.

One trainer entry point: `setup_context_parallel(model, config, parallel_dims)`
in `utils/cp.py` replaces `setup_model_cp` and `setup_sparse_mla_cp`, and both
trainers call it once behind their existing `cp_enabled` guard. It walks
`model.modules()` and calls the method wherever it is defined, depth-first
pre-order, so a module is always configured before its descendants. An unknown
`cp_style` now raises instead of silently taking the ulysses branch.

One model-side method: `PreTrainedModelPrimeRL.setup_context_parallel` stores the
four values for its own module and nothing else. Each family therefore keeps
exactly one such method, on the module that consumes the state, and the
delegating overrides are gone: deepseek_v4 and glm_moe_dsa on their attention,
nemotron_h on its Mamba mixer, qwen3_5 on its GatedDeltaNet. The walk reaches
through activation-checkpoint wrappers and VLM bodies, which also fixes
`setup_sparse_mla_cp` silently no-oping on a VLM.

One spelling: `cp_group` / `cp_rank` / `cp_world_size` / `cp_style`, unprefixed
everywhere, with class-level defaults on the base so read-back needs no getattr
fallbacks. Carrying `cp_style` removes the hardcoded `cp_style="ulysses"` from
the qwen3_5 VLM forward.

Also drops `gpt_oss`'s `cp_support` override, which returned the base default.
The CP-support matrix is otherwise unchanged.

No behavioural change intended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
garrett361 and others added 2 commits September 14, 2026 13:35
The four CP values were homogeneous by convention: every consuming module
declared `cp_group`, `cp_rank`, `cp_world_size` and `cp_style` and implemented a
`setup_context_parallel` method assigning exactly those names. Nothing enforced
it, so a typo in one name would have miswired CP silently.

`CPContext` in `utils/cp.py` now carries the four values and `cp_enabled`, and a
module that consumes CP state declares one field, `self.cp_context`, defaulting
to `CPContext()`, which is the non-CP case. `PreTrainedModelPrimeRL` supplies
that default for every model. `setup_context_parallel` builds one frozen instance
and assigns it to every module that has the field, so all consumers share a
single object, and raises if that attribute is not a `CPContext`, catching a name
collision at setup rather than at the first forward.

This deletes five identical `setup_context_parallel` methods, three duplicate
`cp_enabled` properties and sixteen default assignments. `Qwen3_5VLMModel` holds
its own context instead of reading its child's, leaving the `eager_reference`
helper, which takes the attention module as an argument, as the only place that
reads CP state off another module.

No behavioural change intended.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread src/prime_rl/utils/cp.py
Comment on lines +59 to +68
cp_context = CPContext(cp_group, cp_rank, parallel_dims.cp, config.cp_style)
for module in model.modules():
if not hasattr(module, "cp_context"):
continue
if not isinstance(module.cp_context, CPContext):
raise TypeError(
f"{type(module).__name__}.cp_context is {type(module.cp_context).__name__}, not a CPContext; "
"context-parallel setup claims that attribute name, so rename it"
)
module.cp_context = cp_context

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this keying off cp_context attr existence, but it is better than threading a cp_context attr through all __init__ methods. Open to suggestions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed but can't think of better one

@S1ro1 S1ro1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@garrett361
garrett361 merged commit e0886c1 into main Sep 14, 2026
16 of 18 checks passed
@garrett361
garrett361 deleted the feat/uniform-cp-setup branch September 14, 2026 18:03
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.

3 participants