(self, module: Linear, in_features: int,
out_features: int, bias: bool, dtype: torch.dtype)
| 869 | class NVFP4LinearMethod(LinearMethodBase): |
| 870 | |
| 871 | def create_weights(self, module: Linear, in_features: int, |
| 872 | out_features: int, bias: bool, dtype: torch.dtype): |
| 873 | module.scaling_vector_size = 16 |
| 874 | assert in_features % module.scaling_vector_size == 0, f"in_features {in_features} must be divisible by scaling_vector_size {module.scaling_vector_size}" |
| 875 | |
| 876 | # Quantized weights |
| 877 | module.weight = Parameter(torch.empty([out_features, in_features // 2], |
| 878 | dtype=fp4_utils.float4_e2m1x2), |
| 879 | requires_grad=False) |
| 880 | |
| 881 | # FP8 per-block scaling factors. dtype must be aligned with SF_DTYPE |
| 882 | # Padding is required. See computeSFSize in quantization.h |
| 883 | nrows = fp4_utils.pad_up(out_features, 128) |
| 884 | ncols = fp4_utils.pad_up(in_features // module.scaling_vector_size, 4) |
| 885 | module.weight_scale = Parameter(torch.empty( |
| 886 | [nrows * ncols], dtype=fp4_utils.float4_sf_dtype), |
| 887 | requires_grad=False) |
| 888 | |
| 889 | # FP32 per-tensor global scaling factor = 448*6/amax_input |
| 890 | module.input_scale = Parameter(torch.empty([1], dtype=torch.float32), |
| 891 | requires_grad=False) |
| 892 | module.inv_input_scale = Parameter(torch.empty([1], |
| 893 | dtype=torch.float32), |
| 894 | requires_grad=False) |
| 895 | |
| 896 | # (amax_input * amax_weight) / (448*6 * 448*6) |
| 897 | module.alpha = Parameter(torch.empty([1], dtype=torch.float32), |
| 898 | requires_grad=False) |
| 899 | |
| 900 | # K, V scales for NVFP4 KV cache |
| 901 | module.kv_scales = Parameter(torch.ones(3, dtype=torch.float32), |
| 902 | requires_grad=False) |
| 903 | # K, V scales for NVFP4 KV cache |
| 904 | module.inv_kv_scales = Parameter(torch.ones(3, dtype=torch.float32), |
| 905 | requires_grad=False) |
| 906 | |
| 907 | # NOTE: Not in all linear we have this tensor - pre_quant_scale is computed as an average and merged with the |
| 908 | # LayerNorm for QKV and Gate/Up projection layers when possible. we can see the tensor only for o_proj and down_proj |
| 909 | module.pre_quant_scale = None |
| 910 | |
| 911 | if bias: |
| 912 | module.bias = Parameter(torch.empty((out_features), dtype=dtype), |
| 913 | requires_grad=False) |
| 914 | else: |
| 915 | module.register_parameter("bias", None) |
| 916 | |
| 917 | def _input_prepare(self, module: Linear, input: torch.Tensor): |
| 918 | if isinstance(input, Fp4QuantizedTensor): |
nothing calls this directly
no test coverage detected