66import torch
77from compressed_tensors .quantization .quant_args import (
88 QuantizationArgs ,
9+ QuantizationType ,
910 round_to_quantized_type_args ,
1011)
1112from compressed_tensors .quantization .utils import maybe_pad_tensor_for_block_quant
@@ -187,6 +188,15 @@ def _quantize_dequantize(
187188 - Double scale/global_scale division
188189 - Intermediate quantized dtype allocation
189190 """
191+ if (
192+ getattr (args , "four_over_six" , False )
193+ and args .num_bits == 4
194+ and args .type == QuantizationType .FLOAT
195+ ):
196+ return _four_over_six_quantize_dequantize (
197+ x , scale , zero_point , q_min , q_max , args , global_scale
198+ )
199+
190200 # compute effective scale once
191201 if global_scale is not None :
192202 scale = scale / global_scale
@@ -210,6 +220,56 @@ def _quantize_dequantize(
210220 return dequant * scale
211221
212222
223+ @torch .no_grad ()
224+ def _four_over_six_quantize_dequantize (
225+ x : torch .Tensor ,
226+ scale : torch .Tensor ,
227+ zero_point : torch .Tensor | None ,
228+ q_min : torch .Tensor ,
229+ q_max : torch .Tensor ,
230+ args : QuantizationArgs ,
231+ global_scale : torch .Tensor | None = None ,
232+ ) -> torch .Tensor :
233+ """
234+ Four Over Six adaptive block scaling: for each group, try quantizing
235+ with the standard scale (maps max to 6) and an alternative scale
236+ (maps max to 4, i.e. scale * 1.5). Pick whichever yields lower MSE.
237+ """
238+ if global_scale is not None :
239+ eff_scale = scale / global_scale
240+ else :
241+ eff_scale = scale
242+
243+ # --- Path A: standard (scale to 6) ---
244+ scaled_a = x / eff_scale
245+ if zero_point is not None :
246+ scaled_a = scaled_a + zero_point .to (x .dtype )
247+ q_a = round_to_quantized_type_args (tensor = scaled_a , args = args , min = q_min , max = q_max )
248+ dq_a = q_a .to (eff_scale .dtype )
249+ if zero_point is not None :
250+ dq_a = dq_a - zero_point .to (eff_scale .dtype )
251+ dq_a = dq_a * eff_scale
252+
253+ # --- Path B: scale to 4 (scale * 1.5) ---
254+ eff_scale_b = eff_scale * 1.5
255+ scaled_b = x / eff_scale_b
256+ if zero_point is not None :
257+ scaled_b = scaled_b + zero_point .to (x .dtype )
258+ q_b = round_to_quantized_type_args (tensor = scaled_b , args = args , min = q_min , max = q_max )
259+ dq_b = q_b .to (eff_scale_b .dtype )
260+ if zero_point is not None :
261+ dq_b = dq_b - zero_point .to (eff_scale_b .dtype )
262+ dq_b = dq_b * eff_scale_b
263+
264+ # --- Per-group MSE comparison ---
265+ group_dims = tuple (range (scale .ndim , x .ndim ))
266+ mse_a = ((x - dq_a ) ** 2 ).mean (dim = group_dims , keepdim = True )
267+ mse_b = ((x - dq_b ) ** 2 ).mean (dim = group_dims , keepdim = True )
268+
269+ use_b = mse_b < mse_a
270+ return torch .where (use_b , dq_b , dq_a )
271+
272+
213273@torch .no_grad ()
214274def _quantize (
215275 x : torch .Tensor ,
0 commit comments