emotion-bert-base-binary-ensemble
Nine independent bert-base-cased binary classifiers, one per Plutchik
emotion plus Neutral, applied to English mobile app review sentences. This
is the binary-ensemble formulation's best-performing configuration found in
a broader comparison of encoder-only and decoder-only LLMs for this task:
each emotion gets its own independent encoder and decision boundary rather
than sharing one classification head, trained with focal loss on a
training pool augmented with LLM-generated synthetic reviews (100 per
emotion).
Under 10-fold cross-validation, this configuration reaches
macro-F1 0.530 (+-0.074). It trails the multi-label formulation's best
configuration (quim-motger/emotion-roberta-large-multilabel-genai-bce,
macro-F1 0.591) on this corpus, though binary ensemble is markedly more
robust to loss-reweighting miscalibration and does not share the
multi-label head's complete failure on rare emotions at baseline.
This repo holds nine separate models, not one. Each subfolder is an
independent bert-base-cased checkpoint with a single sigmoid output
(num_labels=1): presence/absence of that one emotion. There is no shared
backbone or parameter tying between them; assembling all nine into a
prediction requires nine forward passes, one per emotion, matching how the
paper reports inference cost for this formulation.
Labels / subfolders
Joy, Trust, Fear, Surprise, Sadness, Disgust, Anger,
Anticipation, Neutral -- each is a subfolder in this repo containing
its own independent binary classifier.
Usage
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
repo_id = "quim-motger/emotion-bert-base-binary-ensemble"
emotions = ["Joy", "Trust", "Fear", "Surprise", "Sadness", "Disgust", "Anger", "Anticipation", "Neutral"]
tok = AutoTokenizer.from_pretrained(repo_id, subfolder=emotions[0]) # tokenizer is identical across subfolders
text = "This app used to be great but the last update broke everything."
inputs = tok(text, return_tensors="pt", truncation=True, max_length=512)
probs = {}
for emotion in emotions:
model = AutoModelForSequenceClassification.from_pretrained(repo_id, subfolder=emotion)
with torch.no_grad():
probs[emotion] = torch.sigmoid(model(**inputs).logits)[0, 0].item()
predicted = [e for e, p in probs.items() if p >= 0.5]
print(predicted, probs)
Note: the paper's decision rule assigns a label when p >= 0.5, falls back
to the single most confident label if none cross that threshold, and caps
predictions at 3 labels (the maximum cardinality observed in the ground
truth). Replicate that rule yourself for scoring compatible with the paper.
Training data
Same recipe as the sibling multi-label model
(quim-motger/emotion-roberta-large-multilabel-genai-bce): the human-labelled
ground truth of 1,112 sentences (Motger et al., 2025), refit on the full
training pool (all cross-validation folds combined) plus up to 100
LLM-generated synthetic reviews per emotion, but with focal loss
(gamma=2.0) in place of BCE positive weighting, and one independent model
per emotion instead of one shared head.
Citation
If you use this model, please cite the ground-truth dataset paper referenced in the parent replication package.
Model tree for quim-motger/emotion-bert-base-binary-ensemble
Base model
google-bert/bert-base-cased