--- 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.