Document offline usage
Browse files
README.md
CHANGED
|
@@ -56,6 +56,50 @@ print(classify([
|
|
| 56 |
|
| 57 |
Classify in batches of 16–32 articles; `max_len=256` is about twice as fast at a small quality cost (see Results).
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
## Results (gold set, CPU Apple M4 Pro, fp32)
|
| 60 |
|
| 61 |
| Max tokens | micro-F1 (random gold, 163) | exact set match | CPU latency |
|
|
|
|
| 56 |
|
| 57 |
Classify in batches of 16–32 articles; `max_len=256` is about twice as fast at a small quality cost (see Results).
|
| 58 |
|
| 59 |
+
## Download once, use without Hugging Face
|
| 60 |
+
|
| 61 |
+
1. Download the files (needs access to this private repo once), with any of:
|
| 62 |
+
- CLI: `hf auth login`, then `hf download maxafanasiev/news-topic-classifier-e5-base --local-dir ./news-topic-classifier-e5-base`
|
| 63 |
+
- git: `git lfs install && git clone https://huggingface.co/maxafanasiev/news-topic-classifier-e5-base` (use a token as the password)
|
| 64 |
+
- browser: the "Files and versions" tab, download every file into one folder
|
| 65 |
+
2. Keep these files together: `model.safetensors`, `config.json`, `tokenizer.json`, `tokenizer_config.json`, `thresholds.json`.
|
| 66 |
+
3. Load from the folder; `HF_HUB_OFFLINE=1` makes sure nothing is fetched from the internet:
|
| 67 |
+
|
| 68 |
+
```python
|
| 69 |
+
import json
|
| 70 |
+
import os
|
| 71 |
+
from pathlib import Path
|
| 72 |
+
|
| 73 |
+
os.environ["HF_HUB_OFFLINE"] = "1"
|
| 74 |
+
|
| 75 |
+
import torch
|
| 76 |
+
from transformers import AutoModelForSequenceClassification, AutoTokenizer
|
| 77 |
+
|
| 78 |
+
MODEL_DIR = Path("./news-topic-classifier-e5-base")
|
| 79 |
+
PREFIX = "passage: "
|
| 80 |
+
PARENTS = {"Theft": "Crime", "Assault": "Crime"}
|
| 81 |
+
|
| 82 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR)
|
| 83 |
+
model = AutoModelForSequenceClassification.from_pretrained(MODEL_DIR).eval()
|
| 84 |
+
thresholds = json.loads((MODEL_DIR / "thresholds.json").read_text())
|
| 85 |
+
categories = list(thresholds)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
@torch.no_grad()
|
| 89 |
+
def classify(articles: list[dict], max_len: int = 512) -> list[list[str]]:
|
| 90 |
+
texts = [f"{PREFIX}{a['title']}\n{a['content']}" for a in articles]
|
| 91 |
+
batch = tokenizer(texts, truncation=True, max_length=max_len, padding=True, return_tensors="pt")
|
| 92 |
+
probs = torch.sigmoid(model(**batch).logits)
|
| 93 |
+
results = []
|
| 94 |
+
for row in probs:
|
| 95 |
+
labels = [c for c, p in zip(categories, row.tolist()) if p >= thresholds[c]]
|
| 96 |
+
labels += [PARENTS[c] for c in labels if c in PARENTS and PARENTS[c] not in labels]
|
| 97 |
+
results.append(labels or ["Other"])
|
| 98 |
+
return results
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
Requirements: `torch` and `transformers` (no `huggingface_hub` login needed at this point).
|
| 102 |
+
|
| 103 |
## Results (gold set, CPU Apple M4 Pro, fp32)
|
| 104 |
|
| 105 |
| Max tokens | micro-F1 (random gold, 163) | exact set match | CPU latency |
|