Skip to content

馃毃 Pass tp_plan from lm_heads - #47253

Merged
ArthurZucker merged 5 commits into
mainfrom
fix_tp_plans_for_lm_heads
Jul 15, 2026
Merged

ArthurZucker merged 5 commits into
mainfrom
fix_tp_plans_for_lm_heads

Conversation

@molbap

@molbap molbap commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

CI

What does this PR do?

Noticed currently the lm_head-specific tp plans are wiped in PreTrainedModel post-init (we just ignore them). This should fix it

@molbap
molbap requested review from 3outeille and ArthurZucker July 10, 2026 14:45
@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

Comment on lines +496 to +501
config = self.model_tester.get_config()
text_config = config.get_text_config()
remainder = text_config.vocab_size % self.tensor_parallel_size
if remainder:
text_config.vocab_size += self.tensor_parallel_size - remainder
return config

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this is because we have typically vocab size 99 on tiny tests, which can't be sharded on 2 ranks obviously

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm thinking wheter we should automatically extend an embedding if we notice this? So in from pretrained, if we notice

  1. TP
  2. Embeddings that get shared we resize the embeddings before

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ah auto-pad you mean? hmm we could ig, I feel like we are already doing it in a couple other places IIRC

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yep, because users will complain I'm sure 馃槄 Maybe a warning but having users to think leads to problems

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

but we should pad just before the gather and unpad right after, no?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

other idea (sorry for the noise): we should just validate, feels less magic. like if TP is provided with a wrong vocab size just raise from the get-go. Should be in another PR though because it could break existing setups

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this is already breaking in itself no? Users could have arbitrary vocab sizes before this

But yea, I can see the validation path - less magic and add how to properly do it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

ah yes, you're right... before it was silently replicating so of course this will raise. I'll add the validation logic then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IMO, if it does not cost much and we can resize for the user, would be nice. People probably expect us to do so, and we are the ones setting the plan to default to colwise rep.
The main concern is for the gather to not take into account the padding, which is important

@molbap molbap changed the title Pass tp_plan from lm_heads 馃毃 Pass tp_plan from lm_heads Jul 10, 2026

@vasqu vasqu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Imo, this looks good but let's wait for @ArthurZucker and @3outeille for a final look 馃

@github-actions

Copy link
Copy Markdown
Contributor

CI recap

Dashboard: View test results in Grafana
Latest run: 29107923987:1
Result: failure | Jobs: 15 | Tests: 170,565 | Failures: 1 | Duration: 15h 14m

@ArthurZucker ArthurZucker left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ty, not sure we need generic, and as pointed let's maybe pad by default?
we can isolate the 2 changes. let's also trace the blame on PR that regressed the init, it was I am certain working before

Comment on lines +726 to +735
def validate_module(self, module: nn.Module, device_mesh, layer_name: str = ""):
out_features = getattr(module, "out_features", None)
if self.gather_output and out_features is not None and out_features % device_mesh.size() != 0:
raise ValueError(
f"`{layer_name}` ({type(module).__name__} with out_features={out_features}) is sharded with "
f"'colwise_gather_output', which requires out_features to be divisible by the number of ranks "
f"({device_mesh.size()}) to all-gather equal-size shards. Resize the weight (e.g. "
f"`model.resize_token_embeddings` for LM heads) or override this module's entry in the tp_plan."
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

since only this layer uses it, we can not make it generic for now

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yeah it's a bit awkward. Wdy suggest? move it the the layer?

# easily available.
self._tp_plan, self._ep_plan, self._pp_plan, self._fsdp_plan = {}, {}, {}, {}
# Start from the class-level plans (e.g. `{"lm_head": "colwise_rep"}` on `...ForCausalLM` classes), copying
# them as they are mutated below and would otherwise contaminate the class attribute shared by all instances

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

absolutely, this was already the case.... do you know where the regression comes from?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yeah wrote that mostly for review. Yes, it seems to be coming from a big Revert, likely an oversight #46246

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.

it's actually in #36677 and then we keep the pattern

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Are you sure @3outeille ? it doesn't seem to be there that we set
self._tp_plan, self._ep_plan, self._pp_plan, self._fsdp_plan = {}, {}, {}, {}

# models, this attribute is currently defined in respective model code. For base models, it comes from
# `config.base_model_pp_plan` during `post_init`.
_pp_plan: dict[str, tuple[str, str]] = None
# An expert parallel plan used instead of `_tp_plan` when expert parallelism is enabled. For base models, it comes

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

not super

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

can you elaborate? 馃榿

Comment on lines +496 to +501
config = self.model_tester.get_config()
text_config = config.get_text_config()
remainder = text_config.vocab_size % self.tensor_parallel_size
if remainder:
text_config.vocab_size += self.tensor_parallel_size - remainder
return config

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IMO, if it does not cost much and we can resize for the user, would be nice. People probably expect us to do so, and we are the ones setting the plan to default to colwise rep.
The main concern is for the gather to not take into account the padding, which is important

@ArthurZucker

Copy link
Copy Markdown
Collaborator

Merging we need it for release

@ArthurZucker
ArthurZucker merged commit f5a67a4 into main Jul 15, 2026
196 of 198 checks passed
@ArthurZucker
ArthurZucker deleted the fix_tp_plans_for_lm_heads branch July 15, 2026 18:17
@arielge arielge mentioned this pull request Jul 22, 2026
3 tasks
stevhliu pushed a commit to stevhliu/transformers that referenced this pull request Jul 30, 2026
* pass tp_plan from lm_heads

* add a small test to avoid regressiosn on TP

* world size must divide vocab size

* early raise for incompatible vocabs

* test our test
Sainava pushed a commit to Sainava/Sai-transformers that referenced this pull request Aug 3, 2026
* pass tp_plan from lm_heads

* add a small test to avoid regressiosn on TP

* world size must divide vocab size

* early raise for incompatible vocabs

* test our test
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.

5 participants