[Python] MobileNet dynamic range quantization breaks model accuracy

Discussão em 'Python' iniciado por Stack, Abril 26, 2025.

  1. Stack

    Stack Membro Participativo

    I've been working on building a binary fire detection model that will run on ESP32s based on TF keras MobileNet v2 and transfer trained from ImageNet weights. After training the model and inferencing it works well with about 95% accuracy, but after converting to TF Lite format and performing dynamic range quantization it always classifies as a single label.

    train_dataset = tf.keras.utils.image_dataset_from_directory(train_dir,
    seed=123,
    image_size=IMG_SIZE,
    batch_size=BATCH_SIZE)

    validation_dataset = tf.keras.utils.image_dataset_from_directory(test_dir,
    seed=123,
    image_size=IMG_SIZE,
    batch_size=BATCH_SIZE)

    class_names = train_dataset.class_names

    val_batches = tf.data.experimental.cardinality(validation_dataset)
    test_dataset = validation_dataset.take(val_batches // 5)
    validation_dataset = validation_dataset.skip(val_batches // 5)

    AUTOTUNE = tf.data.AUTOTUNE

    train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)
    validation_dataset = validation_dataset.prefetch(buffer_size=AUTOTUNE)
    test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)

    data_augmentation = tf.keras.Sequential([
    tf.keras.layers.RandomFlip('horizontal'),
    tf.keras.layers.RandomRotation(0.2),
    ])

    preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input

    # Create the base model from the pre-trained model MobileNet V2
    IMG_SHAPE = IMG_SIZE + (3,)
    base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
    include_top=False,
    alpha=ALPHA,
    weights='imagenet')
    #depth_multiplier=RESMUL,

    image_batch, label_batch = next(iter(train_dataset))
    feature_batch = base_model(image_batch)

    base_model.trainable = True

    # Let's take a look to see how many layers are in the base model
    print("Number of layers in the base model: ", len(base_model.layers))

    fine_tune_at = 100

    for layer in base_model.layers[:fine_tune_at]:
    layer.trainable = False

    global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
    feature_batch_average = global_average_layer(feature_batch)
    print(feature_batch_average.shape)

    prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')
    prediction_batch = prediction_layer(feature_batch_average)
    print(prediction_batch.shape)

    inputs = tf.keras.Input(shape=IMG_SHAPE)
    x = data_augmentation(inputs)
    x = preprocess_input(x)
    x = base_model(x, training=False)
    x = global_average_layer(x)
    x = tf.keras.layers.Dropout(0.2)(x)
    outputs = prediction_layer(x)
    model = tf.keras.Model(inputs, outputs)

    base_learning_rate = 0.0001

    model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
    optimizer = tf.keras.optimizers.RMSprop(learning_rate=base_learning_rate/10),
    metrics=[tf.keras.metrics.BinaryAccuracy(threshold=0.5, name='accuracy')])

    loss0, accuracy0 = model.evaluate(validation_dataset)


    Here is the code for quantization:

    def convert_to_tflite_with_calibration(keras_model_path, output_path, calibration_dataset):
    model = tf.keras.models.load_model(keras_model_path)
    converter = tf.lite.TFLiteConverter.from_keras_model(model)

    def representative_dataset():
    for images, _ in calibration_dataset.take(100): # only a subset for calibration
    yield [images]

    converter.optimizations = [tf.lite.Optimize.DEFAULT]
    converter.representative_dataset = representative_dataset

    # converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]

    tflite_model = converter.convert()
    with open(output_path, 'wb') as f:
    f.write(tflite_model)

    return tflite_model

    # Define paths for different model variants
    base_tflite_path = 'firedetection.tflite'
    quant_tflite_path = 'firedetection_quantized.tflite'


    # Convert to TFLite with dynamic range quantization
    convert_to_tflite_with_calibration(keras_model_path, quant_tflite_path, quantize=True)


    Any ideas on what I'm doing wrong?

    Post-training + TF Lite conversion

    Tested on 100 images
    Overall accuracy: 97.00%


    Post-training + TF Lite conversion + Dynamic range quantization

    Per-class accuracy:
    neutral: 0.0000 (0/3191)
    fire: 1.0000 (1115/1115)

    Overall accuracy: 0.2589%

    Continue reading...

Compartilhe esta Página