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/gen_hate.py from Horizon-Labs/multilingual-hate-speech-base: direct link, hf CLI and curl.
- Browser
- Download file 5.34 kB
-
https://huggingface.co/Horizon-Labs/multilingual-hate-speech-base/resolve/main/code/hate/gen_hate.py
- Command line
-
hf download hf://Horizon-Labs/multilingual-hate-speech-base/code/hate/gen_hate.py
-
curl -L -o gen_hate.py https://huggingface.co/Horizon-Labs/multilingual-hate-speech-base/resolve/main/code/hate/gen_hate.py
5.34 kB
| """Native (not translated) texts for a multilingual hate-speech classifier, Qwen3.8-27B via vLLM. Per prompt: one language, one | |
| platform and one protected-characteristic category; 10 texts: 4 hateful toward a group of that category (explicit and implicit/coded | |
| forms), 3 non-hateful texts that mention such groups (neutral or positive statements, news reporting, counter-speech or quoting hate | |
| to criticise it), 3 offensive but not hate speech (insults or profanity aimed at an individual, or attacks on non-protected targets | |
| such as politicians, sports fans or companies). Labels come later from the teacher (hate/teacher_hate.py); the requested type is kept | |
| only for statistics. No benchmark texts or templates are shown. N=... SHARD=i OUT=dir python hate/gen_hate.py -> $OUT/hate_<shard>.jsonl""" | |
| import json, os, random, sys | |
| sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "sentiment")) | |
| from gen_sent import parse_json | |
| import importlib.util | |
| _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); hard_exit = _m.hard_exit | |
| LANGS = ["English", "Spanish", "French", "German", "Italian", "Portuguese (Brazil)", "Portuguese (Portugal)", "Dutch", "Polish", "Czech", | |
| "Slovak", "Romanian", "Hungarian", "Greek", "Bulgarian", "Serbian", "Croatian", "Ukrainian", "Russian", "Swedish", "Danish", | |
| "Norwegian", "Finnish", "Turkish", "Arabic (Modern Standard)", "Arabic (Egyptian)", "Arabic (Gulf)", "Arabic (Levantine)", | |
| "Arabic (Maghrebi)", "Hebrew", "Persian", "Urdu", "Hindi", "Hinglish (Hindi in Latin letters mixed with English)", "Bengali", | |
| "Tamil", "Telugu", "Marathi", "Chinese (Simplified)", "Chinese (Traditional)", "Japanese", "Korean", "Vietnamese", "Thai", | |
| "Indonesian", "Malay", "Tagalog", "Swahili", "Amharic", "Hausa", "Yoruba", "Afrikaans"] | |
| CATS = ["race or ethnicity", "religion", "nationality, national origin or migration status (immigrants, refugees)", | |
| "gender (women, men, transgender or non-binary people)", "sexual orientation (gay, lesbian, bisexual people)", | |
| "disability (physical, mental or cognitive)", "age (old people, young people)"] | |
| PLATFORMS = ["comments under a news article", "a YouTube comment section", "an online game chat", "a football fan forum", "replies on a social network", | |
| "a political discussion group", "a messaging group", "a local community forum", "a meme page", "an anonymous imageboard"] | |
| def prompt(lang, cat, platform): | |
| return f"""You are creating training data for a content-moderation classifier that must recognise hate speech written in {lang}. | |
| Write 10 different realistic texts from {platform}, in {lang}, as native speakers really write them (slang, abbreviations, | |
| dialect, emojis, typos where natural; do not translate from English). Focus on groups defined by {cat} that are actually targeted | |
| in {lang}-speaking societies: | |
| - 4 HATEFUL texts against such a group, of different kinds: slurs, dehumanising comparisons, harmful stereotypes, calls for exclusion, | |
| discrimination or violence, and implicit or coded hate (dog whistles, "jokes", "just asking questions"). | |
| - 3 NON-HATEFUL texts that mention such groups: neutral or positive statements, a news-style report, counter-speech that rejects hate, | |
| or a quote of a hateful remark in order to criticise it. | |
| - 3 OFFENSIVE BUT NOT HATE SPEECH texts: insults or profanity aimed at one person without referring to the group, or harsh attacks on | |
| non-protected targets (politicians, a sports team's fans, a company, a government's policy). | |
| Return only JSON: {{"texts": [{{"text": "...", "type": "hateful|non-hateful|offensive"}}, ...]}}""" | |
| if __name__ == "__main__": | |
| from vllm import LLM, SamplingParams | |
| n, shard, out = int(os.environ.get("N", 3000)), int(os.environ.get("SHARD", 0)), os.environ["OUT"] | |
| rng = random.Random(9800 + shard) | |
| jobs = [(rng.choice(LANGS), rng.choice(CATS), rng.choice(PLATFORMS)) for _ in range(n)] | |
| llm = LLM(os.environ.get("MODEL", "Qwen/Qwen3.8-27B-FP8"), max_model_len=4096, gpu_memory_utilization=0.92, max_num_seqs=512, | |
| limit_mm_per_prompt={"image": 0, "video": 0}) | |
| outs = llm.chat([[{"role": "user", "content": prompt(*j)}] for j in jobs], SamplingParams(temperature=0.95, top_p=0.95, max_tokens=2500, seed=800 + shard), | |
| chat_template_kwargs={"enable_thinking": False}) | |
| os.makedirs(out, exist_ok=True); k = 0; refused = 0 | |
| with open(f"{out}/hate_{shard}.jsonl", "w") as f: | |
| for (l, c, p), o in zip(jobs, outs): | |
| j = parse_json(o.outputs[0].text) | |
| items = (j or {}).get("texts", []) if isinstance(j, dict) else [] | |
| refused += not items | |
| for it in items: | |
| if isinstance(it, dict) and isinstance(it.get("text"), str) and 3 <= len(it["text"]) <= 1000: | |
| t = it["text"].encode("utf-8", "ignore").decode().strip() | |
| f.write(json.dumps(dict(text=t, lang=l, category=c.split(" (")[0], platform=p, intended=str(it.get("type", ""))), ensure_ascii=False) + "\n"); k += 1 | |
| print("texts", k, "from", len(jobs), "prompts; empty/refused", refused, flush=True); hard_exit(0) | |