Text Classification
Transformers
ONNX
Safetensors
Transformers.js
modernbert
hate-speech
hate-speech-detection
content-moderation
trust-and-safety
multi-label-classification
mmbert
text-embeddings-inference
Instructions to use Horizon-Labs/multilingual-hate-speech-base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Horizon-Labs/multilingual-hate-speech-base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="Horizon-Labs/multilingual-hate-speech-base")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("Horizon-Labs/multilingual-hate-speech-base") model = AutoModelForSequenceClassification.from_pretrained("Horizon-Labs/multilingual-hate-speech-base", device_map="auto") - Transformers.js
How to use Horizon-Labs/multilingual-hate-speech-base with Transformers.js:
// npm i @huggingface/transformers import { pipeline } from '@huggingface/transformers'; // Allocate pipeline const pipe = await pipeline('text-classification', 'Horizon-Labs/multilingual-hate-speech-base'); - Notebooks
- Google Colab
- Kaggle
Download code/hate/teacher_hate.py from Horizon-Labs/multilingual-hate-speech-base: direct link, hf CLI and curl.
- Browser
- Download file 4.98 kB
-
https://huggingface.co/Horizon-Labs/multilingual-hate-speech-base/resolve/main/code/hate/teacher_hate.py
- Command line
-
hf download hf://Horizon-Labs/multilingual-hate-speech-base/code/hate/teacher_hate.py
-
curl -L -o teacher_hate.py https://huggingface.co/Horizon-Labs/multilingual-hate-speech-base/resolve/main/code/hate/teacher_hate.py
4.98 kB
| """Qwen3.8-27B as a hate-speech teacher (vLLM venv): yes/no questions asked after the text (shared cached prefix); | |
| score = P(yes) / (P(yes) + P(no)). | |
| Eval: python hate/teacher_hate.py eval OUT.json EVAL_DIR (hate question on every set; target questions on MHS hateful comments) | |
| Label: LABEL_IN=in.parquet LABEL_OUT=out.parquet [SHARD=i NSHARD=n] python hate/teacher_hate.py label (adds hate + target_* columns)""" | |
| import glob, json, math, os, sys | |
| HATE = ("Is this hate speech? Hate speech attacks, demeans, dehumanises, stereotypes or calls for harm or exclusion against people " | |
| "because of a protected characteristic: race or ethnicity, nationality or migration status, religion, gender, sexual " | |
| "orientation, gender identity, disability or age. Not hate speech: insults or profanity aimed at an individual without " | |
| "targeting such a group, criticism of ideas, governments or organisations, counter-speech, and quoting or reporting hate " | |
| "in order to criticise it.") | |
| GROUP = {"race": "race or ethnicity", "religion": "religion", "origin": "nationality, national origin or migration status", | |
| "gender": "gender (women, men, transgender or non-binary people)", "sexuality": "sexual orientation (gay, lesbian, bisexual people)", | |
| "age": "age (children, young or old people)", "disability": "disability (physical, mental or cognitive)"} | |
| Q = {"hate": HATE, **{f"target_{g}": f"Does this text attack or demean people because of their {d}?" for g, d in GROUP.items()}} | |
| LABELS = list(Q) | |
| def prompt(text, label): | |
| return f"Text (any language):\n<<<\n{text[:3000]}\n>>>\n\nQuestion: {Q[label]}\nAnswer with one word: yes or no." | |
| def score(llm, texts, labels): | |
| from vllm import SamplingParams | |
| msgs = [[{"role": "user", "content": prompt(t, l)}] for t in texts for l in labels] | |
| outs = llm.chat(msgs, SamplingParams(temperature=0, max_tokens=1, logprobs=20), chat_template_kwargs={"enable_thinking": False}, use_tqdm=False) | |
| P = [] | |
| for o in outs: | |
| y = n = 0.0 | |
| for v in (o.outputs[0].logprobs[0] if o.outputs[0].logprobs else {}).values(): | |
| t = v.decoded_token.strip().lower() | |
| if t in ("yes", "y"): y += math.exp(v.logprob) | |
| elif t in ("no", "n"): n += math.exp(v.logprob) | |
| P.append(y / (y + n) if y + n > 0 else 0.5) | |
| k = len(labels) | |
| return [P[i * k:(i + 1) * k] for i in range(len(texts))] | |
| if __name__ == "__main__": | |
| import importlib.util | |
| import numpy as np, pandas as pd | |
| from vllm import LLM | |
| _sp = importlib.util.spec_from_file_location("sc", os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "sentiment", "common.py")) | |
| _m = importlib.util.module_from_spec(_sp); _sp.loader.exec_module(_m) | |
| llm = LLM(os.environ.get("MODEL", "Qwen/Qwen3.8-27B-FP8"), max_model_len=4096, gpu_memory_utilization=0.92, max_num_seqs=512, | |
| enable_prefix_caching=True, limit_mm_per_prompt={"image": 0, "video": 0}) | |
| if sys.argv[1] == "eval": | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))); from metrics import auc, f1 | |
| out, ev = sys.argv[2:4]; res = {} | |
| for p in sorted(glob.glob(f"{ev}/*.parquet")): | |
| name = os.path.basename(p)[:-8]; df = pd.read_parquet(p) | |
| labs = LABELS if name == "mhs" else ["hate"] | |
| S = np.array(score(llm, df.text.tolist(), labs)); s = S[:, 0]; y = df.hate.values | |
| r = dict(n=len(df), auc=auc(y, s), f1_05=f1(y, s >= 0.5), fpr_05=float((s[y == 0] >= 0.5).mean())) | |
| if name.startswith("mhc_"): | |
| r["func_acc"] = {fn: float(((s[g.index] >= 0.5) == g.hate.values.astype(bool)).mean()) for fn, g in df.groupby("functionality")} | |
| if name == "mhs": | |
| h = y == 1; r["target_auc"] = {g: auc(df[f"target_{g}"].values[h], S[h, 1 + i]) for i, g in enumerate(GROUP)} | |
| res[name] = r; print(name, {k: v for k, v in r.items() if k != "func_acc"}, flush=True) | |
| mhc = [k for k in res if k.startswith("mhc_")] | |
| if mhc: | |
| res["_mhc_mean_auc"] = float(np.mean([res[k]["auc"] for k in mhc])); res["_mhc_mean_f1"] = float(np.mean([res[k]["f1_05"] for k in mhc])) | |
| for key, sets in (("_real_mean_auc", ("mhs", "hatexplain", "kmhas")), ("_heldout_real_mean_auc", ("hs18", "ethos", "olidbr", "kmhas"))): | |
| if all(k in res for k in sets): | |
| res[key] = float(np.mean([res[k]["auc"] for k in sets])) | |
| print({k: v for k, v in res.items() if k.startswith("_")}, flush=True); json.dump(res, open(out, "w"), indent=1) | |
| else: | |
| df = pd.read_parquet(os.environ["LABEL_IN"]); sh, ns = int(os.environ.get("SHARD", 0)), int(os.environ.get("NSHARD", 1)) | |
| df = df.iloc[sh::ns].copy(); S = score(llm, df.text.tolist(), LABELS) | |
| for i, l in enumerate(LABELS): | |
| df[l] = [x[i] for x in S] | |
| df.to_parquet(os.environ["LABEL_OUT"]); print("labelled", len(df), flush=True) | |
| _m.hard_exit(0) | |