4.5 KiB
4.5 KiB
07. Fine-Tuned DistilBERT SMS Spam Classifier with ONNX Deployment
meta: id: core-services-07 feature: core-services-implementation priority: P1 depends_on: [core-services-06] tags: [spamshield, ml, nlp, distilbert, onnx, text-classification]
objective:
- Replace the stub
classifyTextBERT()function that returns{ isSpam: false, confidence: 1.0 }with a production ML pipeline: fine-tune DistilBERT on SMS spam data, export to ONNX for fast inference, and integrate into the spam classification flow.
deliverables:
- Training pipeline for fine-tuning DistilBERT on SMS spam dataset
- ONNX-exported model for low-latency CPU inference (~50ms per message)
- Inference server with batching and caching
- Integration with existing spam classification service
- Model versioning and A/B testing framework
steps:
- Set up Python training environment:
- Install
transformers,datasets,onnxruntime,torch,optimum[onnxruntime] - Create
ml/spam-classifier/directory in project root
- Install
- Acquire training data:
- SMS Spam Collection Dataset (UCI ML Repository, 5,574 messages)
- Enron Spam Dataset (email corpus, filter to SMS-like short messages)
- Custom labeled data from user feedback (Phase 2)
- Fine-tune DistilBERT-base-uncased:
- Binary classification: spam vs. ham
- 3 epochs, batch size 32, learning rate 2e-5
- Expected accuracy: 97–99% on SMS Spam Collection
- Export to ONNX:
- Use Optimum CLI:
optimum-cli export onnx --model distilbert-spam ./onnx_model/ - Quantize to INT8 for 2x speedup with minimal accuracy loss
- Target model size: ~65MB (DistilBERT base), ~33MB (INT8)
- Use Optimum CLI:
- Create Node.js ONNX inference wrapper:
- Install
onnxruntime-node - Load model once at startup, reuse session
- Preprocess: tokenize with DistilBERT tokenizer (max length 128)
- Postprocess: sigmoid on logits → probability → binary decision
- Target latency: <50ms per message on CPU, <10ms on GPU
- Install
- Integrate into
spamshield.service.ts:- Replace
classifyTextBERT()call with real ONNX inference - Classification flow: reputation lookup → rule engine → ML classifier (ensemble)
- Threshold tuning: default 0.5, adjustable per user preference
- Replace
- Implement feedback loop:
- User can report false positive/negative
- Store feedback in
spamFeedbacktable (already exists) - Weekly retraining batch using accumulated feedback
- Add model versioning:
- Store model artifact in S3-compatible storage
- A/B test new models on subset of traffic
- Rollback capability if accuracy degrades
tests:
- Unit: Verify ONNX inference produces correct labels for known spam/ham test cases
- Integration: End-to-end classification flow with real model loading
- E2E: Submit SMS text → receive classification with confidence score
acceptance_criteria:
classifyTextBERT()runs real ONNX inference (not returning hardcoded{ isSpam: false })- Model accuracy > 95% on held-out test set from SMS Spam Collection
- Inference latency < 50ms per message on CPU (measured in production)
- Model file is versioned and loadable from external storage (S3/local path)
- False positive rate < 2% (legitimate messages incorrectly flagged as spam)
- User feedback ("not spam" / "spam") is stored and used for model improvement
- Classification threshold is configurable per user (strict/moderate/lenient)
- ONNX model loads once at server startup, not per-request
- Graceful fallback to rule engine if ONNX runtime fails
- Model size < 100MB for reasonable cold-start time
validation:
- Run
vitest run spamshield.service.test.ts— tests use real ONNX model - Benchmark:
bun run benchmark:spamshield— measure 1000 inferences, report p50/p95/p99 latency - Manual: Classify known spam message "Congratulations! You've won $1000...", verify
isSpam: true, confidence > 0.9 - Check feedback: Database
spamFeedbacktable accumulates user corrections
notes:
- DistilBERT is chosen over BERT for 40% smaller size and 60% faster inference with minimal accuracy loss
- ONNX Runtime Node.js has limited platform support — test on your deployment target (Linux x64, macOS ARM)
- Training can happen in CI (GitHub Actions with GPU runner) or locally — inference happens in production
- Consider TensorFlow Lite or ONNX Runtime Web for on-device mobile inference later
- The SMS Spam Collection is small (5,574 messages) — augment with synthetic spam variants for robustness
- For European languages, consider multilingual model like
distilbert-base-multilingual-cased