Horizon-Labs/multilingual-emotions-base

Model

Multilingual Emotions (base, 308M): the 28 GoEmotions labels in many languages

0

3 commits

1 linked in READMEs

updated Oct 2, 2026

See the code

README

Multilingual Emotions (base, 308M): the 28 GoEmotions labels in many languages

A multi-label emotion classifier with the 28 labels of Google's GoEmotions (admiration, amusement, anger, ... , surprise, neutral). It works on text in English and 35 other languages. It is a drop-in multilingual alternative to English-only GoEmotions models such as SamLowe/roberta-base-go_emotions: the labels are the same and it uses the same sigmoid multi-label output. Built on mmBERT-base, Apache-2.0. ONNX files for CPU and the browser (transformers.js) are included. A smaller, faster version is available as multilingual-emotions-small. Try it in the browser.

  • Each label gets an independent probability. A text can have several emotions, or only neutral.
  • thresholds.json has one threshold per label, tuned on the GoEmotions validation set. Use it instead of 0.5, especially for rare labels (grief, pride, relief, nervousness). See Usage.
  • For the 6 Ekman emotions (anger, disgust, fear, joy, sadness, surprise), group the labels with the GoEmotions paper's mapping and take the maximum per group (ekman_mapping.json, code below).
  • onnx/model_quantized.onnx (int8 embeddings, 641 MB) agrees with fp32 on 99.1% of 448 test texts (all 28 labels thresholded at 0.5).

Usage

import json
from huggingface_hub import hf_hub_download
from transformers import pipeline

clf = pipeline("text-classification", model="Horizon-Labs/multilingual-emotions-base", top_k=None)
thr = json.load(open(hf_hub_download("Horizon-Labs/multilingual-emotions-base", "thresholds.json")))
out = clf(["Thank you so much, this made my day!", "Tengo miedo de que no lleguemos a tiempo."])
print([[x["label"] for x in o if x["score"] >= thr[x["label"]]] for o in out])
# e.g. [['excitement', 'gratitude', 'joy'], ['fear']]

# 6 Ekman emotions: max score over each group
ekman = json.load(open(hf_hub_download("Horizon-Labs/multilingual-emotions-base", "ekman_mapping.json")))
scores = {x["label"]: x["score"] for x in out[1]}
print({e: max(scores[l] for l in ls) for e, ls in ekman.items()})

transformers.js:

import { pipeline } from "@huggingface/transformers";
const clf = await pipeline("text-classification", "Horizon-Labs/multilingual-emotions-base", { dtype: "q8" });
console.log(await clf("Je suis tellement fier de toi !", { top_k: 5 }));

Evaluation

The benchmarks were used only for evaluation, and training texts that also occur in them were removed.

  • GoEmotions test (English Reddit comments, 5,427, 28 labels). Macro-F1 over the 28 labels, at threshold 0.5 and with per-label thresholds tuned on the GoEmotions validation set. Only models with the 28 GoEmotions labels are scored.
  • BRIGHTER (brighter-dataset/BRIGHTER-emotion-categories, CC-BY-4.0): human-labelled texts written in 28 languages (not translations), with 6 emotions and multiple labels per text; up to 1,500 test texts per language. Every model's labels are grouped into the 6 emotions (GoEmotions labels via the GoEmotions paper's Ekman mapping; for other label sets, by name). Each model gets one threshold per language and emotion, tuned on that language's BRIGHTER dev set. The score is macro-F1 over the annotated emotions, averaged over languages. "4 emotions" = anger, fear, joy and sadness only, the set every compared model covers.
modellicenceGoEmotions test, macro-F1 @0.5GoEmotions test, macro-F1 (tuned thresholds)BRIGHTER, 6 emotionsBRIGHTER, 4 emotionslabels
this model (308M)Apache-2.00.4730.5160.4200.44928 GoEmotions labels, multilingual
multilingual-emotions-small (141M)Apache-2.00.4470.4940.4060.432
SamLowe/roberta-base-go_emotions (125M)MIT0.4500.5190.2820.29128 GoEmotions labels, English
AnasAlokla/multilingual_go_emotionsMIT0.4550.5380.3370.35528 GoEmotions labels, multilingual
j-hartmann/emotion-english-distilroberta-base (82M)none givenβ€”β€”0.2970.3157 labels, English
MilaNLProc/xlm-emo-t (278M)none givenβ€”β€”β€”0.4564 labels (anger, fear, joy, sadness), multilingual tweets
tabularisai/multilingual-emotion-classification (135M)CC-BY-NC-4.0β€”β€”0.4040.42811 labels, multilingual
  • The table shows the released checkpoint. Means over two training seeds: small GoEmotions tuned .499, BRIGHTER 6 emotions .405, 4 emotions .434; base GoEmotions tuned .520, BRIGHTER 6 emotions .424, 4 emotions .454.
  • Models ahead of this one: GoEmotions (tuned): roberta-base-go_emotions, multilingual_go_emotions; BRIGHTER 6 emotions: none; BRIGHTER 4 emotions: xlm-emo-t. Most BRIGHTER languages are low-resource African and Asian languages that are not in our training data; GoEmotions texts are Reddit comments, while BRIGHTER includes tweets, news comments and other sources.

Per BRIGHTER language (macro-F1):

languagethis model (6 emotions)this model (4)xlm-emo-t (4)tabularisai (6, NC)
Afrikaans0.4330.4770.3500.339
Algerian Arabic0.4480.4520.4790.442
Moroccan Arabic0.3780.4330.4570.314
Chinese0.4480.4890.5640.439
German0.4320.4750.5100.434
English0.5650.5910.6180.522
Spanish0.6670.6750.7720.636
Hausa0.3190.3210.3420.354
Hindi0.6310.6690.7310.757
Igbo0.2690.2720.2940.272
Indonesian0.5160.5450.5870.495
Javanese0.4530.4750.4250.433
Kinyarwanda0.2260.2820.2610.194
Marathi0.6170.6120.6240.670
Nigerian Pidgin0.4320.3790.4250.451
Portuguese (Brazil)0.3880.5010.5640.406
Portuguese (Mozambique)0.3120.3910.3840.287
Romanian0.6660.7190.6830.570
Russian0.6570.6570.7550.706
Sundanese0.3610.4150.4580.389
Swahili0.2840.2810.2780.244
Swedish0.4640.4920.4750.367
Tatar0.5310.5480.3520.359
Ukrainian0.4540.5150.5170.462
Makhuwa0.1810.2040.1740.151
isiXhosa0.3090.3180.2940.300
Yoruba0.1650.2030.1960.154
isiZulu0.1650.1860.1890.164

Weakest GoEmotions labels (test F1, tuned thresholds): relief 0.26, realization 0.27, disappointment 0.30, embarrassment 0.36, annoyance 0.37, nervousness 0.37. Several of these are rare, and GoEmotions annotators often disagree on such labels.

Training

  • Data: the GoEmotions training set (43,410 English Reddit comments with human labels; Apache-2.0), plus translations of it into 35 languages made with Qwen3.8-27B (Apache-2.0), published as Horizon-Labs/go-emotions-multilingual. Each language gets its own random sample of 12,000 comments, and the human labels are copied to the translation (442,991 training examples in total). The languages are Afrikaans, Arabic, Bengali, Chinese (Simplified), Czech, Danish, Dutch, Finnish, French, German, Greek, Hausa, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Marathi, Norwegian, Persian, Polish, Portuguese (Brazilian), Romanian, Russian, Spanish, Swahili, Swedish, Tatar, Thai, Turkish, Ukrainian, Urdu, Vietnamese.
  • Translations that failed to parse, looked like refusals, had an implausible length or were copied unchanged were dropped (about 1.2%). 3% of the source comments (in every language) were held out for validation.
  • Model: mmBERT-base with 28 sigmoid outputs and binary cross-entropy, 1 epoch, learning rate 5e-5, max length 256 tokens. Epochs and learning rate were chosen on the GoEmotions validation set and BRIGHTER dev sets, never the test sets. The checkpoint was chosen by macro-F1 on held-out training comments.
  • Code: code/ in this repository.

Limitations

  • The labels come from English Reddit comments. Translations keep the labels but can shift nuance, and the model has seen little native (non-translated) emotional text outside English. BRIGHTER results show it is much weaker in languages it was not trained on.
  • The labels are subjective and inter-annotator agreement on GoEmotions is modest, so F1 around 0.5 is typical for this task. Rare labels are unreliable.
  • It classifies the emotion expressed in the text, not the writer's actual state. Don't use it to make decisions about individuals.
emotion
emotion-classification
endpoints_compatible
go_emotions
mmbert
modernbert
multi-label-classification
multilingual
onnx
safetensors
text-classification
text-embeddings-inference
transformers
transformers.js

Horizon-Labs/multilingual-emotions-base

Model

Multilingual Emotions (base, 308M): the 28 GoEmotions labels in many languages

0

3 commits

1 linked in READMEs

updated Oct 2, 2026

See the code

README

Multilingual Emotions (base, 308M): the 28 GoEmotions labels in many languages

A multi-label emotion classifier with the 28 labels of Google's GoEmotions (admiration, amusement, anger, ... , surprise, neutral). It works on text in English and 35 other languages. It is a drop-in multilingual alternative to English-only GoEmotions models such as SamLowe/roberta-base-go_emotions: the labels are the same and it uses the same sigmoid multi-label output. Built on mmBERT-base, Apache-2.0. ONNX files for CPU and the browser (transformers.js) are included. A smaller, faster version is available as multilingual-emotions-small. Try it in the browser.

  • Each label gets an independent probability. A text can have several emotions, or only neutral.
  • thresholds.json has one threshold per label, tuned on the GoEmotions validation set. Use it instead of 0.5, especially for rare labels (grief, pride, relief, nervousness). See Usage.
  • For the 6 Ekman emotions (anger, disgust, fear, joy, sadness, surprise), group the labels with the GoEmotions paper's mapping and take the maximum per group (ekman_mapping.json, code below).
  • onnx/model_quantized.onnx (int8 embeddings, 641 MB) agrees with fp32 on 99.1% of 448 test texts (all 28 labels thresholded at 0.5).

Usage

import json
from huggingface_hub import hf_hub_download
from transformers import pipeline

clf = pipeline("text-classification", model="Horizon-Labs/multilingual-emotions-base", top_k=None)
thr = json.load(open(hf_hub_download("Horizon-Labs/multilingual-emotions-base", "thresholds.json")))
out = clf(["Thank you so much, this made my day!", "Tengo miedo de que no lleguemos a tiempo."])
print([[x["label"] for x in o if x["score"] >= thr[x["label"]]] for o in out])
# e.g. [['excitement', 'gratitude', 'joy'], ['fear']]

# 6 Ekman emotions: max score over each group
ekman = json.load(open(hf_hub_download("Horizon-Labs/multilingual-emotions-base", "ekman_mapping.json")))
scores = {x["label"]: x["score"] for x in out[1]}
print({e: max(scores[l] for l in ls) for e, ls in ekman.items()})

transformers.js:

import { pipeline } from "@huggingface/transformers";
const clf = await pipeline("text-classification", "Horizon-Labs/multilingual-emotions-base", { dtype: "q8" });
console.log(await clf("Je suis tellement fier de toi !", { top_k: 5 }));

Evaluation

The benchmarks were used only for evaluation, and training texts that also occur in them were removed.

  • GoEmotions test (English Reddit comments, 5,427, 28 labels). Macro-F1 over the 28 labels, at threshold 0.5 and with per-label thresholds tuned on the GoEmotions validation set. Only models with the 28 GoEmotions labels are scored.
  • BRIGHTER (brighter-dataset/BRIGHTER-emotion-categories, CC-BY-4.0): human-labelled texts written in 28 languages (not translations), with 6 emotions and multiple labels per text; up to 1,500 test texts per language. Every model's labels are grouped into the 6 emotions (GoEmotions labels via the GoEmotions paper's Ekman mapping; for other label sets, by name). Each model gets one threshold per language and emotion, tuned on that language's BRIGHTER dev set. The score is macro-F1 over the annotated emotions, averaged over languages. "4 emotions" = anger, fear, joy and sadness only, the set every compared model covers.
modellicenceGoEmotions test, macro-F1 @0.5GoEmotions test, macro-F1 (tuned thresholds)BRIGHTER, 6 emotionsBRIGHTER, 4 emotionslabels
this model (308M)Apache-2.00.4730.5160.4200.44928 GoEmotions labels, multilingual
multilingual-emotions-small (141M)Apache-2.00.4470.4940.4060.432
SamLowe/roberta-base-go_emotions (125M)MIT0.4500.5190.2820.29128 GoEmotions labels, English
AnasAlokla/multilingual_go_emotionsMIT0.4550.5380.3370.35528 GoEmotions labels, multilingual
j-hartmann/emotion-english-distilroberta-base (82M)none givenβ€”β€”0.2970.3157 labels, English
MilaNLProc/xlm-emo-t (278M)none givenβ€”β€”β€”0.4564 labels (anger, fear, joy, sadness), multilingual tweets
tabularisai/multilingual-emotion-classification (135M)CC-BY-NC-4.0β€”β€”0.4040.42811 labels, multilingual
  • The table shows the released checkpoint. Means over two training seeds: small GoEmotions tuned .499, BRIGHTER 6 emotions .405, 4 emotions .434; base GoEmotions tuned .520, BRIGHTER 6 emotions .424, 4 emotions .454.
  • Models ahead of this one: GoEmotions (tuned): roberta-base-go_emotions, multilingual_go_emotions; BRIGHTER 6 emotions: none; BRIGHTER 4 emotions: xlm-emo-t. Most BRIGHTER languages are low-resource African and Asian languages that are not in our training data; GoEmotions texts are Reddit comments, while BRIGHTER includes tweets, news comments and other sources.

Per BRIGHTER language (macro-F1):

languagethis model (6 emotions)this model (4)xlm-emo-t (4)tabularisai (6, NC)
Afrikaans0.4330.4770.3500.339
Algerian Arabic0.4480.4520.4790.442
Moroccan Arabic0.3780.4330.4570.314
Chinese0.4480.4890.5640.439
German0.4320.4750.5100.434
English0.5650.5910.6180.522
Spanish0.6670.6750.7720.636
Hausa0.3190.3210.3420.354
Hindi0.6310.6690.7310.757
Igbo0.2690.2720.2940.272
Indonesian0.5160.5450.5870.495
Javanese0.4530.4750.4250.433
Kinyarwanda0.2260.2820.2610.194
Marathi0.6170.6120.6240.670
Nigerian Pidgin0.4320.3790.4250.451
Portuguese (Brazil)0.3880.5010.5640.406
Portuguese (Mozambique)0.3120.3910.3840.287
Romanian0.6660.7190.6830.570
Russian0.6570.6570.7550.706
Sundanese0.3610.4150.4580.389
Swahili0.2840.2810.2780.244
Swedish0.4640.4920.4750.367
Tatar0.5310.5480.3520.359
Ukrainian0.4540.5150.5170.462
Makhuwa0.1810.2040.1740.151
isiXhosa0.3090.3180.2940.300
Yoruba0.1650.2030.1960.154
isiZulu0.1650.1860.1890.164

Weakest GoEmotions labels (test F1, tuned thresholds): relief 0.26, realization 0.27, disappointment 0.30, embarrassment 0.36, annoyance 0.37, nervousness 0.37. Several of these are rare, and GoEmotions annotators often disagree on such labels.

Training

  • Data: the GoEmotions training set (43,410 English Reddit comments with human labels; Apache-2.0), plus translations of it into 35 languages made with Qwen3.8-27B (Apache-2.0), published as Horizon-Labs/go-emotions-multilingual. Each language gets its own random sample of 12,000 comments, and the human labels are copied to the translation (442,991 training examples in total). The languages are Afrikaans, Arabic, Bengali, Chinese (Simplified), Czech, Danish, Dutch, Finnish, French, German, Greek, Hausa, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Marathi, Norwegian, Persian, Polish, Portuguese (Brazilian), Romanian, Russian, Spanish, Swahili, Swedish, Tatar, Thai, Turkish, Ukrainian, Urdu, Vietnamese.
  • Translations that failed to parse, looked like refusals, had an implausible length or were copied unchanged were dropped (about 1.2%). 3% of the source comments (in every language) were held out for validation.
  • Model: mmBERT-base with 28 sigmoid outputs and binary cross-entropy, 1 epoch, learning rate 5e-5, max length 256 tokens. Epochs and learning rate were chosen on the GoEmotions validation set and BRIGHTER dev sets, never the test sets. The checkpoint was chosen by macro-F1 on held-out training comments.
  • Code: code/ in this repository.

Limitations

  • The labels come from English Reddit comments. Translations keep the labels but can shift nuance, and the model has seen little native (non-translated) emotional text outside English. BRIGHTER results show it is much weaker in languages it was not trained on.
  • The labels are subjective and inter-annotator agreement on GoEmotions is modest, so F1 around 0.5 is typical for this task. Rare labels are unreliable.
  • It classifies the emotion expressed in the text, not the writer's actual state. Don't use it to make decisions about individuals.
emotion
emotion-classification
endpoints_compatible
go_emotions
mmbert
modernbert
multi-label-classification
multilingual
onnx
safetensors
text-classification
text-embeddings-inference
transformers
transformers.js