Source code for qkeras.qtools.quantized_operators.quantizer_factory

# Copyright 2019 Google LLC
#
#
# 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.
# ==============================================================================
"""decides which quantizer implementation to use."""


import copy

from qkeras import quantizers

# from qkeras.google_internals import experimental_quantizers
# from qkeras.google_internals import experimental_quantizer_impl
from qkeras.qtools.quantized_operators import quantizer_impl
from qkeras.qtools.settings import cfg


[docs] class QuantizerFactory: """Convert qkeras quantizer to qtools quantizer type.""" def __init__(self): self.quantizer_lookup = { quantizers.quantized_bits: quantizer_impl.QuantizedBits, quantizers.binary: quantizer_impl.Binary, quantizers.quantized_relu: quantizer_impl.QuantizedRelu, quantizers.ternary: quantizer_impl.Ternary, quantizers.quantized_relu_po2: quantizer_impl.ReluPowerOfTwo, quantizers.quantized_po2: quantizer_impl.PowerOfTwo, quantizers.stochastic_ternary: quantizer_impl.StochasticTernary, quantizers.stochastic_binary: quantizer_impl.StochasticBinary, quantizers.bernoulli: quantizer_impl.Bernoulli, quantizers.quantized_tanh: quantizer_impl.QuantizedTanh, quantizers.quantized_ulaw: quantizer_impl.QuantizedUlaw, # experimental_quantizers.quantized_bits_learnable_scale: # experimental_quantizer_impl.QuantizedBitsLearnableScale, # experimental_quantizers.parametric_quantizer_d_xmax: # experimental_quantizer_impl.ParametricQuantizer, # add following quantizer types for the use in GraphUpdateEdge quantizer_impl.QuantizedBits: quantizer_impl.QuantizedBits, quantizer_impl.Binary: quantizer_impl.Binary, quantizer_impl.QuantizedRelu: quantizer_impl.QuantizedRelu, quantizer_impl.Ternary: quantizer_impl.Ternary, quantizer_impl.ReluPowerOfTwo: quantizer_impl.ReluPowerOfTwo, quantizer_impl.PowerOfTwo: quantizer_impl.PowerOfTwo, quantizer_impl.FloatingPoint: quantizer_impl.FloatingPoint, quantizer_impl.StochasticTernary: quantizer_impl.StochasticTernary, quantizer_impl.StochasticBinary: quantizer_impl.StochasticTernary, quantizer_impl.Bernoulli: quantizer_impl.StochasticTernary, quantizer_impl.QuantizedTanh: quantizer_impl.StochasticTernary, quantizer_impl.QuantizedUlaw: quantizer_impl.StochasticTernary, # experimental_quantizer_impl.QuantizedBitsLearnableScale: # experimental_quantizer_impl.QuantizedBitsLearnableScale, # experimental_quantizer_impl.ParametricQuantizer: # experimental_quantizer_impl.ParametricQuantizer, } self._default_interm_quantizer = cfg.default_interm_quantizer def _make_quantizer_util(self, quantizer) -> quantizer_impl.IQuantizer: """make quantizer util function.""" if quantizer in ["int8", "int16", "int32", "fp16", "fp32"]: return self.make_default_quantizer(mode=quantizer) elif isinstance(quantizer, tuple(self.quantizer_lookup.keys())): quantizer_class = self.quantizer_lookup[type(quantizer)] if quantizer_class == type(quantizer): return self.clone_quantizer(quantizer) else: q = quantizer_class() q.convert_qkeras_quantizer(quantizer) return q return None
[docs] def make_quantizer(self, quantizer) -> quantizer_impl.IQuantizer: """create quantizer according to input qkeras quantizer.""" q = None if quantizer is not None: q = self._make_quantizer_util(quantizer) if q is None: return self.make_default_quantizer(mode=self._default_interm_quantizer) return q
[docs] def is_quantizer_supported(self, quantizer) -> bool: if quantizer is None: # if None, will use default quantizer defined in config.json return True return isinstance(quantizer, tuple(self.quantizer_lookup.keys()))
[docs] def make_default_quantizer(self, mode) -> quantizer_impl.IQuantizer: """make quantizer given qkeras quantizer type.""" if mode == "fp32": return quantizer_impl.FloatingPoint(bits=32) elif mode == "fp16": return quantizer_impl.FloatingPoint(bits=16) elif mode == "int8": qbits = quantizer_impl.QuantizedBits() qbits.convert_qkeras_quantizer(quantizers.quantized_bits(8, 0, 1)) return qbits elif mode == "int16": qbits = quantizer_impl.QuantizedBits() qbits.convert_qkeras_quantizer(quantizers.quantized_bits(16, 7, 1)) return qbits elif mode == "int32": qbits = quantizer_impl.QuantizedBits() qbits.convert_qkeras_quantizer(quantizers.quantized_bits(32, 10, 1)) return qbits else: try: # string to quantizer object q_name = "quantizers." + mode qkeras_object = eval(q_name) # pylint: disable=eval-used return self._make_quantizer_util(qkeras_object) except: # pylint: disable=bare-except raise ValueError(f"unaccepted quantizer {mode}!")
[docs] def clone_quantizer( self, quantizer: quantizer_impl.IQuantizer ) -> quantizer_impl.IQuantizer: """clone the given quantizer.""" return copy.deepcopy(quantizer)