Model Optimization and Deployment Basics
Model Optimization and Deployment Basics
Training a model is only half the job. The other half is getting it to run efficiently in the real world on a server, in a browser, or on a device with limited battery and memory. TensorFlow provides a complete path from trained model to deployed application, with tools for optimisation at every step.
Introduction to Model Deployment
Deployment means running a trained model to make predictions on new data in a production environment. The three most common TensorFlow deployment targets are:
Target | Tool | Best For |
Cloud/server | TensorFlow Serving | High-throughput REST/gRPC inference endpoints |
Mobile (Android/iOS) | TensorFlow Lite | Real-time on-device inference, privacy-sensitive apps |
Browser | TensorFlow.js | Client-side inference, interactive web applications |
Edge / IoT | TFLite + EdgeTPU | Microcontrollers, cameras, wearables, and drones |
TensorFlow Lite Overview
TensorFlow Lite is TensorFlow's cross-platform library for deploying models on mobile, embedded, and IoT devices. The conversion pipeline is two steps: convert the SavedModel to a .tflite flat buffer file, then run it using the TFLite interpreter on the target device. A Medium article from July 2025 on edge AI notes: 'Edge AI is advancing rapidly, enabling real-time, efficient processing without relying on cloud computing, enhancing privacy, reducing latency, and lowering operational costs.'
import tensorflow as tf
# Step 1: Convert SavedModel to TFLite
converter = tf.lite.TFLiteConverter.from_saved_model('saved_models/my_model')
tflite_model = converter.convert()
# Step 2: Save the .tflite file
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
print(f'TFLite model size: {len(tflite_model) / 1024:.1f} KB')
# Step 3: Run the TFLite model (e.g., on a Raspberry Pi)
interpreter = tf.lite.Interpreter(model_path='model.tflite')
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]['index'], sample_input)
interpreter.invoke()
output = interpreter.get_tensor(output_details[0]['index'])
print(output)
Quantization Basics
Quantization reduces a model's numerical precision from 32-bit floating point (float32) to 8-bit integers (int8) or 16-bit floats (float16). According to the TensorFlow Model Optimization Toolkit documentation, 'Quantization brings improvements via model compression and latency reduction.' The trade-off is a small accuracy drop usually less than 1% for int8 on image classification tasks.
Quantization Type | Precision | Size Reduction | Speed Gain | Accuracy Drop |
Float16 | float32 → float16 | ~50% | Moderate | Minimal (<0.1%) |
Dynamic range | float32 → int8 (weights) | ~75% | Good | Small (<0.5%) |
Full integer | float32 → int8 (all) | ~75% | Best (EdgeTPU compatible) | Small (<1%) |
# Post-training quantization (no retraining required)
# Float16 quantization (good starting point)
converter = tf.lite.TFLiteConverter.from_saved_model('saved_models/my_model')
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_fp16 = converter.convert()
# Full integer quantization (requires calibration data)
def representative_dataset():
for sample in x_test[:100]:
yield [sample.reshape(1, 784).astype('float32')]
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
tflite_int8 = converter.convert()
print(f'FP32 size: {len(tflite_model)/1024:.0f} KB')
print(f'INT8 size: {len(tflite_int8)/1024:.0f} KB') # ~4x smaller
Model Compression Techniques
Beyond quantization, TensorFlow offers a full toolkit of compression methods through the TF Model Optimization Toolkit (TFMOT):
• Pruning: zeros out weights below a threshold, creating a sparse model. The TensorFlow blog notes that TFMOT supports pruning for both Sequential/Functional models and custom subclassed layers. Pruning can remove 50–90% of weights with minimal accuracy loss, and the zeroed weights compress very well.
• Weight clustering: groups similar weights into clusters and replaces them with a shared centroid value. Reduces the number of unique values that need to be encoded.
• Quantization-aware training (QAT): simulates quantization during training by inserting fake quantization nodes. This allows the model to adapt its weights to the precision loss, recovering accuracy that post-training quantization sometimes loses.
import tensorflow_model_optimization as tfmot
# Pruning example: prune 50% of weights in Dense layers, prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
pruning_schedule = tfmot.sparsity.keras.PolynomialDecay(
initial_sparsity=0.0,
final_sparsity=0.5,
begin_step=0,
end_step=1000
)
pruned_model = prune_low_magnitude(model, pruning_schedule=pruning_schedule)
pruned_model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
Deploying Models on Edge Devices
Edge deployment means the model runs directly on the device: a Raspberry Pi, an Android phone, an Arduino, or a custom ASIC. No internet connection required, no cloud latency, and all data stays on-device. The typical pipeline is:
• Train and evaluate your model in TensorFlow (full precision).
• Save as SavedModel with model.save('my_model').
• Convert to .tflite with optional quantization using TFLiteConverter.
• Copy the .tflite file to the target device.
• Run inference using the TFLite interpreter for Python, Java (Android), Swift (iOS), or C++ (embedded).
# Raspberry Pi / Python edge inference example
import tensorflow as tf
import numpy as np
# Load the TFLite model
interpreter = tf.lite.Interpreter(model_path='model.tflite')
interpreter.allocate_tensors()
input_index = interpreter.get_input_details()[0]['index']
output_index = interpreter.get_output_details()[0]['index']
# Capture a sample (e.g., from a camera)
sample = np.random.random((1, 224, 224, 3)).astype(np.float32)
# Run inference
interpreter.set_tensor(input_index, sample)
interpreter.invoke()
result = interpreter.get_tensor(output_index)
predicted_class = result.argmax()
confidence = result.max() * 100
print(f'Predicted: class {predicted_class} ({confidence:.1f}% confidence)')










