SilverGuard / README.md
tanishqmudaliar's picture
Update README.md
335ed20 verified
---
license: mit
language:
- en
pipeline_tag: text-classification
base_model: google/mobilebert-uncased
datasets:
- uciml/sms-spam-collection-dataset
- junioralive/india-spam-sms-classification
tags:
- sms
- spam-detection
- phishing-detection
- onnx
- cybersecurity
- india
- dlt
- mobilebert
---
# πŸ›‘οΈ SilverGuard β€” Indian SMS Scam Detector
SilverGuard is a fine-tuned **MobileBERT** model exported to ONNX for detecting scam and phishing SMS messages in the Indian context. It outputs a continuous **threat score (0.0–1.0)** and is designed for real-time inference on mobile and edge devices via `onnxruntime`.
---
## 🧠 Model Overview
| Property | Details |
|----------|---------|
| **Base Model** | `google/mobilebert-uncased` (24M params) |
| **Task** | Binary SMS classification β€” Ham (0) vs Scam (1) |
| **Output** | `threat_score` β€” softmax scam probability \[0.0–1.0\] |
| **Export Format** | ONNX (opset 14), single self-contained file |
| **Max Sequence Length** | 128 tokens |
| **Target Deployment** | `onnxruntime`, `onnxruntime_flutter` |
---
## πŸ“¦ Files Included
| File | Description |
|------|-------------|
| `silver_guard.onnx` | Self-contained ONNX model (~90 MB) |
| `vocab.txt` | MobileBERT WordPiece vocabulary (~230 KB) |
| `model_config.json` | Inference configuration (max_length, labels, input format) |
---
## πŸ“Š Training Data
~18,000 messages across four sources:
| Source | Type | Count |
|--------|------|-------|
| [UCI SMS Spam Collection](https://www.kaggle.com/datasets/uciml/sms-spam-collection-dataset) | Kaggle | ~5,500 |
| [India SMS Spam Classification](https://www.kaggle.com/datasets/junioralive/india-spam-sms-classification) | Kaggle | ~2,200 |
| Synthetic Indian Scam Templates | Generated | ~5,200 |
| Personal SMS (Phone Link export) | User Data | ~5,100 |
**Split:** 80% train / 10% validation / 10% test (stratified)
---
## πŸ—οΈ Input Format β€” TRAI DLT Header System
All inputs follow the format:
```
HEADER [SEP] message body
```
The `HEADER` is the **TRAI DLT sender ID** or phone number β€” a critical signal for scam detection:
| Header Type | Example | Meaning |
|-------------|---------|---------|
| Registered DLT (bank) | `JD-SBINOT` | βœ… Legitimate transactional |
| Registered DLT (govt) | `DL-UIDAIG` | βœ… Legitimate government |
| Raw phone number | `+919876543210` | 🚨 Strong scam indicator |
| Gibberish / spoofed | `VM-URGENT`, `XX-WINNER` | 🚨 Scam indicator |
**DLT suffix convention:** `G` = Government Β· `T` = Transactional Β· `S` = Service Β· `P` = Promotional
If no sender ID is available (e.g. personal messages), pass the message body directly without a header.
---
## 🚨 Scam Categories Covered
The model was trained on 11 Indian scam archetypes:
- **Digital Arrest** β€” CBI/Police impersonation, Aadhaar fraud threats
- **Bank Freeze / KYC** β€” Account suspension, fake KYC update links
- **OTP Fraud** β€” "Share OTP to cancel/confirm transaction"
- **Link Phishing** β€” Fake rewards, government subsidies, shortened URLs
- **Lottery / Prize** β€” KBC, WhatsApp lucky draw, Google Annual Prize
- **Job Scam** β€” Work from home, Telegram task jobs
- **Parcel / Courier** β€” Fake customs duty, contraband claims
- **Insurance / Loan** β€” Pre-approved loan fraud, LIC bonus scams
- **Government Impersonation** β€” TRAI, RBI, EPFO, Income Tax fake notices
- **Investment Scam** β€” Crypto, Forex, guaranteed returns
- **Utility Scam** β€” Fake electricity/gas disconnection threats
---
## βš™οΈ Usage
### Python (ONNX Runtime)
```python
import onnxruntime as ort
import numpy as np
import unicodedata
import re
# ── Minimal tokenizer (mirrors google/mobilebert-uncased exactly) ─────────────
class BertTokenizer:
def __init__(self, vocab_file):
with open(vocab_file, encoding="utf-8") as f:
self.vocab = {line.rstrip("\n"): i for i, line in enumerate(f)}
self.cls_id = self.vocab.get("[CLS]", 101)
self.sep_id = self.vocab.get("[SEP]", 102)
self.pad_id = self.vocab.get("[PAD]", 0)
self.unk_id = self.vocab.get("[UNK]", 100)
def _wordpiece(self, word):
ids, start = [], 0
while start < len(word):
end, cur = len(word), None
while start < end:
sub = ("##" if start > 0 else "") + word[start:end]
if sub in self.vocab:
cur = self.vocab[sub]; break
end -= 1
if cur is None:
return [self.unk_id]
ids.append(cur); start = end
return ids
def encode(self, text_a, text_b=None, max_length=128):
text_a = unicodedata.normalize("NFD", text_a.lower())
ids_a = [wp for tok in re.findall(r'\w+|[^\w\s]', text_a)
for wp in self._wordpiece(tok)]
ids_b = None
if text_b:
text_b = unicodedata.normalize("NFD", text_b.lower())
ids_b = [wp for tok in re.findall(r'\w+|[^\w\s]', text_b)
for wp in self._wordpiece(tok)]
budget = max_length - (3 if ids_b else 2)
if ids_b:
while len(ids_a) + len(ids_b) > budget:
(ids_a if len(ids_a) >= len(ids_b) else ids_b).pop()
else:
ids_a = ids_a[:budget]
tokens = [self.cls_id] + ids_a + [self.sep_id]
if ids_b:
tokens += ids_b + [self.sep_id]
mask = [1] * len(tokens)
pad = max_length - len(tokens)
tokens += [self.pad_id] * pad
mask += [0] * pad
return tokens, mask
# ── Inference ──────────────────────────────────────────────────────────────────
session = ort.InferenceSession("model/silver_guard.onnx")
tokenizer = BertTokenizer("model/vocab.txt")
def predict(header: str, message: str) -> float:
"""Returns threat score 0.0 (safe) β†’ 1.0 (scam)."""
ids, mask = tokenizer.encode(header, message) if header else tokenizer.encode(message)
result = session.run(None, {
"input_ids": np.array([ids], dtype=np.int64),
"attention_mask": np.array([mask], dtype=np.int64),
})
return float(result[0][0][0]) # already softmaxed β€” do NOT apply softmax again
# Examples
print(predict("+919876543210", "Your Aadhaar is linked to money laundering. Call CBI now.")) # β†’ ~1.0
print(predict("JD-SBINOT", "Your a/c XX5678 credited with Rs 25,000 by NEFT. -SBI")) # β†’ ~0.0
print(predict("", "Hey, are we meeting for dinner tonight?")) # β†’ ~0.0
```
### Verdict Thresholds
| Score | Verdict |
|-------|---------|
| β‰₯ 0.80 | 🚨 HIGH RISK SCAM |
| β‰₯ 0.55 | ⚠️ LIKELY SCAM |
| β‰₯ 0.40 | 🟑 BORDERLINE |
| < 0.40 | βœ… SAFE (HAM) |
### Flutter / Dart
```yaml
# pubspec.yaml
flutter:
assets:
- assets/silver_guard.onnx
- assets/vocab.txt
- assets/model_config.json
dependencies:
onnxruntime_flutter: ^1.0.0
```
```dart
final session = await OrtSession.fromAsset('assets/silver_guard.onnx');
// Combine as: "$senderHeader [SEP] $messageBody"
// Tokenize with WordPiece β†’ pad to 128 β†’ run session
// Output: threat_score [0.0 – 1.0]
```
---
## πŸ”§ ONNX Architecture
```
Input: input_ids [batch, 128] int64
attention_mask [batch, 128] int64
↓
MobileBERT Encoder (24 transformer layers)
↓
Classification Head (linear β†’ 2 logits)
↓
Softmax β†’ scam probability
↓
Output: threat_score [batch, 1] float32
```
> **Important:** The output is already softmaxed. Do **not** apply softmax again.
---
## πŸ‹οΈ Training Configuration
| Hyperparameter | Value |
|----------------|-------|
| Optimizer | AdamW |
| Learning Rate | 2e-5 |
| Batch Size | 32 |
| Max Epochs | 4 |
| Early Stopping | Patience = 2 |
| Gradient Clipping | max_norm = 1.0 |
| Warmup | 10% of total steps |
| Runtime | Google Colab T4 GPU |
---
## ⚠️ Limitations
- Optimized for **Indian SMS** β€” performance on non-Indian content may vary
- Scam tactics evolve rapidly; periodic retraining is recommended
- Short messages without a header (<10 tokens) may be less reliable
- Model does not analyze embedded URLs for malicious content
---
## πŸ“„ License
MIT β€” free for commercial and personal use.