Study interactive :: Progress tools open in the Study Hub reader.

Model Deployment Cheatsheet

Comprehensive quick reference for deploying ML models to production.

Table of Contents


Model Serialization

Scikit-learn

import joblib

# Save model
joblib.dump(model, 'model.joblib')

# Load model
model = joblib.load('model.joblib')

# Save with metadata
joblib.dump({
    'model': model,
    'scaler': scaler,
    'version': '1.0.0',
    'features': feature_names
}, 'model_package.joblib')

TensorFlow/Keras

# Save entire model
model.save('model.h5')
model.save('model/')  # SavedModel format

# Load model
model = tf.keras.models.load_model('model.h5')

# Save weights only
model.save_weights('weights.h5')
model.load_weights('weights.h5')

PyTorch

import torch

# Save model state
torch.save(model.state_dict(), 'model.pth')

# Load model state
model = MyModel()
model.load_state_dict(torch.load('model.pth'))
model.eval()

# Save entire model
torch.save(model, 'model.pth')
model = torch.load('model.pth')

ONNX (Cross-platform)

# Convert to ONNX
import onnx
from skl2onnx import convert_sklearn

 'model.onnx')

# Load ONNX
import onnxruntime as ort
session = ort.InferenceSession('model.onnx')

API Development

FastAPI

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import joblib
import numpy as np

app = FastAPI(title="ML API")

# Load model
model = joblib.load('model.joblib')

# Request model
class PredictionRequest(BaseModel):
    features: list[float]

# Response model
class PredictionResponse(BaseModel):
    prediction: float
    probability: float

@app.post("/predict", response_model=PredictionResponse)
async def predict(request: PredictionRequest):
    try:
        # Preprocess
        features = np.array(request.features).reshape(1, -1)
        
        # Predict
        prediction = model.predict(features)[0]
        probability = model.predict_proba(features)[0].max()
        
        return PredictionResponse(
            prediction=float(prediction),
            probability=float(probability)
        )
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@app.get("/health")
async def health():
    return {"status": "healthy"}

# Run: uvicorn main:app --reload

Flask

from flask import Flask, request, jsonify
import joblib
import numpy as np

app = Flask(__name__)
model = joblib.load('model.joblib')

@app.route('/predict', methods=['POST'])
def predict():
    try:
        data = request.json
        features = np.array(data['features']).reshape(1, -1)
        prediction = model.predict(features)[0]
        return jsonify({'prediction': float(prediction)})
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/health', methods=['GET'])
def health():
    return jsonify({'status': 'healthy'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Streamlit

import streamlit as st
import joblib
import pandas as pd

# Load model
model = joblib.load('model.joblib')

st.title("ML Prediction App")

# Input form
features = []
for i in range(4):
    feature = st.number_input(f"Feature {i+1}", value=0.0)
    features.append(feature)

# Predict button
if st.button("Predict"):
    prediction = model.predict([features])[0]
    st.success(f"Prediction: {prediction}")

# Run: streamlit run app.py

Containerization

Dockerfile

FROM python:3.9-slim

WORKDIR /app

# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Expose port
EXPOSE 8000

# Run application
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Docker Commands

# Build image
docker build -t ml-api:latest .

# Run container
docker run -p 8000:8000 ml-api:latest

# Run in background
docker run -d -p 8000:8000 --name ml-api ml-api:latest

# View logs
docker logs ml-api

# Stop container
docker stop ml-api

# Remove container
docker rm ml-api

Docker Compose

version: '3.8'

services:
  ml-api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - MODEL_PATH=/models/model.joblib
    volumes:
      - ./models:/models
    restart: unless-stopped

Cloud Deployment

AWS SageMaker

import sagemaker
from sagemaker.sklearn import SKLearnModel

# Create model
sklearn_model = SKLearnModel(
    model_data='s3://bucket/model.tar.gz',
    role=sagemaker.get_execution_role(),
    entry_point='inference.py',
    framework_version='0.23-1'
)

# Deploy
predictor = sklearn_model.deploy(
    instance_type='ml.t2.medium',
    initial_instance_count=1
)

# Predict
prediction = predictor.predict(data)

Google Cloud AI Platform

from google.cloud import aiplatform

# Deploy model
endpoint = aiplatform.Endpoint.create(
    display_name="my-endpoint"
)

# Upload model
model = aiplatform.Model.upload(
    display_name="my-model",
    artifact_uri="gs://bucket/model"
)

# Deploy to endpoint
model.deploy(
    endpoint=endpoint,
    machine_type="n1-standard-4"
)

Azure ML

from azureml.core import Model, Workspace
from azureml.core.webservice import AciWebservice, Webservice

# Register model
model = Model.register(
    workspace=ws,
    model_path="model.pkl",
    model_name="my-model"
)

# Deploy
service = Model.deploy(
    workspace=ws,
    name="my-service",
    models=[model],
    inference_config=inference_config,
    deployment_config=deployment_config
)

A/B Testing

Statistical Significance

from scipy import stats
import numpy as np

def analyze_ab_test(conversions_a, total_a, conversions_b, total_b):
    """Z-test for two proportions"""
    rate_a = conversions_a / total_a
    rate_b = conversions_b / total_b
    
    # Pooled proportion
    pooled = (conversions_a + conversions_b) / (total_a + total_b)
    se = np.sqrt(pooled * (1 - pooled) * (1/total_a + 1/total_b))
    
    # Z-score and p-value
    z = (rate_b - rate_a) / se
    p_value = 2 * (1 - stats.norm.cdf(abs(z)))
    
    return {
        'rate_a': rate_a,
        'rate_b': rate_b,
        'lift': (rate_b - rate_a) / rate_a,
        'p_value': p_value,
        'significant': p_value < 0.05
    }

Multi-Armed Bandit

import numpy as np

class EpsilonGreedy:
    def __init__(self, n_arms, epsilon=0.1):
        self.n_arms = n_arms
        self.epsilon = epsilon
        self.counts = np.zeros(n_arms)
        self.values = np.zeros(n_arms)
    
    def select_arm(self):
        if np.random.random() < self.epsilon:
            return np.random.randint(self.n_arms)
        else:
            return np.argmax(self.values)
    
    def update(self, arm, reward):
        self.counts[arm] += 1
        n = self.counts[arm]
        value = self.values[arm]
        self.values[arm] = ((n - 1) / n) * value + (1 / n) * reward

Model Serving

TensorFlow Serving

# Install TensorFlow Serving
docker pull tensorflow/serving

# Serve model
docker run -p 8501:8501 \
  --mount type=bind,source=/path/to/model,target=/models/my_model \
  -e MODEL_NAME=my_model \
  tensorflow/serving

# Predict
curl -d '{"instances": [[1, 2, 3]]}' \
  -X POST http://localhost:8501/v1/models/my_model:predict

TorchServe

# Create model archive
torch-model-archiver \
  --model-name my_model \
  --version 1.0 \
  --serialized-file model.pth \
  --handler handler.py \
  --export-path model_store

# Start server
torchserve --start \
  --model-store model_store \
  --models my_model=my_model.mar

Monitoring

Logging

import logging
from datetime import datetime

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

logger = logging.getLogger(__name__)

@app.post("/predict")
async def predict(request: PredictionRequest):
    logger.info(f"Received prediction request: {request.features}")
    try:
        prediction = model.predict([request.features])[0]
        logger.info(f"Prediction: {prediction}")
        return {"prediction": prediction}
    except Exception as e:
        logger.error(f"Prediction error: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))

Metrics Collection

from prometheus_client import Counter, Histogram, start_http_server

# Define metrics
predicti>'predictions_total', 'Total predictions')
predicti>'prediction_latency_seconds', 'Prediction latency')

@app.post("/predict")
async def predict(request: PredictionRequest):
    with prediction_latency.time():
        prediction = model.predict([request.features])[0]
        prediction_counter.inc()
    return {"prediction": prediction}

# Start metrics server
start_http_server(8000)

Best Practices

Deployment Checklist

Security Checklist


Quick Reference

Model Formats

Format Library Use Case
joblib scikit-learn Python-only, fast
pickle Python General Python objects
H5 Keras TensorFlow models
ONNX Cross-platform Multi-language deployment
SavedModel TensorFlow TensorFlow serving

Deployment Options

Option Best For Complexity
FastAPI/Flask Custom APIs Medium
Docker Containerized apps Medium
AWS SageMaker AWS ecosystem High
Google Cloud AI GCP ecosystem High
Azure ML Azure ecosystem High
Kubernetes Scalable deployments High

Try next: Add auth or an API key check and a /health endpoint to your serving demo.