Source code for qkeras.qtools.quantized_operators.fused_bn_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.
# ==============================================================================
"""quantized batch normliaztion quantizer implementation."""




from qkeras import base_quantizer
from qkeras.qtools import qtools_util
from qkeras.qtools.quantized_operators import (
    adder_factory,
    multiplier_factory,
    quantizer_impl,
)


[docs] class FusedBNFactory: """determine which quantizer implementation to use. Create an fused bn instance. The type and bit width of the output_quantizer is deteremined from both the previous layer and batchnorm weight types: z = bn(y) = bn_inv * x - fused_bias is the output of the previous layer and the following bn layer, with: bn_inv = gamma * rsqrt(variance^2+epsilon) is computed from the bn layer weights with inverse_quantizer datatype x is the previous layer's output fused_bias = bn_inv * bias + beta - bn_inv*mean where bias is the bias term from the previous layer, beta and mean are the bn layer weights. """
[docs] def make_quantizer( self, prev_output_quantizer: quantizer_impl.IQuantizer, beta_quantizer: quantizer_impl.IQuantizer, mean_quantizer: quantizer_impl.IQuantizer, inverse_quantizer: quantizer_impl.IQuantizer, prev_bias_quantizer: quantizer_impl.IQuantizer, use_beta: bool, use_bias: bool, qkeras_inverse_quantizer: base_quantizer.BaseQuantizer, ): """Makes a fused_bn quantizer. Args: prev_output_quantizer: IQuantizer type. Previous layer output quantizer beta_quantizer: IQuantizer type. bn layer beta quantizer mean_quantizer: IQuantizer type. layer mean quantizer inverse_quantizer: IQuantizer type. bn layer inverse quantizer prev_bias_quantizer: IQuantizer type. conv layer bias quantizer use_beta: Bool. whether enabling beta in batch_normalization layer use_bias: Bool. Whether bias is used in conv layer. qkeras_inverse_quantizer: qkeras quantizer type. bn layer inverse quantizer with qkeras quantizer type Returns: None """ assert not isinstance(inverse_quantizer, quantizer_impl.FloatingPoint), ( "inverse_quantizer in batchnorm layer has to be set for " "fused bn inference in hardware!" ) # bn_inv * x multiplier_instance = multiplier_factory.MultiplierFactory() multiplier_x = multiplier_instance.make_multiplier( inverse_quantizer, prev_output_quantizer ) qtools_util.adjust_multiplier_for_auto_po2( multiplier_x, qkeras_inverse_quantizer ) # fused_bias = bn_inv * bias + beta - bn_inv*mean # This step derives the datatype for bn_inv * mean multiplier_mean = multiplier_instance.make_multiplier( inverse_quantizer, mean_quantizer ) qtools_util.adjust_multiplier_for_auto_po2( multiplier_mean, qkeras_inverse_quantizer ) adder_instance = adder_factory.IAdder() if use_bias: # Derives datatype of bn_inv*bias multiplier_bias = multiplier_instance.make_multiplier( inverse_quantizer, prev_bias_quantizer ) qtools_util.adjust_multiplier_for_auto_po2( multiplier_bias, qkeras_inverse_quantizer ) # Derives datatype of bn_inv*bias - bn_inv*mean adder_1 = adder_instance.make_quantizer( multiplier_bias.output, multiplier_mean.output ) else: # There is no bias from the previous layer, # therefore datatype of bn_inv*bias - bn_inv*mean is the same # as bn_inv*mean adder_1 = multiplier_mean if use_beta: # Derives datatype of fused_bias = bn_inv * bias + beta - bn_inv*mean adder_bias = adder_instance.make_quantizer(adder_1.output, beta_quantizer) else: # Since beta is not used, fused_bias = bn_inv * bias - bn_inv*mean adder_bias = adder_1 # bn_inv * x - fused_bias adder = adder_instance.make_quantizer(multiplier_x.output, adder_bias.output) self.internal_accumulator = adder self.internal_output = adder