# Copyright 2024 The HuggingFace Inc. team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from ..utils import is_compressed_tensors_available, is_torch_available, logging from ..utils.quantization_config import CompressedTensorsConfig from .base import HfQuantizer if is_torch_available(): import torch logger = logging.get_logger(__name__) class CompressedTensorsHfQuantizer(HfQuantizer): """ Quantizer for the compressed_tensors package. Loads and restores models to quantized state with compressed_tensors """ requires_calibration = True required_packages = ["compressed_tensors"] def __init__(self, quantization_config: CompressedTensorsConfig, **kwargs): super().__init__(quantization_config, **kwargs) if not is_compressed_tensors_available(): raise ImportError( "Using `compressed_tensors` quantized models requires the compressed-tensors library: " "`pip install compressed-tensors`" ) # Call post_init here to ensure proper config setup when `run_compressed` # is provided directly via CompressedTensorsConfig, and to avoid duplicate logging. quantization_config.post_init() from compressed_tensors.compressors import ModelCompressor self.compressor = ModelCompressor.from_compression_config(quantization_config) self.run_compressed = quantization_config.run_compressed self.quantization_config = quantization_config def validate_environment(self, *args, **kwargs): if not is_compressed_tensors_available(): raise ImportError( "Using `compressed_tensors` quantized models requires the compressed-tensors library: " "`pip install compressed-tensors`" ) if not is_torch_available(): # torch already should be installed as part of compressed tensors raise ImportError("torch is required for using compressed-tensors quantization") def update_dtype(self, dtype: "torch.dtype") -> "torch.dtype": if dtype is None: logger.info("Loading model using torch.float16 for compressed-tensors quantization") dtype = torch.float16 elif dtype != torch.float16: logger.info("We suggest you to set `dtype=torch.float16` for better efficiency with compressed_tensors.") return dtype def _process_model_before_weight_loading(self, model, **kwargs): from compressed_tensors.quantization import apply_quantization_config ct_quantization_config = self.compressor.quantization_config # Always initialize compressed wrappers to match the checkpoint apply_quantization_config(model, ct_quantization_config, self.run_compressed) if ( self.quantization_config.is_quantization_compressed or self.quantization_config.is_sparsification_compressed ): self.compressor.compress_model(model=model) def _process_model_after_weight_loading(self, model, **kwargs): """Decompress loaded model if necessary - need for qat""" if ( self.quantization_config.is_quantization_compressed and not self.run_compressed ) or self.quantization_config.is_sparsification_compressed: self.compressor.decompress_model(model=model) def update_tp_plan(self, config): additional_plan = { "layers.*.feed_forward.experts.*.gate_proj.weight": "local_colwise", "layers.*.feed_forward.experts.*.gate_proj.weight_scale": "local_colwise", "layers.*.feed_forward.experts.*.up_proj.weight": "local_colwise", "layers.*.feed_forward.experts.*.up_proj.weight_scale": "local_colwise", "layers.*.feed_forward.experts.*.down_proj.weight": "local_rowwise", } if config.get_text_config() is not None and config.get_text_config().base_model_tp_plan is not None: config.get_text_config().base_model_tp_plan.update(additional_plan) return config @property def is_trainable(self): return True def is_qat_trainable(self) -> bool: """Loaded Models can carry out quantization aware training""" # models need to be decompressed carry out qat return not self.run_compressed or not self.quantization_config.is_quantization_compressed def is_serializable(self, safe_serialization=None) -> bool: """Models quantized using compressed tensors can be saved to disk""" return True