Repository navigation
[OMNIML-6076] [13/21] Describe expert parallelism in the model specs - #2746
Open
shengliangxu wants to merge 29 commits into
Open
shengliangxu wants to merge 29 commits into
shengliangxu wants to merge 29 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Contributor
shengliangxu
added this pull request to stack #2755
October 12, 2026 00:57
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 12, 2026 02:35
2142693 to
2e134ec
Compare
Contributor
|
Collaborator
Author
|
/ok to test 2e134ec |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## shengliangx/hfep-9b-ep-load-routing #2746 +/- ##
=======================================================================
+ Coverage 61.70% 61.75% +0.04%
=======================================================================
Files 649 655 +6
Lines 72892 72990 +98
=======================================================================
+ Hits 44976 45072 +96
- Misses 27916 27918 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 12, 2026 08:39
2e134ec to
fdd217a
Compare
Collaborator
Author
|
/ok to test fdd217a |
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 13, 2026 00:53
fdd217a to
0a3e056
Compare
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 13, 2026 01:32
0a3e056 to
67f1c8f
Compare
Collaborator
Author
|
/ok to test 67f1c8f |
shengliangxu
removed this pull request from stack #2755
October 13, 2026 17:42
shengliangxu
added this pull request to stack #2775
October 13, 2026 17:43
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 13, 2026 19:38
67f1c8f to
2f18815
Compare
shengliangxu
removed this pull request from stack #2775
October 13, 2026 19:38
shengliangxu
added this pull request to stack #2781
October 13, 2026 19:40
Collaborator
Author
|
/ok to test 2f18815 |
shengliangxu
removed this pull request from stack #2781
October 14, 2026 00:13
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 14, 2026 00:14
2f18815 to
d68e7ff
Compare
shengliangxu
added this pull request to stack #2786
October 14, 2026 00:14
shengliangxu
force-pushed
the
shengliangx/hfep-9-ep-model-specs
branch
from
October 14, 2026 01:47
d68e7ff to
da76af0
Compare
The DP=EP path needs three things from a model before it can shard its experts: which modules the routed experts are and how they shard, which transformers release first ships that information, and -- for a VLM -- which nested config the plan has to be attached to. All three are facts about the architecture, so they belong with the model's other facts. So this adds an EPSpec section to ModelSpec, and apply_distributed_support, the one applier that reads it. Most models become data in the spec package they already had: deepseek_v3 carries the plan stock transformers does not ship, while qwen3_moe and gpt_oss carry only the release their own plan needs. An existing plan on the config always wins, since overwriting it would substitute our idea of the layout for the model's. Two things resisted being data and kept code, deliberately. NemotronH needs a custom parallel style, because its gate emits logits only and the group-limited top-k happens inside the MoE block -- so the usual ep_router has nothing to remap and the remap has to move to the experts' input. transformers resolves styles through a global registry rather than from config, so that registration is code, in nemotron_h/ep.py. And EPSpec.prepare is the escape hatch for checkpoints carrying their own modeling code. NemotronH-Omni is registered separately because the difference is real: its experts live in the language sub-model, and transformers aggregates a sub-model's plan up to the root WITH its module prefix -- so a plan on llm_config matches the actual parameter paths while a plan on the VLM root matches nothing at all, which fails as silence rather than as an error. A test pins both the placement and that the two spellings share one plan. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
keep_compressed asked a model's prepare hook to keep its experts packed, for a frozen speculative-decoding target. PTQ always needs the decompressed weights and hf_ptq never set it, so the knob and its pass-through go. prepare now receives ckpt_path and trust_remote_code only, which the test pins. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The applier they exercise enforces each model's transformers floor, which imports transformers. The sibling model tests skip without it the same way. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
transformers ships a base_model_ep_plan for gpt_oss, so a torchrun run took the expert-parallel path and failed only at quantization, minutes into the load. The loader drops GptOssExperts' own quantized wrapper so that the generic grouped-GEMM one takes over, and that one refuses experts stored transposed: the fused-experts export cannot write them. It would split gate and up on the wrong axis, and GPT-OSS also interleaves them. Add EPSpec.unsupported. apply_distributed_support refuses a model that names a reason, before anything is applied or loaded, and points at FSDP2. Mark gpt_oss with it. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Per-model expert-parallel support in the same structure as the model specs: one package per HF model type under modelopt/torch/models, data in specs.py, and code in ep.py only where the model genuinely needs it. These two need code. Llama-4 is the one MoE that does not follow the transformers sparse-dispatch convention -- its block routes inline and computes every expert densely, so there is no router-to-experts seam for the transport to wrap; ep.py adapts it to the ExpertsInterface contract instead. llama4_text reuses llama4's adapter and differs only in where the plan lives -- the config itself rather than a nested text config, since there is no VLM wrapper. MiniMax-M3 already follows the convention, with fused [E, out, in] expert params, but hardcodes a per-expert loop in its experts forward, so it only needs its experts class routed through the ExpertsInterface. The declarative half is covered by the spec tests. The prepare hooks patch real transformers classes, so they are exercised by the PTQ runs rather than by unit tests. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The Llama-4 adapter rewrote Llama4TextMoe.forward to dispatch its top-k through the experts interface, but it scaled each expert's output by the router score where Llama-4 scales the input, and SwiGLU does not commute with that: on a tiny config the outputs differ by up to 6.9 on values near 11. Its experts are also stored transposed, which the expert-parallel export cannot write, so the run failed at quantization anyway. Drop the adapter and refuse llama4 and llama4_text the way gpt_oss is refused: transformers ships a plan for both, which would otherwise route them into the expert-parallel path. Every transformers release with minimax_m3_vl already decorates MiniMaxM3VLExperts exactly as the M3 adapter did and ships the text config's base_model_ep_plan, and the loader selects the all-to-all experts forward after loading, so the adapter changed nothing at runtime. Keep only its transformers floor. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
nemotron_h/ep.py registered a NemotronHExpertsEP parallel style for the plan's nemotron_experts_ep entry, but load_and_prepare_ep maps that entry to torch_a2a_experts before loading, so the style never ran. Registering it imported transformers' all_reduce_forward, which 5.18 no longer has, so applying Nemotron-H's spec failed on CI's latest transformers; its _prepare_* hooks are not called from 5.16 on either. The plan moves into the spec that both spellings of the architecture share, with no prepare hook. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
transformers 5.18 added nemotron_h_omni, so its spec can no longer claim remote code; test_specs_vs_transformers fails on the latest transformers until it names the release. Expert parallelism still needs the checkpoint's code, whose llm_config the plan targets. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
For several models the spec is what supplies the expert-parallel plan: DeepSeek-V3 ships none of its own, so deciding without the spec would read its MoE as dense. Unless the run rules expert parallelism out (a single process, or an EP degree of 1), the model's spec is applied to the config before rank 0 builds the model to decide, and the returned config carries it. A load prepares that config once, and not at all when handed the one resolve_distribution_plan returned, since a model's preparation can patch its modeling code. A run that rules expert parallelism out applies no spec, so a model whose spec refuses expert parallelism, like GPT-OSS, still loads FSDP2-sharded. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Each rank read its own MODELOPT_EP_DEGREE to decide whether to apply the model spec, though the knobs are rank 0's. A rank whose environment ruled expert parallelism out skipped the spec rank 0 applied, loaded without the expert-parallel plan the others shard by, and raised once the mesh was up, leaving them waiting. Rank 0 decides it and sends it, as it does the plan. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
An EP degree of 1 skips the model's spec, so the guard against leaving an expert-parallel MoE whole on every rank found routed experts only through the config's own base_model_ep_plan. DeepSeek-V3, whose plan comes only from its spec, therefore loaded whole on every rank at MODELOPT_EP_DEGREE=1 with a replicated dense part, where Qwen3-MoE, which carries its plan, refused. The guard now also looks for the experts through the plan the spec would supply. The spec itself stays skipped: it refuses models that cannot be expert-parallel, which an EP degree of 1 is how to load. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
At an EP degree of 1 the guard against holding an expert-parallel MoE whole on every rank falls back on the plan the model's spec would supply, since that degree skips the spec. It read only the spec's base_model_ep_plan, so a remote-code model whose prepare attaches the plan, after patching the checkpoint's modeling, showed no routed experts and loaded whole on every rank. Running prepare there is not an option: it patches the model's code, for a run that is not expert-parallel. EPSpec.prepared_ep_plan states the plan prepare attaches, and the plan the guard reads includes it. prepare still attaches the plan itself; the spec only states it. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The refusal of an MoE held whole on every rank told every model to raise MODELOPT_EP_DEGREE above 1. GPT-OSS and Llama-4 carry plans of their own, so they reach that refusal too, but their specs refuse expert parallelism: following the advice would only have hit that refusal next. For them the error now says they cannot be quantized expert-parallel yet and points at FSDP2 alone, as their specs' own refusal does. Both messages name the ways to ask for FSDP2: --use_fsdp2 in hf_ptq, or MODELOPT_FSDP_SIZE=world. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…ided The test played rank 1 against a stand-in broadcast that answered with rank 0's decision. The pooled job that checks every rank takes rank 0's plan now covers the spec too: rank 1's own EP knob says the opposite of rank 0's, and rank 1 must apply DeepSeek-V3's spec exactly when rank 0 did, over the real broadcast, or it would load without the plan the others shard by. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
test_the_plan_a_spec_would_supply imported modelopt.torch.models and modelopt.torch.utils.moe inside the test, for no circular-import or optional-dependency reason: the module's transformers guard already precedes its other modelopt imports. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
- test_some_model_declares_expert_parallel_support goes: with no spec registered, the named-model applier and decision tests fail first. - test_a_model_type_with_no_spec_is_left_alone goes: every multi-rank dense decision test runs the same early return. - test_the_plan_is_attached_when_the_config_has_none goes: test_the_spec_is_applied_before_the_decision attaches the real deepseek_v3 plan. - The refusal test is parametrized over gpt_oss, llama4 and llama4_text by name rather than over whichever specs refuse, so a lost refusal fails it instead of shrinking it. It replaces test_models_whose_own_plan_would_misroute_them_are_refused. - The two prepare probes are one test. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
modelopt.torch.models exports EPSpec, but specs.py, where it is defined, left it out of its __all__. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The expert-parallel route of a sharded load handed a plan but no config read the config without token, cache_dir or local_files_only, as the FSDP2 route did before. It now reads it with the Hub options the load was given. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
A config passed for the load is the caller's own. With the plan decided by the load, resolve_distribution_plan prepares a copy of it through the model spec. With a plan handed in, the expert-parallel load took the config raw, so the spec's preparation never ran: DeepSeek-V3 failed for want of the expert-parallel plan the spec adds, and a model the spec refuses was not refused. The load now prepares a copy, once, as deciding does. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The config resolve_distribution_plan prepared comes back to the load with its plan, and the load does not prepare it again: preparing can patch modeling code. It skipped the spec's checks with the preparation, so a hand-made plan and config loaded GPT-OSS or Llama-4 expert-parallel although their specs refuse it. check_distributed_support now runs the spec's refusal and transformers floor on their own, and apply_distributed_support starts with it. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…sformers floor A multi-rank run that leaves the EP degree to auto checks the model's spec before its plan is decided, so a model whose expert parallelism needs a newer transformers (Qwen3-MoE below 5.7) stops there. Like the refusal of a model that cannot be expert-parallel yet, the error now says it can also be quantized without expert parallelism. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
…very rank on a spec error resolve_distribution_plan applies the model's spec to a copy of the config and returns that copy only when the plan it decides is expert-parallel. Any other plan returns the config as read: a decision that lands on FSDP2, as when no EP degree divides the experts, would otherwise build the model from a config carrying a base_model_ep_plan its checkpoint never had, and the export would write it into config.json. Every rank applies the spec under a collective, so a rank that cannot fails every rank instead of leaving the others waiting in the plan's broadcast. A config missing the sub-model config its spec targets is told how the checkpoint's own code names it. The nemotron_h_omni spec says it registers only the expert-parallel plan for now. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
With the EP degree left to auto, MODELOPT_FSDP_SIZE=world still applied GPT-OSS's or Llama-4's spec, whose refusal stopped the run before the plan was decided, although the run asked only for FSDP2; and the refusal of such an MoE left whole on every rank names exactly that knob. Auto now resolves to an EP degree of 1 for a model whose spec refuses expert parallelism, so the spec is skipped and FSDP2 shards the model whole; only an EP degree asked for explicitly meets the spec's refusal. The spec gate reads the EP knob through the decision's own _ep_degree, so the two cannot disagree, and a malformed knob fails every rank before any spec runs. At an EP degree of 1, the refusal of an MoE whose plan only its spec supplies reported 0 experts, since the count was read only when the config's own plan found experts. The experts found through the spec's plan now count too, so DeepSeek-V3 at MODELOPT_EP_DEGREE=1 is told the expert count an EP degree has to divide. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
An MoE whose spec refuses expert parallelism and whose plan replicates it on every rank was pointed at FSDP2 alone, unconditionally. The FSDP2 load refuses a quantized checkpoint, which GPT-OSS's MXFP4 one is, so that refusal now offers what its sibling for an expert-parallel-capable MoE offers beside sharding the experts: FSDP2 if the checkpoint is unquantized, a single process, or a replicated plan handed in. The two messages share that text. apply_distributed_support attached a VLM's plan to whatever config attribute its spec named, but the load reads a nested plan, and the expert count, only from text_config and llm_config: a plan put anywhere else was read as none and the MoE planned as a dense model. A spec naming another attribute is now refused, and _ep_config and _num_experts_from_config read the same tuple. Docs: the models README lists the ep_spec section, EPSpec.plan_config_attr names the two attributes it can take, and nemotron_h_omni's docstring says why no export needs the MoE and export sections its root type lacks: its language model's experts are one fused container, which the export writes through its own handler whatever the root type. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
The spec's refusal of expert parallelism, and of a transformers below its floor, offered FSDP2 as the way around it, and the decision's refusals offered FSDP2 for any unquantized checkpoint. The FSDP2 load builds a causal LM and reads its tensors as stored, so neither GPT-OSS's MXFP4 checkpoint nor the multimodal Llama-4 can take it. The spec's refusals now name a single process first and FSDP2 only for an unquantized causal LM, and the decision's say the same. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
An EP degree left to auto resolved to 1 only for a spec that refuses expert parallelism outright. A model below its spec's transformers floor (Qwen3-MoE before 5.7, MiniMax-M3 before 5.13) still had its spec applied before the plan was decided, so a multi-rank FSDP2 or replicated run, which never asked for expert parallelism, was refused by the floor, whose remedy then offered the FSDP2 it had asked for. Auto now resolves to 1 wherever check_distributed_support refuses the model (_spec_refuses_ep), so only an explicit EP degree or a handed expert-parallel plan meets it. EPSpec.plan_config_attr also takes several spellings, the first one the config has taking the plan. NemotronH-Omni lists llm_config (the checkpoint's own code) and text_config (transformers' 5.18 port): the port's config has no llm_config, so every multi-rank run of it was refused before its plan was decided, an FSDP2 or replicated one included. check_distributed_support's remedy names MODELOPT_FSDP_SIZE=world beside --use_fsdp2, as the decision's refusal does, for a caller outside hf_ptq. Tests: a Qwen3-MoE whose spec floor is unmet plans FSDP2 under auto and is refused at an explicit EP degree; the Omni plan lands on either spelling; the MoE-without-a-plan decision test runs on transformers 5.5 again. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
apply_distributed_support refused a plan_config_attr the expert-parallel load does not read only for a spec that attaches a base_model_ep_plan itself. It now checks every spec's spellings before anything is attached or prepare runs, so a spec whose prepare supplies the plan meets the same refusal. nemotron_h_omni lists text_config before llm_config, the order _ep_config and _num_experts_from_config read them, so a config carrying both takes the plan on the config its expert count is read from. _spec_ep_plan's docstring now says what it does: only a spec refusing expert parallelism outright reports no plan; a model below its spec's transformers floor keeps its plan, so the decision still refuses holding its experts whole on every rank. Its test pins that case. Signed-off-by: Shengliang Xu <shengliangx@nvidia.com>
Collaborator
Author
|
/ok to test e2db64b |
This branch has not been deployed
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.
What does this PR do?
Type of change: New feature
Before it can shard a model's experts, the expert-parallel path needs three facts about the model:
All three are facts about the architecture, so they belong with the model's other facts in
modelopt.torch.models.EPSpec, a newModelSpecsection, andapply_distributed_support, the one applier that reads it. Most models become data in the spec package they already had:deepseek_v3carries the plan stock transformers ships only from 5.13;qwen3_moeandminimax_m3_vlcarry only the transformers release their own plan needs.EPSpec.prepare, the escape hatch for checkpoints that ship their own modeling code ([18/21] to [20/21]). A spec whose plan onlyprepareattaches states that plan too (EPSpec.prepared_ep_plan), so it can be read without runningprepare, which patches the model's code. Nemotron-H needs none. Its gate emits logits and the block runs its own top-k, so the experts receive global expert ids, which the all-to-all experts forward ([1/21]) routes on directly.llm_configand transformers' 5.18 porttext_config; the spec lists both,text_configfirst as the load reads them, and the first one a config has takes the plan. On a tiny port built on CPU, the plan ontext_confignames itsNemotronHExpertsparameters; the port has not been run expert-parallel on GPUs. Its root type registers only the expert-parallel plan, sois_moeby the root type is False for itsNemotronHMoEblocks. No export depends on the missing MoE and export sections: on transformers 5 its experts are one fused container, exported by its own handler (checked locally, see Testing).apply_distributed_supportrefuses a spec whoseplan_config_attris neithertext_confignorllm_config, the two nested configs the expert-parallel load reads a plan and the expert count from (one module-level tuple), instead of attaching a plan that would be read as none and plan the MoE as dense.plan_config_attrmay list several spellings, the first one the config has taking the plan; each must be one the load reads, and a config with none of them is refused, naming them all. The spellings are checked for every spec, whether the spec or itspreparesupplies the plan, before anything is attached or prepared.EPSpec.unsupportedrefuses a model whose own plan would route it into the expert-parallel path before that path can handle it. The refusal comes before anything is loaded and names a single process first, and FSDP2 (--use_fsdp2orMODELOPT_FSDP_SIZE=world) only for an unquantized causal LM: GPT-OSS ships MXFP4, which the FSDP2 load refuses, and Llama-4's checkpoint is multimodal. A spec's transformers-floor refusal says the same.resolve_distribution_planapplies the model's spec to a copy of the config before rank 0 builds the model on meta; without it, DeepSeek-V3 before 5.13 would show no experts to shard. Every rank applies it under a collective, so a rank that cannot fails every rank. An expert-parallel plan returns the prepared copy; any other plan returns the config as read, which the export would otherwise write the spec's plan into. Neither the spec's plan nor the load'storch_a2aswap of it reaches an exportedconfig.json: this PR adds no export path, and the expert-parallel export ([17/21]) writes each config'sbase_model_ep_planas the sourceconfig.jsondeclares it (none for DeepSeek-V3 before 5.13, Nemotron-H or Nemotron-H-Omni).check_distributed_support). Aconfig=passed for the load with a plan handed in is the caller's own, so an expert-parallel load prepares a copy of it once, as deciding does._spec_refuses_ep, askscheck_distributed_support), so its spec is skipped and only an explicit EP degree above 1 (or a handed expert-parallel plan) meets the refusal:MODELOPT_FSDP_SIZE=worldalone plans FSDP2 for GPT-OSS, and for Qwen3-MoE on transformers 5.5.prepareattaches, without applying anything. DeepSeek-V3 atMODELOPT_EP_DEGREE=1, replicated, is refused like a native-plan MoE instead of loading whole on every rank, and the refusal reports the expert count found through the spec's plan, which an EP degree has to divide.--use_fsdp2in hf_ptq, orMODELOPT_FSDP_SIZE=world) if the checkpoint is an unquantized causal LM, a single process, or a replicated plan handed in (DistributionPlan(world_size, 1, 'replicate'))._ep_degree, so a malformed knob fails every rank before any spec runs.Usage
Testing
tests/unit/torch/models/test_ep_specs.py:llm_configortext_config), and ontext_configfor a config with both;prepareordering;preparesupplies the plan;tests/unit/torch/utils/test_resolve_distribution_plan.pyandtest_load_pretrained_distribution.pygain the spec's cases, which [12/21] carried before the reorder:MODELOPT_EP_DEGREE=1, so GPT-OSS's spec does not refuse an FSDP2 run;MODELOPT_FSDP_SIZE=worldalone plans FSDP2, and an explicitep_size=2meets the spec's refusal;ep_size=2; the decision test of an MoE without a plan runs on transformers 5.5 again;cpu_dist_workers), every rank applying the spec, or not, as rank 0 decided, whatever its own knob says;prepare: the spec's own plan, or the one it statesprepareattaches, and nothing for a model with no spec or EP section, or whose spec refuses expert parallelism, and a spec below its transformers floor keeping its plan;config=with a handed plan;prepare, letting auto pick an EP degree for a model whose spec refuses expert parallelism or below a spec's floor, leaving the spec plan's experts out of the refusal's count, attaching a plan where the load reads none, dropping the single process or FSDP2's unquantized-causal-LM condition from the left-whole and spec refusals, reading the Omni plan offllm_configalone, tryingllm_configbeforetext_config, checking a plan spelling only when the spec supplies the plan itself, hiding the plan of a spec below its transformers floor, and dropping the EP-unsupported branch each fail a test.torch_a2astyles as the expert-parallel load does are written by the expert-parallel export with nobase_model_ep_plan, as their sources have none (transformers 5.18 on torch 2.14 and 2.8, and 5.5.4); a baresave_pretrainedof the same configs writes the swapped plan.tests/unit/torch/utils,export,models, the fused-experts quantization tests and the hf_ptq example tests) on transformers 5.18 and 5.5 and on torch 2.8. They pass apart from the diffusers-export and GGML tests, which fail the same way on main in that environment. CI runs the full unit suite.torchrunstopped at the plan decision with the spec's refusal message, before any weights load. That run predates auto picking no EP degree for GPT-OSS: left to auto, a replicated run now stops at the decision's refusal ("cannot be quantized expert-parallel yet, and the plan replicates it ..."), still before any weights load; this was not re-run on GPU. MiniMax-M3 runs on stock transformers 5.13 code (see [21/21]).Before your PR is "Ready for review"
CONTRIBUTING.md: N/AAdditional Information
Part 13 of 21 of expert-parallel PTQ for Hugging Face MoE models; merges after [12/21]. The branch's history adds a Llama-4 and a MiniMax-M3 adapter and then removes them. The Llama-4 adapter's routing was numerically wrong (it scaled expert outputs where Llama-4 scales inputs), and the M3 one only repeated what transformers 5.13 ships. Review the net diff.
Summary by CodeRabbit