saidutta69 commited on
Commit
fd10cf3
·
verified ·
1 Parent(s): e901687

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +227 -0
README.md ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: onnx
4
+ tags:
5
+ - ad-blocking
6
+ - cybersecurity
7
+ - domain-classification
8
+ - dns-filtering
9
+ - edge-inference
10
+ - on-device
11
+ - esp8266
12
+ - nodemcu
13
+ - logistic-regression
14
+ language:
15
+ - en
16
+ metrics:
17
+ - accuracy
18
+ - precision
19
+ - recall
20
+ - f1
21
+ - roc_auc
22
+ model-index:
23
+ - name: AdVig
24
+ results:
25
+ - task:
26
+ type: text-classification
27
+ name: Domain Classification
28
+ dataset:
29
+ name: AdTrap v1 (test split)
30
+ type: saidutta69/AdTrap
31
+ metrics:
32
+ - type: accuracy
33
+ value: 0.9485
34
+ name: Accuracy
35
+ - type: precision
36
+ value: 0.8491
37
+ name: Precision
38
+ - type: recall
39
+ value: 0.7307
40
+ name: Recall
41
+ - type: f1
42
+ value: 0.7854
43
+ name: F1
44
+ - type: roc_auc
45
+ value: 0.9478
46
+ name: ROC AUC
47
+ ---
48
+
49
+ # AdVig
50
+
51
+ ![RACER IS OP](https://res.cloudinary.com/cmazqjs6/image/upload/racer_is_op_banner_branded_pu7zud.png)
52
+
53
+ > Block ads and trackers at the DNS layer before they load - **16 KB of int8 weights running on a NodeMCU**. No cloud, no runtime lists, no API calls. The offline, no-dependency Pi-hole, distilled into a single dot product.
54
+
55
+ Priorities: **Quality > Size > Speed**
56
+
57
+ **Trained on:** AdTrap v1 - 713,539 domains (93,541 ad/tracker + 619,998 legitimate), built from StevenBlack/hosts, AdAway, Yoyo, and Majestic Million.
58
+
59
+ Sibling of [saidutta69/PhishScout](https://huggingface.co/saidutta69/PhishScout).
60
+
61
+ ---
62
+
63
+ ## Model Overview
64
+
65
+ AdVig is a tiny hybrid logistic regression that classifies any bare domain as `BLOCK` (ad/tracker) or `ALLOW` (legitimate) using the **domain string alone** - the exact input a DNS query carries. No page content, no network calls at inference time. Score = one int32 dot product over hashed character n-grams plus 34 structural features.
66
+
67
+ | Property | Value |
68
+ |---|---|
69
+ | Architecture | Logistic regression: hashed char n-grams + structural features |
70
+ | Features | 16,384 hashed n-gram buckets (FNV-1a, sign trick) + 34 structural |
71
+ | Input | Bare domain string (DNS query hostname) |
72
+ | Model size | **64.4 KB** float32 ONNX / **16.0 KB** int8 quantized |
73
+ | Training time | ~18 s CPU |
74
+ | Inference | **933 us/domain measured on NodeMCU @160 MHz**; ~113 us reference Python |
75
+ | License | MIT |
76
+
77
+ ## Performance
78
+
79
+ Final model (test split, held out, group-disjoint by registrable domain, seed 42):
80
+
81
+ | Metric | float32 | int8 quantized |
82
+ |---|---|---|
83
+ | Accuracy | 0.9485 | 0.9486 |
84
+ | Precision | 0.8491 | 0.8597* |
85
+ | Recall | 0.7307 | 0.7069* |
86
+ | F1 | **0.7854** | **0.7862** |
87
+ | ROC AUC | **0.9478** | 0.9477 |
88
+ | False positive rate | 1.87% | 1.87% |
89
+
90
+ *int8 row evaluated at its own val-tuned threshold; quantization changed F1 by +0.0007 (hash-collision regularization).
91
+
92
+ ### Why not bigger? (bucket sweep)
93
+
94
+ Smaller hashing spaces beat larger ones - collisions regularize:
95
+
96
+ | buckets | C | F1 | AUC | int8 size |
97
+ |---|---|---|---|---|
98
+ | 2^16 | 10 | 0.7271 | 0.9288 | 64 KB |
99
+ | 2^15 | 10 | 0.7415 | 0.9337 | 32 KB |
100
+ | **2^14** | **1** | **0.7854** | **0.9478** | **16 KB** |
101
+ | 2^13 | 10 | 0.7756 | 0.9444 | 8 KB |
102
+ | 2^12 | 10 | 0.7585 | 0.9372 | 4 KB |
103
+
104
+ ### Baseline benchmark
105
+
106
+ Structural features alone top out at F1 0.634 (XGBoost): most blocklisted spam/parked domains have no structural tells. Lexical memory is what unlocks quality:
107
+
108
+ | model | F1 | AUC |
109
+ |---|---|---|
110
+ | gaussian_nb | 0.5674 | 0.8197 |
111
+ | logistic_regression (structural) | 0.6006 | 0.8298 |
112
+ | decision_tree d8 (structural) | 0.6157 | 0.8112 |
113
+ | lightgbm 30x6L15 (structural) | 0.6222 | 0.8515 |
114
+ | xgboost 30x4 (structural) | 0.6341 | 0.8598 |
115
+ | gram-only LR 2^15 | 0.6953 | 0.9180 |
116
+ | **AdVig hybrid LR 2^14** | **0.7854** | **0.9478** |
117
+
118
+ ## On-Device Benchmarks (NodeMCU ESP8266)
119
+
120
+ Measured on hardware (Arduino core 3.1.2, 240 stratified test domains x 30 passes = 7,200 inferences per run):
121
+
122
+ | Metric | 80 MHz | 160 MHz |
123
+ |---|---|---|
124
+ | Avg latency | **1840 us/domain** | **933 us/domain** |
125
+ | Min / Max | 1280 / 3043 us | 650 / 1879 us |
126
+ | Throughput | ~543 domains/s | ~1072 domains/s |
127
+ | Gram-hash phase | 144 us | 77 us |
128
+ | Structural phase | 1685 us | 850 us |
129
+
130
+ - **Memory**: int8 weights live in flash (`PROGMEM`, 16.4 KB, zero RAM); working set is a 2048-entry tally table + bookkeeping (~7.7 KB static). Free heap: **42,192 B**.
131
+ - **Accuracy on-device** (balanced sample): acc 0.8792, precision **0.9789**, recall 0.7750, F1 0.8651 - bit-exact with host emulation, **100% parity (240/240)**, identical prediction bitmap at both clock speeds.
132
+ - **Scaling is linear with clock** (compute-bound); other MCUs scale predictably.
133
+ - Known headroom: the structural phase dominates (~92% of latency) due to linear PROGMEM lexicon scans; sorted arrays + binary search should roughly halve total latency.
134
+
135
+ At ~1,000 domains/s, one NodeMCU comfortably keeps up with household-scale DNS traffic.
136
+
137
+ ## Use Cases
138
+
139
+ - **DNS-level Pi-hole replacement** - answer DNS queries with an on-device verdict; fully offline, zero external dependencies
140
+ - **Router/firewall firmware integration** - classify unknown domains at query time, complementing exact-match blocklists
141
+ - **Parental controls & IoT gateways** - block ad/tracker endpoints on devices that cannot run browser extensions
142
+ - **Privacy tooling research** - a compact baseline model for tracker-domain generalization studies
143
+ - **Browser/proxy pre-fetch screening** - cheap first-pass filter ahead of heavier analysis
144
+
145
+ ## Features
146
+
147
+ ### Structural (34)
148
+
149
+ `length`, `label_count`, `max_label_len`, `digit_count`, `max_digit_run`, `hyphen_count`, `entropy`, `vowel_ratio`, `starts_with_www`, `has_punycode`, `subdomain_depth`, `tld_trusted`, `tld_adheavy`, `tld_is_cctld`, `tld_length`, `tok_ad`, `tok_advert`, `tok_banner`, `tok_promo`, `tok_sponsor`, `tok_track`, `tok_analytics`, `tok_metrics`, `tok_telemetry`, `tok_beacon`, `tok_pixel`, `tok_tag`, `tok_click`, `tok_impression`, `tok_affiliate`, `tok_syndication`, `tok_vendor`, `tok_bigtech`, `bigtech_and_adtoken`
150
+
151
+ ### Hashed lexical memory
152
+
153
+ Char 3/4/5-grams over `.domain.` hashed with FNV-1a (random sign projection) into 2^14 buckets. Inference collapses to `logit = SCALE * gram_sum + BIAS + dot(STRUCT_W, feats)` - trivially portable to any MCU in C.
154
+
155
+ ## Usage
156
+
157
+ ### Python (ONNX Runtime)
158
+
159
+ ```python
160
+ import numpy as np
161
+ import onnxruntime as ort
162
+ from gramlib import hash_grams # reference hasher (in repo files)
163
+ from features import extract_features # reference structural extractor
164
+
165
+ sess = ort.InferenceSession("advig.onnx", providers=["CPUExecutionProvider"])
166
+ domain = "ads.tracker-cdn.example.com"
167
+
168
+ grams = np.zeros((1 << 14), dtype=np.float32)
169
+ for idx, val in hash_grams(domain, buckets=1 << 14).items():
170
+ grams[idx] += np.sign(val)
171
+ x = np.concatenate([grams, extract_features(domain)]).astype(np.float32)[None]
172
+
173
+ p_block = sess.run(["prob"], {"features": x})[0].item()
174
+ blocked = p_block >= 0.477
175
+ ```
176
+
177
+ ### ESP8266 / NodeMCU (C)
178
+
179
+ Flash `advig_weights.h` alongside the ~40-line scorer (reference firmware in the linked training repo). Decision rule on device:
180
+
181
+ ```c
182
+ logit = GRAM_SCALE_F * gsum_int32 + BIAS_F + dot(STRUCT_W, struct_feats);
183
+ block = (logit >= ADVIG_T_LNIT_F);
184
+ ```
185
+
186
+ ## Verification & Reproducibility
187
+
188
+ - **ONNX parity** - 100% match between ONNX Runtime and closed-form sigmoid(Gemm).
189
+ - **On-device parity** - 100% (240/240) agreement between NodeMCU firmware and host emulation; confusion matrices identical.
190
+ - **Deterministic** - identical test predictions across seeds 42/1/7/123.
191
+ - **No leakage** - train/val/test disjoint at the registrable-domain level; synthetic subdomains inherit their parent's split.
192
+ - **int8 verified end-to-end** - quantized weights re-evaluated after quantization, not assumed lossless.
193
+
194
+ ## Limitations
195
+
196
+ - **Enumeration ceiling** - random parked/spam domains (`05tz2e9.com`) carry zero signal in their names; no string-based model can catch them. Pair AdVig with an exact-match blocklist: the list memorizes the tail, AdVig generalizes over unseen trackers.
197
+ - **"ad-" prefix traps** - `adyen.com`-style collateral exists (~1.9% FPR). Raise the threshold for allow-biased operation.
198
+ - **English-centric lexicons** - token lists are Western-market oriented.
199
+ - **Feed dependence** - inherits StevenBlack/AdAway/Yoyo coverage as of build date; retrain for fresh feeds.
200
+ - **Dataset noise** - Majestic top-1M contains some parked/ad-heavy registrable domains treated as ALLOW.
201
+
202
+ ## Training Data
203
+
204
+ AdTrap v1: 713,539 rows, 70/15/15 split by registrable domain, seed 42.
205
+
206
+ | Source | Class | Domains |
207
+ |---|---|---|
208
+ | StevenBlack hosts (ads+trackers base) | BLOCK | 93,512 |
209
+ | AdAway | BLOCK | 6,540 |
210
+ | Yoyo | BLOCK | 3,515 |
211
+ | Majestic Million (overlap removed) | ALLOW | 400,000 |
212
+ | Synthetic legit subdomains (augmentation) | ALLOW | 220,000 |
213
+
214
+ ## Citation
215
+
216
+ ```bibtex
217
+ @misc{saidutta69_2026_advig,
218
+ author = {Sai Dutta Abhishek Dash},
219
+ title = {AdVig: Tiny On-Device Ad and Tracker Domain Classifier},
220
+ year = {2026},
221
+ publisher = {Hugging Face},
222
+ howpublished = {\url{https://huggingface.co/saidutta69/AdVig}},
223
+ note = {Trained on the AdTrap dataset}
224
+ }
225
+ ```
226
+
227
+ Built on AdTrap + StevenBlack/hosts, AdAway, Yoyo, and Majestic Million. MIT licensed.