@@ -1296,3 +1296,175 @@ def test_flashkda_chunk_varlen(H, D, cu_seqlens, monkeypatch):
12961296 )
12971297 assert_close ("o" , ref_o , tri_o , _FLASHKDA_RTOL )
12981298 assert_close ("ht" , ref_ht , tri_ht .to (ref_ht .dtype ), _FLASHKDA_RTOL )
1299+
1300+
1301+ @pytest .mark .parametrize (
1302+ ("B" , "T" , "H" , "HV" , "D" , "scale" , "has_dt_bias" , "use_gate_in_kernel" , "dtype" ),
1303+ [
1304+ pytest .param (
1305+ * test ,
1306+ id = "B{}-T{}-H{}-HV{}-D{}-scale{}-has_dt_bias{}-use_gate{}-{}" .format (* test ),
1307+ )
1308+ for test in [
1309+ (4 , 1024 , 4 , 4 , 128 , 0.1 , True , True , torch .bfloat16 ),
1310+ (2 , 2048 , 4 , 8 , 64 , 0.1 , True , True , torch .bfloat16 ),
1311+ (1 , 8192 , 4 , 4 , 128 , 0.1 , False , True , torch .bfloat16 ),
1312+ (4 , 1024 , 4 , 4 , 128 , 0.1 , True , False , torch .bfloat16 ),
1313+ (2 , 2048 , 4 , 8 , 64 , 0.1 , True , False , torch .float16 ),
1314+ ]
1315+ ],
1316+ )
1317+ @torch .inference_mode ()
1318+ def test_chunk_fwd_inference (
1319+ B : int ,
1320+ T : int ,
1321+ H : int ,
1322+ HV : int ,
1323+ D : int ,
1324+ scale : float ,
1325+ has_dt_bias : bool ,
1326+ use_gate_in_kernel : bool ,
1327+ dtype : torch .dtype ,
1328+ ):
1329+ torch .manual_seed (42 )
1330+
1331+ q = torch .rand (B , T , H , D , dtype = dtype , device = device )
1332+ k = torch .rand (B , T , H , D , dtype = dtype , device = device )
1333+ v = torch .rand (B , T , HV , D , dtype = dtype , device = device )
1334+ g = torch .randn (B , T , HV , D , dtype = dtype , device = device )
1335+ beta_raw = torch .randn (B , T , HV , dtype = dtype , device = device )
1336+ A_log = torch .log (torch .empty (HV , dtype = torch .float32 , device = device ).uniform_ (1 , 16 ))
1337+ dt_bias = torch .randn (HV * D , dtype = torch .float32 , device = device ) if has_dt_bias else None
1338+ h0 = torch .randn (B , HV , D , D , dtype = torch .float32 , device = device )
1339+
1340+ if use_gate_in_kernel :
1341+ g_activated = naive_kda_lowerbound_gate (
1342+ g .clone ().float (), A_log .clone (),
1343+ dt_bias .clone () if dt_bias is not None else torch .zeros (HV * D , device = device ),
1344+ lower_bound = - 5.0
1345+ )
1346+ else :
1347+ g_activated = F .logsigmoid (g .clone ().float ())
1348+
1349+ q_norm = F .normalize (q .float (), p = 2 , dim = - 1 )
1350+ k_norm = F .normalize (k .float (), p = 2 , dim = - 1 )
1351+
1352+ ref , ref_ht = naive_recurrent_kda (
1353+ q = q_norm ,
1354+ k = k_norm ,
1355+ v = v .clone ().float (),
1356+ g = g_activated ,
1357+ beta = beta_raw .clone ().float ().sigmoid (),
1358+ scale = scale ,
1359+ initial_state = h0 .clone (),
1360+ output_final_state = True ,
1361+ )
1362+
1363+ if use_gate_in_kernel :
1364+ tri , tri_ht = chunk_kda (
1365+ q = q , k = k , v = v , g = g , beta = beta_raw ,
1366+ scale = scale ,
1367+ initial_state = h0 .clone (),
1368+ output_final_state = True ,
1369+ use_qk_l2norm_in_kernel = True ,
1370+ use_gate_in_kernel = True ,
1371+ use_beta_sigmoid_in_kernel = True ,
1372+ safe_gate = True ,
1373+ lower_bound = - 5.0 ,
1374+ A_log = A_log ,
1375+ dt_bias = dt_bias ,
1376+ )
1377+ else :
1378+ tri , tri_ht = chunk_kda (
1379+ q = q , k = k , v = v , g = g_activated .to (dtype ), beta = beta_raw .sigmoid (),
1380+ scale = scale ,
1381+ initial_state = h0 .clone (),
1382+ output_final_state = True ,
1383+ use_qk_l2norm_in_kernel = True ,
1384+ use_gate_in_kernel = False ,
1385+ use_beta_sigmoid_in_kernel = False ,
1386+ )
1387+ assert_close ("o" , ref , tri , 0.005 )
1388+ assert_close ("ht" , ref_ht , tri_ht , 0.005 )
1389+
1390+
1391+ @pytest .mark .parametrize (
1392+ ("H" , "HV" , "D" , "scale" , "cu_seqlens" , "has_dt_bias" , "dtype" ),
1393+ [
1394+ pytest .param (
1395+ * test ,
1396+ id = "H{}-HV{}-D{}-scale{}-cu_seqlens-has_dt_bias{}-{}" .format (* test ),
1397+ )
1398+ for test in [
1399+ (4 , 4 , 128 , 0.1 , [0 , 256 , 500 , 1000 ], True , torch .bfloat16 ),
1400+ (4 , 8 , 128 , 0.1 , [0 , 100 , 300 , 1200 , 2000 ], True , torch .float16 ),
1401+ (4 , 4 , 64 , 0.1 , [0 , 101 , 303 , 1205 , 3007 , 4096 ], False , torch .bfloat16 ),
1402+ ]
1403+ ],
1404+ )
1405+ @torch .inference_mode ()
1406+ def test_chunk_fwd_inference_varlen (
1407+ H : int ,
1408+ HV : int ,
1409+ D : int ,
1410+ scale : float ,
1411+ cu_seqlens : list [int ],
1412+ has_dt_bias : bool ,
1413+ dtype : torch .dtype ,
1414+ ):
1415+ torch .manual_seed (42 )
1416+
1417+ cu_seqlens_t = torch .LongTensor (cu_seqlens ).to (device )
1418+ T = cu_seqlens [- 1 ]
1419+ N = len (cu_seqlens ) - 1
1420+
1421+ q = torch .randn (1 , T , H , D , dtype = dtype , device = device )
1422+ k = torch .randn (1 , T , H , D , dtype = dtype , device = device )
1423+ v = torch .randn (1 , T , HV , D , dtype = dtype , device = device )
1424+ g = torch .randn (1 , T , HV , D , dtype = dtype , device = device )
1425+ beta_raw = torch .randn (1 , T , HV , dtype = dtype , device = device )
1426+ A_log = torch .log (torch .empty (HV , dtype = torch .float32 , device = device ).uniform_ (1 , 16 ))
1427+ dt_bias = torch .randn (HV * D , dtype = torch .float32 , device = device ) if has_dt_bias else None
1428+ h0 = torch .randn (N , HV , D , D , dtype = torch .float32 , device = device )
1429+
1430+ g_activated = naive_kda_lowerbound_gate (
1431+ g .clone ().float (), A_log .clone (),
1432+ dt_bias .clone () if dt_bias is not None else torch .zeros (HV * D , device = device ),
1433+ lower_bound = - 5.0
1434+ )
1435+ q_norm = F .normalize (q .float (), p = 2 , dim = - 1 )
1436+ k_norm = F .normalize (k .float (), p = 2 , dim = - 1 )
1437+
1438+ ref_list , ref_ht_list = [], []
1439+ for i in range (N ):
1440+ ref_i , ref_ht_i = naive_recurrent_kda (
1441+ q = q_norm [:, cu_seqlens [i ]:cu_seqlens [i + 1 ]],
1442+ k = k_norm [:, cu_seqlens [i ]:cu_seqlens [i + 1 ]],
1443+ v = v [:, cu_seqlens [i ]:cu_seqlens [i + 1 ]].clone ().float (),
1444+ g = g_activated [:, cu_seqlens [i ]:cu_seqlens [i + 1 ]],
1445+ beta = beta_raw [:, cu_seqlens [i ]:cu_seqlens [i + 1 ]].clone ().float ().sigmoid (),
1446+ scale = scale ,
1447+ initial_state = h0 [i :i + 1 ].clone (),
1448+ output_final_state = True ,
1449+ )
1450+ ref_list .append (ref_i )
1451+ ref_ht_list .append (ref_ht_i )
1452+ ref = torch .cat (ref_list , 1 )
1453+ ref_ht = torch .cat (ref_ht_list , 0 )
1454+
1455+ tri , tri_ht = chunk_kda (
1456+ q = q , k = k , v = v , g = g , beta = beta_raw ,
1457+ scale = scale ,
1458+ initial_state = h0 .clone (),
1459+ output_final_state = True ,
1460+ cu_seqlens = cu_seqlens_t ,
1461+ use_qk_l2norm_in_kernel = True ,
1462+ use_gate_in_kernel = True ,
1463+ use_beta_sigmoid_in_kernel = True ,
1464+ safe_gate = True ,
1465+ lower_bound = - 5.0 ,
1466+ A_log = A_log ,
1467+ dt_bias = dt_bias ,
1468+ )
1469+ assert_close ("o" , ref , tri , 0.005 )
1470+ assert_close ("ht" , ref_ht , tri_ht , 0.005 )
0 commit comments