Classify EP replicas by declared EP_SUM reduction, not the singleton axis - #76
Draft
qywu wants to merge 1 commit into
Draft
Classify EP replicas by declared EP_SUM reduction, not the singleton axis#76qywu wants to merge 1 commit into
qywu wants to merge 1 commit into
Conversation
…axis The prior draft required a singleton leading axis for is_ep_replicated, which is ambiguous: with ep_size == num_experts a rank-unique per-expert LoRA factor is also [1, ...]-shaped, so its norm was still averaged across EP (grad norm under-reported by ~sqrt(ep_size)) and checkpoint/export consumers still saw it stamped as a replica. The owner's declared gradient-reduction domain is the authoritative signal — a replica is only coherent across EP when its gradient is EP-summed at the optimizer boundary — and every in-tree factor owner already declares it (_ep_gradient_reduction_by_parameter / _ep_gradient_reduction_domain). - _build_ep_param_groups: is_ep_replicated = Replicate placement AND EP_SUM. Frozen replicas stay out of the sync queue. Fail closed when a trainable EP_SUM replica lands off the EP mesh (it would silently miss the sync and diverge) instead of the previous fail-open empty sync list. - ParallelPlan.apply singleton branch: replicate only declared-EP_SUM factors; an already_local singleton is annotated as a per-expert Shard; anything else raises rather than guessing between a replica and a local expert slice. - ParallelPlan.apply fallback: stamp the owner's declared reduction domain so plan-gap shared factors (minimax_m3 has no LoRA patterns; nemotron_h omits gate_proj_lora_A/B) keep their EP_SUM sync contract. - MoEExpertsLoRA: a post-EP construction declares its per-expert factors already-local (and exposes num_local_experts), so EP application annotates instead of slicing them a second time or misreading the num_local_experts == 1 singleton as shared. - inject_lora_into_experts: carry _xorl_ep_load_presliced onto the replacement module (translating gate_proj -> gate_up_proj) so the checkpoint pre-shrink record survives injection and base expert weights are never EP-sliced twice. - Tests pin the new semantics: declared-reduction classification is shape-agnostic, frozen replicas skip sync, off-mesh EP_SUM raises, undeclared singletons raise, already_local singletons annotate Shard, fallback specs carry the declared domain, and injection preserves the pre-slice record.
Broly Security ScanNote ✅ Clean scan Note Re-scan this PR anytime with
|
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.
Follow-up to #72.
_build_ep_param_groupsclassified anyReplicate()-stamped parameter as an EP replica, butParallelPlan.applystampsReplicate()for several unrelated reasons: a genuine shared factor, the fallback for every parameter noep_planpattern matched, and rank-unique per-expert slices whose expert axis happens to be singleton (ep_size == num_experts). Grad-norm clipping divides EP-replica norms byep_world, so any misclassified rank-unique gradient under-reported the global norm by ~√(ep_size); worse, a misclassified stamp also misleads checkpoint/export consumers, and a genuinely-shared plan-gap factor was "replicated" for the norm while never actually EP-summed — silently diverging across ranks every step.The fix: one authoritative signal
A replica is only coherent across EP — and its norm may only be averaged across EP — when its gradient is EP-summed at the optimizer boundary. That is exactly what the owner modules already declare (
_ep_gradient_reduction_by_parameter/_ep_gradient_reduction_domain, populated byMoEExpertsLoRA, the QLoRA expert module, and the GLM-5.2 exact experts). So:_build_ep_param_groups:is_ep_replicated=Replicateplacement andgradient_reduction is EP_SUM. Shape plays no role. Frozen replicas stay out of the sync queue. A trainableEP_SUMreplica that lands off the EP mesh now fails closed with an actionable error instead of the previous fail-open empty sync list (it would have silently missed the optimizer-boundary reduction and diverged).ParallelPlan.applysingleton branch: replicates only declared-EP_SUMfactors; analready_localsingleton is annotated as a per-expertShard; anything else raises rather than guessing between a replica and a rank-unique expert slice.ParallelPlan.applyfallback: stamps the owner's declared reduction domain, so plan-gap shared factors (minimax_m3 lists no LoRA patterns; nemotron_h omitsgate_proj_lora_A/B) keep theirEP_SUMsync contract instead of losing it to the dataclass default.MoEExpertsLoRA: a post-EP construction declares its per-expert factors already-local (and exposesnum_local_experts), so EP application annotates instead of slicing them a second time — or misreading thenum_local_experts == 1singleton as shared.inject_lora_into_experts: carries_xorl_ep_load_preslicedonto the replacement module (translatinggate_proj→gate_up_proj), so the checkpoint pre-shrink record survives injection and base expert weights are never EP-sliced twice.Tests
New tests pin the semantics the old fixtures couldn't distinguish (both used leading-dim-1 shapes): declared-reduction classification is shape-agnostic (a
[1, 4]NONEparam is excluded, a[2, 4]EP_SUMparam is included), frozen replicas skip sync, an off-meshEP_SUMreplica raises, undeclared singletons raise at the stamp site,already_localsingletons annotateShard, fallback specs carry the declared domain, post-EP LoRA construction declares its locals, and injection preserves the pre-slice record.Verified locally:
test_ep_clip_grad_norm+test_parallel_plan_meta_slice+test_ep_lora_weight_slicing+test_ep_gradient_reduction_contract+test_moe_expert_weight_init(38 tests), plus the blast radius on the same tree: QLoRA/GLM-52 expert-contract and construction suites (61), and canonical-MoE / adapter-gradient /tests/lora(102).