Menu

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)')