TensorFlow版本2中的量化感知训练及批归一化折叠

7

我想知道在Tensorflow 2中,在量化感知训练期间模拟BatchNorm折叠的当前可用选项是什么。Tensorflow 1有tf.contrib.quantize.create_training_graph函数,它将FakeQuantization层插入到图形中,并负责模拟批归一化折叠(根据这篇white paper)。

Tensorflow 2在其最近采用的tf.keras API中有一个tutorial,介绍如何在其中使用量化,但他们没有提及任何关于批归一化的内容。我尝试了以下带有BatchNorm层的简单示例:

import tensorflow_model_optimization as tfmo

model = tf.keras.Sequential([
      l.Conv2D(32, 5, padding='same', activation='relu', input_shape=input_shape),
      l.MaxPooling2D((2, 2), (2, 2), padding='same'),
      l.Conv2D(64, 5, padding='same', activation='relu'),
      l.BatchNormalization(),    # BN!
      l.MaxPooling2D((2, 2), (2, 2), padding='same'),
      l.Flatten(),
      l.Dense(1024, activation='relu'),
      l.Dropout(0.4),
      l.Dense(num_classes),
      l.Softmax(),
])
model = tfmo.quantization.keras.quantize_model(model)

然而,它会产生以下异常:

RuntimeError: Layer batch_normalization:<class 'tensorflow.python.keras.layers.normalization.BatchNormalization'> is not supported. You can quantize this layer by passing a `tfmot.quantization.keras.QuantizeConfig` instance to the `quantize_annotate_layer` API.

这表明TF不知道如何处理它。
我还看到了这个相关主题,他们在keras构建的模型上应用了tf.contrib.quantize.create_training_graph。 但是他们没有使用BatchNorm层,所以我不确定这是否有效。
那么,在TF2中如何使用BatchNorm折叠功能的选项是什么? 这可以通过keras API完成,还是应该切换回TensorFlow 1 API并以旧方式定义图形?
2个回答

2
如果您在激活之前添加BatchNormalization,则不会遇到量化问题。请注意:仅当该层紧随Conv2D层时,批量规范化才支持量化。更多信息请参见:https://www.tensorflow.org/model_optimization/guide/quantization/training
# Change
l.Conv2D(64, 5, padding='same', activation='relu'),
l.BatchNormalization(),    # BN!
# with this
l.Conv2D(64, 5, padding='same'),
l.BatchNormalization(),
l.Activation('relu'),

#Other way of declaring the same
o = (Conv2D(512, (3, 3), padding='valid' , data_format=IMAGE_ORDERING))(o)
o = (BatchNormalization())(o)
o = Activation('relu')(o)

2
您应该按照说明书中的方式使用量化注释。我认为您现在可以像这样调用BatchNorm:
class DefaultBNQuantizeConfig(tfmot.quantization.keras.QuantizeConfig):

def get_weights_and_quantizers(self, layer):
    return []

def get_activations_and_quantizers(self, layer):
    return []

def set_quantize_weights(self, layer, quantize_weights):
    pass
def set_quantize_activations(self, layer, quantize_activations):
    pass
def get_output_quantizers(self, layer):
    return [tfmot.quantization.keras.quantizers.MovingAverageQuantizer(
    num_bits=8, per_axis=False, symmetric=False, narrow_range=False)]

def get_config(self):
    return {}

如果您仍想对该层进行量化,请将get_weights_and_quantizers的返回更改为return [(layer.weights[i], LastValueQuantizer(num_bits=8, symmetric=True, narrow_range=False, per_axis=False)) for i in range(2)]。然后根据上面返回列表中的索引,将量化器设置回gamma、beta等。但是,我不鼓励这种方法,因为它肯定会损害准确性,因为BN应该作为激活量化。RESNET50的结果如下所示:enter image description here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接