Chapter 5: Model Optimization & Quantization

WIA-AI-008 Standard • Estimated reading time: 55 minutes

5.1 Why Optimize Models?

Model optimization reduces size, improves inference speed, and decreases energy consumption while maintaining acceptable accuracy. This is critical for deployment on resource-constrained devices like smartphones, embedded systems, and edge devices where memory and compute are limited.

Optimization Goals

5.2 Quantization Fundamentals

Quantization reduces the precision of model weights and activations from floating-point (FP32) to lower-precision formats (FP16, INT8, INT4). This dramatically reduces model size and improves inference speed on hardware with specialized integer arithmetic units.

Quantization Types

Type Precision Size Reduction Speedup Accuracy Loss
FP32 (Baseline) 32-bit float 1x 1x 0%
FP16 16-bit float 2x 1.5-2x < 0.1%
INT8 Dynamic 8-bit integer 4x 2-4x 0.5-2%
INT8 Static 8-bit integer 4x 3-4x 1-3%
INT4 4-bit integer 8x 4-8x 3-5%

5.3 Post-Training Quantization

Post-training quantization (PTQ) applies quantization to an already-trained model without retraining.

PyTorch Dynamic Quantization

import torch
import torch.quantization
import torchvision.models as models

# Load pretrained model
model = models.resnet18(pretrained=True)
model.eval()

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

# Compare sizes
def get_model_size(model):
    torch.save(model.state_dict(), "temp.pth")
    size_mb = os.path.getsize("temp.pth") / (1024 * 1024)
    os.remove("temp.pth")
    return size_mb

original_size = get_model_size(model)
quantized_size = get_model_size(quantized_model)

print(f"Original model: {original_size:.2f} MB")
print(f"Quantized model: {quantized_size:.2f} MB")
print(f"Compression ratio: {original_size / quantized_size:.2f}x")

PyTorch Static Quantization

import torch
import torch.quantization

# Prepare model for static quantization
model = models.resnet18(pretrained=True)
model.eval()

# Set quantization config
model.qconfig = torch.quantization.get_default_qconfig('fbgemm')

# Prepare for quantization (insert observers)
model_prepared = torch.quantization.prepare(model)

# Calibrate with representative data
def calibrate(model, data_loader):
    model.eval()
    with torch.no_grad():
        for data, _ in data_loader:
            model(data)

calibrate(model_prepared, calibration_loader)

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

# Test inference
test_input = torch.randn(1, 3, 224, 224)
output = model_quantized(test_input)

print("Static quantization completed")

TensorFlow Lite Quantization

import tensorflow as tf

# Load model
model = tf.keras.applications.MobileNetV2(weights='imagenet')

# Convert to TFLite with quantization
converter = tf.lite.TFLiteConverter.from_keras_model(model)

# Dynamic range quantization (weights only)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

# Full integer quantization (weights + activations)
def representative_dataset():
    for _ in range(100):
        # Use real data or synthetic data matching input distribution
        data = np.random.rand(1, 224, 224, 3).astype(np.float32)
        yield [data]

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

# Convert
tflite_quantized_model = converter.convert()

# Save
with open('model_quantized.tflite', 'wb') as f:
    f.write(tflite_quantized_model)

print(f"Quantized model size: {len(tflite_quantized_model) / 1024:.2f} KB")

5.4 Quantization-Aware Training

Quantization-Aware Training (QAT) simulates quantization during training, allowing the model to adapt and maintain higher accuracy after quantization.

PyTorch QAT

import torch
import torch.quantization as quantization

# Define model
model = models.resnet18(pretrained=True)

# Set QAT config
model.train()
model.qconfig = quantization.get_default_qat_qconfig('fbgemm')

# Prepare for QAT
model_prepared = quantization.prepare_qat(model)

# Training loop with QAT
optimizer = torch.optim.SGD(model_prepared.parameters(), lr=0.001)
criterion = torch.nn.CrossEntropyLoss()

for epoch in range(num_epochs):
    for data, target in train_loader:
        optimizer.zero_grad()
        output = model_prepared(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

    # Disable observer and fold batch norm after a few epochs
    if epoch > 3:
        model_prepared.apply(torch.quantization.disable_observer)
    if epoch > 2:
        model_prepared.apply(torch.nn.intrinsic.qat.freeze_bn_stats)

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

# Evaluate
test_accuracy = evaluate(model_quantized, test_loader)
print(f"QAT model accuracy: {test_accuracy:.2f}%")

TensorFlow QAT

import tensorflow as tf
import tensorflow_model_optimization as tfmot

# Load model
model = tf.keras.applications.MobileNetV2(weights='imagenet', classes=1000)

# Apply quantization-aware training
quantize_model = tfmot.quantization.keras.quantize_model

qat_model = quantize_model(model)

# Compile with QAT
qat_model.compile(
    optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(),
    metrics=['accuracy']
)

# Train
qat_model.fit(train_dataset, epochs=10, validation_data=val_dataset)

# Convert to TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(qat_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]

tflite_qat_model = converter.convert()

with open('model_qat.tflite', 'wb') as f:
    f.write(tflite_qat_model)

5.5 Pruning

Pruning removes unimportant weights from the network, creating sparse models that are smaller and faster.

Magnitude-Based Pruning

import torch
import torch.nn.utils.prune as prune

# Load model
model = models.resnet18(pretrained=True)

# Prune 30% of Conv2d weights by 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')

# Check sparsity
def check_sparsity(model):
    total_params = 0
    zero_params = 0
    for param in model.parameters():
        total_params += param.numel()
        zero_params += (param == 0).sum().item()

    sparsity = 100.0 * zero_params / total_params
    return sparsity

sparsity = check_sparsity(model)
print(f"Model sparsity: {sparsity:.2f}%")

Structured Pruning

# Prune entire channels/filters (more hardware-friendly)
prune.ln_structured(
    module,
    name='weight',
    amount=0.5,  # Prune 50% of filters
    n=2,         # L2 norm
    dim=0        # Prune along output channel dimension
)

# TensorFlow pruning
import tensorflow_model_optimization as tfmot

# Define pruning schedule
pruning_params = {
    'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(
        initial_sparsity=0.0,
        final_sparsity=0.5,
        begin_step=0,
        end_step=1000
    )
}

# Apply pruning
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(model, **pruning_params)

# Compile and train
model_for_pruning.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model_for_pruning.fit(train_dataset, epochs=10, callbacks=[tfmot.sparsity.keras.UpdatePruningStep()])

# Strip pruning wrappers
model_pruned = tfmot.sparsity.keras.strip_pruning(model_for_pruning)

5.6 Knowledge Distillation

Knowledge distillation trains a smaller "student" model to mimic a larger "teacher" model, achieving better accuracy than training the student from scratch.

import torch
import torch.nn as nn
import torch.nn.functional as F

class DistillationLoss(nn.Module):
    def __init__(self, temperature=3.0, alpha=0.5):
        super().__init__()
        self.temperature = temperature
        self.alpha = alpha
        self.ce_loss = nn.CrossEntropyLoss()

    def forward(self, student_logits, teacher_logits, targets):
        # Soft targets from teacher
        soft_loss = F.kl_div(
            F.log_softmax(student_logits / self.temperature, dim=1),
            F.softmax(teacher_logits / self.temperature, dim=1),
            reduction='batchmean'
        ) * (self.temperature ** 2)

        # Hard targets (ground truth)
        hard_loss = self.ce_loss(student_logits, targets)

        # Combined loss
        return self.alpha * soft_loss + (1 - self.alpha) * hard_loss

# Teacher model (large)
teacher = models.resnet50(pretrained=True)
teacher.eval()

# Student model (small)
student = models.resnet18(pretrained=False)

# Training loop
distill_loss_fn = DistillationLoss(temperature=3.0, alpha=0.7)
optimizer = torch.optim.Adam(student.parameters(), lr=0.001)

for epoch in range(num_epochs):
    for data, targets in train_loader:
        # Teacher predictions (no gradients)
        with torch.no_grad():
            teacher_logits = teacher(data)

        # Student predictions
        student_logits = student(data)

        # Distillation loss
        loss = distill_loss_fn(student_logits, teacher_logits, targets)

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

print("Knowledge distillation completed")

5.7 Graph Optimization

Graph-level optimizations transform the computational graph for better performance.

Operator Fusion

# Conv + BatchNorm + ReLU → Fused ConvBNReLU
# Reduces memory access and improves performance

# PyTorch fusion
model = models.resnet18(pretrained=True)
model.eval()

# Fuse modules
model_fused = torch.quantization.fuse_modules(
    model,
    [['conv1', 'bn1', 'relu']],  # Modules to fuse
    inplace=False
)

# ONNX Runtime optimizations
import onnxruntime as ort

session_options = ort.SessionOptions()
session_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL

session = ort.InferenceSession("model.onnx", session_options)

Constant Folding

# Evaluate constant expressions at compile time
# Example: If model has "x * 2 + 3", compute it once instead of every inference

# Automatically done during ONNX export
torch.onnx.export(
    model,
    dummy_input,
    "model.onnx",
    do_constant_folding=True  # Enable constant folding
)

5.8 Hardware-Specific Optimizations

NVIDIA TensorRT

import tensorrt as trt

# Build optimized engine for NVIDIA GPUs
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH))
parser = trt.OnnxParser(network, logger)

# Parse ONNX model
with open('model.onnx', 'rb') as f:
    parser.parse(f.read())

# Configure optimization
config = builder.create_builder_config()
config.max_workspace_size = 1 << 30  # 1GB
config.set_flag(trt.BuilderFlag.FP16)  # Enable FP16
config.set_flag(trt.BuilderFlag.STRICT_TYPES)

# Build optimized engine
engine = builder.build_engine(network, config)

# Speedup: 3-5x on NVIDIA GPUs

Apple Core ML

import coremltools as ct

# Convert with optimizations for Apple Neural Engine
model = ct.convert(
    "model.onnx",
    compute_units=ct.ComputeUnit.ALL,  # Use Neural Engine + GPU + CPU
    minimum_deployment_target=ct.target.iOS15
)

# Apply optimizations
model = ct.models.neural_network.quantization_utils.quantize_weights(model, nbits=8)

model.save("model_optimized.mlmodel")

5.9 Measuring Optimization Impact

Benchmark Suite

import time
import numpy as np

def benchmark_model(model, input_shape, num_iterations=100, warmup=10):
    """
    Benchmark model inference performance
    """
    # Warmup
    dummy_input = torch.randn(*input_shape)
    for _ in range(warmup):
        _ = model(dummy_input)

    # Benchmark
    torch.cuda.synchronize() if torch.cuda.is_available() else None
    start_time = time.time()

    for _ in range(num_iterations):
        _ = model(dummy_input)

    torch.cuda.synchronize() if torch.cuda.is_available() else None
    end_time = time.time()

    # Calculate metrics
    total_time = end_time - start_time
    avg_latency = (total_time / num_iterations) * 1000  # ms
    throughput = num_iterations / total_time  # fps

    return {
        'avg_latency_ms': avg_latency,
        'throughput_fps': throughput,
        'total_time_s': total_time
    }

# Compare original vs optimized
results_original = benchmark_model(model_original, (1, 3, 224, 224))
results_optimized = benchmark_model(model_optimized, (1, 3, 224, 224))

print("Original Model:")
print(f"  Latency: {results_original['avg_latency_ms']:.2f} ms")
print(f"  Throughput: {results_original['throughput_fps']:.2f} FPS")

print("\nOptimized Model:")
print(f"  Latency: {results_optimized['avg_latency_ms']:.2f} ms")
print(f"  Throughput: {results_optimized['throughput_fps']:.2f} FPS")

speedup = results_original['avg_latency_ms'] / results_optimized['avg_latency_ms']
print(f"\nSpeedup: {speedup:.2f}x")

5.10 Accuracy-Performance Trade-offs

Pareto Frontier Analysis

# Evaluate different optimization configurations
configs = [
    {'name': 'Baseline', 'quantization': None, 'pruning': 0},
    {'name': 'FP16', 'quantization': 'fp16', 'pruning': 0},
    {'name': 'INT8', 'quantization': 'int8', 'pruning': 0},
    {'name': 'INT8+Prune30', 'quantization': 'int8', 'pruning': 0.3},
    {'name': 'INT8+Prune50', 'quantization': 'int8', 'pruning': 0.5},
]

results = []
for config in configs:
    model_opt = apply_optimizations(model, config)
    accuracy = evaluate_accuracy(model_opt, test_loader)
    latency = benchmark_model(model_opt, (1, 3, 224, 224))['avg_latency_ms']
    size_mb = get_model_size(model_opt)

    results.append({
        'name': config['name'],
        'accuracy': accuracy,
        'latency': latency,
        'size_mb': size_mb
    })

# Print results
print("Optimization Results:")
print(f"{'Config':<20} {'Accuracy':<12} {'Latency (ms)':<15} {'Size (MB)':<12}")
print("-" * 60)
for r in results:
    print(f"{r['name']:<20} {r['accuracy']:<12.2f} {r['latency']:<15.2f} {r['size_mb']:<12.2f}")

Summary

Review Questions

  1. What are the main goals of model optimization?
  2. Compare FP16, INT8, and INT4 quantization in terms of size, speed, and accuracy.
  3. What is the difference between dynamic and static quantization?
  4. Why does quantization-aware training (QAT) maintain higher accuracy than post-training quantization?
  5. Explain the difference between structured and unstructured pruning.
  6. How does knowledge distillation work? What are the "soft" and "hard" targets?
  7. What is operator fusion and why does it improve performance?
  8. When would you use TensorRT vs ONNX Runtime for deployment?
  9. Design a benchmark suite to compare model optimizations.
  10. How do you analyze accuracy-performance trade-offs when applying multiple optimizations?

Korea Standardization Infrastructure Mapping

Korea operates a comprehensive standards governance system through inter-ministerial cooperation. National Standards Council (under Prime Minister's Office, per Framework Act on National Standards Article 5) coordinates KATS (Korean Agency for Technology and Standards), MFDS (Ministry of Food and Drug Safety), MOTIE (Ministry of Trade, Industry and Energy), MSIT (Ministry of Science and ICT), MOIS (Ministry of the Interior and Safety), MOE (Ministry of Environment), MOHW (Ministry of Health and Welfare), MND (Ministry of National Defense), MCST (Ministry of Culture, Sports and Tourism), MOFA (Ministry of Foreign Affairs), MOJ (Ministry of Justice), and FSC (Financial Services Commission). Accreditation and Testing: KOLAS (Korea Laboratory Accreditation Scheme) accredits 800+ testing laboratories. KAS (Korea Accreditation System) accredits 50+ certification bodies. KTC (Korea Testing Certification), KTR (Korea Testing & Research Institute), KTL (Korea Testing Laboratory), and KCL (Korea Conformity Laboratories) provide conformance testing. Telecom and Cyber: KCC (Korea Communications Commission), KCA (Korea Communications Agency), TTA (Telecommunications Technology Association), IITP (Institute for Information & Communications Technology Planning & Evaluation), NIPA (National IT Industry Promotion Agency), KISA (Korea Internet & Security Agency), KCMVP (Korea Cryptographic Module Validation Program), NIS (National Intelligence Service), NSR (National Security Research Institute), and NCSC (National Cyber Security Center). National R&D Centers: KIST, ETRI, KAIST, Seoul National University, Yonsei University, Korea University, POSTECH, UNIST, GIST, DGIST, KISTI, KIER, KIMM, KRICT, KFRI, KRIBB. International Standards Cooperation: ISO TC/SC Korean secretariats, IEC TC/SC Korean secretariats, ITU-T Study Group Korean chairs, 3GPP RAN/SA Korean chairs, IEEE 802 Korean chairs, W3C Korea office, OASIS Korea office, IETF Korea cooperation, OECD CSTP, UN ESCAP, APEC SCSC Korean cooperation. Korean Industrial Standards (KS) Catalog: KS X (Information) 25,000+, KS A (Basic) 15,000+, KS B (Machinery) 25,000+, KS C (Electrical) 18,000+, KS D (Metallurgy) 12,000+, KS E (Mining) 5,000+, KS F (Construction) 18,000+, KS H (Food) 8,000+, KS I (Environment) 5,000+, KS J (Biology) 3,000+, KS K (Textile) 15,000+, KS L (Ceramics) 7,000+, KS M (Chemistry) 12,000+, KS P (Medical) 5,000+, KS Q (Quality Mgmt) 4,000+, KS R (Transport) 12,000+, KS S (Service) 3,000+, KS T (Packaging) 4,000+, KS V (Shipbuilding) 5,000+, KS W (Aerospace) 3,000+ — totaling 220,000+ Korean Industrial Standards. Key Acts: Personal Information Protection Act (Act 19234, effective Sept 15, 2024), Electronic Government Act, Electronic Signature Act, Act on Promotion of Information and Communications Network Utilization and Information Protection, Information and Communications Infrastructure Protection Act, Data Industry Act, Public Data Act, AI Framework Act (Act 20212, effective July 2026), Industrial Technology Innovation Promotion Act, Framework Act on Science and Technology — 70+ Korean standardization-related laws.

Korea Digital Transformation Detailed Mapping

Korea operates digital transformation through a comprehensive governance system. Digital Government: Digital Platform Government Committee (established September 2022, under the President)·Ministry of the Interior and Safety Digital Government Bureau·e-Government Support Center·Gov.kr·National Citizen Service·KDIS (Korea Digital Information Society)·NIA (National Information Society Agency)·MOIS (Ministry of the Interior and Safety). K-DNS Infrastructure: Korea Internet & Security Agency (KISA) Korea Internet Center·KISA DNS Root Server·KRNIC (Korea Network Information Center)·BGP Korea·National Cyber Security Center (NCSC)·KCC (Korea Communications Commission)·MSIT (Ministry of Science and ICT)·NIA·NIPA. Korean Cloud Infrastructure: KT Cloud·NAVER Cloud (NCloud)·Samsung SDS Cloud·LG U+ Cloud·NHN Cloud·Kakao Enterprise Cloud·SK Telecom Cloud·KISA Cloud Security Assurance Program (CSAP)·KCMVP-validated cloud·ISMS-P (Information Security & Personal Information Management System). Korean Security Certifications: KISA ISMS-P certification·KCMVP (Korean Cryptographic Module Validation Program)·NIS (National Intelligence Service) "National Cryptographic Technology Operation Standards"·NCSC "National Cyber Security Strategy 2024-2028"·CC (Common Criteria) Korean evaluation bodies·EAL4·EAL5·KS X ISO/IEC 15408·19790·24759 Korean Profile. Korean Data Standards: NIA AI Hub·National Data Standardization Committee·Statistics Korea (KOSTAT)·MyData 4 Designated Combination Specialists (Samsung SDS, KICI, KOSTAT, KFTC)·National Institute of Korean Language·National Law Information Center·National Spatial Information Platform·National Spatial Data Center·Korean Spatial Information Standards. Finance and Fintech Standards: FSC (Financial Services Commission)·FSS (Financial Supervisory Service)·FIU (Financial Intelligence Unit)·BOK (Bank of Korea)·FSEC (Financial Security Institute)·KFTC (Korea Financial Telecommunications)·KSD (Korea Securities Depository)·KRX (Korea Exchange) 8-agency cooperation. 5G/6G Communications Infrastructure: 5G subscribers 35 million (2024)·5G base stations 350,000·6G commercialization target 2028·5G dedicated networks 16 operators·6G Acceleration Council (MSIT, 2024). K-Content: KOCCA (Korea Creative Content Agency)·MCST (Ministry of Culture, Sports and Tourism)·KCA (Korea Communications Agency)·Korea Culture Information Service Agency·Korean Film Archive·Korea Publishing Industry Promotion Agency. Data 3 Acts (Personal Information Protection Act·Credit Information Act·Telecommunications Network Act, 2020 enforcement)·Data Industry Act (2021)·Public Data Act (2013)·AI Framework Act (2026)·Digital Platform Government Framework Act (2024 proposed) — Korea digital transformation core legislation.