BruceIC commited on
Commit
142ebfc
·
verified ·
1 Parent(s): e93b079

Add Emoticare

Browse files

Add EmotiCare: DistilBERT multi-label emotion classifier (GoEmotions, 28 classes)

Files changed (7) hide show
  1. .gitattributes +35 -35
  2. README.md +189 -0
  3. config.json +84 -0
  4. model.safetensors +3 -0
  5. special_tokens_map.json +7 -0
  6. tokenizer_config.json +58 -0
  7. vocab.txt +0 -0
.gitattributes CHANGED
@@ -1,35 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,192 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ base_model: distilbert-base-uncased
4
+ tags:
5
+ - text-classification
6
+ - multi-label-classification
7
+ - emotion-detection
8
+ - distilbert
9
+ - pytorch
10
+ datasets:
11
+ - go_emotions
12
+ language:
13
+ - en
14
+ metrics:
15
+ - f1
16
+ pipeline_tag: text-classification
17
  ---
18
+
19
+ # EmotiCare — Multi-Label Emotion Classifier
20
+
21
+ 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.
22
+
23
+ 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.
24
+
25
+ ## Emotions
26
+
27
+ The model classifies text into 28 emotions:
28
+
29
+ `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`
30
+
31
+ ## Model Details
32
+
33
+ | Property | Value |
34
+ |---|---|
35
+ | Base model | `distilbert-base-uncased` |
36
+ | Architecture | DistilBertForSequenceClassification |
37
+ | Task | Multi-label text classification |
38
+ | Dataset | GoEmotions (simplified, 43,410 train samples) |
39
+ | Training epochs | 3 |
40
+ | Max sequence length | 512 tokens |
41
+ | Framework | PyTorch + 🤗 Transformers |
42
+
43
+ ## Evaluation Results
44
+
45
+ Evaluated on the GoEmotions test set (5,427 examples):
46
+
47
+ | Metric | Score |
48
+ |---|---|
49
+ | F1 Macro | **0.4019** |
50
+ | F1 Micro | **0.5702** |
51
+ | Eval Loss | 0.0843 |
52
+
53
+ > 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.
54
+
55
+ ## Inference
56
+
57
+ ### Using the 🤗 `pipeline` (recommended)
58
+
59
+ ```python
60
+ from transformers import pipeline
61
+ import torch
62
+
63
+ classifier = pipeline(
64
+ "text-classification",
65
+ model="YOUR_USERNAME/emoticare", # replace with your HF repo path
66
+ tokenizer="YOUR_USERNAME/emoticare",
67
+ top_k=None, # return scores for all labels
68
+ device=0 if torch.cuda.is_available() else -1,
69
+ )
70
+
71
+ text = "I can't believe how thoughtful that was, I'm so touched."
72
+ results = classifier(text)
73
+
74
+ # Filter to emotions above a confidence threshold
75
+ threshold = 0.3
76
+ detected = [r for r in results[0] if r["score"] > threshold]
77
+ for emotion in sorted(detected, key=lambda x: -x["score"]):
78
+ print(f"{emotion['label']:<20} {emotion['score']:.3f}")
79
+ ```
80
+
81
+ **Example output:**
82
+ ```
83
+ gratitude 0.847
84
+ admiration 0.612
85
+ love 0.431
86
+ ```
87
+
88
+ ---
89
+
90
+ ### Manual inference (more control)
91
+
92
+ ```python
93
+ import torch
94
+ import torch.nn.functional as F
95
+ from transformers import DistilBertTokenizer, DistilBertForSequenceClassification
96
+
97
+ model_name = "YOUR_USERNAME/emoticare" # replace with your HF repo path
98
+
99
+ tokenizer = DistilBertTokenizer.from_pretrained(model_name)
100
+ model = DistilBertForSequenceClassification.from_pretrained(model_name)
101
+ model.eval()
102
+
103
+ def predict_emotions(text: str, threshold: float = 0.3):
104
+ inputs = tokenizer(
105
+ text,
106
+ return_tensors="pt",
107
+ truncation=True,
108
+ max_length=512,
109
+ padding=True,
110
+ )
111
+ with torch.no_grad():
112
+ logits = model(**inputs).logits
113
+ probs = torch.sigmoid(logits).squeeze() # sigmoid for multi-label
114
+
115
+ emotions = model.config.id2label
116
+ results = [
117
+ {"label": emotions[i], "score": float(probs[i])}
118
+ for i in range(len(emotions))
119
+ if float(probs[i]) > threshold
120
+ ]
121
+ return sorted(results, key=lambda x: -x["score"])
122
+
123
+ # Example
124
+ print(predict_emotions("I'm so proud of everything we've built together!"))
125
+ ```
126
+
127
+ ---
128
+
129
+ ### Batch inference
130
+
131
+ ```python
132
+ texts = [
133
+ "I'm terrified of what might happen next.",
134
+ "This is the best day of my life!",
135
+ "I don't really feel anything about it.",
136
+ ]
137
+
138
+ inputs = tokenizer(
139
+ texts,
140
+ return_tensors="pt",
141
+ truncation=True,
142
+ max_length=512,
143
+ padding=True,
144
+ )
145
+
146
+ with torch.no_grad():
147
+ logits = model(**inputs).logits
148
+
149
+ probs = torch.sigmoid(logits) # shape: (batch_size, 28)
150
+ threshold = 0.3
151
+
152
+ for i, text in enumerate(texts):
153
+ detected = [
154
+ model.config.id2label[j]
155
+ for j in range(28)
156
+ if probs[i][j] > threshold
157
+ ]
158
+ print(f"Text: {text}")
159
+ print(f"Emotions: {', '.join(detected) or 'none above threshold'}\n")
160
+ ```
161
+
162
+ ## Training Details
163
+
164
+ - **Base model:** `distilbert-base-uncased`
165
+ - **Dataset:** [go_emotions](https://huggingface.co/datasets/go_emotions) (simplified config)
166
+ - **Loss function:** Binary Cross-Entropy (multi-label)
167
+ - **Optimizer:** AdamW with linear warmup + decay
168
+ - **Learning rate:** 2e-5 (peak)
169
+ - **Batch size:** 16
170
+ - **Epochs:** 3
171
+ - **Best checkpoint:** step 8142 (epoch 3)
172
+
173
+ ## Limitations
174
+
175
+ - Trained on Reddit comments — performance may degrade on formal text, non-native English, or very short inputs.
176
+ - Some rare emotions (grief, pride, relief) have limited training examples and lower per-class F1.
177
+ - Outputs are probabilities; the optimal threshold (default 0.3) may need tuning for your use case.
178
+
179
+ ## Citation
180
+
181
+ If you use this model, please cite the GoEmotions dataset:
182
+
183
+ ```bibtex
184
+ @inproceedings{demszky-etal-2020-goemotions,
185
+ title = {{GoEmotions}: A Dataset of Fine-Grained Emotions},
186
+ author = {Demszky, Dorottya and Movshovitz-Attias, Dana and Ko, Jeongwook
187
+ and Cowen, Alan and Nemade, Gaurav and Ravi, Sujith},
188
+ booktitle = {Proceedings of the 58th Annual Meeting of the Association for
189
+ Computational Linguistics},
190
+ year = {2020},
191
+ }
192
+ ```
config.json ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation": "gelu",
3
+ "architectures": [
4
+ "DistilBertForSequenceClassification"
5
+ ],
6
+ "attention_dropout": 0.1,
7
+ "dim": 768,
8
+ "dropout": 0.1,
9
+ "dtype": "float32",
10
+ "hidden_dim": 3072,
11
+ "id2label": {
12
+ "0": "admiration",
13
+ "1": "amusement",
14
+ "2": "anger",
15
+ "3": "annoyance",
16
+ "4": "approval",
17
+ "5": "caring",
18
+ "6": "confusion",
19
+ "7": "curiosity",
20
+ "8": "desire",
21
+ "9": "disappointment",
22
+ "10": "disapproval",
23
+ "11": "disgust",
24
+ "12": "embarrassment",
25
+ "13": "excitement",
26
+ "14": "fear",
27
+ "15": "gratitude",
28
+ "16": "grief",
29
+ "17": "joy",
30
+ "18": "love",
31
+ "19": "nervousness",
32
+ "20": "optimism",
33
+ "21": "pride",
34
+ "22": "realization",
35
+ "23": "relief",
36
+ "24": "remorse",
37
+ "25": "sadness",
38
+ "26": "surprise",
39
+ "27": "neutral"
40
+ },
41
+ "label2id": {
42
+ "admiration": 0,
43
+ "amusement": 1,
44
+ "anger": 2,
45
+ "annoyance": 3,
46
+ "approval": 4,
47
+ "caring": 5,
48
+ "confusion": 6,
49
+ "curiosity": 7,
50
+ "desire": 8,
51
+ "disappointment": 9,
52
+ "disapproval": 10,
53
+ "disgust": 11,
54
+ "embarrassment": 12,
55
+ "excitement": 13,
56
+ "fear": 14,
57
+ "gratitude": 15,
58
+ "grief": 16,
59
+ "joy": 17,
60
+ "love": 18,
61
+ "nervousness": 19,
62
+ "optimism": 20,
63
+ "pride": 21,
64
+ "realization": 22,
65
+ "relief": 23,
66
+ "remorse": 24,
67
+ "sadness": 25,
68
+ "surprise": 26,
69
+ "neutral": 27
70
+ },
71
+ "initializer_range": 0.02,
72
+ "max_position_embeddings": 512,
73
+ "model_type": "distilbert",
74
+ "n_heads": 12,
75
+ "n_layers": 6,
76
+ "pad_token_id": 0,
77
+ "problem_type": "multi_label_classification",
78
+ "qa_dropout": 0.1,
79
+ "seq_classif_dropout": 0.2,
80
+ "sinusoidal_pos_embds": false,
81
+ "tie_weights_": true,
82
+ "transformers_version": "4.57.3",
83
+ "vocab_size": 30522
84
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c1b6ec3adbe9c0063f972240d1e8f2c5fde8bb496e626593fafdda212a8ffc8
3
+ size 202334208
special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
tokenizer_config.json ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_basic_tokenize": true,
47
+ "do_lower_case": true,
48
+ "extra_special_tokens": {},
49
+ "mask_token": "[MASK]",
50
+ "model_max_length": 512,
51
+ "never_split": null,
52
+ "pad_token": "[PAD]",
53
+ "sep_token": "[SEP]",
54
+ "strip_accents": null,
55
+ "tokenize_chinese_chars": true,
56
+ "tokenizer_class": "DistilBertTokenizer",
57
+ "unk_token": "[UNK]"
58
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff