CoolFace
Apppublic

Paolify/RVC_4

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
uniform.py122 linesDownload Raw Back to diffq
1# Copyright (c) Facebook, Inc. and its affiliates.2# All rights reserved.3#4# This source code is licensed under the license found in the5# LICENSE file in the root directory of this source tree.6 7"""8Classic uniform quantization over n bits.9"""10from typing import Tuple11import torch12 13from .base import BaseQuantizer14from .utils import simple_repr15 16 17def uniform_quantize(p: torch.Tensor, bits: torch.Tensor = torch.tensor(8.)):18    """19    Quantize the given weights over `bits` bits.20 21    Returns:22        - quantized levels23        - (min, max) range.24 25    """26    assert (bits >= 1).all() and (bits <= 15).all()27    num_levels = (2 ** bits.float()).long()28    mn = p.min().item()29    mx = p.max().item()30    p = (p - mn) / (mx - mn)  # put p in [0, 1]31    unit = 1 / (num_levels - 1)  # quantization unit32    levels = (p / unit).round()33    if (bits <= 8).all():34        levels = levels.byte()35    else:36        levels = levels.short()37    return levels, (mn, mx)38 39 40def uniform_unquantize(levels: torch.Tensor, scales: Tuple[float, float],41                       bits: torch.Tensor = torch.tensor(8.)):42    """43    Unquantize the weights from the levels and scale. Return a float32 tensor.44    """45    mn, mx = scales46    num_levels = 2 ** bits.float()47    unit = 1 / (num_levels - 1)48    levels = levels.float()49    p = levels * unit  # in [0, 1]50    return p * (mx - mn) + mn51 52 53class UniformQuantizer(BaseQuantizer):54    def __init__(self, model: torch.nn.Module, bits: float = 8., min_size: float = 0.01,55                 float16: bool = False, qat: bool = False, exclude=[], detect_bound=True):56        """57        Args:58            model (torch.nn.Module): model to quantize59            bits (float): number of bits to quantize over.60            min_size (float): minimum size in MB of a parameter to be quantized.61            float16 (bool): if a layer is smaller than min_size, should we still do float16?62            qat (bool): perform quantized aware training.63            exclude (list[str]): list of patterns used to match parameters to exclude.64                For instance `['bias']` to exclude all bias terms.65            detect_bound (bool): if True, will detect bound parameters and reuse66                the same quantized tensor for both.67        """68        self.bits = float(bits)69        self.qat = qat70 71        super().__init__(model, min_size, float16, exclude, detect_bound)72 73    def __repr__(self):74        return simple_repr(self, )75 76    def _pre_forward_train(self):77        if self.qat:78            for qparam in self._qparams:79                if qparam.other is not None:80                    new_param = qparam.other.module._parameters[qparam.other.name]81                else:82                    quantized = self._quantize_param(qparam)83                    qvalue = self._unquantize_param(qparam, quantized)84                    new_param = qparam.param + (qvalue - qparam.param).detach()85                qparam.module._parameters[qparam.name] = new_param86            return True87        return False88 89    def _post_forward_train(self):90        if self.qat:91            for qparam in self._qparams:92                qparam.module._parameters[qparam.name] = qparam.param93            return True94        return False95 96    def _quantize_param(self, qparam):97        levels, scales = uniform_quantize(qparam.param.data, torch.tensor(self.bits))98        return (levels, scales)99 100    def _unquantize_param(self, qparam, quantized):101        levels, scales = quantized102        return uniform_unquantize(levels, scales, torch.tensor(self.bits))103 104    def model_size(self):105        """106        Non differentiable model size in MB.107        """108        total = super().model_size()109        subtotal = 0110        for qparam in self._qparams:111            if qparam.other is None:  # if parameter is bound, count only one copy.112                subtotal += self.bits * qparam.param.numel() + 64  # 2 float for the overall scales113        subtotal /= 2**20 * 8  # bits to MegaBytes114        return total + subtotal115 116    def true_model_size(self):117        """118        Return the true quantized model size, in MB, without extra119        compression.120        """121        return self.model_size().item()122