@@ -215,7 +215,8 @@ def __init__(self,
215215 self .linear_policies = None
216216 self .conv_linear_layer = False
217217 self .partition_config = partition_config
218- self ._gathered_column_ties_validated = False
218+ self ._gathered_column_tie_fallbacks_configured = False
219+ self ._tied_gathered_column_module_names = set ()
219220 TensorParallel_Layer .set_keep_module_on_host (keep_module_on_host )
220221
221222 def in_module_list (module , module_list ):
@@ -494,19 +495,31 @@ def _create_column_parallel_layer(self, module, spec: TPLayerSpec, name: str):
494495 print_dist (f"AutoTP: replacing '{ name } ' with LinearLayer(gather_output=True)" , ranks = [0 ])
495496 return LinearLayer (module , self .mp_group , name = name , gather_output = spec .gather_output )
496497
497- def _validate_gathered_column_ties (self ):
498- """Reject gathered output layers that share their Parameter with an embedding ."""
499- if self ._gathered_column_ties_validated or self .partition_config is None :
498+ def _configure_gathered_column_tie_fallbacks (self ):
499+ """Configure a replicated fallback for gathered output layers tied to embeddings ."""
500+ if self ._gathered_column_tie_fallbacks_configured or self .partition_config is None :
500501 return
501502
502- embeddings = [(name , module ) for name , module in self .module .named_modules ()
503+ named_modules = list (self .module .named_modules ())
504+ embeddings = [(name , module ) for name , module in named_modules
503505 if isinstance (module , nn .Embedding ) and hasattr (module , "weight" )]
506+ get_input_embeddings = getattr (self .module , "get_input_embeddings" , None )
507+ if callable (get_input_embeddings ):
508+ input_embedding = get_input_embeddings ()
509+ if input_embedding is not None and hasattr (input_embedding , "weight" ):
510+ input_embedding_name = next (
511+ (name for name , module in named_modules if module is input_embedding ),
512+ None ,
513+ )
514+ is_known_embedding = any (module is input_embedding for _ , module in embeddings )
515+ if input_embedding_name is not None and not is_known_embedding :
516+ embeddings .append ((input_embedding_name , input_embedding ))
504517 if not embeddings :
505- self ._gathered_column_ties_validated = True
518+ self ._gathered_column_tie_fallbacks_configured = True
506519 return
507520
508521 model_type = self ._get_model_type ()
509- for module_name , module in self . module . named_modules () :
522+ for module_name , module in named_modules :
510523 if not module_name or isinstance (module , nn .Embedding ) or not hasattr (module , "weight" ):
511524 continue
512525
@@ -521,13 +534,14 @@ def _validate_gathered_column_ties(self):
521534 if spec is None or spec .partition_type != PartitionType .COLUMN or not spec .gather_output :
522535 continue
523536
524- raise NotImplementedError (
525- f"AutoTP cannot apply gathered column parallelism to '{ module_name } .weight' because it is tied "
526- f"to embedding '{ tied_embedding_name } .weight' (both reference the same Parameter). Tied output "
527- "weights require a coupled vocabulary-parallel embedding, which is not supported yet. Untie "
528- "the weights before enabling gathered column parallelism." )
537+ self ._tied_gathered_column_module_names .update ((module_name , tied_embedding_name ))
538+ print_dist (
539+ f"AutoTP: '{ module_name } .weight' is tied to '{ tied_embedding_name } .weight'; leaving both modules "
540+ "replicated because coupled vocabulary-parallel embedding is not supported yet." ,
541+ ranks = [0 ],
542+ )
529543
530- self ._gathered_column_ties_validated = True
544+ self ._gathered_column_tie_fallbacks_configured = True
531545
532546 def _get_model_type (self ) -> Optional [str ]:
533547 """Extract model type from module config or class name."""
@@ -623,7 +637,7 @@ def _replace_autoep_shared_experts(self, autoep_layer, autoep_name):
623637
624638 def _replace_module (self , r_module , prev_name = '' , prev_class_name = '' ):
625639 if prev_name == '' and prev_class_name == '' :
626- self ._validate_gathered_column_ties ()
640+ self ._configure_gathered_column_tie_fallbacks ()
627641
628642 for name , child in r_module .named_children ():
629643 if getattr (child , "_is_autoep_layer" , False ):
@@ -650,7 +664,9 @@ def _replace_module(self, r_module, prev_name='', prev_class_name=''):
650664 # instead of linear_policies. This keeps all pattern logic centralized here.
651665 if self .partition_config is not None :
652666 full_name = class_name + '.' + name if class_name else name
653- if isinstance (child , nn .Embedding ):
667+ if full_name in self ._tied_gathered_column_module_names :
668+ continue
669+ elif isinstance (child , nn .Embedding ):
654670 # Check if embedding matches any pattern
655671 param_name = full_name + ".weight"
656672 model_type = self ._get_model_type ()
0 commit comments