A6 Report – SVM Classification and Response Time Assessment¶
This sprint focuses on:
- SVM classification with GridSearchCV hyperparameter optimization
- Benchmarking response times using all classification models from A4 to A6
- Champion selection based on accuracy and speed trade-offs
1. SVM Classification¶
In [1]:
import os
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
from pathlib import Path
warnings.filterwarnings('ignore')
REPO_ROOT = os.path.abspath(os.path.join(os.getcwd(), '..'))
BENCHMARK_DIR = Path('benchmark_results')
Grid Search Configuration¶
| Parameter | Values |
|---|---|
| Kernel | rbf, poly, linear |
| C | 2^(-5), 2^(-1), 2^3, 2^7 |
| Gamma | 2^(-10), 2^(-6), 2^(-2), 2^2 |
| Degree (poly) | 2, 3 |
| Class weight | balanced |
Cross-validation: 5 fold outer CV, 3 fold inner CV nested
In [2]:
C_range = [2**i for i in range(-5, 10, 4)]
gamma_range = [2**i for i in range(-10, 4, 4)]
print(f"C values: {C_range}")
print(f"Gamma values: {[f'{g:.5f}' for g in gamma_range]}")
print(f"Total grid combinations: {len(C_range) * len(gamma_range) * 3 + len(C_range) * len(gamma_range) * 2 + len(C_range)}")
C values: [0.03125, 0.5, 8, 128] Gamma values: ['0.00098', '0.01562', '0.25000', '4.00000'] Total grid combinations: 84
Results¶
| Model | CV F1 Mean | CV F1 Std | vs A5b |
|---|---|---|---|
| SVM with nested CV | ~0.65 | ~0.05 | +0.2% |
| A5 Soft Voting | ~0.64 | ~0.04 | baseline |
Nadeau-Bengio corrected t-test: Not statistically significant (p > 0.05)
Models Benchmarked¶
| Model | Type | Source |
|---|---|---|
| A4 Random Forest | RandomForestClassifier | A4/models/ |
| A5 Ensemble | VotingClassifier | A5/models/ |
| A5b Adaboost | AdaBoostEnsemble | A5b/models/ |
| A5b Bagging Trees | LGBMClassifier | A5b/models/ |
| A6 SVM | Pipeline (Scaler + SVC) | A6/models/ |
In [3]:
with open(BENCHMARK_DIR / 'benchmark_20260310_090052.json', 'r') as f:
benchmark = json.load(f)
with open(BENCHMARK_DIR / 'single_benchmark_20260310_090011.json', 'r') as f:
single_benchmark = json.load(f)
print(f"Benchmark config: {benchmark['num_samples']} samples, {benchmark['num_repeats']} repeats")
Benchmark config: 100 samples, 10 repeats
In [4]:
results = []
for name, data in benchmark['models'].items():
results.append({
'Model': name,
'Mean (ms)': f"{data['inference_time_mean']*1000:.2f}",
'Std (ms)': f"{data['inference_time_std']*1000:.2f}",
'P95 (ms)': f"{data['inference_time_p95']*1000:.2f}",
'Accuracy': f"{data['accuracy']*100:.0f}%",
'Size (MB)': f"{data['model_size_bytes']/1e6:.1f}"
})
df = pd.DataFrame(results)
print(df.to_string(index=False))
Model Mean (ms) Std (ms) P95 (ms) Accuracy Size (MB)
A4 Random Forest 60.72 3.05 68.96 89% 16.4
A5 Ensemble 87.92 19.67 138.67 67% 26.7
A5b Adaboost 34.67 6.93 48.36 52% 0.7
A5b Bagging Trees 6.08 1.79 9.79 0% 6.5
A6 SVM 9.10 0.32 9.63 83% 0.7
In [5]:
# Accuracy vs inference time
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
models = list(benchmark['models'].keys())
times = [benchmark['models'][m]['inference_time_mean']*1000 for m in models]
accs = [benchmark['models'][m]['accuracy']*100 for m in models]
colors = ['green' if a >= 80 else 'orange' if a >= 50 else 'red' for a in accs]
axes[0].barh(models, times, color='steelblue')
axes[0].set_xlabel('Mean Inference Time (ms)')
axes[0].set_title('Inference Time by Model')
for i, (t, a) in enumerate(zip(times, accs)):
axes[0].text(t + 1, i, f'{t:.1f}ms', va='center')
for m, t, a in zip(models, times, accs):
axes[1].scatter(t, a, s=150)
axes[1].annotate(m, (t, a), xytext=(5, 5), textcoords='offset points', fontsize=8)
axes[1].set_xlabel('Mean Inference Time (ms)')
axes[1].set_ylabel('Accuracy (%)')
axes[1].set_title('Accuracy vs Speed Trade-off')
axes[1].axhline(80, color='green', linestyle='--', alpha=0.5)
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Summary¶
| Model | Mean Std (ms) | Min | Max | Accuracy |
|---|---|---|---|---|
| A4 Random Forest | 60.7 +- 3.0 | 58.1 | 69.0 | 89% |
| A5 Ensemble | 87.9 +- 19.7 | 67.9 | 138.7 | 67% |
| A5b Adaboost | 34.7 +- 6.9 | 30.5 | 48.4 | 52% |
| A5b Bagging Trees | 6.1 +- 1.8 | 3.8 | 9.8 | 0%* |
| A6 SVM | 9.1 +- 0.3 | 8.7 | 9.6 | 83% |
*A5b Bagging Trees: 0% due to class label mismatch in benchmark evaluation
In [6]:
def score_model(data):
acc = data['accuracy']
speed = max(0, 1 - data['inference_time_mean'] / 0.1)
size = max(0, 1 - data['model_size_bytes'] / 30e6)
consistency = max(0, 1 - data['inference_time_std'] / 0.02)
return 0.5*acc + 0.3*speed + 0.1*size + 0.1*consistency
scores = [(m, score_model(d)) for m, d in benchmark['models'].items()]
scores.sort(key=lambda x: x[1], reverse=True)
print("Champion Ranking:")
for i, (m, s) in enumerate(scores, 1):
print(f" {i}. {m}: {s:.3f}")
Champion Ranking: 1. A6 SVM: 0.884 2. A4 Random Forest: 0.693 3. A5b Adaboost: 0.619 4. A5b Bagging Trees: 0.451 5. A5 Ensemble: 0.384
Recommendation¶
| Use Case | Model | Accuracy | Latency |
|---|---|---|---|
| Accuracy-critical | A4 Random Forest | 89% | 61ms |
| Low-latency | A6 SVM | 83% | 9ms |
5. Conclusion¶
- SVM achieved 83% accuracy with 9.1ms inference time
- A4 Random Forest still remains accuracy champion (89%) but at 61ms
- A6 SVM is 6.7x faster with only 6% accuracy drop
- For low latency production: deploy A6 SVM