Aluode/PerceptionLabPortable
0
1# Copyright 2024 The HuggingFace 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.14"HQQ (Half-Quadratic Quantization) integration file"15 16from ..utils import is_hqq_available, is_torch_available, logging17 18 19if is_torch_available():20 import torch21 22logger = logging.get_logger(__name__)23 24 25# Name all modules inside the model26def autoname_modules(model):27 for name, module in model.named_modules():28 module.name = name29 30 31# Get the linear_tag from a module name. For example: model.layers.31.self_attn.k_proj -> self_attn.k_proj32def name_to_linear_tag(name):33 return ".".join([n for n in name.split(".") if ((n not in ["model", "layers"]) and (not n.isnumeric()))])34 35 36# Get all linear tags available37def get_linear_tags(model):38 if is_hqq_available():39 from hqq.core.quantize import HQQLinear40 41 linear_tags = set()42 for name, module in model.named_modules():43 if isinstance(module, (torch.nn.Linear, HQQLinear)):44 linear_tags.add(name_to_linear_tag(name))45 return list(linear_tags)46 47 48def _prepare_for_hqq_linear(model, patch_params, has_been_replaced, current_key_name=None):49 for name, module in model.named_children():50 if current_key_name is None:51 current_key_name = []52 current_key_name.append(name)53 54 if isinstance(module, torch.nn.Linear):55 # Get linear tag56 linear_tag = name_to_linear_tag(module.name)57 58 # We put the module quant_config into the nn.Linear layer so we can access it later in quantizer_hqq.create_quantized_param()59 if linear_tag in patch_params:60 if patch_params[linear_tag] is not None:61 model._modules[name].quant_config = patch_params[linear_tag]62 # Store the module class in case we need to transpose the weight later63 model._modules[name].source_cls = type(module)64 # Force requires grad to False to avoid unexpected errors65 model._modules[name].requires_grad_(False)66 67 has_been_replaced = True68 69 # Add these fake parameters to avoid loading fail70 for att in ["W_q", "meta"]:71 setattr(module, att, None)72 73 if len(list(module.children())) > 0:74 _, has_been_replaced = _prepare_for_hqq_linear(75 module,76 patch_params=patch_params,77 has_been_replaced=has_been_replaced,78 )79 # Remove the last key for recursion80 current_key_name.pop(-1)81 82 return model, has_been_replaced83 84 85def prepare_for_hqq_linear(model, quantization_config=None, modules_to_not_convert=None, has_been_replaced=False):86 """87 Prepares nn.Linear layers for HQQ quantization.88 Since each layer type can have separate quantization parameters, we need to do the following:89 1- tag each module with its name via autoname_modules()90 2- Extract linear_tags (e.g. ['self_attn.q_proj', ...])91 3- Map quantization parameters as a dictionary linear_tag -> quant_params as HQQLinear expects it, this is referred to as patch_params92 """93 94 modules_to_not_convert = [] if modules_to_not_convert is None else modules_to_not_convert95 96 # Add name to module97 autoname_modules(model)98 99 # Get linear tags. This allows us to use different quant params to different layer types100 linear_tags = get_linear_tags(model)101 102 # Convert quantization_config to layer-wise config103 skip_modules = quantization_config.skip_modules104 quant_config = quantization_config.quant_config105 linear_tags = list(set(linear_tags) - set(skip_modules) - set(modules_to_not_convert))106 107 if any(key in linear_tags for key in quant_config):108 # If the user doesn't specify a key from get_linear_tags, the layer is not quantized via (key, None)109 patch_params = dict.fromkeys(linear_tags)110 patch_params.update(quant_config)111 else:112 # Same quant_config for all layers113 patch_params = dict.fromkeys(linear_tags, quant_config)114 115 model, has_been_replaced = _prepare_for_hqq_linear(116 model, patch_params=patch_params, has_been_replaced=has_been_replaced117 )118 119 # We store quantization config as linear_tag -> hqq quant config120 model.config.quantization_config = {121 "quant_config": quant_config,122 "quant_method": quantization_config.quant_method,123 "skip_modules": skip_modules,124 }125 126 if not has_been_replaced:127 logger.warning("No linear modules were found in your model for quantization.")128 129 return model130 