@@ -865,6 +865,82 @@ def test_tpu_flash_attention_context_parallel(
865865 f" ici_expert_parallelism={ ici_expert_parallelism } ." ,
866866 )
867867
868+ @parameterized .named_parameters (
869+ {"testcase_name" : "no_load_balance" , "context_parallel_load_balance" : False },
870+ {"testcase_name" : "load_balance" , "context_parallel_load_balance" : True },
871+ )
872+ @pytest .mark .tpu_only
873+ def test_tpu_flash_attention_packed_all_gather_context_parallel (self , context_parallel_load_balance ):
874+ """Test equivalence between packed dot_product and packed flash attention + all-gather context parallelism."""
875+ lnx = jax .random .normal (
876+ self .rng ,
877+ shape = (self .global_batch_size , self .max_target_length , self .embed_dim ),
878+ dtype = self .dtype ,
879+ )
880+ tokens_per_segment = self .max_target_length // 4
881+ segment_ids = jnp .repeat (jnp .arange (1 , 5 , dtype = jnp .int32 ), tokens_per_segment )
882+ positions = jnp .tile (jnp .arange (tokens_per_segment , dtype = jnp .int32 ), 4 )
883+ decoder_segment_ids = jnp .broadcast_to (segment_ids , (self .global_batch_size , self .max_target_length ))
884+ decoder_positions = jnp .broadcast_to (positions , (self .global_batch_size , self .max_target_length ))
885+ mha_generic_output , _ = self ._attention_as_mha_generic (
886+ lnx ,
887+ lnx ,
888+ decoder_segment_ids = decoder_segment_ids ,
889+ inputs_positions = decoder_positions ,
890+ deterministic = True ,
891+ model_mode = MODEL_MODE_TRAIN ,
892+ )
893+ generic_state = nnx .state (self ._attention_as_mha_generic )
894+
895+ cfg_cp = pyconfig .initialize (
896+ [sys .argv [0 ], get_test_config_path ()],
897+ ** self .config_arguments ,
898+ ici_context_parallelism = 4 ,
899+ context_parallel_strategy = "all_gather" ,
900+ context_parallel_load_balance = context_parallel_load_balance ,
901+ packing = True ,
902+ )
903+ devices_array_cp = maxtext_utils .create_device_mesh (cfg_cp )
904+ mesh_cp = Mesh (devices_array_cp , cfg_cp .mesh_axes )
905+ attention_as_mha_flash_cp = Attention (
906+ config = cfg_cp ,
907+ num_query_heads = cfg_cp .num_query_heads ,
908+ num_kv_heads = cfg_cp .num_kv_heads ,
909+ head_dim = cfg_cp .head_dim ,
910+ max_target_length = cfg_cp .max_target_length ,
911+ max_prefill_predict_length = cfg_cp .max_prefill_predict_length ,
912+ inputs_q_shape = lnx .shape ,
913+ inputs_kv_shape = lnx .shape ,
914+ mesh = mesh_cp ,
915+ attention_kernel = "flash" ,
916+ dtype = self .dtype ,
917+ dropout_rate = cfg_cp .dropout_rate ,
918+ model_mode = MODEL_MODE_PREFILL ,
919+ rngs = self .nnx_rng ,
920+ )
921+ nnx .update (attention_as_mha_flash_cp , generic_state )
922+
923+ mha_generic_flash_cp_output = attention_test_util .forward_with_context_expert_parallelism (
924+ cfg_cp ,
925+ mesh_cp ,
926+ attention_as_mha_flash_cp ,
927+ lnx ,
928+ decoder_segment_ids ,
929+ decoder_positions ,
930+ )
931+
932+ self .assertTrue (
933+ jax .numpy .allclose (
934+ jax .device_get (mha_generic_output ),
935+ jax .device_get (mha_generic_flash_cp_output ),
936+ rtol = 1e-01 ,
937+ atol = 1e-01 ,
938+ equal_nan = False ,
939+ ),
940+ msg = "Logits from packed generic dot product and packed flash attention + all-gather context parallelism "
941+ f"are not close. context_parallel_load_balance={ context_parallel_load_balance } ." ,
942+ )
943+
868944 @pytest .mark .tpu_only
869945 def test_dot_product_cache_axis_order (self ):
870946 all_axis_orders = tuple (itertools .permutations (range (4 )))
0 commit comments