onnx-email-gate / README.md
pranav0494's picture
docs: trim internal training-provenance from the model card
c4516f7 verified
|
Raw
History Blame Contribute Delete
3.34 kB
---
license: apache-2.0
language:
- multilingual
library_name: onnxruntime
pipeline_tag: text-classification
base_model: sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2
tags:
- email-classification
- onnx
- int8
- multilingual
- prefilter
---
# onnx-email-gate β€” multilingual KEEP/DROP email prefilter
A tiny **multilingual** CPU classifier that labels an inbound email **KEEP** (looks like a real
job application β†’ worth further processing) or **DROP** (junk β†’ skip). It's meant as a cheap
pre-filter in front of a more expensive downstream model, discarding obvious junk β€” newsletters,
notifications, one-time codes, job-board alerts, bounces β€” at roughly a millisecond per email.
- **Labels:** `{0: DROP, 1: KEEP}`
- **Architecture:** `paraphrase-multilingual-MiniLM-L12-v2` sentence embedder (mean-pool +
L2-normalize) with a logistic-regression head folded into the ONNX graph as a final linear
layer β€” so the whole thing is one classifier ONNX: `tokens β†’ 2 logits β†’ argmax`.
- **Quantization:** dynamic **INT8** (`model_int8.onnx`, ~119 MB).
- **Runtime:** `onnxruntime` on CPU, ~ms per email.
## Why multilingual
The embedder covers ~50 languages, so the gate reads non-English application emails directly
instead of wrong-dropping them (verified on English, Hindi, and Spanish).
## Recommended use β€” an override ladder
The model is best used as the **last rung** of a cheap rule ladder, so a genuine application is
never dropped by the model alone:
1. **KEEP overrides** β€” rΓ©sumΓ© attachment / forwarded application / recruiter-style sender β†’ **KEEP**.
2. **regex junk** β€” noreply / notifications / OTP / bounce / job-board-alert / newsletter β†’ **DROP**.
3. **this model** β€” KEEP/DROP on the remaining ambiguous mail.
## Usage
```python
import numpy as np, onnxruntime as ort
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("curriculo-tech/onnx-email-gate")
sess = ort.InferenceSession("model_int8.onnx", providers=["CPUExecutionProvider"])
I2L = {0: "DROP", 1: "KEEP"}
def gate(from_addr, from_name, subject, body):
text = f"{from_addr}\n{from_name}\n{subject}\n{body}"
enc = tok(text, truncation=True, max_length=128, return_tensors="np", padding="max_length")
feed = {"input_ids": enc["input_ids"].astype(np.int64),
"attention_mask": enc["attention_mask"].astype(np.int64)}
logits = sess.run(None, feed)[0][0]
p = int(np.argmax(logits))
sm = np.exp(logits - logits.max()); sm /= sm.sum()
return I2L[p], float(sm[p]) # (label, confidence)
```
Input text = `from_address\nfrom_name\nsubject\nbody`, truncated to 128 tokens.
## Files
| File | Purpose |
|------|---------|
| `model_int8.onnx` | the model β€” embedder + folded logistic-regression head, INT8 |
| `tokenizer.json`, `tokenizer_config.json`, `special_tokens_map.json` | tokenizer |
| `config.json` | model config + `id2label` |
| `logreg_head.npz`, `gate_meta.json` | raw head weights + fold record (reproducibility) |
## Limitations
- The model alone has modest recall β€” **use it behind the override ladder**, not standalone.
- Dynamic INT8 shifts a small fraction of borderline predictions vs fp32; ship fp32 if you need
exact parity.
- Very low-resource languages may be weaker than the ~50 the embedder covers well.