| import torch |
| import torch.nn as nn |
| from dataclasses import dataclass |
| from transformers.quantizers import HfQuantizer, register_quantizer |
| from transformers.utils.quantization_config import QuantizationConfigMixin, register_quantization_config |
|
|
| |
| |
| |
| @register_quantization_config("adaptive_quant") |
| @dataclass |
| class AdaptiveQuantConfig(QuantizationConfigMixin): |
| """ |
| تنظیمات مربوط به فریمورک کوانتیزاسیون پویای زمان اجرا (Adaptive Quantization) |
| """ |
| def __init__( |
| self, |
| quant_method="adaptive_quant", |
| fp32_threshold=0.7, |
| int8_threshold=0.3, |
| scorer_weight_path=None, |
| **kwargs |
| ): |
| self.quant_method = quant_method |
| self.fp32_threshold = fp32_threshold |
| self.int8_threshold = int8_threshold |
| self.scorer_weight_path = scorer_weight_path |
| super().__init__(**kwargs) |
|
|
|
|
| |
| |
| |
| class AdaptiveQuantizedLinear(nn.Module): |
| """ |
| لایهای سفارشی که جایگزین nn.Linear معمولی شده و بر اساس امتیاز Scorer، |
| دقت محاسبات (FP32, INT8, INT4) را به صورت پویا انتخاب میکند. |
| """ |
| def __init__(self, in_features, out_features, bias=True, config=None): |
| super().__init__() |
| self.in_features = in_features |
| self.out_features = out_features |
| self.config = config |
| |
| |
| self.weight = nn.Parameter(torch.empty(out_features, in_features)) |
| if bias: |
| self.bias = nn.Parameter(torch.empty(out_features)) |
| else: |
| self.register_parameter('bias', None) |
| |
| |
| self.input_complexity_scorer = nn.Sequential( |
| nn.Linear(in_features, 16), |
| nn.ReLU(), |
| nn.Linear(16, 1), |
| nn.Sigmoid() |
| ) |
|
|
| def forward(self, x): |
| |
| with torch.no_grad(): |
| mean_input = x.mean(dim=0) if x.dim() > 2 else x |
| score = self.input_complexity_scorer(mean_input).mean().item() |
| |
| |
| if score > self.config.fp32_threshold: |
| |
| return nn.functional.linear(x, self.weight, self.bias) |
| |
| elif score > self.config.int8_threshold: |
| |
| scale = self.weight.abs().max() / 127.0 |
| quant_weight = torch.clamp(torch.round(self.weight / scale), -128, 127) |
| dequant_weight = quant_weight * scale |
| return nn.functional.linear(x, dequant_weight.to(x.dtype), self.bias) |
| |
| else: |
| |
| scale = self.weight.abs().max() / 7.0 |
| quant_weight = torch.clamp(torch.round(self.weight / scale), -8, 7) |
| dequant_weight = quant_weight * scale |
| return nn.functional.linear(x, dequant_weight.to(x.dtype), self.bias) |
|
|
|
|
| |
| |
| |
| @register_quantizer("adaptive_quant") |
| class AdaptiveHfQuantizer(HfQuantizer): |
| """ |
| مدیریت تزریق لایه AdaptiveQuantizedLinear به جای لایههای خطی استاندارد مدل |
| """ |
| requires_calibration = False |
|
|
| def __init__(self, quantization_config, **kwargs): |
| super().__init__(quantization_config, **kwargs) |
| self.quantization_config = quantization_config |
|
|
| def _process_model_before_weight_loading(self, model, **kwargs): |
| """ |
| قبل از پر شدن مدل با وزنها، تمام لایههای nn.Linear را پیدا کرده |
| و آنها را با لایه پویای پروژه شما جایگزین میکند. |
| """ |
| for name, module in model.named_modules(): |
| if isinstance(module, nn.Linear): |
| |
| if "lm_head" in name: |
| continue |
| |
| parent_name = ".".join(name.split(".")[:-1]) |
| child_name = name.split(".")[-1] |
| parent = model.get_submodule(parent_name) if parent_name else model |
| |
| |
| new_layer = AdaptiveQuantizedLinear( |
| in_features=module.in_features, |
| out_features=module.out_features, |
| bias=module.bias is not None, |
| config=self.quantization_config |
| ) |
| |
| |
| setattr(parent, child_name, new_layer) |
|
|
| def _process_model_after_weight_loading(self, model, **kwargs): |
| """ |
| پس از بارگذاری وزنها، در صورت وجود وزنهای ذخیرهشده برای Scorer، آنها را اعمال میکند. |
| """ |
| if self.quantization_config.scorer_weight_path: |
| pass |
| return model |
|
|
| |
| |
| |
| try: |
| from transformers.quantizers import AUTO_QUANTIZER_MAPPING |
| if "adaptive_quant" not in AUTO_QUANTIZER_MAPPING: |
| AUTO_QUANTIZER_MAPPING["adaptive_quant"] = AdaptiveHfQuantizer |
| except ImportError: |
| pass |
|
|