Skip to main content

CTR Prediction Model System Design

Comprehensive architecture for real-time click-through rate prediction system with scalable ML pipelines and low-latency serving

Click-through rate prediction systems power ad revenue optimization and user experience in digital platforms, requiring real-time decision making with high accuracy and low latency across massive-scale data processing pipelines.

1. Problem Statement & ML Task Definition

Clarifying questions

  1. What is the expected QPS and latency budget for serving predictions (e.g., <50ms p99)?
  2. What is the scale of training data (e.g., billions of impressions, millions of users)?
  3. What is the expected accuracy target (e.g., AUC-ROC > 0.85) and how does it trade with latency?
  4. Is this a real-time or batch serving system (e.g., user sees recommendation within 100ms)?
  5. What is the primary business metric to optimize for (e.g., revenue per user, engagement rate)?
  6. What is the expected data freshness requirement (e.g., daily updates vs. real-time)?
  7. How does the system handle cold start scenarios for new users or items?

Business use case and success criteria

The CTR prediction model aims to predict the probability that a user will click on a given ad or content item in real-time. This is a core component of digital advertising and content recommendation systems, directly impacting revenue and user engagement. The model's success is measured by:

  • Business metrics: Revenue per thousand impressions (RPM), click-through rate (CTR), user engagement time, and conversion rate
  • User experience: Reducing irrelevant content delivery and increasing relevant content exposure

ML problem formulation

This is a binary classification task where the model predicts whether a user will click (1) or not click (0) on an ad/content item. Justification:

  • The outcome is binary (click vs no-click)
  • Real-time decision making requires probabilistic outputs for ranking
  • Binary cross-entropy loss is standard for this type of prediction task

ML evaluation metrics

Offline evaluation metrics:

  • AUC-ROC (primary metric for model discrimination)
  • Precision@K (for top-K recommendation quality)
  • NDCG@K (normalized discounted cumulative gain for ranking)
  • Log Loss (for probabilistic calibration)

Online evaluation metrics:

  • Click-Through Rate (CTR) - primary business metric
  • Revenue per thousand impressions (RPM)
  • User engagement time and session duration

Scale and constraints

Back-of-envelope estimates:

ComponentEstimate
Training data size100B impressions (50M users × 2K items × 1000 interactions)
Number of features50K-100K (user, item, context features)
Embedding matrix size~50GB (50M users × 128-dim embeddings)
Serving QPS10,000-50,000 (assuming 50ms p99 latency)

QPS math:

  • If serving 10,000 QPS with 50ms p99 latency, system needs to process ~200 requests/sec per second
  • For 50ms p99, we need ~2000 requests/sec peak to handle burst traffic

Non-ML baseline strategy

Baseline approach includes:

  1. Rule-based fallback:
    • Default to highest-performing content for new users
    • Age/gender-based targeting rules (e.g., 25-35 year olds get tech content)
  2. Cold start handling:
    • Use popularity-based ranking for new users/items
    • Default to recent trending content for unknown user segments
  3. Static feature-based ranking:
    • Content category popularity (e.g., "Sports" > "Politics")
    • User demographic targeting rules (e.g., age, location)
  4. A/B testing fallback:
    • If model fails to return prediction within 50ms, use last known good model version

2. Data Strategy

Training Data Sources

  • Explicit feedback: Click-through data from user interactions (primary signal)
  • Implicit signals: Time spent on page, scroll depth, conversion events, bounce rate
  • Third-party data: Demographic information from partner APIs, contextual signals (weather, time of day)
  • Historical behavior: User browsing history, item popularity trends, seasonal patterns
  • A/B test data: Controlled experiments with different ad placements or content

Labeling Pipeline Design

  • Primary labels: Binary click/no-click (1/0) for each user-item-context triplet
  • Weak supervision: Use click patterns to generate pseudo-labels for cold start items, apply active learning for uncertain predictions
  • Programmatic labeling: For new users with no history, use demographic or content similarity matching to assign labels from similar user groups
  • Human annotation: For edge cases and quality control, particularly for rare but important events (e.g., fraud detection)

Class Imbalance Handling Strategy

  • Target ratio: ~1:100 (clicks vs non-clicks) - typical in CTR systems
  • Justification: Most ad impressions don't get clicked, but even rare clicks have high business value
  • Approach:
    • Oversample click events with SMOTE-style synthetic generation for rare user-item combinations
    • Use weighted loss functions (e.g., Focal Loss) to reduce impact of majority class
    • Implement stratified sampling during training to ensure balanced representation across user segments

Negative Sampling Approach

  • Strategy: Importance sampling with inverse frequency weighting to balance rare clicks and common non-clicks
  • Method:
    • Sample negative examples with probability proportional to item popularity (inverse frequency)
    • For cold start items, use uniform sampling from recent impressions
  • Rationale:
    • Reduces training bias toward popular items
    • Maintains diversity in training data

Data Freshness and Update Frequency Requirements

  • Real-time: User behavior updates every 5 minutes (user session data)
  • Batch: Item metadata and user profile updates daily
  • Historical: 30-day rolling window for behavioral features (user history)
  • Freshness SLA:
    • p95 of user features updated within 1 hour
    • p95 of item features updated within 24 hours

Privacy Compliance

  • GDPR/CCPA:
    • Anonymize user IDs using hash functions before training
    • Implement data retention policies (6 months for behavioral logs, 1 year for demographic data)
    • Provide user opt-out mechanisms in UI and API
  • Data minimization:
    • Only collect necessary features (user ID, item ID, timestamp, click status)
    • Remove PII from training data before ingestion

Data Quality Validation and Monitoring

  • Validation checks:
    • Duplicate impression detection (user-item-context triplets)
    • Timestamp consistency validation (future timestamps, gaps > 24h)
    • Feature value range checks (user age must be between 0-150, item price > 0)
  • Monitoring:
    • Daily data quality reports (missing values, schema drift, distribution shifts)
    • Automated alerting for >5% drop in click rate or >10% increase in missing features
    • Weekly manual review of top 100 most frequent user-item pairs for data integrity
# Sample data validation function in Python
def validate_impression_data(df):
    """
    Validate training data for CTR prediction model.
    
    Args:
        df: DataFrame containing impression-level features
    
    Returns:
        bool: True if data passes validation
    """
    # Check for missing values in key columns
    required_columns = ['user_id', 'item_id', 'timestamp', 'clicked']
    missing_cols = [col for col in required_columns if df[col].isnull().any()]
    
    # Validate timestamp consistency
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    now = datetime.now()
    future_timestamps = df[df['timestamp'] > now]
    
    # Validate click labels
    invalid_labels = df[~df['clicked'].isin([0, 1])]
    
    # Check for duplicates
    duplicates = df.duplicated(subset=['user_id', 'item_id', 'timestamp'], keep=False)
    
    return len(missing_cols) == 0 and len(future_timestamps) == 0 and len(invalid_labels) == 0

3. Feature Engineering

Feature Taxonomy

Features are categorized into four main types:

  1. User Features: Demographics, behavior patterns, historical engagement
  2. Item Features: Content metadata, category, popularity metrics, freshness
  3. Context Features: Time, device, location, session information
  4. Interaction Features: User-item interaction history, temporal signals

Embedding Design

Entity Embeddings:

  • User ID embeddings: 128-dim, trained with negative sampling
  • Item ID embeddings: 128-dim, learned from click-through patterns
  • Category embeddings: 64-dim, hierarchical category encoding

Text Embeddings:

  • Item title/content embeddings: 256-dim using BERT-base fine-tuned on product descriptions
  • User preference embeddings: 128-dim from user browsing history

Graph Embeddings:

  • User-item interaction graph embeddings: 64-dim using Node2Vec for neighborhood context

Real-time vs Batch Feature Computation

Feature TypeReal-time?Reasoning
User session featuresYesSession state changes frequently
Item popularityNoUpdated daily, batch processed
User preference scoresYesRequires real-time updates
Historical engagementNoBatch processed, updated hourly

Feature Store Design

Online Store:

  • Low-latency key-value store (Redis/FAISS)
  • TTL: 1 hour for user features, 24 hours for item features
  • Supports atomic updates and batch reads

Offline Store:

  • Data warehouse (Snowflake/BigQuery)
  • Partitioned by date for efficient training
  • Supports complex joins and aggregations

Feature Freshness and TTL

FeatureSourceUpdate FrequencyStore Type
User IDUser profileReal-timeOnline
Item categoryProduct catalogDailyOffline
User session countSession logsReal-timeOnline
Item popularity scoreClick logsHourlyOffline
User preference vectorInteraction historyReal-timeOnline

Cross Features and Feature Interactions

Cross features are engineered to capture complex user-item relationships:

  1. User-Item Cross Features:

    • User-category affinity scores
    • Time-since-last-interaction features
    • Session-based user-item temporal patterns
  2. Context-User Interactions:

    • Time-of-day × user segment combinations
    • Device × item category interactions

Feature Importance and Selection

Methodology:

  • SHAP values for global feature importance
  • Permutation importance in training pipeline
  • L1 regularization (Lasso) for automatic feature selection

Selection Strategy:

# Feature importance filtering logic
def filter_features_by_importance(feature_importances, threshold=0.01):
    """
    Filter features based on SHAP importance scores
    Returns top 500 features above threshold
    """
    selected_features = []
    for feature, importance in feature_importances.items():
        if importance > threshold:
            selected_features.append(feature)
    return selected_features

# Example feature importance data structure
feature_importances = {
    "user_session_count": 0.15,
    "item_category_popularity": 0.12,
    "user_time_of_day": 0.08,
    "item_title_bert_embedding": 0.06,
    "user_item_interaction_time": 0.05
}

Selection Criteria:

  • Top 500 features by SHAP importance
  • Remove highly correlated features (VIF > 5)
  • Maintain minimum feature diversity for model robustness

4. Model Architecture

Model Selection with Justification

For CTR prediction, I'll select a Two-Tower Deep Neural Network architecture that balances model expressiveness with serving latency requirements. The choice is driven by:

  • Logistic Regression: Too simple for complex user-item interactions
  • GBM (XGBoost/LightGBM): Good baseline but limited expressiveness for high-dimensional sparse features
  • DNN: Excellent for capturing complex feature interactions and can scale to large embedding spaces
  • Transformer: Overkill for CTR prediction, introduces unnecessary complexity and latency

The Two-Tower architecture is optimal because:

  1. Efficient for real-time serving with low latency (5-20ms p99)
  2. Can handle sparse categorical features and dense numerical features
  3. Supports multi-task learning for related signals (conversion, watch time)
  4. Enables efficient embedding lookup and computation

Architecture Diagram

graph TD
    A[User Features] --> B[User Tower]
    C[Item Features] --> D[Item Tower]
    B --> E[Merge]
    D --> E
    E --> F[MLP Layers]
    F --> G[Logistic Regression Output]
    
    subgraph UserTower
        B1[Embedding Lookup]
        B2[MLP Layers]
        B3[Feature Aggregation]
    end
    
    subgraph ItemTower
        D1[Embedding Lookup]
        D2[MLP Layers]
        D3[Feature Aggregation]
    end
    
    B1 --> B2
    B2 --> B3
    D1 --> D2
    D2 --> D3
    B3 --> E
    D3 --> E

Two-Tower / Multi-Task / Ensemble Design

The model uses a two-tower architecture:

  • User Tower: Processes user features (demographics, behavior history, session context)
  • Item Tower: Processes item features (content metadata, category, popularity)
  • Interaction Layer: Combines both towers with dot product or MLP fusion

For multi-task learning, we can extend this to include:

  • Conversion prediction (for revenue optimization)
  • Watch time prediction (for engagement)
  • Relevance scoring (for ranking)

Pre-trained Model Selection and Fine-tuning Strategy

For foundation model integration:

  • Pre-trained embeddings: Use pre-trained word embeddings (Word2Vec, GloVe) for text features
  • Fine-tuning: Fine-tune on domain-specific CTR data with smaller learning rates (1e-5)
  • Adapter layers: Add adapter modules for efficient fine-tuning without full model retraining

Model Complexity vs Latency Trade-off Analysis

ModelMetricLatency (p99)Size (GB)Accuracy (AUC)
Logistic RegressionAUC1ms0.010.72
DNN (256-128-64)AUC15ms0.50.82
DNN (512-256-128)AUC25ms1.20.85
Two-Tower (512-256)AUC20ms1.00.84
Transformer (6-layer)AUC50ms3.00.86

Offline Evaluation Baseline Framing

Baseline model: Logistic regression with 100M training samples, 50K features, achieving AUC ~0.72 Proposed model: Two-Tower DNN with 512-256-128 architecture achieving AUC ~0.84

Core Model Code Snippet

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

class TwoTowerCTRModel(nn.Module):
    def __init__(self, user_feature_dim, item_feature_dim, 
                 user_embedding_dim=128, item_embedding_dim=128,
                 hidden_dims=[256, 128, 64], dropout_rate=0.2):
        super(TwoTowerCTRModel, self).__init__()
        
        # User tower
        self.user_embedding = nn.Embedding(user_feature_dim, user_embedding_dim)
        self.user_mlp = nn.Sequential(
            nn.Linear(user_embedding_dim, hidden_dims[0]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_dims[0], hidden_dims[1]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_dims[1], hidden_dims[2]),
            nn.ReLU()
        )
        
        # Item tower
        self.item_embedding = nn.Embedding(item_feature_dim, item_embedding_dim)
        self.item_mlp = nn.Sequential(
            nn.Linear(item_embedding_dim, hidden_dims[0]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_dims[0], hidden_dims[1]),
            nn.ReLU(),
            nn.Dropout(dropout_rate),
            nn.Linear(hidden_dims[1], hidden_dims[2]),
            nn.ReLU()
        )
        
        # Final prediction layer
        self.final_layer = nn.Linear(hidden_dims[2] * 2, 1)
        
    def forward(self, user_features, item_features):
        # User tower processing
        user_emb = self.user_embedding(user_features).mean(dim=1)  # Average embeddings if multiple
        user_repr = self.user_mlp(user_emb)
        
        # Item tower processing  
        item_emb = self.item_embedding(item_features).mean(dim=1)
        item_repr = self.item_mlp(item_emb)
        
        # Combine representations
        combined = torch.cat([user_repr, item_repr], dim=1)
        
        # Final prediction
        output = self.final_layer(combined)
        return torch.sigmoid(output)
    
    def compute_loss(self, predictions, targets):
        # Binary cross entropy loss
        return F.binary_cross_entropy(predictions.squeeze(), targets.float())
    
    def predict(self, user_features, item_features):
        # Return probability of click
        with torch.no_grad():
            return self.forward(user_features, item_features).squeeze()

# Example usage:
# model = TwoTowerCTRModel(user_feature_dim=10000, item_feature_dim=5000)
# user_input = torch.randint(0, 10000, (32, 5))  # batch_size=32, 5 user features
# item_input = torch.randint(0, 5000, (32, 3))   # batch_size=32, 3 item features
# predictions = model(user_input, item_input)
# loss = model.compute_loss(predictions, torch.randint(0, 2, (32, 1)))

This implementation provides:

  • Efficient embedding lookups for sparse features
  • Modular MLP towers for feature processing
  • Concatenation-based interaction between user and item representations
  • Standard binary cross-entropy loss for training
  • Clean forward pass for serving predictions
  • Memory-efficient design suitable for real-time inference

5. Serving & Inference Architecture

System Diagram

graph TD
    A[User Request] --> B[Load Balancer]
    B --> C[API Gateway]
    C --> D[Feature Store Lookup]
    D --> E[Model Serving Layer]
    E --> F[Scoring Engine]
    F --> G[Response Formatter]
    G --> H[Return to Client]

    subgraph "Real-time Serving"
        C
        D
        E
        F
        G
    end

    subgraph "Feature Store"
        D
    end

    subgraph "Model Serving"
        E
        F
    end

Online vs Batch Serving Decision

Online serving is required for CTR prediction due to:

  • Real-time personalization needs: User interactions must be immediately processed for relevance
  • Low latency requirement: <20ms p99 for user-facing experiences
  • User session context: Real-time feature aggregation is essential for accurate predictions

Batch serving is not suitable as it introduces unacceptable delays and cannot support dynamic personalization.

Two-Stage Pipeline

Candidate Retrieval → Scoring → Re-ranking
  1. Candidate Retrieval:

    • Retrieve top-K items from item catalog using content-based filtering or popularity
    • Use approximate nearest neighbor (ANN) search for efficiency
  2. Scoring:

    • Apply trained model to compute CTR probability for candidate items
    • Filter out low-probability candidates
  3. Re-ranking:

    • Apply business rules (e.g., diversity, freshness)
    • Use contextual features for final ranking

Serving Infrastructure

Primary choice: TorchServe with custom model wrapper

Justification:

  • Supports PyTorch models natively
  • Built-in model versioning and A/B testing capabilities
  • Easy integration with Kubernetes for scaling
  • Low latency inference (sub-20ms p99 target)

Alternative consideration: Triton Inference Server for multi-model serving and model compression.

Latency Budget Breakdown

Stagep50 Latencyp99 LatencyBudget
Feature Lookup2ms5ms5ms
Model Inference3ms8ms10ms
Scoring & Ranking2ms5ms5ms
Total7ms18ms20ms

Model Compression Strategy

Quantization:

  • INT8 quantization for model size reduction (2x smaller)
  • Minimal accuracy loss (<1% AUC drop)

Pruning:

  • Structured pruning to reduce model size by 30%
  • Maintains inference speed while reducing memory footprint

Distillation:

  • Teacher model: 10M parameters
  • Student model: 2M parameters (90% compression)
  • Maintains >95% of teacher model performance

Caching Strategy

Prediction Cache:

  • LRU cache for recent user-item predictions (100K entries)
  • TTL: 5 minutes to maintain freshness

Embedding Cache:

  • User/item embedding cache with TTL: 1 hour
  • Reduces feature lookup latency by 60%

KV Cache for LLMs:

  • Not applicable for CTR models (typically not transformer-based)
  • For future LLM-based content generation, would use KV caching

Auto-scaling and Capacity Planning

Horizontal Scaling:

  • Target: 100K QPS capacity with 20ms p99 latency
  • Auto-scaling based on QPS and latency metrics

Capacity Calculation:

QPS = 100K
Latency = 20ms
Throughput = QPS * Latency = 100K * 0.02s = 2000 seconds/sec

Instance Requirements:

  • Each instance handles ~5K QPS with 20ms p99
  • Target: 20 serving instances for peak load
  • Auto-scaling from 5 to 50 instances based on QPS

Resource Allocation:

  • CPU: 2 vCPUs per instance
  • Memory: 8GB per instance (for embeddings and model)
  • GPU: 1x A10 or V100 for inference (if using PyTorch model)

6. Evaluation Framework

Offline Evaluation Methodology

For CTR prediction models, we employ a temporal cross-validation approach to ensure realistic evaluation that accounts for data drift and temporal dependencies. We split the dataset chronologically into training (last 6 months), validation (1 month), and test (1 month) sets. This prevents data leakage and ensures the model generalizes to future data.

We also implement time-based holdout splits where we train on older data and evaluate on newer data to simulate real-world deployment conditions. For model selection, we use 5-fold temporal cross-validation with each fold maintaining the same time distribution across folds to ensure robustness.

Slice-Based Evaluation

We define critical slices for comprehensive evaluation:

Slice TypeDefinitionRationale
User DemographicsAge groups (18-25, 26-35, 36+), genderDifferent user behaviors and preferences
Geographic RegionsCountry/region clustersRegional content preferences and engagement patterns
Device TypesMobile, Desktop, TabletDifferent interaction patterns and ad formats
Time of DayMorning, Afternoon, Evening, NightUser activity patterns and engagement levels
Content CategoriesNews, Sports, Entertainment, etc.Content relevance to ad targeting

We monitor key metrics (CTR, Precision@K, NDCG) across these slices to detect performance degradation or bias in specific user segments.

A/B Test Design

Randomization Unit: User ID (to prevent leakage between users)

Sample Size Calculation:

  • Target effect size: 2% CTR improvement
  • Power: 80%
  • Significance level: 5%
  • Baseline CTR: 2.5% (estimated from historical data)
  • Expected sample size: ~130,000 users per variant

Test Duration: 2 weeks (to capture seasonal patterns and ensure statistical significance)

Primary Metric: Click-Through Rate (CTR) - measured as clicks / impressions

Secondary Metrics:

  • Revenue per user (RPU)
  • User engagement (time spent, session count)
  • Ad quality score (based on user feedback)

Guardrail Metrics and Blocking Conditions

We implement strict guardrails to prevent model rollouts that could harm business:

Guardrail MetricThresholdAction
CTR Drop Below Baseline-5%Block rollout
Revenue Drop Below Baseline-3%Block rollout
User Engagement Drop-2%Block rollout
Model Confidence Variance>50%Block rollout
Fairness ViolationsAny slice below 90% of overall performanceBlock rollout

Shadow Mode Rollout Plan

Before full A/B testing, we implement shadow mode where:

  1. 5% of production traffic is routed to the new model in parallel with the existing model
  2. Both models generate predictions for identical user impressions
  3. We compare performance metrics between shadowed and production models
  4. If shadow model shows >2% improvement in key metrics, proceed to full A/B test
  5. Shadow mode logs all predictions and features for offline analysis

Long-Term Metric Measurement

We track delayed conversion metrics to ensure model quality extends beyond immediate CTR:

Delayed MetricTime WindowBusiness Impact
7-day Conversion Rate7 days post-clickRevenue impact
30-day Retention30 days post-clickUser engagement and loyalty
Revenue per UserOngoingDirect business impact
Advertiser ROIOngoingPartner satisfaction and revenue

We implement a 30-day retention tracking system to ensure our CTR model doesn't just drive immediate clicks but also improves long-term user engagement and monetization.

# Example A/B test evaluation logic in Python
import numpy as np
from scipy import stats

class ABTestEvaluator:
    def __init__(self, baseline_ctr=0.025, target_improvement=0.02):
        self.baseline_ctr = baseline_ctr
        self.target_improvement = target_improvement
    
    def evaluate_ab_test(self, control_clicks, control_impressions, treatment_clicks, treatment_impressions):
        # Calculate CTRs
        control_ctr = control_clicks / control_impressions
        treatment_ctr = treatment_clicks / treatment_impressions
        
        # Calculate confidence intervals
        control_lower, control_upper = self._calculate_ci(control_clicks, control_impressions)
        treatment_lower, treatment_upper = self._calculate_ci(treatment_clicks, treatment_impressions)
        
        # Statistical significance test (two-sample z-test)
        pooled_std_error = np.sqrt(
            (control_ctr * (1 - control_ctr) / control_impressions) +
            (treatment_ctr * (1 - treatment_ctr) / treatment_impressions)
        )
        
        z_score = (treatment_ctr - control_ctr) / pooled_std_error
        p_value = 2 * (1 - stats.norm.cdf(abs(z_score)))
        
        return {
            "control_ctr": control_ctr,
            "treatment_ctr": treatment_ctr,
            "improvement": treatment_ctr - control_ctr,
            "p_value": p_value,
            "confidence_interval": (control_lower, control_upper, treatment_lower, treatment_upper),
            "statistically_significant": p_value < 0.05,
            "business_justified": (treatment_ctr - control_ctr) >= self.target_improvement
        }
    
    def _calculate_ci(self, clicks, impressions, confidence=0.95):
        # Calculate 95% confidence interval for binomial proportion
        z = stats.norm.ppf((1 + confidence) / 2)
        p_hat = clicks / impressions
        margin_error = z * np.sqrt((p_hat * (1 - p_hat)) / impressions)
        return (p_hat - margin_error, p_hat + margin_error)

7. Training Pipeline

Training Data Pipeline

The training data pipeline follows a multi-stage ETL process:

  1. Data Extraction: Pull raw clickstream logs from Kafka/Redshift with 1-hour latency
  2. Preprocessing:
    • Join user/item/context features from feature store
    • Apply feature transformations (normalization, bucketing)
    • Filter out invalid samples (missing features, duplicate clicks)
  3. Shuffling & Batching:
    • Shuffle data in batches of 100k samples
    • Apply temporal ordering to handle data drift
  4. Data Partitioning:
    • 80% training, 10% validation, 10% test splits
    • Time-based splits to prevent data leakage

Distributed Training Strategy

For distributed training, we use data parallelism with PyTorch's DistributedDataParallel (DDP) across 8 GPUs:

  • Each GPU processes 1M samples per batch
  • Gradient synchronization every 100 steps
  • Model checkpointing every epoch to S3

Training Infrastructure

  • Compute: 8x NVIDIA A100 GPUs (40GB VRAM each)
  • Storage: 2TB SSD for training data cache
  • Training Time: ~4 hours per epoch on 10M samples
  • Memory Usage: ~2GB per GPU for model + features

Hyperparameter Tuning Approach

We use Bayesian Optimization with Optuna for hyperparameter tuning:

  • Key parameters: learning rate (1e-4 to 1e-2), batch size (512-4096), embedding dimension (64-256)
  • Search space: 50 trials with early stopping
  • Primary metric: AUC-ROC on validation set

Experiment Tracking and Reproducibility

We implement MLflow for experiment tracking:

  • Logging: Model parameters, metrics, artifacts (model checkpoints)
  • Versioning: Git commit hash, model version tags
  • Reproducibility: Docker containers with pinned dependencies

Model Versioning and Registry Strategy

  • Version Control: Git-based model registry with semantic versioning (v1.0.0, v1.1.0)
  • Registry: MLflow Model Registry with staging/production environments
  • Rollback Capability: Automatic rollback to previous stable version on performance degradation

Continual / Online Learning Design

We implement online learning with incremental updates:

  • Update Frequency: Daily model retraining on latest 24h of data
  • Learning Rate Decay: 0.95 decay every 1000 samples
  • Drift Detection: PSI monitoring for feature distribution shifts
  • Adaptive Sampling: Increase weight for rare but high-value user segments
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, Dataset

class CTRModel(nn.Module):
    def __init__(self, user_emb_dim=64, item_emb_dim=64, context_emb_dim=32):
        super().__init__()
        self.user_embedding = nn.Embedding(1000000, user_emb_dim)
        self.item_embedding = nn.Embedding(500000, item_emb_dim)
        self.context_embedding = nn.Embedding(1000, context_emb_dim)
        
        # Feature fusion layer
        self.fusion_layer = nn.Linear(user_emb_dim + item_emb_dim + context_emb_dim, 128)
        self.output_layer = nn.Linear(128, 1)
        self.dropout = nn.Dropout(0.2)
        
    def forward(self, user_ids, item_ids, context_ids):
        user_emb = self.user_embedding(user_ids)
        item_emb = self.item_embedding(item_ids)
        context_emb = self.context_embedding(context_ids)
        
        # Concatenate all embeddings
        features = torch.cat([user_emb, item_emb, context_emb], dim=1)
        
        # Forward pass through layers
        fused = self.fusion_layer(features)
        fused = torch.relu(fused)
        fused = self.dropout(fused)
        output = self.output_layer(fused)
        
        return torch.sigmoid(output)

# Training loop example
def train_model(model, dataloader, optimizer, criterion, num_epochs=5):
    model.train()
    for epoch in range(num_epochs):
        total_loss = 0
        for batch in dataloader:
            user_ids, item_ids, context_ids, labels = batch
            
            # Forward pass
            predictions = model(user_ids, item_ids, context_ids).squeeze()
            
            # Compute loss
            loss = criterion(predictions, labels.float())
            
            # Backward pass
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            total_loss += loss.item()
        
        print(f"Epoch {epoch+1}, Loss: {total_loss/len(dataloader):.4f}")

8. Monitoring & Observability

Data Drift Detection

Data drift detection is critical for maintaining model performance in production. We implement drift detection using Population Stability Index (PSI) and KL divergence for continuous features, with a threshold of 0.1 for PSI and 0.05 for KL divergence.

import numpy as np
from scipy import stats

def calculate_psi(expected, actual, bins=10):
    """Calculate PSI between expected and actual distributions"""
    # Ensure both arrays have same bins
    _, bin_edges = np.histogram(expected, bins=bins)
    
    # Count occurrences in each bin
    expected_counts, _ = np.histogram(expected, bins=bin_edges)
    actual_counts, _ = np.histogram(actual, bins=bin_edges)
    
    # Avoid zero division
    expected_counts = np.where(expected_counts == 0, 1e-6, expected_counts)
    actual_counts = np.where(actual_counts == 0, 1e-6, actual_counts)
    
    # Calculate PSI
    psi = np.sum((actual_counts - expected_counts) * 
                 np.log(actual_counts / expected_counts))
    return psi

def detect_drift(expected_data, actual_data, feature_name):
    """Detect drift using PSI and KL divergence"""
    psi_value = calculate_psi(expected_data, actual_data)
    
    # For continuous features, also compute KL divergence
    kl_div = stats.entropy(actual_data, expected_data)
    
    drift_detected = psi_value > 0.1 or kl_div > 0.05
    
    return {
        "feature": feature_name,
        "psi": psi_value,
        "kl_divergence": kl_div,
        "drift_detected": drift_detected
    }

Prediction Drift and Label Drift Monitoring

Prediction drift is monitored by comparing the distribution of model predictions over time to historical baselines. Label drift is detected through monitoring label shifts in the training data.

Model Performance Degradation Alerting

We implement alerting thresholds for key metrics:

  • AUC-ROC drop > 5% over 7-day window triggers medium severity alert
  • CTR prediction drift > 10% over 30-day window triggers high severity alert
  • Model confidence distribution shift > 15% triggers medium severity alert

Retraining Trigger Strategy

Retraining is triggered by:

  1. Scheduled retraining every 30 days or when data volume exceeds 1M samples
  2. Drift-triggered retraining when PSI > 0.15 or KL divergence > 0.1 for any feature
  3. Performance-triggered retraining when AUC-ROC drops below 0.85 or CTR prediction error exceeds threshold

Logging Design

Prediction logs include:

  • Request ID, timestamp, user ID, item ID, features used in prediction
  • Model input features and their values
  • Raw model scores and final CTR predictions
  • Feature logs for drift monitoring (feature values, timestamps)
  • Label collection pipeline with manual feedback logging

Feedback Loop for Continuous Improvement

We implement a feedback loop where user interactions (clicks, views, conversions) are logged and used to:

  1. Update training data with new labels
  2. Retrain models with updated data every 7 days or when drift detected
  3. Incorporate user feedback into model retraining to improve accuracy
class PredictionLogger:
    def __init__(self, model_name):
        self.model_name = model_name
        self.prediction_log = []
    
    def log_prediction(self, request_id, user_id, item_id, features, 
                      raw_score, final_ctr, timestamp):
        """Log prediction for monitoring and feedback"""
        log_entry = {
            "request_id": request_id,
            "user_id": user_id,
            "item_id": item_id,
            "features": features,
            "raw_score": raw_score,
            "final_ctr": final_ctr,
            "timestamp": timestamp,
            "model_name": self.model_name
        }
        
        # Store in monitoring system (e.g., Kafka, BigQuery)
        self.prediction_log.append(log_entry)
        
        # Also store in feature store for drift analysis
        self._log_feature_values(features, timestamp)
        
    def _log_feature_values(self, features, timestamp):
        """Log feature values for drift monitoring"""
        # Implementation to store features in feature store
        pass

# Example usage:
logger = PredictionLogger("ctr_prediction_model")
logger.log_prediction(
    request_id="req_12345",
    user_id="user_67890",
    item_id="item_abcde",
    features={"age": 25, "gender": "M", "device_type": "mobile"},
    raw_score=0.75,
    final_ctr=0.023,
    timestamp="2023-10-15T14:30:00Z"
)

Real-time Monitoring Dashboard

We provide a real-time dashboard with:

  • Model performance metrics (AUC, CTR accuracy, precision)
  • Drift indicators for key features
  • Prediction distribution over time
  • User segment performance breakdowns

Anomaly Detection in Model Outputs

We implement statistical anomaly detection for model outputs using:

  • Z-score analysis for prediction outliers
  • Isolation Forest for identifying unusual prediction patterns
  • Threshold-based alerts when predictions exceed 3 standard deviations from historical mean

Model Version Monitoring

Each model version is tracked with:

  • Performance metrics per version
  • Feature impact analysis for each version
  • Rollback capability for failed versions
  • Version-specific drift monitoring

Alerting and Escalation Matrix

Alert TypeSeverityTrigger ConditionEscalation Path
Data DriftHighPSI > 0.15ML Team, Engineering
Performance DropMediumAUC < 0.85ML Team
Prediction AnomalyLowZ-score > 3Monitoring Team
Label DriftHighKL divergence > 0.1Data Science, ML Team

This comprehensive monitoring framework ensures model reliability and enables proactive maintenance of the CTR prediction system in production.

9. Responsible AI & Safety

Bias Analysis

Training data audit reveals potential demographic bias in user engagement patterns. Historical data shows higher click rates from urban users and younger demographics, potentially leading to underrepresentation of rural or older user segments. We implement slice-based fairness evaluation across age groups, geographic regions, and device types to detect and mitigate bias in model predictions.

Fairness Metrics and Constraints

We prioritize demographic parity as the primary fairness constraint, ensuring that click probability is approximately equal across user segments. Equalized odds will be evaluated as a secondary constraint to maintain high recall for all user groups. The model will be optimized to meet a fairness threshold of ±5% difference in click probability across key demographic slices.

Explainability Requirements and Approach

For business stakeholders, we implement SHAP-based explainability to understand feature importance in individual predictions. For technical teams, attention-weighted visualization will be provided for transformer-based models to show which user-item interactions drive predictions. The system will log explanations with each prediction for downstream analysis and debugging.

For LLM Systems: Safety Guardrails

While this is a CTR prediction model, we implement content filtering for ad text and image embeddings to prevent exposure of harmful or inappropriate content. Output validation includes checking for hallucination in ad copy generation and maintaining rate limiting to prevent abuse. Red teaming exercises will be conducted quarterly to identify potential safety gaps in the recommendation pipeline.

Model Card Documentation Plan

We will maintain a comprehensive model card documenting:

  • Training data sources and preprocessing steps
  • Model architecture and hyperparameters used
  • Performance metrics across different user segments
  • Known limitations and bias considerations
  • Fairness constraints and validation results
  • Model version history and update frequency

Incident Response Plan for Model Failures or Harmful Outputs

In case of significant performance degradation or bias drift:

  1. Immediate alert triggers when AUC drops below 0.85 or fairness constraints exceed thresholds
  2. Shadow mode activation to route traffic to backup models while investigating
  3. Emergency retraining pipeline initiated with bias-corrected data samples
  4. Stakeholder communication protocol for business impact notifications
  5. Manual override capability for critical user segments during model recovery

10. Scalability & Reliability

Bottleneck Analysis Per Pipeline Stage

Training Pipeline:

  • Data ingestion: 100GB/day → 500GB/week → 2TB/month (assuming 4x data volume for preprocessing)
  • Feature computation: 100M users × 100 features = 10B features per batch → 50GB feature matrix
  • Model training: 200M samples, 100K features → 20B parameters (if DNN) → 80GB model size
  • Model serving: 1M QPS → 86.4B predictions/day (assuming 10ms p99 latency)

Serving Pipeline:

  • Feature lookup: 1M QPS → 100M feature lookups/sec (assuming 10 features per user)
  • Model inference: 1M QPS → 20M inferences/sec (assuming 20ms p99 latency)
  • Prediction caching: 1M QPS → 100GB cache (assuming 100KB per cached prediction)

Scale-up Strategy

Horizontal Scaling of Serving:

  • Auto-scaling groups with 100+ instances per region
  • Load balancing across multiple availability zones (AZs)
  • Cross-region failover with 50ms latency budget for primary region failure

Distributed Feature Computation:

  • Feature store with 100+ parallel readers for real-time feature lookups
  • Batch job distribution across 50+ compute nodes for offline features

Fault Tolerance

Model Serving Fallbacks:

  • 95% success rate threshold → fallback to rule-based model or last known good model
  • Graceful degradation: if primary model fails, use ensemble of 3 models or static thresholds
  • Health checks every 10 seconds with circuit breaker pattern

Stale Model Serving on Failure:

  • Model versioning with rollback capability (last 3 versions)
  • Graceful degradation to warm start model if primary model is unavailable
  • 5-minute timeout for model loading before fallback

Cold Start Handling Strategy

New Users:

  • Use demographic features (age, gender, location) with default embeddings
  • Fallback to popular item ranking for new users with no history
  • Implement user embedding warm-up using cohort-based features

New Items:

  • Use item category, popularity, and metadata embeddings
  • Fallback to trending items or recent popular items for new items with no engagement
  • Implement item embedding warm-up using content-based features

Multi-Region Serving Strategy

Primary Region (e.g., us-west-2):

  • 60% of traffic with 50ms p99 latency target
  • 3x redundancy for all services (feature store, model serving, cache)
  • 50ms SLA for model inference and feature lookup

Secondary Region (e.g., us-east-1):

  • 20% of traffic with 100ms p99 latency target
  • Asynchronous replication for feature store and model artifacts
  • 200ms SLA for model inference with 500ms graceful degradation

Tertiary Region (e.g., eu-west-1):

  • 20% of traffic with 200ms p99 latency target
  • Synchronous replication for critical features only (user demographics, item categories)
  • 500ms SLA for model inference with 1s graceful degradation

Cross-Region Failover:

  • Health monitoring every 5 seconds for each region
  • Automatic failover within 100ms of primary region failure
  • Traffic shifting using weighted round-robin with 5% traffic shift per region

Cross-Region Data Consistency:

  • Feature store with 5-second TTL for real-time features
  • Model artifacts replicated with 1-hour freshness window
  • Eventual consistency model with 30-second reconciliation window
# Example of region-aware model serving logic (Python)
class MultiRegionModelServing:
    def __init__(self):
        self.regions = {
            'us-west-2': {'latency_target': 50, 'healthy': True},
            'us-east-1': {'latency_target': 100, 'healthy': True},
            'eu-west-1': {'latency_target': 200, 'healthy': True}
        }
        self.current_region = 'us-west-2'
    
    def get_model_for_region(self, region):
        if self.regions[region]['healthy']:
            return f"model_{region}"
        else:
            # Fallback to primary region or rule-based model
            return "fallback_model"
    
    def route_request(self, user_id):
        # Simple region-based routing logic
        if self.regions['us-west-2']['healthy']:
            return self.get_model_for_region('us-west-2')
        elif self.regions['us-east-1']['healthy']:
            return self.get_model_for_region('us-east-1')
        else:
            return "fallback_model"

Traffic Management:

  • Load balancer with region-aware routing
  • 50ms p99 target for primary region, 100ms for secondary, 200ms for tertiary
  • Automatic traffic shifting based on region health monitoring

11. Open Questions, Risks & Trade-offs

Decisions requiring product / engineering / policy alignment

  • User consent and data collection policies - What level of user data can be collected for training? How do we handle opt-out mechanisms and privacy compliance?
  • Model serving latency requirements - Should we prioritize sub-100ms response times for real-time serving or can we accept 500ms+ delays?
  • A/B testing randomization unit - Should we randomize at the user level or session level for stable comparisons?
  • Cold start handling strategy - How do we handle new users/items that have no historical interaction data?

Key ML risks

RiskImpactLikelihoodMitigation
Data drift in user behavior patternsHigh - model performance degradationMedium - daily/weekly data driftsImplement continuous drift monitoring, automatic retraining triggers
Negative sampling bias in trainingMedium - skewed model predictionsHigh - imbalanced data distributionUse stratified sampling, adjust for class imbalance
Cold start problem for new users/itemsMedium - poor initial recommendationsHigh - frequent new user/item additionsImplement hybrid approach with content-based fallback
Model overfitting to training dataMedium - reduced generalizationMedium - high model complexityUse regularization, cross-validation, early stopping
Label noise in implicit feedbackMedium - misleading training signalsHigh - noisy user behavior dataImplement label validation, use weak supervision

Trade-offs made with justification

  • Accuracy vs Latency: Prioritizing sub-100ms serving latency over marginal accuracy gains by using model compression (quantization, pruning) and simplified architectures
  • Freshness vs Cost: Accepting 1-hour feature freshness window to reduce compute cost of real-time feature computation, balancing between model quality and infrastructure cost
  • Model Size vs Quality: Choosing a two-tower DNN over transformer-based models to maintain low latency while achieving competitive performance
  • Online vs Batch Learning: Using batch training with periodic model updates instead of continuous online learning to reduce system complexity and ensure model stability

Alternatives considered and rejected

  • Transformer-based architectures: Rejected due to high latency requirements (500ms+ inference time) and complexity in production deployment
  • Online learning with SGD: Rejected due to stability concerns and difficulty in maintaining consistent model quality with streaming data
  • Multi-task learning: Rejected for initial MVP due to complexity in managing multiple objectives and potential conflict between CTR prediction and other KPIs

Technical debt acknowledged

  • Feature store implementation: Initial version uses a simplified in-memory store that will need to be replaced with a production-grade solution supporting high QPS and data consistency
  • Model versioning: Current approach relies on manual version tracking which will need to be replaced with an automated ML pipeline versioning system
  • A/B testing infrastructure: Basic A/B test setup that will require extension to support multi-armed bandits and more sophisticated experiment tracking
  • Cold start handling: Simple fallback logic that will need to be enhanced with more sophisticated content-based recommendation strategies

12. Phased Implementation Roadmap

Phase 1: MVP (Weeks 1-4)

Objective: Establish baseline prediction capability with minimal viable system.

Deliverables:

  • Rule-based fallback system (e.g., popular item ranking, user preference rules)
  • Basic feature extraction pipeline
  • Simple logistic regression model trained on historical data
  • Online serving infrastructure with 100 QPS capacity

Dependencies:

  • Data pipeline availability (user, item, interaction logs)
  • Feature store MVP (batch features only)
  • Model serving infrastructure (TorchServe or custom)

Critical Path:

  1. Data ingestion pipeline → 2. Feature extraction → 3. Model training (logistic regression) → 4. Online serving setup

Phase 2: Scale & Stability (Weeks 5-8)

Objective: Expand to support production-scale serving and feature engineering.

Deliverables:

  • Feature store with online and offline stores
  • Distributed training pipeline (Spark + PyTorch)
  • Real-time feature computation capabilities
  • A/B testing infrastructure (10% shadow mode, 50% rollout)
  • Model versioning and registry system

Dependencies:

  • Feature store with real-time updates
  • Distributed training cluster (20x GPU nodes)
  • ML platform for experiment tracking (MLflow)

Critical Path:

  1. Feature store deployment → 2. Distributed training pipeline → 3. A/B testing infrastructure → 4. Model registry

Phase 3: Excellence & Optimization (Weeks 9-12)

Objective: Deploy advanced models with real-time features and continuous learning.

Deliverables:

  • Two-tower DNN model with user/item embeddings
  • Real-time feature integration (user session, context)
  • Online learning pipeline for model updates
  • Advanced monitoring and drift detection system
  • Multi-region serving capability (if required)

Dependencies:

  • Real-time feature pipeline (Kafka + Redis)
  • Online learning framework (e.g., PyTorch with online training support)
  • Multi-region infrastructure (AWS/GCP regions)

Critical Path:

  1. Real-time feature pipeline → 2. Advanced model training (DNN) → 3. Online learning implementation → 4. Multi-region deployment

Risk Mitigation & Contingency:

  • Data availability delays: Start with synthetic data for model training in Phase 1
  • Feature store latency: Implement caching and pre-computation strategies
  • Model drift: Establish automatic retraining triggers based on PSI and performance degradation

Success Metrics:

  • Phase 1: CTR improvement of 5% over rule-based baseline
  • Phase 2: 10x QPS increase with <50ms p99 latency
  • Phase 3: 15% CTR improvement over Phase 2 with continuous model updates

Was this article helpful?

Topics in this article

More from AI/ML System Design

  • AI/ML System Design

    Feature Backfill Strategy for ML Systems

    Comprehensive guide to designing robust feature backfill strategies for machine learning pipelines, covering incremental updates, data consistency, and system reliability patterns.

Stay in the Loop

Get curated DSA patterns, coding problems, frontend and backend LLD/HLD, and AI/ML System Design insights delivered straight to your inbox. No spam, just focused interview and engineering content.