ONNX Model Zoo

tanishqmudaliar/SilverGuard

By tanishqmudaliar · ↓ 0 · ♥ 0 · Updated 2026-02-22

What's in this repo

This page lists the files in tanishqmudaliar/SilverGuard, including silver_guard.onnx.

  • 1 ONNX models (.onnx files)
  • 5 files, including 1 .md, 1 .json, 1 .onnx, 1 .txt
  • Last updated 2026-02-22

ONNX files

File Size Download
silver_guard.onnx — Download

How to use

These ONNX files can be loaded with ONNX Runtime. To inspect a model graph, upload the file to the Netron viewer. Download links point to the original files on Hugging Face.

README

🛡️ 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 Kaggle ~5,500
India SMS Spam 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)

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

# pubspec.yaml
flutter:
  assets:
    - assets/silver_guard.onnx
    - assets/vocab.txt
    - assets/model_config.json
dependencies:
  onnxruntime_flutter: ^1.0.0
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.

Model info

onnx sms spam-detection phishing-detection cybersecurity india dlt mobilebert text-classification en dataset:uciml/sms-spam-collection-dataset dataset:junioralive/india-spam-sms-classification
↓ 0 ♥ 0

Created: 2026-02-22

Updated: 2026-02-22

View on Hugging Face

Files (5)

.gitattributes
README.md
model_config.json
silver_guard.onnx ONNX
vocab.txt

Related models