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