1919import torch
2020import torch .nn as nn
2121from executorch .backends .cuda .dp4a_planar_int6_tensor import (
22+ _encode_int8_per_super ,
2223 CudaDp4aPlanarInt6Tensor ,
2324 pack_int6 ,
2425 unpack_int6 ,
@@ -145,8 +146,18 @@ def _make_int6(self, N, K, gs=16):
145146 q = torch .randint (- 32 , 32 , (N , K ), dtype = torch .int8 )
146147 scale = (torch .rand (N , K // gs ) * 0.1 + 0.01 ).to (torch .bfloat16 )
147148 ql , qh = pack_int6 (q )
148- t = CudaDp4aPlanarInt6Tensor (ql , qh , scale , [1 , gs ], torch .Size ([N , K ]))
149- return t , q , scale
149+ # The tensor stores int8 scale *codes* + a per-256-super-block [N, K/256]
150+ # fp16 step (scale = code * step[:, g // (256 // gs)]); encode here and
151+ # return the effective scale so the reference dequant matches the kernel.
152+ scale_codes , steps = _encode_int8_per_super (scale .float (), gs )
153+ n_super = steps .shape [1 ]
154+ gps = (K // gs ) // n_super
155+ step_g = steps .to (torch .bfloat16 ).repeat_interleave (gps , dim = 1 )
156+ eff_scale = (scale_codes .to (torch .bfloat16 ) * step_g ).to (torch .bfloat16 )
157+ t = CudaDp4aPlanarInt6Tensor (
158+ ql , qh , scale_codes , steps , [1 , gs ], torch .Size ([N , K ])
159+ )
160+ return t , q , eff_scale
150161
151162 def _make_q6k_gguf (self , N , nb = 1 ):
152163 """Build a synthetic q6_k ExportableGGUFTensor (see test_gguf.py).
@@ -179,7 +190,7 @@ def test_pack_unpack_roundtrip(self):
179190 self .assertTrue (torch .equal (q_rt , q ))
180191
181192 def test_dequantize_equals_q_scale (self ):
182- t , q , scale = self ._make_int6 (32 , 128 , gs = 16 )
193+ t , q , scale = self ._make_int6 (32 , 256 , gs = 16 )
183194 ref = q .to (torch .bfloat16 ) * scale .to (torch .bfloat16 ).repeat_interleave (
184195 16 , dim = - 1
185196 )
@@ -348,8 +359,8 @@ def setUp(self):
348359
349360 def test_mixed_precision (self ):
350361 torch .manual_seed (0 )
351- w4 = torch .randn (64 , 128 , dtype = torch .bfloat16 )
352- w8 = torch .randn (64 , 128 , dtype = torch .bfloat16 )
362+ w4 = torch .randn (64 , 256 , dtype = torch .bfloat16 )
363+ w8 = torch .randn (64 , 256 , dtype = torch .bfloat16 )
353364 q4 = quantize_weight (
354365 w4 ,
355366 QuantConfig (bits = 4 , group_size = 32 , symmetric = False , method = "min_max" ),
@@ -361,15 +372,15 @@ def test_mixed_precision(self):
361372 with torch .device ("meta" ):
362373 model = nn .ModuleDict (
363374 {
364- "q_proj" : nn .Linear (128 , 64 , bias = False ),
365- "v_proj" : nn .Linear (128 , 64 , bias = False ),
375+ "q_proj" : nn .Linear (256 , 64 , bias = False ),
376+ "v_proj" : nn .Linear (256 , 64 , bias = False ),
366377 }
367378 )
368379 pack_model (
369380 model , {"q_proj.weight" : q4 , "v_proj.weight" : q8 }, DEFAULT_CUDA_PACKERS
370381 )
371382 model .cuda ()
372- x = torch .randn (1 , 128 , dtype = torch .bfloat16 , device = "cuda" )
383+ x = torch .randn (1 , 256 , dtype = torch .bfloat16 , device = "cuda" )
373384
374385 ref4 = torch .nn .functional .linear (x , w4 .cuda ())
375386 out4 = model .q_proj (x )
@@ -389,7 +400,7 @@ def test_mixed_precision(self):
389400
390401 def test_load_and_pack_from_disk (self ):
391402 torch .manual_seed (0 )
392- weight = torch .randn (64 , 128 , dtype = torch .bfloat16 )
403+ weight = torch .randn (64 , 256 , dtype = torch .bfloat16 )
393404 config = QuantConfig (bits = 4 , group_size = 32 , symmetric = False , method = "min_max" )
394405 q = quantize_weight (weight , config )
395406
@@ -405,27 +416,27 @@ def test_load_and_pack_from_disk(self):
405416 with torch .device ("meta" ):
406417 model = nn .ModuleDict (
407418 {
408- "proj" : nn .Linear (128 , 64 , bias = False ),
419+ "proj" : nn .Linear (256 , 64 , bias = False ),
409420 "norm" : nn .LayerNorm (64 , bias = False ),
410421 }
411422 )
412423 load_and_pack_for_cuda (path , model )
413424
414- self .assertEqual (model .proj .weight .shape , torch .Size ([64 , 128 ]))
425+ self .assertEqual (model .proj .weight .shape , torch .Size ([64 , 256 ]))
415426 self .assertEqual (model .norm .weight .shape , torch .Size ([64 ]))
416427
417428 model .proj .cuda ()
418- x = torch .randn (1 , 128 , dtype = torch .bfloat16 , device = "cuda" )
429+ x = torch .randn (1 , 256 , dtype = torch .bfloat16 , device = "cuda" )
419430 ref = torch .nn .functional .linear (x , weight .cuda ())
420431 out = model .proj (x )
421432 rel_error = (out .float () - ref .float ()).abs ().mean () / ref .float ().abs ().mean ()
422433 self .assertLess (rel_error .item (), 0.15 )
423434
424435 def test_pack_one_quantized (self ):
425436 config = QuantConfig (bits = 4 , group_size = 32 , symmetric = False , method = "min_max" )
426- q = quantize_weight (torch .randn (64 , 128 , dtype = torch .bfloat16 ), config )
437+ q = quantize_weight (torch .randn (64 , 256 , dtype = torch .bfloat16 ), config )
427438 with torch .device ("meta" ):
428- model = nn .ModuleDict ({"proj" : nn .Linear (128 , 64 , bias = False )})
439+ model = nn .ModuleDict ({"proj" : nn .Linear (256 , 64 , bias = False )})
429440 pack_one (model , "proj.weight" , q , DEFAULT_CUDA_PACKERS )
430441 self .assertNotEqual (model .proj .weight .device .type , "meta" )
431442
@@ -463,13 +474,13 @@ def __init__(self):
463474
464475 def test_missing_weight_detected (self ):
465476 config = QuantConfig (bits = 4 , group_size = 32 , symmetric = False , method = "min_max" )
466- q = quantize_weight (torch .randn (32 , 64 , dtype = torch .bfloat16 ), config )
477+ q = quantize_weight (torch .randn (32 , 256 , dtype = torch .bfloat16 ), config )
467478
468479 with torch .device ("meta" ):
469480 model = nn .ModuleDict (
470481 {
471- "a" : nn .Linear (64 , 32 , bias = False ),
472- "b" : nn .Linear (64 , 32 , bias = False ),
482+ "a" : nn .Linear (256 , 32 , bias = False ),
483+ "b" : nn .Linear (256 , 32 , bias = False ),
473484 }
474485 )
475486 with self .assertRaises (RuntimeError ) as ctx :
0 commit comments