""" KestrelNet Fraud Classifier — Gradio Space Interactive demo for a 1,059-parameter fraud detection model. Pure NumPy inference, no GPU required. """ import json import math import time import gradio as gr import numpy as np # ── Inference-only model (self-contained, no source code dependency) ───────── def _softmax(logits): m = np.max(logits) e = np.exp(logits - m) return e / e.sum() class KestrelNet: def __init__(self, input_dim, hidden_dims, output_dim): self.input_dim = input_dim self.hidden_dims = list(hidden_dims) self.output_dim = output_dim dims = [input_dim] + list(hidden_dims) + [output_dim] self.layer_dims = list(zip(dims[:-1], dims[1:])) self.n_layers = len(self.layer_dims) self.Ws = [np.zeros((fo, fi)) for fi, fo in self.layer_dims] self.bs = [np.zeros(fo) for _, fo in self.layer_dims] def load(self, path): with open(path) as f: params = np.array([float(x) for x in f.read().split()]) idx = 0 for i, (fi, fo) in enumerate(self.layer_dims): n = fo * fi self.Ws[i] = params[idx:idx + n].reshape(fo, fi) idx += n self.bs[i] = params[idx:idx + fo].copy() idx += fo return self def predict_proba(self, x): h = np.asarray(x, dtype=np.float64) for i, (W, b) in enumerate(zip(self.Ws, self.bs)): h = W @ h + b if i < self.n_layers - 1: h = np.maximum(0.0, h) return _softmax(h) def param_count(self): return sum(W.size + b.size for W, b in zip(self.Ws, self.bs)) # ── Load model ────────────────────────────────────────────────────────────── model = KestrelNet(14, [32, 16], 3).load("weights.txt") # ── Feature normalization ─────────────────────────────────────────────────── def normalize(amount_ratio, hour, day_of_week, location_delta, velocity_1h, velocity_24h, merchant_risk, international, card_present, device_match, account_age_days, prev_fraud_score): h_rad = 2 * math.pi * hour / 24 d_rad = 2 * math.pi * day_of_week / 7 return np.array([ amount_ratio, math.sin(h_rad), math.cos(h_rad), math.sin(d_rad), math.cos(d_rad), location_delta, min(velocity_1h / 10.0, 1.0), min(velocity_24h / 30.0, 1.0), merchant_risk, 1.0 if international else 0.0, 1.0 if card_present else 0.0, 1.0 if device_match else 0.0, min(account_age_days / 3650.0, 1.0), prev_fraud_score, ], dtype=np.float64) # ── Classification logic ─────────────────────────────────────────────────── THRESHOLDS = { "Standard": {"review": 0.30, "fraudulent": 0.55}, "Conservative": {"review": 0.20, "fraudulent": 0.40}, "Strict": {"review": 0.45, "fraudulent": 0.70}, } def classify(amount_ratio, hour, day_of_week, location_delta, velocity_1h, velocity_24h, merchant_risk, international, card_present, device_match, account_age_days, prev_fraud_score, threshold_mode): x = normalize(amount_ratio, hour, day_of_week, location_delta, velocity_1h, velocity_24h, merchant_risk, international, card_present, device_match, account_age_days, prev_fraud_score) t0 = time.perf_counter() proba = model.predict_proba(x) latency_us = (time.perf_counter() - t0) * 1e6 p_legit, p_review, p_fraud = proba t = THRESHOLDS[threshold_mode] if p_fraud >= t["fraudulent"]: verdict = "FRAUDULENT" elif p_fraud >= t["review"] or p_review >= 0.45: verdict = "REVIEW" else: verdict = "LEGITIMATE" # Verdict display colors = {"LEGITIMATE": "#22c55e", "REVIEW": "#eab308", "FRAUDULENT": "#ef4444"} color = colors[verdict] verdict_html = f"""
1,059 parameters · 5μs inference · pure NumPy · no GPU
A fully-connected classifier smaller than most models' bias vectors.
All datasets publicly available. Results independently reproducible. Pure NumPy, CPU only.
| Dataset | Task | Accuracy | F1 / AUC | Params | Latency |
|---|---|---|---|---|---|
| ECG Heartbeat MIT-BIH Arrhythmia |
5-class arrhythmia | 97.2% | F1 0.853 | 12,756 | 56 μs |
| EEG Emotions Brainwave Sentiment |
3-class emotion | 99.1% | F1 0.991 | 163,788 | 1.3 ms |
| EEG Eye State Roesler / UCI |
Binary open/closed | 94.2% | AUC 0.986 | 1,576 | 17 μs |
| Seizure Prediction Bonn University EEG |
Binary seizure | 97.1% | AUC 0.988 | 12,072 | — |
| HAR Smartphones UCI Activity Recognition |
6-class activity | 94.9% | F1 0.949 | 15,416 | 70 μs |
| Fraud Detection Proprietary |
3-class fraud | 91.6% | — | 1,059 | 5 μs |
| Dataset | Typical CNN/LSTM | Ours | Reduction |
|---|---|---|---|
| ECG Heartbeat | 500K – 2M | 12,756 | 40–160x smaller |
| EEG Emotions | 1M+ | 163,788 | 6x smaller |
| EEG Eye State | 100K+ | 1,576 | 63x smaller |
| HAR Smartphones | 200K – 1M | 15,416 | 13–65x smaller |
Two model families: KestrelNet (standard FC, minimal params) and GoshawkNet (multivector products, deeper pattern capture).
Named after raptors — bird size matches model size, hunting style matches classification style.