|
Download README.md from maxafanasiev/news-topic-classifier-e5-base: direct link, hf CLI and curl.
- Browser
- Download file 5.06 kB
-
https://huggingface.co/maxafanasiev/news-topic-classifier-e5-base/resolve/main/README.md
- Command line
-
hf download hf://maxafanasiev/news-topic-classifier-e5-base/README.md
-
curl -L -o README.md https://huggingface.co/maxafanasiev/news-topic-classifier-e5-base/resolve/main/README.md
5.06 kB
| license: other | |
| base_model: intfloat/multilingual-e5-base | |
| pipeline_tag: text-classification | |
| tags: [multi-label, news, multilingual] | |
| # News topic classifier (e5-base) | |
| Fine-tuned `intfloat/multilingual-e5-base` for multi-label classification of news articles into 13 topics: | |
| Business And Finance, Market And Exchange, Demographics, Scientific Exploration, Labour Dispute, Disaster, | |
| Conflicts And War, Politics, Crime, Theft, Assault, Corporate Crime, Fraud. No label means "Other". | |
| ## Usage | |
| - Input: `"passage: " + title + "\n" + content`, truncated to 512 tokens. | |
| - Output: sigmoid per category, compared with the per-category threshold in `thresholds.json` (not 0.5). | |
| - If Theft or Assault is predicted, add Crime as well. | |
| ```python | |
| import json | |
| import torch | |
| from huggingface_hub import hf_hub_download | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| REPO = "maxafanasiev/news-topic-classifier-e5-base" # private: run `hf auth login` first | |
| PREFIX = "passage: " | |
| PARENTS = {"Theft": "Crime", "Assault": "Crime"} | |
| tokenizer = AutoTokenizer.from_pretrained(REPO) | |
| model = AutoModelForSequenceClassification.from_pretrained(REPO).eval() | |
| thresholds = json.load(open(hf_hub_download(REPO, "thresholds.json"))) | |
| categories = list(thresholds) # same order as the model outputs | |
| @torch.no_grad() | |
| def classify(articles: list[dict], max_len: int = 512) -> list[list[str]]: | |
| texts = [f"{PREFIX}{a['title']}\n{a['content']}" for a in articles] | |
| batch = tokenizer(texts, truncation=True, max_length=max_len, padding=True, return_tensors="pt") | |
| probs = torch.sigmoid(model(**batch).logits) | |
| results = [] | |
| for row in probs: | |
| labels = [c for c, p in zip(categories, row.tolist()) if p >= thresholds[c]] | |
| labels += [PARENTS[c] for c in labels if c in PARENTS and PARENTS[c] not in labels] | |
| results.append(labels or ["Other"]) | |
| return results | |
| print(classify([ | |
| {"title": "Police arrest two men over jewellery store robbery", "content": "Officers detained the suspects after ..."}, | |
| {"title": "El banco central sube los tipos de interés", "content": "La decisión responde a la inflación ..."}, | |
| ])) | |
| # e.g. [['Crime', 'Theft'], ['Business And Finance']] | |
| ``` | |
| Classify in batches of 16–32 articles; `max_len=256` is about twice as fast at a small quality cost (see Results). | |
| ## Download once, use without Hugging Face | |
| 1. Download the files (needs access to this private repo once), with any of: | |
| - CLI: `hf auth login`, then `hf download maxafanasiev/news-topic-classifier-e5-base --local-dir ./news-topic-classifier-e5-base` | |
| - git: `git lfs install && git clone https://huggingface.co/maxafanasiev/news-topic-classifier-e5-base` (use a token as the password) | |
| - browser: the "Files and versions" tab, download every file into one folder | |
| - one archive: download `news-topic-classifier-e5-base.tar.gz` from "Files and versions" (or `hf download maxafanasiev/news-topic-classifier-e5-base news-topic-classifier-e5-base.tar.gz --local-dir .`), then `tar xzf news-topic-classifier-e5-base.tar.gz`; it unpacks into `./news-topic-classifier-e5-base/`, ready for the code below. Windows 10+ has `tar` built in. | |
| 2. Keep these files together: `model.safetensors`, `config.json`, `tokenizer.json`, `tokenizer_config.json`, `thresholds.json`. | |
| 3. Load from the folder; `HF_HUB_OFFLINE=1` makes sure nothing is fetched from the internet: | |
| ```python | |
| import json | |
| import os | |
| from pathlib import Path | |
| os.environ["HF_HUB_OFFLINE"] = "1" | |
| import torch | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| MODEL_DIR = Path("./news-topic-classifier-e5-base") | |
| PREFIX = "passage: " | |
| PARENTS = {"Theft": "Crime", "Assault": "Crime"} | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR) | |
| model = AutoModelForSequenceClassification.from_pretrained(MODEL_DIR).eval() | |
| thresholds = json.loads((MODEL_DIR / "thresholds.json").read_text()) | |
| categories = list(thresholds) | |
| @torch.no_grad() | |
| def classify(articles: list[dict], max_len: int = 512) -> list[list[str]]: | |
| texts = [f"{PREFIX}{a['title']}\n{a['content']}" for a in articles] | |
| batch = tokenizer(texts, truncation=True, max_length=max_len, padding=True, return_tensors="pt") | |
| probs = torch.sigmoid(model(**batch).logits) | |
| results = [] | |
| for row in probs: | |
| labels = [c for c, p in zip(categories, row.tolist()) if p >= thresholds[c]] | |
| labels += [PARENTS[c] for c in labels if c in PARENTS and PARENTS[c] not in labels] | |
| results.append(labels or ["Other"]) | |
| return results | |
| ``` | |
| Requirements: `torch` and `transformers` (no `huggingface_hub` login needed at this point). | |
| ## Results (gold set, CPU Apple M4 Pro, fp32) | |
| | Max tokens | micro-F1 (random gold, 163) | exact set match | CPU latency | | |
| | --- | --- | --- | --- | | |
| | 512 | 0.860 | 0.804 | 42 ms/article | | |
| | 256 | 0.836 | 0.785 | 20 ms/article | | |
| Training data: ~8k news articles labeled by an LLM teacher (Sonnet 5.5); gold built from three blind LLM labelers plus a judge, not hand-checked. Training data is private and not included. | |