TensorFlow MobileNet in Practice

MobileNetV2 is the most practical pre-trained model for real-world projects. It is small enough to run on a smartphone, fast enough for real-time video, accurate enough for production use, and available with ImageNet weights in TensorFlow in one line. This topic builds a complete, production-quality image classifier using MobileNetV2 — from raw images to a deployed, prediction-ready model.

Why MobileNetV2

MobileNetV2 design principles:
  1. Inverted residuals: expand channels, depthwise conv, compress back
  2. Linear bottlenecks: no activation at bottleneck to preserve information
  3. Depthwise separable convolutions: 8–9× fewer params than standard Conv

Result:
  Parameters:   3.4 million  (VGG16 has 138M — 40× more)
  Size on disk: 14 MB        (VGG16 is 528 MB)
  Inference:    25ms on CPU  (VGG16 takes ~150ms)
  Accuracy:     71.8% on ImageNet (VGG16: 71.3%)
  
MobileNetV2 is as accurate as VGG16 at 1/40th the size.

Complete Project: Plant Disease Classifier

You will classify plant leaf images into three categories: healthy, bacterial infection, and fungal infection. This type of classifier has real agricultural value — farmers can photograph leaves and get instant disease diagnosis.

Step 1 — Set Up the Data Pipeline

import tensorflow as tf

IMG_SIZE = (224, 224)
BATCH_SIZE = 32
AUTOTUNE = tf.data.AUTOTUNE
CLASS_NAMES = ['bacterial', 'fungal', 'healthy']

def build_dataset(directory, training=True):
    ds = tf.keras.utils.image_dataset_from_directory(
        directory,
        image_size=IMG_SIZE,
        batch_size=BATCH_SIZE,
        shuffle=training,
        seed=42
    )
    if training:
        ds = ds.map(augment, num_parallel_calls=AUTOTUNE)
    return ds.prefetch(AUTOTUNE)

def augment(image, label):
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_brightness(image, max_delta=0.2)
    image = tf.image.random_contrast(image, lower=0.8, upper=1.2)
    return image, label

train_ds = build_dataset('data/train/', training=True)
val_ds   = build_dataset('data/val/',   training=False)

Step 2 — Build MobileNetV2 Transfer Learning Model

import tensorflow as tf

def build_model(num_classes=3):
    # Load base model
    base = tf.keras.applications.MobileNetV2(
        input_shape=(224, 224, 3),
        include_top=False,
        weights='imagenet'
    )
    base.trainable = False

    # Build full model
    inputs = tf.keras.Input(shape=(224, 224, 3))

    # MobileNetV2-specific preprocessing: scales to [-1, 1]
    x = tf.keras.applications.mobilenet_v2.preprocess_input(inputs)
    x = base(x, training=False)
    x = tf.keras.layers.GlobalAveragePooling2D()(x)
    x = tf.keras.layers.Dense(128, activation='relu')(x)
    x = tf.keras.layers.Dropout(0.3)(x)
    outputs = tf.keras.layers.Dense(num_classes, activation='softmax')(x)

    model = tf.keras.Model(inputs, outputs)
    return model, base

model, base = build_model(num_classes=3)
model.summary()

Step 3 — Phase 1 Training

model.compile(
    optimizer=tf.keras.optimizers.Adam(0.001),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

history_phase1 = model.fit(
    train_ds,
    epochs=15,
    validation_data=val_ds,
    callbacks=[
        tf.keras.callbacks.ModelCheckpoint(
            'best_phase1.keras',
            monitor='val_accuracy',
            save_best_only=True
        )
    ]
)

print(f"Phase 1 best val_accuracy: {max(history_phase1.history['val_accuracy']):.2%}")

Step 4 — Phase 2 Fine-Tuning

# Unfreeze last 30 layers of MobileNetV2
base.trainable = True
for layer in base.layers[:-30]:
    layer.trainable = False

# Recompile with lower learning rate
model.compile(
    optimizer=tf.keras.optimizers.Adam(1e-5),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

history_phase2 = model.fit(
    train_ds,
    epochs=10,
    validation_data=val_ds,
    callbacks=[
        tf.keras.callbacks.EarlyStopping(
            monitor='val_accuracy', patience=4,
            restore_best_weights=True
        ),
        tf.keras.callbacks.ModelCheckpoint(
            'best_final.keras',
            monitor='val_accuracy',
            save_best_only=True
        )
    ]
)

print(f"Phase 2 best val_accuracy: {max(history_phase2.history['val_accuracy']):.2%}")

Step 5 — Evaluate and Predict

# Load best model
best_model = tf.keras.models.load_model('best_final.keras')

# Evaluate
loss, acc = best_model.evaluate(val_ds)
print(f"Final accuracy: {acc:.2%}")

# Predict a single leaf image
def classify_leaf(model, image_path):
    img = tf.keras.utils.load_img(image_path, target_size=(224, 224))
    img_array = tf.keras.utils.img_to_array(img)
    img_array = tf.expand_dims(img_array, 0)

    predictions = model.predict(img_array, verbose=0)
    predicted_class = CLASS_NAMES[tf.argmax(predictions[0]).numpy()]
    confidence = tf.reduce_max(predictions[0]).numpy()

    print(f"Diagnosis: {predicted_class} ({confidence:.1%} confidence)")
    for name, prob in zip(CLASS_NAMES, predictions[0]):
        bar = '█' * int(prob * 20)
        print(f"  {name:12s}: {prob:.1%} {bar}")

classify_leaf(best_model, 'test_leaf.jpg')

Step 6 — Export for Mobile Deployment

# Convert to TFLite for mobile deployment
converter = tf.lite.TFLiteConverter.from_keras_model(best_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]  # Apply quantization
tflite_model = converter.convert()

with open('plant_classifier.tflite', 'wb') as f:
    f.write(tflite_model)

print(f"TFLite model size: {len(tflite_model) / 1024:.0f} KB")
# Typically ~4–6 MB after quantization (down from 14 MB)

MobileNetV2 Architecture Highlights

Input: (224, 224, 3)
  │
  ▼ First Conv (32 filters, stride 2)       → (112, 112, 32)
  ▼ Bottleneck blocks (×17, expansion 6)    → various sizes
  ▼ Last Conv (1280 filters, 1×1)           → (7, 7, 1280)
  ▼ GlobalAveragePooling                    → (1280,)
  ▼ [include_top=True] Dense(1000)          → (1000,) ImageNet classes
     [include_top=False] output here        → (7, 7, 1280) for transfer learning

Performance Targets for Production

Use case                 Target latency  Model variant
──────────────────────────────────────────────────────────
Server API (batch)       <100ms/image    MobileNetV2 or EfficientNetB0
Mobile app (real-time)   <50ms/frame     MobileNetV2 TFLite quantized
Edge camera              <30ms/frame     MobileNetV3Small TFLite
Browser (TF.js)          <200ms/image    MobileNetV2 JS converted
──────────────────────────────────────────────────────────

MobileNetV2 with transfer learning and fine-tuning is one of the most powerful and practical tools in the TensorFlow ecosystem. It achieves production-level accuracy with minimal data, trains in minutes rather than days, and deploys to any platform. The skills you practiced here — two-phase training, quantized export, single-image prediction — apply to every future computer vision project you build. The advanced section now covers training techniques that push model quality and efficiency even further.

Leave a Comment

Your email address will not be published. Required fields are marked *