@@ -61,14 +61,15 @@ def wrapped_func(*args, **kwarg):
6161 return wrapped_func
6262
6363
64- def should_free_input (name , is_moe , is_deepep ):
64+ def should_free_input (name , is_moe , enable_deepep , enable_hybridep ):
6565 """Determine if the node should free its input memory.
6666
6767 Args:
6868 name: Node name
6969 is_moe: Whether it's a MoE model
70- is_deepep: Whether it's a DeepEP model
71-
70+ enable_deepep: Whether to use DeepEP dispatcher
71+ enable_hybridep: Whether to use HybridEP dispatcher
72+
7273 Returns:
7374 bool: Whether to free input memory
7475 """
@@ -81,13 +82,13 @@ def should_free_input(name, is_moe, is_deepep):
8182 # The input and output of A2A are not needed anymore after the forward pass,
8283 # so we can free the input memory after the forward pass.
8384 free_input_nodes = {
84- "mlp" : True ,
85+ "mlp" : not enable_hybridep ,
8586 "moe_combine" : True ,
86- "post_combine" : is_deepep ,
87+ "post_combine" : enable_deepep or enable_hybridep ,
8788 # For non-deepep mode, the input is the un-dispatched tokens and probs before dispatch A2A
8889 # and it's not needed anymore after the forward pass
8990 # For deepep mode, they are both needed in backward pass, so they cannot be freed.
90- "moe_dispatch" : not is_deepep ,
91+ "moe_dispatch" : not ( enable_deepep or enable_hybridep ) ,
9192 }
9293
9394 return free_input_nodes .get (name , False )
@@ -625,12 +626,13 @@ def __init__(
625626 it's the per_batch_state_context, o.w. nullcontext
626627 name (str): Node name, also used to determine memory strategy
627628 bwd_dw_callables (list): List of weight gradient functions for the layer.
628- extra_args (dict): Extra arguments for the node : is_moe, enable_deepep.
629+ extra_args (dict): Extra arguments for nodes : is_moe, enable_deepep, enable_hybridep .
629630 """
630631 # determine whether to free input memory
631632 is_moe = extra_args .get ("is_moe" , False )
632633 enable_deepep = extra_args .get ("enable_deepep" , False )
633- free_input = should_free_input (name , is_moe , enable_deepep )
634+ enable_hybridep = extra_args .get ("enable_hybridep" , False )
635+ free_input = should_free_input (name , is_moe , enable_deepep , enable_hybridep )
634636 self .delay_wgrad_compute = extra_args .get ("delay_wgrad_compute" , False )
635637 self .layer_idx = extra_args .get ("layer_idx" , None )
636638
@@ -727,7 +729,14 @@ def build_transformer_layer_callables(layer: TransformerLayer):
727729 """
728730
729731 is_moe = isinstance (layer .mlp , MoELayer )
730- enable_deepep = layer .config .moe_enable_deepep
732+ enable_deepep = (
733+ layer .config .moe_token_dispatcher_type == "flex"
734+ and layer .config .moe_flex_dispatcher_backend == "deepep"
735+ )
736+ enable_hybridep = (
737+ layer .config .moe_token_dispatcher_type == "flex"
738+ and layer .config .moe_flex_dispatcher_backend == "hybridep"
739+ )
731740 is_alltoall_dispatcher = (
732741 is_moe and layer .config .moe_token_dispatcher_type == "alltoall"
733742 )
@@ -782,13 +791,17 @@ def submodule_post_attn_forward(node: ScheduleNode, hidden_states: torch.Tensor)
782791 pre mlp layernorm->router->dispatch preprocess
783792 """
784793 if layer .a2a_overlap_post_attn_recompute :
794+ metadata_holder = {}
785795 def custom_forward (hidden_states ):
786796 pre_mlp_layernorm_output = layer .pre_mlp_layernorm (hidden_states )
787- local_tokens , probs , _ = layer .mlp .router_and_preprocess (pre_mlp_layernorm_output )
788- return pre_mlp_layernorm_output , local_tokens , probs
797+ local_tokens , probs , metadata_holder ['metadata' ], _ = (
798+ layer .mlp .router_and_preprocess (pre_mlp_layernorm_output )
799+ )
800+ return pre_mlp_layernorm_output , local_tokens , probs
789801
790802 pre_mlp_layernorm_output , local_tokens , probs = tensor_parallel .checkpoint (
791803 custom_forward , False , hidden_states )
804+ metadata = metadata_holder ['metadata' ]
792805
793806 else :
794807 if layer .offload_mlp_norm :
@@ -803,26 +816,30 @@ def custom_forward(hidden_states):
803816 with get_fine_grained_offloading_context (layer .offload_mlp_norm ):
804817 pre_mlp_layernorm_output = layer .pre_mlp_layernorm (hidden_states )
805818
806- local_tokens , probs , _ = layer .mlp .router_and_preprocess (pre_mlp_layernorm_output )
819+ local_tokens , probs , metadata , _ = layer .mlp .router_and_preprocess (
820+ pre_mlp_layernorm_output
821+ )
822+
823+ node .layer_state .dispatch_metadata = metadata
807824
808825 # Save token_dispatcher attributes to per-microbatch layer_state to protect against
809826 # recompute corruption when f_layer == b_layer in combined 1F1B schedule
810827 # (occurs at the middle layer when chunk has odd number of layers).
811828 # These attributes are used in combine_postprocess for unpermute and view operations.
812- node .layer_state .hidden_shape = layer . mlp . token_dispatcher .hidden_shape
829+ node .layer_state .hidden_shape = metadata .hidden_shape
813830 # hidden_shape_before_permute and reversed_local_input_permutation_mapping are only
814831 # used in AlltoAll dispatcher's combine_postprocess (unpermute). AllGather uses them
815832 # in combine_preprocess which runs before post_combine, and Flex uses a different
816833 # attribute (reversed_mapping_for_combine). So we only save them for alltoall.
817834 if is_alltoall_dispatcher :
818835 node .layer_state .hidden_shape_before_permute = (
819- layer . mlp . token_dispatcher .hidden_shape_before_permute
836+ metadata .hidden_shape_before_permute
820837 )
821838 # reversed_local_input_permutation_mapping is used as indices in unpermute.
822839 # It's an index tensor that doesn't require grad, so we save it directly
823840 # without using node.detach() to avoid adding it to the backward graph.
824841 node .layer_state .reversed_local_input_permutation_mapping = (
825- layer . mlp . token_dispatcher .reversed_local_input_permutation_mapping
842+ metadata .reversed_local_input_permutation_mapping
826843 )
827844
828845 # Detach here for mlp_bda residual connection
@@ -840,12 +857,13 @@ def submodule_dispatch_forward(
840857 Dispatches tokens to the experts based on the router output.
841858 """
842859 token_dispatcher = layer .mlp .token_dispatcher
843- if enable_deepep :
860+ if enable_deepep or enable_hybridep :
844861 # update token_probs to be the detached version, prevents
845862 # backward graph from connecting to attn submodule
846863 token_dispatcher ._comm_manager .token_probs = probs
847864
848- dispatched_tokens , dispatched_probs = layer .mlp .dispatch (local_tokens , probs )
865+ metadata = node .layer_state .dispatch_metadata
866+ dispatched_tokens , dispatched_probs = layer .mlp .dispatch (local_tokens , probs , metadata )
849867 node .layer_state .dispatched_probs = node .detach (dispatched_probs )
850868 return dispatched_tokens
851869
@@ -859,15 +877,16 @@ def submodule_moe_forward(
859877 shared_expert_output = None
860878 dispatched_probs = node .layer_state .dispatched_probs
861879 token_dispatcher = layer .mlp .token_dispatcher
862- if enable_deepep :
880+ if enable_deepep or enable_hybridep :
863881 # update dispatched_probs to be detached version, prevents
864882 # backward graph from connecting to dispatch submodule
865883 token_dispatcher ._comm_manager .dispatched_probs = dispatched_probs
866884
867885 pre_mlp_layernorm_output = getattr (node .layer_state , 'pre_mlp_layernorm_output' , None )
886+ metadata = node .layer_state .dispatch_metadata
868887
869888 dispatched_input , tokens_per_expert , permuted_probs = layer .mlp .pre_routed_experts_compute (
870- dispatched_tokens , dispatched_probs )
889+ dispatched_tokens , dispatched_probs , metadata )
871890
872891 if layer .a2a_overlap_mlp_recompute :
873892 def custom_forward (dispatched_input , tokens_per_expert , permuted_probs , pre_mlp_layernorm_output ):
@@ -892,7 +911,7 @@ def custom_forward(dispatched_input, tokens_per_expert, permuted_probs, pre_mlp_
892911 dispatched_input , tokens_per_expert , permuted_probs
893912 )
894913
895- expert_output = layer .mlp .post_routed_experts_compute (expert_output )
914+ expert_output = layer .mlp .post_routed_experts_compute (expert_output , metadata )
896915
897916 if layer .recompute_pre_mlp_layernorm :
898917 # discard the output of the pre-mlp layernorm and register the recompute
@@ -923,7 +942,8 @@ def submodule_combine_forward(
923942 Triggers token combine communication.
924943 This communication can be overlapped with computation from another microbatch.
925944 """
926- output = layer .mlp .combine (output )
945+ metadata = node .layer_state .dispatch_metadata
946+ output = layer .mlp .combine (output , metadata )
927947 return output
928948
929949 def submodule_post_combine_forward (
@@ -935,14 +955,15 @@ def submodule_post_combine_forward(
935955 """
936956 residual = node .layer_state .residual
937957 shared_expert_output = getattr (node .layer_state , 'shared_expert_output' , None )
958+ metadata = node .layer_state .dispatch_metadata
938959
939960 # Restore token_dispatcher attributes from per-microbatch layer_state before
940961 # combine_postprocess, to avoid corruption when backward recompute of another
941962 # microbatch overwrites token_dispatcher attributes (happens when f_layer == b_layer
942963 # in combined 1F1B).
943964 saved_hidden_shape = getattr (node .layer_state , 'hidden_shape' , None )
944965 if saved_hidden_shape is not None :
945- layer . mlp . token_dispatcher .hidden_shape = saved_hidden_shape
966+ metadata .hidden_shape = saved_hidden_shape
946967 # Only restore alltoall-specific attributes when using alltoall dispatcher.
947968 if is_alltoall_dispatcher :
948969 saved_hidden_shape_before_permute = getattr (
@@ -952,16 +973,16 @@ def submodule_post_combine_forward(
952973 node .layer_state , 'reversed_local_input_permutation_mapping' , None
953974 )
954975 if saved_hidden_shape_before_permute is not None :
955- layer . mlp . token_dispatcher .hidden_shape_before_permute = saved_hidden_shape_before_permute
976+ metadata .hidden_shape_before_permute = saved_hidden_shape_before_permute
956977 if saved_reversed_local_input_permutation_mapping is not None :
957- layer . mlp . token_dispatcher .reversed_local_input_permutation_mapping = (
978+ metadata .reversed_local_input_permutation_mapping = (
958979 saved_reversed_local_input_permutation_mapping
959980 )
960981 # Release the index tensor reference early to allow GC before _release_state()
961982 node .layer_state .reversed_local_input_permutation_mapping = None
962983
963984 # Post-process combine and add shared expert output
964- output = layer .mlp .post_combine (output , shared_expert_output )
985+ output = layer .mlp .post_combine (output , metadata , shared_expert_output )
965986 mlp_output_with_bias = (output , None )
966987
967988 with layer .bias_dropout_add_exec_handler ():
@@ -984,6 +1005,7 @@ def submodule_post_combine_forward(
9841005 shared_expert_output .untyped_storage ().resize_ (0 )
9851006 node .layer_state .residual = None
9861007 node .layer_state .shared_expert_output = None
1008+ node .layer_state .dispatch_metadata = None
9871009
9881010 # final layer norm from decoder
9891011 final_layernorm = node .chunk_state .model .foundation_model .decoder .final_layernorm
0 commit comments