Menu

AI & Machine Learning Topic

Deploying ML Models

Why Model Deployment Matters

You can have the best model in the world, but if it's stuck in a Jupyter notebook, it provides zero business value. Deployment makes your work:

  • Accessible to end-users and other systems

  • Scalable to handle multiple requests

  • Reliable with proper monitoring and maintenance

  • Integratable with existing applications and workflows


Web Frameworks for Model Serving

1. Flask: The Simple & Flexible Approach

Flask is a micro web framework that's perfect for getting started quickly.

Basic Flask API Structure:

python

from flask import Flask, request, jsonify
import pickle
import pandas as pd

# Load your trained model
with open('model.pkl', 'rb') as f:
    model = pickle.load(f)

app = Flask(__name__)

@app.route('/')
def home():
    return {'message': 'ML Model API is running!'}

@app.route('/predict', methods=['POST'])
def predict():
    # Get data from request
    data = request.get_json()
    
    # Convert to DataFrame (assuming same structure as training)
    input_data = pd.DataFrame([data])
    
    # Make prediction
    prediction = model.predict(input_data)
    
    # Return response
    return jsonify({
        'prediction': prediction[0],
        'status': 'success'
    })

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

Running the Flask App:

bash

pip install flask
python app.py

Pros: Simple, lightweight, great for prototypes
Cons: Manual setup for production, fewer built-in features

2. FastAPI: The Modern, High-Performance Approach

FastAPI is newer, faster, and designed specifically for APIs with automatic documentation.

Basic FastAPI Structure:

python

from fastapi import FastAPI
from pydantic import BaseModel
import pickle
import pandas as pd
from typing import List

# Define input data schema
class PredictionInput(BaseModel):
    feature1: float
    feature2: float
    feature3: int

# Load model
with open('model.pkl', 'rb') as f:
    model = pickle.load(f)

app = FastAPI(title="ML Model API", version="1.0")

@app.get("/")
async def root():
    return {"message": "ML Model API is running!"}

@app.post("/predict")
async def predict(input_data: PredictionInput):
    # Convert to dict then DataFrame
    input_dict = input_data.dict()
    input_df = pd.DataFrame([input_dict])
    
    # Make prediction
    prediction = model.predict(input_df)
    probability = model.predict_proba(input_df).max()
    
    return {
        "prediction": int(prediction[0]),
        "probability": float(probability),
        "status": "success"
    }

# Batch prediction endpoint
@app.post("/predict_batch")
async def predict_batch(inputs: List[PredictionInput]):
    input_dicts = [item.dict() for item in inputs]
    input_df = pd.DataFrame(input_dicts)
    
    predictions = model.predict(input_df).tolist()
    
    return {
        "predictions": predictions,
        "count": len(predictions)
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

Running the FastAPI App:

bash

pip install fastapi uvicorn
uvicorn app:app --host 0.0.0.0 --port 8000 --reload

FastAPI Advantages:

  • Automatic API documentation at /docs and /redoc

  • Type validation with Pydantic

  • Async support for better performance

  • Data serialization built-in


Model Serving Best Practices

1. Input Validation

Never trust user input! Always validate and sanitize.

python

from pydantic import BaseModel, ValidationError, validator

class HouseFeatures(BaseModel):
    bedrooms: int
    bathrooms: float
    sqft: float
    location: str
    
    @validator('bedrooms')
    def validate_bedrooms(cls, v):
        if v < 0 or v > 10:
            raise ValueError('Bedrooms must be between 0 and 10')
        return v
    
    @validator('sqft')
    def validate_sqft(cls, v):
        if v <= 0:
            raise ValueError('Square footage must be positive')
        return v

2. Error Handling

Gracefully handle errors and provide helpful messages.

python

from fastapi import HTTPException

@app.post("/predict")
async def predict(input_data: PredictionInput):
    try:
        # Your prediction logic here
        result = make_prediction(input_data)
        return result
    except ValidationError as e:
        raise HTTPException(status_code=422, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail="Internal server error")

3. Model Versioning

Keep track of different model versions.

python

MODEL_VERSION = "v1.2.0"
MODEL_ARTIFACT = f"models/random_forest_{MODEL_VERSION}.pkl"

@app.get("/model_info")
async def model_info():
    return {
        "version": MODEL_VERSION,
        "type": "Random Forest",
        "training_date": "2024-01-15"
    }

4. Health Checks

Monitor your API's health.

python

@app.get("/health")
async def health_check():
    # Check if model is loaded and working
    try:
        test_prediction = model.predict(pd.DataFrame([{
            'feature1': 1.0,
            'feature2': 2.0,
            'feature3': 3
        }]))
        return {"status": "healthy", "model_loaded": True}
    except Exception as e:
        return {"status": "unhealthy", "error": str(e)}

Docker: Containerizing Your Application

Docker packages your application and its dependencies into a container that runs consistently anywhere.

1. Dockerfile: The Blueprint

dockerfile

# Use Python base image
FROM python:3.9-slim

# Set working directory
WORKDIR /app

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

# Copy application code
COPY . .

# Expose port
EXPOSE 8000

# Command to run the application
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]

2. Requirements File

txt

fastapi==0.104.1
uvicorn==0.24.0
pandas==2.0.3
scikit-learn==1.3.0
pydantic==2.5.0

3. Docker Commands

bash

# Build the Docker image
docker build -t ml-api .

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

# Run in background (detached mode)
docker run -d -p 8000:8000 --name ml-api-container ml-api

# View running containers
docker ps

# Stop container
docker stop ml-api-container

Complete Deployment Workflow

Project Structure:

text

ml-deployment/
├── app.py
├── requirements.txt
├── Dockerfile
├── models/
│   └── model.pkl
├── tests/
│   └── test_api.py
└── README.md

Testing Your API

python

# test_api.py
import requests

# Test the API
response = requests.post(
    "http://localhost:8000/predict",
    json={
        "feature1": 5.1,
        "feature2": 3.5,
        "feature3": 1
    }
)

print(response.json())

Using the API from Other Applications

python

import requests

def get_prediction(features):
    response = requests.post(
        "http://your-api-url/predict",
        json=features
    )
    if response.status_code == 200:
        return response.json()['prediction']
    else:
        raise Exception(f"API Error: {response.text}")

# Usage
prediction = get_prediction({
    "feature1": 6.2,
    "feature2": 2.8,
    "feature3": 2
})

Production Considerations

1. Environment Configuration

python

import os
from dotenv import load_dotenv

load_dotenv()  # Load environment variables from .env file

MODEL_PATH = os.getenv('MODEL_PATH', 'models/default_model.pkl')
API_PORT = int(os.getenv('API_PORT', 8000))
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'

2. Logging

python

import logging

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

@app.post("/predict")
async def predict(input_data: PredictionInput):
    logger.info(f"Received prediction request: {input_data.dict()}")
    # ... prediction logic

3. Rate Limiting

python

from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.post("/predict")
@limiter.limit("5/minute")
async def predict(input_data: PredictionInput):
    # Your prediction logic
    return result

Deployment Platforms

1. Cloud Platforms:

  • AWS: EC2, ECS, Lambda, SageMaker

  • Google Cloud: Cloud Run, Compute Engine, AI Platform

  • Azure: Container Instances, App Service, Machine Learning

2. Simplified Deployment:

bash

# Heroku example
heroku create my-ml-api
git push heroku main

# Railway example
railway deploy

Key Takeaways

  1. Flask is great for simplicity, FastAPI is better for performance and features

  2. Always validate inputs and handle errors gracefully

  3. Docker ensures consistency across different environments

  4. API design matters - think about your consumers

  5. Monitoring and logging are crucial for production systems

  6. Start simple with a basic API, then add complexity as needed

Deployment turns your ML model from a science project into a valuable tool that can drive real business decisions and user experiences!

Comments (0)

No comments yet. Be the first to comment!

AlphaAI Assistant

Hello! I'm AlphaAI

What would you like to learn today?