emoticare / README.md
BruceIC's picture
Update README
c161bc5 verified
|
Raw
History Blame Contribute Delete
5.81 kB
---
license: apache-2.0
base_model: distilbert-base-uncased
tags:
- text-classification
- multi-label-classification
- emotion-detection
- distilbert
- pytorch
datasets:
- go_emotions
language:
- en
metrics:
- f1
pipeline_tag: text-classification
---
# EmotiCare — Multi-Label Emotion Classifier
EmotiCare is a fine-tuned [DistilBERT](https://huggingface.co/distilbert-base-uncased) model for **multi-label emotion detection** in English text. Given a sentence, it predicts one or more emotions from 28 categories drawn from the [GoEmotions](https://huggingface.co/datasets/go_emotions) dataset.
It is designed for use in applications that need nuanced, fine-grained emotion understanding — such as mental health tools, sentiment dashboards, chatbots, and content moderation systems.
## Emotions
The model classifies text into 28 emotions:
`admiration` · `amusement` · `anger` · `annoyance` · `approval` · `caring` · `confusion` · `curiosity` · `desire` · `disappointment` · `disapproval` · `disgust` · `embarrassment` · `excitement` · `fear` · `gratitude` · `grief` · `joy` · `love` · `nervousness` · `optimism` · `pride` · `realization` · `relief` · `remorse` · `sadness` · `surprise` · `neutral`
## Model Details
| Property | Value |
|---|---|
| Base model | `distilbert-base-uncased` |
| Architecture | DistilBertForSequenceClassification |
| Task | Multi-label text classification |
| Dataset | GoEmotions (simplified, 43,410 train samples) |
| Training epochs | 3 |
| Max sequence length | 512 tokens |
| Framework | PyTorch + 🤗 Transformers |
## Evaluation Results
Evaluated on the GoEmotions test set (5,427 examples):
| Metric | Score |
|---|---|
| F1 Macro | **0.4019** |
| F1 Micro | **0.5702** |
| Eval Loss | 0.0843 |
> Note: Multi-label emotion classification on GoEmotions is a challenging task due to class imbalance and overlapping emotions. F1 Micro of ~0.57 is competitive with similar fine-tuned DistilBERT baselines.
## Inference
### Using the 🤗 `pipeline` (recommended)
```python
from transformers import pipeline
import torch
classifier = pipeline(
"text-classification",
model="BruceIC/emoticare", # replace with your HF repo path
tokenizer="BruceIC/emoticare",
top_k=None, # return scores for all labels
device=0 if torch.cuda.is_available() else -1,
)
text = "I can't believe how thoughtful that was, I'm so touched."
results = classifier(text)
# Filter to emotions above a confidence threshold
threshold = 0.3
detected = [r for r in results[0] if r["score"] > threshold]
for emotion in sorted(detected, key=lambda x: -x["score"]):
print(f"{emotion['label']:<20} {emotion['score']:.3f}")
```
**Example output:**
```
gratitude 0.847
admiration 0.612
love 0.431
```
---
### Manual inference (more control)
```python
import torch
import torch.nn.functional as F
from transformers import DistilBertTokenizer, DistilBertForSequenceClassification
model_name = "BruceIC/emoticare" # replace with your HF repo path
tokenizer = DistilBertTokenizer.from_pretrained(model_name)
model = DistilBertForSequenceClassification.from_pretrained(model_name)
model.eval()
def predict_emotions(text: str, threshold: float = 0.3):
inputs = tokenizer(
text,
return_tensors="pt",
truncation=True,
max_length=512,
padding=True,
)
with torch.no_grad():
logits = model(**inputs).logits
probs = torch.sigmoid(logits).squeeze() # sigmoid for multi-label
emotions = model.config.id2label
results = [
{"label": emotions[i], "score": float(probs[i])}
for i in range(len(emotions))
if float(probs[i]) > threshold
]
return sorted(results, key=lambda x: -x["score"])
# Example
print(predict_emotions("I'm so proud of everything we've built together!"))
```
---
### Batch inference
```python
texts = [
"I'm terrified of what might happen next.",
"This is the best day of my life!",
"I don't really feel anything about it.",
]
inputs = tokenizer(
texts,
return_tensors="pt",
truncation=True,
max_length=512,
padding=True,
)
with torch.no_grad():
logits = model(**inputs).logits
probs = torch.sigmoid(logits) # shape: (batch_size, 28)
threshold = 0.3
for i, text in enumerate(texts):
detected = [
model.config.id2label[j]
for j in range(28)
if probs[i][j] > threshold
]
print(f"Text: {text}")
print(f"Emotions: {', '.join(detected) or 'none above threshold'}\n")
```
## Training Details
- **Base model:** `distilbert-base-uncased`
- **Dataset:** [go_emotions](https://huggingface.co/datasets/go_emotions) (simplified config)
- **Loss function:** Binary Cross-Entropy (multi-label)
- **Optimizer:** AdamW with linear warmup + decay
- **Learning rate:** 2e-5 (peak)
- **Batch size:** 16
- **Epochs:** 3
- **Best checkpoint:** step 8142 (epoch 3)
## Limitations
- Trained on Reddit comments — performance may degrade on formal text, non-native English, or very short inputs.
- Some rare emotions (grief, pride, relief) have limited training examples and lower per-class F1.
- Outputs are probabilities; the optimal threshold (default 0.3) may need tuning for your use case.
## Citation
If you use this model, please cite the GoEmotions dataset:
```bibtex
@inproceedings{demszky-etal-2020-goemotions,
title = {{GoEmotions}: A Dataset of Fine-Grained Emotions},
author = {Demszky, Dorottya and Movshovitz-Attias, Dana and Ko, Jeongwook
and Cowen, Alan and Nemade, Gaurav and Ravi, Sujith},
booktitle = {Proceedings of the 58th Annual Meeting of the Association for
Computational Linguistics},
year = {2020},
}
```