CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
quantizer_fp_quant.py180 linesDownload Raw Back to quantizers
1# Copyright 2025 The HuggingFace Inc. team. All rights reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14from typing import TYPE_CHECKING, Optional15 16from .base import HfQuantizer17from .quantizers_utils import get_module_from_name18 19 20if TYPE_CHECKING:21    from ..modeling_utils import PreTrainedModel22 23from ..utils import is_fp_quant_available, is_qutlass_available, is_torch_available, logging24from ..utils.quantization_config import QuantizationConfigMixin25 26 27if is_torch_available():28    import torch29 30logger = logging.get_logger(__name__)31 32 33class FPQuantHfQuantizer(HfQuantizer):34    """35    Quantizer for the FP-Quant method. Enables the loading of prequantized models and in-flight quantization of full-precision models.36    """37 38    requires_calibration = False39    requires_parameters_quantization = True40    is_qat_trainable = True41    required_packages = ["fp_quant"]42 43    def __init__(self, quantization_config: QuantizationConfigMixin, **kwargs):44        super().__init__(quantization_config, **kwargs)45        self.quantization_config = quantization_config46 47    def validate_environment(self, device_map, **kwargs):48        if not torch.cuda.is_available():49            raise NotImplementedError(50                "FPQuant quantization is only supported on GPU. Please use a different quantizer."51            )52 53        if not is_qutlass_available() and not self.quantization_config.pseudoquantization:54            raise ImportError(55                "Using `fp_quant` with real quantization requires a **Blackwell GPU** and qutlass: `git clone https://github.com/IST-DASLab/qutlass.git && cd qutlass && pip install --no-build-isolation .`. You can use `FPQuantConfig(pseudoquantization=True, ...)` to use Triton-based pseudo-quantization. It doesn't provide any speedups but emulates the quantization behavior of the real quantization."56            )57 58        if self.quantization_config.pseudoquantization:59            logger.warning(60                "Using pseudo-quantization for FP-Quant. This doesn't provide any speedups but emulates the quantization behavior of the real quantization."61            )62 63        if not is_fp_quant_available():64            raise ImportError("Using `fp_quant` quantization requires fp_quant: `pip install fp_quant`")65 66        if device_map is None and not self.quantization_config.pseudoquantization:67            raise ValueError(68                "You are attempting to load a FPQuant model without setting device_map."69                " Please set device_map comprised of 'cuda' devices."70            )71        elif (72            isinstance(device_map, dict)73            and ("cpu" in device_map.values() or "disk" in device_map.values())74            and not self.quantization_config.pseudoquantization75        ):76            raise ValueError(77                "You are attempting to load a FPQuant model with a device_map that contains a CPU or disk device."78                " This is not supported. Please remove the CPU or disk device from the device_map."79            )80 81    def update_dtype(self, dtype: "torch.dtype") -> "torch.dtype":82        if dtype is None:83            logger.info("`dtype` is None. Setting `dtype=torch.bfloat16` for qutlass compatibility.")84            dtype = torch.bfloat1685        elif dtype != torch.bfloat16:86            raise ValueError(f"Invalid `dtype` {dtype}. fp_quant quantization only supports `dtype=torch.bfloat16`.")87 88        return dtype89 90    def create_quantized_param(91        self,92        model: "PreTrainedModel",93        param_value: "torch.Tensor",94        param_name: str,95        target_device: "torch.device",96        **kwargs,97    ):98        module, _ = get_module_from_name(model, param_name)99 100        # The module holds either:101        #  * `weight` when `store_master_weights=True`102        #  * `qweight` and `scales` when `store_master_weights=False` and `pseudoquantization=False`103        #  * `dqweight` when `store_master_weights=False` and `pseudoquantization=True`104 105        if param_name.endswith(".qweight"):106            # Loading a real quantized checkpoint without master weights107            module.qweight = torch.nn.Parameter(108                param_value.to(target_device),109                requires_grad=False,110            )111            module.weight = None112            module.dqweight = None113            return114 115        if param_name.endswith(".dqweight"):116            # Loading a pseudo-quantized checkpoint without master weights117            module.dqweight = torch.nn.Parameter(param_value.to(target_device))118            module.weight = None119            module.qweight = None120            module.scales = None121            return122 123        # Loading master weights or an unquantized checkpoint124        module.weight = torch.nn.Parameter(param_value.to(target_device))125        # Let pre-forward handle the quantization and set None where necessary126        module.pre_forward()127 128    def _process_model_before_weight_loading(129        self,130        model: "PreTrainedModel",131        **kwargs,132    ):133        from fp_quant import replace_with_fp_quant_linear134 135        from ..integrations.fp_quant import adapt_fp_quant_config136 137        replace_with_fp_quant_linear(138            model,139            fp_quant_linear_config=adapt_fp_quant_config(self.quantization_config),140        )141        model.config.quantization_config = self.quantization_config142 143    def _process_model_after_weight_loading(self, model: "PreTrainedModel", **kwargs):144        return model145 146    def update_missing_keys(self, model, missing_keys: list[str], prefix: str) -> list[str]:147        from fp_quant import FPQuantLinear148 149        fp_quant_names = {name for name, module in model.named_modules() if isinstance(module, FPQuantLinear)}150 151        def should_exclude(key: str) -> bool:152            if key.endswith(".weight") or key.endswith(".bias"):153                return False154            full_key = f"{prefix}.{key}"155            return any(name in key or name in full_key for name in fp_quant_names)156 157        return [key for key in missing_keys if not should_exclude(key)]158 159    @property160    def is_trainable(self, model: Optional["PreTrainedModel"] = None):161        trainable = self.quantization_config.store_master_weights162        if not trainable:163            logger.warning(164                "You are attempting to train a model with FPQuant quantization. This is only supported when `store_master_weights=True`. Please set `store_master_weights=True` to train the model."165            )166        return trainable167 168    def is_serializable(self, safe_serialization=None):169        return True170 171    def param_needs_quantization(self, model: "PreTrainedModel", param_name: str, **kwargs) -> bool:172        from fp_quant import FPQuantLinear173 174        module, tensor_name = get_module_from_name(model, param_name)175        if isinstance(module, FPQuantLinear) and tensor_name in ["weight", "qweight", "dqweight"]:176            # Only quantize weights of FPQuantLinear modules that are not already quantized177            return True178        else:179            return False180 
Aluode/PerceptionLabPortable · CoolFace