@@ -2011,8 +2011,8 @@ def test_indexer_loss(self):
20112011 attention_mask = self .get_causal_mask_for_indexer (batch_size , q_len , kv_len )
20122012 indexer_score += attention_mask
20132013
2014- topk_indices = jnp . array ([[[ 0 , 1 ], [ 0 , 1 ], [ 0 , 1 ]], [[ 0 , 1 ], [ 0 , 1 ], [ 0 , 1 ]]] )
2015- indexer_mask = mla .indexer .generate_mask (topk_indices , kv_len ) + attention_mask
2014+ topk_values , _ = jax . lax . top_k ( indexer_score , k = 2 )
2015+ indexer_mask = mla .indexer .generate_mask (indexer_score , topk_values ) + attention_mask
20162016
20172017 loss_dense = mla .calculate_indexer_loss (
20182018 indexer_score = indexer_score ,
@@ -2061,8 +2061,8 @@ def test_indexer_loss_kl_divergence_zero(self):
20612061 # Indexer score matches the shape and is uniform
20622062 indexer_score = jnp .zeros ((batch_size , q_len , kv_len )) + attention_mask
20632063
2064- topk_indices = jnp . array ([[[ 0 , 1 ], [ 0 , 1 ], [ 0 , 1 ]], [[ 0 , 1 ], [ 0 , 1 ], [ 0 , 1 ]]] )
2065- indexer_mask = mla .indexer .generate_mask (topk_indices , kv_len ) + attention_mask
2064+ topk_values , _ = jax . lax . top_k ( indexer_score , k = 2 )
2065+ indexer_mask = mla .indexer .generate_mask (indexer_score , topk_values ) + attention_mask
20662066
20672067 loss = mla .calculate_indexer_loss (
20682068 indexer_score = indexer_score ,
@@ -2230,6 +2230,220 @@ def full_indexer_loss_fn(inputs_q, inputs_kv, low_rank_q, mla, sparse_training=s
22302230 self .assertTrue (jnp .all (grad_kv == 0.0 ))
22312231 self .assertTrue (jnp .all (grad_low_rank_q == 0.0 ))
22322232
2233+ def old_generate_mask (self , topk_indices , s , dtype = jnp .float32 ):
2234+ """Old baseline implementation using pairwise broadcast comparison.
2235+
2236+ Retained exclusively in unit tests as a ground-truth reference for cross-checking mathematical equivalence.
2237+ """
2238+ is_topk = (jnp .arange (s ) == topk_indices [..., None ]).any (axis = - 2 )
2239+ val_true = jnp .array (0.0 , dtype = dtype )
2240+ val_false = jnp .array (DEFAULT_MASK_VALUE , dtype = dtype )
2241+ return jnp .where (is_topk , val_true , val_false )
2242+
2243+ def test_generate_mask_threshold_equivalence (self ):
2244+ """Verifies that TPU-native threshold cutoff masking matches exact top-k selection when scores are unique."""
2245+ mla_config_args = self .config_arguments .copy ()
2246+ mla_config_args ["use_indexer" ] = True
2247+ mla_config_args ["indexer_topk" ] = 64
2248+ mla_config_args ["attention" ] = "dot_product"
2249+
2250+ _ , mla = self .init_mla (mla_config_args , rope_type = "default" )
2251+
2252+ jax_rng = jax .random .PRNGKey (0 )
2253+ b , t , s , k = 2 , 128 , 1024 , 64
2254+ dtype = jnp .float32
2255+
2256+ scores = jax .random .normal (jax_rng , (b , t , s ), dtype = dtype )
2257+ # Add tiny position-dependent epsilon so all scores are strictly unique (preventing sorting tie-breaker divergence)
2258+ scores = scores + jnp .arange (s , dtype = dtype ) * (1e-6 / s )
2259+ topk_values , topk_indices = jax .lax .top_k (scores , k = k )
2260+
2261+ # Call original broadcast Indexer logic for cross-checking
2262+ mask_original = self .old_generate_mask (topk_indices , s , dtype = dtype )
2263+
2264+ # Call actual optimized Indexer logic
2265+ mask_threshold = mla .indexer .generate_mask (scores , topk_values )
2266+
2267+ self .assertTrue (jnp .allclose (mask_original , mask_threshold , atol = 1e-5 ))
2268+
2269+ def test_generate_mask_threshold_ties_exact_k (self ):
2270+ """Verifies that prefix-sum pruning guarantees exactly k unmasked tokens even with boundary ties."""
2271+ mla_config_args = self .config_arguments .copy ()
2272+ mla_config_args ["use_indexer" ] = True
2273+ mla_config_args ["indexer_topk" ] = 3
2274+ mla_config_args ["attention" ] = "dot_product"
2275+ mla_config_args ["indexer_mask_exact_topk" ] = True
2276+
2277+ _ , mla = self .init_mla (mla_config_args , rope_type = "default" )
2278+
2279+ k = 3
2280+ dtype = jnp .float32
2281+ scores = jnp .array (
2282+ [
2283+ [
2284+ [0.9 , 0.8 , 0.5 , 0.5 , 0.1 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2285+ [0.5 , 0.5 , 0.9 , 0.8 , 0.1 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2286+ ]
2287+ ],
2288+ dtype = dtype ,
2289+ )
2290+
2291+ topk_values , topk_indices = jax .lax .top_k (scores , k = k )
2292+ mask = mla .indexer .generate_mask (scores , topk_values )
2293+ mask_original = self .old_generate_mask (topk_indices , s = scores .shape [- 1 ], dtype = dtype )
2294+
2295+ val_true = jnp .array (0.0 , dtype = dtype )
2296+
2297+ self .assertFalse (jnp .isnan (mask ).any ())
2298+ self .assertEqual (jnp .sum (mask [0 , 0 ] == val_true ), 3 ) # Exactly 3 tokens (exact k) unmasked
2299+ self .assertEqual (jnp .sum (mask [0 , 1 ] == val_true ), 3 ) # Exactly 3 tokens (exact k) unmasked
2300+
2301+ # Assert equivalence to original broadcast baseline
2302+ self .assertTrue (jnp .allclose (mask_original , mask , atol = 1e-5 ))
2303+
2304+ # Assert exact unmasked elements
2305+ np .testing .assert_array_equal (
2306+ mask [0 , 0 ] == val_true ,
2307+ [True , True , True , False , False , False , False , False , False , False ],
2308+ )
2309+ np .testing .assert_array_equal (
2310+ mask [0 , 1 ] == val_true ,
2311+ [True , False , True , True , False , False , False , False , False , False ],
2312+ )
2313+
2314+ def test_generate_mask_threshold_ties_unsorted (self ):
2315+ """Verifies that elements strictly greater than cutoff are preserved even if they appear after ties."""
2316+ mla_config_args = self .config_arguments .copy ()
2317+ mla_config_args ["use_indexer" ] = True
2318+ mla_config_args ["indexer_topk" ] = 3
2319+ mla_config_args ["attention" ] = "dot_product"
2320+ mla_config_args ["indexer_mask_exact_topk" ] = True
2321+
2322+ _ , mla = self .init_mla (mla_config_args , rope_type = "default" )
2323+
2324+ k = 3
2325+ dtype = jnp .float32
2326+ scores = jnp .array (
2327+ [
2328+ [
2329+ # 0.9 is strictly greater but appears after three 0.5s.
2330+ # If cumsum was used unconditionally on (score >= cutoff), 0.9 would get rank 4 and be masked out!
2331+ # Correct behavior: keep 0.9, and the first two 0.5s to reach exactly k=3.
2332+ [0.5 , 0.5 , 0.5 , 0.9 , 0.1 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2333+ ]
2334+ ],
2335+ dtype = dtype ,
2336+ )
2337+
2338+ topk_values , topk_indices = jax .lax .top_k (scores , k = k )
2339+ mask = mla .indexer .generate_mask (scores , topk_values )
2340+ mask_original = self .old_generate_mask (topk_indices , s = scores .shape [- 1 ], dtype = dtype )
2341+
2342+ val_true = jnp .array (0.0 , dtype = dtype )
2343+
2344+ self .assertFalse (jnp .isnan (mask ).any ())
2345+ self .assertEqual (jnp .sum (mask [0 , 0 ] == val_true ), 3 ) # Exactly 3 tokens unmasked
2346+
2347+ # Assert equivalence to original broadcast baseline
2348+ self .assertTrue (jnp .allclose (mask_original , mask , atol = 1e-5 ))
2349+
2350+ np .testing .assert_array_equal (
2351+ mask [0 , 0 ] == val_true ,
2352+ [True , True , False , True , False , False , False , False , False , False ],
2353+ )
2354+
2355+ def test_generate_mask_approx_k_overflow (self ):
2356+ """Verifies exact-k guarantee when approx_top_k underestimates the threshold."""
2357+ mla_config_args = self .config_arguments .copy ()
2358+ mla_config_args ["use_indexer" ] = True
2359+ mla_config_args ["indexer_topk" ] = 3
2360+ mla_config_args ["attention" ] = "dot_product"
2361+ mla_config_args ["indexer_mask_exact_topk" ] = True
2362+
2363+ _ , mla = self .init_mla (mla_config_args , rope_type = "default" )
2364+
2365+ dtype = jnp .float32
2366+ scores = jnp .array (
2367+ [
2368+ [
2369+ # Simulating approx_max_k returning an underestimated threshold of 0.5.
2370+ # However, 0.9, 0.8, 0.7, 0.6 (4 elements) are strictly > 0.5.
2371+ [0.9 , 0.8 , 0.7 , 0.6 , 0.5 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2372+ ]
2373+ ],
2374+ dtype = dtype ,
2375+ )
2376+
2377+ # Artificially supply a threshold of 0.5 at the end
2378+ topk_values = jnp .array ([[[1.0 , 1.0 , 0.5 ]]], dtype = dtype )
2379+ mask = mla .indexer .generate_mask (scores , topk_values )
2380+
2381+ val_true = jnp .array (0.0 , dtype = dtype )
2382+
2383+ self .assertFalse (jnp .isnan (mask ).any ())
2384+ self .assertEqual (jnp .sum (mask [0 , 0 ] == val_true ), 3 ) # Exactly 3 tokens unmasked
2385+
2386+ # It should keep the first 3 elements that are > 0.5 which are 0.9, 0.8, 0.7
2387+ np .testing .assert_array_equal (
2388+ mask [0 , 0 ] == val_true ,
2389+ [True , True , True , False , False , False , False , False , False , False ],
2390+ )
2391+
2392+ def test_generate_mask_threshold_ties_raw (self ):
2393+ """Verifies that raw thresholding allows more than k unmasked tokens under boundary ties."""
2394+ mla_config_args = self .config_arguments .copy ()
2395+ mla_config_args ["use_indexer" ] = True
2396+ mla_config_args ["indexer_topk" ] = 3
2397+ mla_config_args ["attention" ] = "dot_product"
2398+ mla_config_args ["indexer_mask_exact_topk" ] = False
2399+
2400+ _ , mla = self .init_mla (mla_config_args , rope_type = "default" )
2401+
2402+ k = 3
2403+ dtype = jnp .float32
2404+ scores = jnp .array (
2405+ [
2406+ [
2407+ [0.9 , 0.8 , 0.5 , 0.5 , 0.1 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2408+ [0.7 , 0.6 , 0.5 , 0.2 , 0.1 , 0.0 , - 1.0 , - 2.0 , - 3.0 , - 4.0 ],
2409+ ]
2410+ ],
2411+ dtype = dtype ,
2412+ )
2413+
2414+ topk_values , _ = jax .lax .top_k (scores , k = k )
2415+ mask = mla .indexer .generate_mask (scores , topk_values )
2416+
2417+ self .assertFalse (jnp .isnan (mask ).any ())
2418+ self .assertEqual (jnp .sum (mask [0 , 0 ] == 0.0 ), 4 ) # 4 tokens unmasked (tied >= 0.5)
2419+ self .assertEqual (jnp .sum (mask [0 , 1 ] == 0.0 ), 3 ) # Exactly 3 tokens unmasked (no boundary ties)
2420+
2421+ def test_generate_mask_sequence_smaller_than_k (self ):
2422+ """Verifies that the indexer handles sequence length smaller than or equal to k by returning None."""
2423+ mla_config_args = self .config_arguments .copy ()
2424+ mla_config_args ["use_indexer" ] = True
2425+ mla_config_args ["indexer_topk" ] = 10 # k = 10
2426+ mla_config_args ["attention" ] = "dot_product"
2427+
2428+ cfg , mla = self .init_mla (mla_config_args , rope_type = "default" )
2429+
2430+ dtype = jnp .float32
2431+ inputs_q = jnp .zeros ((1 , 5 , cfg .emb_dim ), dtype = dtype )
2432+ inputs_kv = jnp .zeros ((1 , 5 , cfg .emb_dim ), dtype = dtype ) # s = 5 <= k
2433+ low_rank_q = jnp .zeros ((1 , 5 , cfg .q_lora_rank ), dtype = dtype )
2434+ inputs_positions = jnp .zeros ((1 , 5 ), dtype = jnp .int32 )
2435+
2436+ mask , indices , score = mla .indexer (
2437+ inputs_q = inputs_q ,
2438+ low_rank_q = low_rank_q ,
2439+ inputs_kv = inputs_kv ,
2440+ inputs_positions = inputs_positions ,
2441+ )
2442+
2443+ self .assertIsNone (mask )
2444+ self .assertIsNone (indices )
2445+ self .assertIsNone (score )
2446+
22332447
22342448class Qwen3NextGatedDeltaNetTest (unittest .TestCase ):
22352449 """Test for the Gated Delta Net in Qwen3-Next"""
0 commit comments