Home▸Articles▸Edge ML and On-Device Inference

Model Compression

Making models smaller and faster - quantization, pruning, knowledge distillation, and efficient architectures for deployment.

mysimulator teamUpdated 2026-01≈ 5 min read▶ Open the simulation

Model compression reduces model size and computational requirements while preserving accuracy. This enables deployment on edge devices, reduces serving costs, and improves latency. Techniques include quantization, pruning, knowledge distillation, and efficient architectures.

Where It Is Used

Model compression enables ML everywhere:

Products: Siri (on-device), Google Lens, smart home devices, autonomous vehicles.

Compression Techniques

Technique Description Compression Accuracy Loss
Quantization Reduce precision (FP32→INT8) 4x 0-2%
Pruning Remove unnecessary weights 2-10x 0-5%
Knowledge distillation Train smaller model 10-100x 1-5%
Architecture search Find efficient architecture Varies Minimal
Weight sharing Share weights across layers 2-4x 1-3%

Typical Targets

Metric Server Mobile Embedded
Model size GBs 10-100 MB < 10 MB
Latency 10-100ms 20-100ms < 50ms
Memory GBs 100s MB < 100 MB
Power High Medium Low

What You Do in Practice

  1. Profile baseline model - Size, latency, accuracy, memory
  2. Set deployment constraints - Target device specifications
  3. Choose compression approach - Based on constraints and model type
  4. Apply compression - Quantization, pruning, distillation
  5. Fine-tune if needed - Recover accuracy loss
  6. Validate on target hardware - Real device testing
  7. Optimize runtime - TensorRT, ONNX Runtime, etc.
  8. Benchmark thoroughly - Latency, accuracy, memory
  9. Deploy and monitor - Track real-world performance
  10. Iterate - Further optimization if needed

Quantization

Reduce numerical precision of weights and activations.

Post-training quantization (simple):

import torch

# Load FP32 model
model = torch.load('model.pth')

# Dynamic quantization (weights only)
quantized_model = torch.quantization.quantize_dynamic(
    model,
    {torch.nn.Linear, torch.nn.LSTM},
    dtype=torch.qint8
)

# Static quantization (weights + activations)
model.qconfig = torch.quantization.get_default_qconfig('fbgemm')
torch.quantization.prepare(model, inplace=True)

# Calibrate with representative data
with torch.no_grad():
    for batch in calibration_dataloader:
        model(batch)

torch.quantization.convert(model, inplace=True)

Quantization-aware training (higher accuracy):

import torch.quantization as quant

# Prepare model for QAT
model.qconfig = quant.get_default_qat_qconfig('fbgemm')
model_prepared = quant.prepare_qat(model, inplace=False)

# Train with fake quantization
optimizer = torch.optim.Adam(model_prepared.parameters())
for epoch in range(num_epochs):
    for batch in train_loader:
        loss = train_step(model_prepared, batch)
        loss.backward()
        optimizer.step()

# Convert to quantized model
model_quantized = quant.convert(model_prepared)

Pruning

Remove weights or structures that contribute little to accuracy.

Magnitude pruning:

import torch.nn.utils.prune as prune

# Prune 30% of weights with lowest magnitude
for name, module in model.named_modules():
    if isinstance(module, torch.nn.Conv2d):
        prune.l1_unstructured(module, name='weight', amount=0.3)

# Make pruning permanent
for name, module in model.named_modules():
    if isinstance(module, torch.nn.Conv2d):
        prune.remove(module, 'weight')

Structured pruning (remove entire filters/channels):

# Prune entire filters based on L1 norm
def prune_filters(model, amount=0.3):
    for name, module in model.named_modules():
        if isinstance(module, torch.nn.Conv2d):
            prune.ln_structured(
                module,
                name='weight',
                amount=amount,
                n=1,  # L1 norm
                dim=0  # Prune filters
            )

Iterative pruning (prune-retrain cycle):

def iterative_pruning(model, target_sparsity, steps=5):
    current_sparsity = 0
    step_sparsity = target_sparsity / steps

    for step in range(steps):
        # Prune
        prune_model(model, amount=step_sparsity)

        # Retrain
        train_model(model, epochs=5)

        current_sparsity += step_sparsity
        print(f"Step {step}: Sparsity = {current_sparsity:.1%}")

Knowledge Distillation

Train a smaller "student" model to mimic a larger "teacher".

import torch.nn.functional as F

def distillation_loss(student_logits, teacher_logits, labels,
                      temperature=4.0, alpha=0.5):
    """
    Combine soft targets (from teacher) with hard targets (labels).
    """
    # Soft targets: KL divergence with temperature
    soft_loss = F.kl_div(
        F.log_softmax(student_logits / temperature, dim=1),
        F.softmax(teacher_logits / temperature, dim=1),
        reduction='batchmean'
    ) * (temperature ** 2)

    # Hard targets: cross-entropy with true labels
    hard_loss = F.cross_entropy(student_logits, labels)

    return alpha * soft_loss + (1 - alpha) * hard_loss

# Training loop
teacher.eval()
student.train()

for batch in train_loader:
    inputs, labels = batch

    with torch.no_grad():
        teacher_logits = teacher(inputs)

    student_logits = student(inputs)
    loss = distillation_loss(student_logits, teacher_logits, labels)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

Efficient Architectures

Use architectures designed for efficiency:

Architecture Use Case Key Innovation
MobileNet Mobile vision Depthwise separable convolutions
EfficientNet Scalable Compound scaling
DistilBERT NLP Distilled BERT
TinyBERT NLP Layer-wise distillation
MobileViT Vision Transformer Mobile-friendly ViT
# Example: MobileNetV3
from torchvision.models import mobilenet_v3_small

model = mobilenet_v3_small(pretrained=True)
# Already ~2.5M parameters vs ResNet50's 25M

Evaluation and Metrics

Metric Description How to Measure
Model size Disk/memory footprint os.path.getsize()
Latency Inference time Benchmark on target device
Throughput Inferences per second Batch processing
Accuracy Task performance Standard metrics
Memory Peak RAM usage Profiling tools
Power Energy consumption Device-specific tools

Compression ratio:

def compression_stats(original_model, compressed_model):
    orig_size = sum(p.numel() for p in original_model.parameters())
    comp_size = sum(p.numel() for p in compressed_model.parameters())

    orig_bytes = sum(p.numel() * p.element_size()
                     for p in original_model.parameters())
    comp_bytes = sum(p.numel() * p.element_size()
                     for p in compressed_model.parameters())

    return {
        'param_reduction': 1 - comp_size / orig_size,
        'size_reduction': 1 - comp_bytes / orig_bytes,
    }

Failure Modes and Debugging Checklist

Production Checklist

Before compression: - [ ] Baseline metrics documented - [ ] Target constraints defined - [ ] Compression approach selected - [ ] Calibration data prepared - [ ] Target device available for testing

After compression: - [ ] Accuracy validated on test set - [ ] Latency benchmarked on target device - [ ] Memory usage verified - [ ] Edge cases tested - [ ] Model format compatible - [ ] Deployment pipeline tested

Deployment: - [ ] Runtime optimized (TensorRT, ONNX Runtime) - [ ] Model versioning in place - [ ] Monitoring for quality degradation - [ ] Rollback plan ready

Tools and Stack

Category Tools
PyTorch torch.quantization, torch.nn.utils.prune
TensorFlow TF Lite, TF Model Optimization Toolkit
Runtimes TensorRT, ONNX Runtime, TVM
Mobile CoreML, TF Lite, PyTorch Mobile
Profiling NVIDIA Nsight, TensorBoard

Example Mini-Case

Scenario: Deploy image classification model on mobile app.

Baseline: ResNet50, 98MB, 150ms latency on mobile.

Target: < 10MB, < 50ms latency, < 1% accuracy drop.

Approach: 1. Architecture: Switch to MobileNetV3-Small (10MB, 85ms) 2. Quantization: INT8 post-training (2.5MB, 45ms) 3. Fine-tuning: 5 epochs to recover accuracy

Results:

Metric ResNet50 MobileNetV3-Q
Size 98 MB 2.5 MB
Latency 150 ms 42 ms
Top-1 Acc 76.1% 74.8%

Key learnings: - Architecture choice > post-hoc compression - Calibration data quality matters for quantization - Test on actual device, not emulator - INT8 quantization gave best size/accuracy trade-off

Related Pages

Further Reading

Try it live

Everything above runs in your browser — open Model Compression Lab — Shrink a Network Without Wrecking It and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.

▶ Open Model Compression Lab — Shrink a Network Without Wrecking It simulation

What did you find?

Add reproduction steps (optional)