23f2001106 commited on
Commit ·
2564e6d
0
Parent(s):
Initial commit with model files tracked via Git LFS
Browse files- .gitattributes +3 -0
- LICENSE +21 -0
- README.md +85 -0
- added_tokens.json +3 -0
- config.json +3 -0
- model.py +88 -0
- pytorch_model.bin +3 -0
- special_tokens_map.json +3 -0
- spm.model +3 -0
- tokenizer.json +3 -0
- tokenizer_config.json +3 -0
.gitattributes
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.json filter=lfs diff=lfs merge=lfs -text
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 NeuralNest05
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# emo-detector
|
| 2 |
+
|
| 3 |
+
**emo-detector** is a multi-label emotion detection model for text. It predicts one or more emotions from the following labels:
|
| 4 |
+
|
| 5 |
+
- anger
|
| 6 |
+
- fear
|
| 7 |
+
- joy
|
| 8 |
+
- sadness
|
| 9 |
+
- surprise
|
| 10 |
+
|
| 11 |
+
## Model Details
|
| 12 |
+
|
| 13 |
+
- **Architecture:** Pretrained DeBERTa + custom FFNN classifier
|
| 14 |
+
- **Task:** Multi-label text classification
|
| 15 |
+
- **Tokenizer:** DeBERTa tokenizer (`microsoft/deberta-v3-base`)
|
| 16 |
+
- **Output:** Probabilities → Thresholded to 0/1
|
| 17 |
+
|
| 18 |
+
## Custom Model Class
|
| 19 |
+
|
| 20 |
+
This model uses a custom architecture implemented in `model.py`, specifically the class:
|
| 21 |
+
```
|
| 22 |
+
BERT_FFNN
|
| 23 |
+
```
|
| 24 |
+
If you want to load this model locally or fine-tune it further, make sure you have `model.py` in your working directory or import it correctly.
|
| 25 |
+
|
| 26 |
+
## Installation
|
| 27 |
+
```bash
|
| 28 |
+
pip install torch transformers
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
## Usage
|
| 32 |
+
|
| 33 |
+
```python
|
| 34 |
+
from transformers import AutoTokenizer
|
| 35 |
+
import torch
|
| 36 |
+
from model import BERT_FFNN
|
| 37 |
+
|
| 38 |
+
# Load tokenizer
|
| 39 |
+
tokenizer = AutoTokenizer.from_pretrained("NeuralNest05/emo-detector")
|
| 40 |
+
|
| 41 |
+
# Load model
|
| 42 |
+
config = {
|
| 43 |
+
"bert_model_name": "microsoft/deberta-v3-base",
|
| 44 |
+
"hidden_dims": [192, 96],
|
| 45 |
+
"output_dim": 5,
|
| 46 |
+
"dropout": 0.2,
|
| 47 |
+
"pooling": "attention",
|
| 48 |
+
"freeze_bert": False,
|
| 49 |
+
"freeze_layers": 0,
|
| 50 |
+
"use_layer_norm": True
|
| 51 |
+
}
|
| 52 |
+
model = BERT_FFNN(**config)
|
| 53 |
+
model.load_state_dict(torch.load("pytorch_model.bin", map_location="cpu"))
|
| 54 |
+
model.eval()
|
| 55 |
+
|
| 56 |
+
# Example prediction
|
| 57 |
+
texts = ["I am very happy today!", "This is scary..."]
|
| 58 |
+
encodings = tokenizer(texts, truncation=True, padding=True, return_tensors="pt")
|
| 59 |
+
with torch.no_grad():
|
| 60 |
+
logits = model(**encodings)
|
| 61 |
+
probs = torch.sigmoid(logits)
|
| 62 |
+
threshold = 0.5
|
| 63 |
+
preds = (probs > threshold).int()
|
| 64 |
+
|
| 65 |
+
print(preds)
|
| 66 |
+
```
|
| 67 |
+
|
| 68 |
+
## Output Format
|
| 69 |
+
Each prediction corresponds to the five emotion labels in this order:
|
| 70 |
+
```
|
| 71 |
+
["anger", "fear", "joy", "sadness", "surprise"]
|
| 72 |
+
```
|
| 73 |
+
Output is a multi-hot vector, e.g.:
|
| 74 |
+
```
|
| 75 |
+
[0, 0, 1, 0, 0] → joy
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
## License
|
| 79 |
+
MIT License
|
| 80 |
+
|
| 81 |
+
## Acknowledgements
|
| 82 |
+
|
| 83 |
+
- Microsoft DeBERTa-v3
|
| 84 |
+
- Hugging Face Transformers
|
| 85 |
+
- PyTorch
|
added_tokens.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a4b6bfe668f2b3cf6f0cd535e98a0663d2d0d4a4a15f13075ad3597d33985a23
|
| 3 |
+
size 26
|
config.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b2b9861148aff6e66b6d3e2e1c7a8f688dd68b5a92489471713bc9aac0a6431b
|
| 3 |
+
size 263
|
model.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch.nn as nn
|
| 2 |
+
import torch
|
| 3 |
+
from transformers import AutoModel
|
| 4 |
+
|
| 5 |
+
class BERT_FFNN(nn.Module):
|
| 6 |
+
"""
|
| 7 |
+
BERT_FFNN: BERT + feed-forward network for text classification tasks.
|
| 8 |
+
"""
|
| 9 |
+
def __init__(
|
| 10 |
+
self,
|
| 11 |
+
bert_model_name= "microsoft/deberta-v3-base",
|
| 12 |
+
hidden_dims=[192, 96],
|
| 13 |
+
output_dim=5,
|
| 14 |
+
dropout=0.2,
|
| 15 |
+
pooling='attention',
|
| 16 |
+
freeze_bert=False,
|
| 17 |
+
freeze_layers=0,
|
| 18 |
+
use_layer_norm=True
|
| 19 |
+
):
|
| 20 |
+
super().__init__()
|
| 21 |
+
|
| 22 |
+
# Load pretrained BERT
|
| 23 |
+
self.bert = AutoModel.from_pretrained(bert_model_name)
|
| 24 |
+
self.use_layer_norm = use_layer_norm
|
| 25 |
+
self.pooling = pooling
|
| 26 |
+
|
| 27 |
+
if pooling == 'attention':
|
| 28 |
+
self.attention_pool = AttentionPooling(self.bert.config.hidden_size)
|
| 29 |
+
|
| 30 |
+
if freeze_bert:
|
| 31 |
+
for param in self.bert.parameters():
|
| 32 |
+
param.requires_grad = False
|
| 33 |
+
elif freeze_layers > 0:
|
| 34 |
+
for layer in self.bert.encoder.layer[:freeze_layers]:
|
| 35 |
+
for param in layer.parameters():
|
| 36 |
+
param.requires_grad = False
|
| 37 |
+
|
| 38 |
+
# Build FFNN layers
|
| 39 |
+
fc_input_dim = self.bert.config.hidden_size
|
| 40 |
+
layers = []
|
| 41 |
+
in_dim = fc_input_dim
|
| 42 |
+
for h_dim in hidden_dims:
|
| 43 |
+
layers.append(nn.Linear(in_dim, h_dim))
|
| 44 |
+
layers.append(nn.ReLU())
|
| 45 |
+
if use_layer_norm:
|
| 46 |
+
layers.append(nn.LayerNorm(h_dim))
|
| 47 |
+
layers.append(nn.Dropout(dropout))
|
| 48 |
+
in_dim = h_dim
|
| 49 |
+
layers.append(nn.Linear(in_dim, output_dim))
|
| 50 |
+
self.classifier = nn.Sequential(*layers)
|
| 51 |
+
|
| 52 |
+
def forward(self, input_ids, attention_mask):
|
| 53 |
+
# BERT forward
|
| 54 |
+
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
|
| 55 |
+
|
| 56 |
+
if self.pooling == 'mean':
|
| 57 |
+
mask = attention_mask.unsqueeze(-1).float()
|
| 58 |
+
sum_emb = (outputs.last_hidden_state * mask).sum(1)
|
| 59 |
+
features = sum_emb / mask.sum(1).clamp(min=1e-9)
|
| 60 |
+
elif self.pooling == 'max':
|
| 61 |
+
mask = attention_mask.unsqueeze(-1).float()
|
| 62 |
+
masked_emb = outputs.last_hidden_state.masked_fill(mask == 0, float('-inf'))
|
| 63 |
+
features, _ = masked_emb.max(dim=1)
|
| 64 |
+
elif self.pooling == 'attention':
|
| 65 |
+
features = self.attention_pool(outputs.last_hidden_state, attention_mask)
|
| 66 |
+
else:
|
| 67 |
+
# CLS pooling
|
| 68 |
+
features = outputs.pooler_output if getattr(outputs, 'pooler_output', None) is not None else outputs.last_hidden_state[:, 0]
|
| 69 |
+
|
| 70 |
+
logits = self.classifier(features)
|
| 71 |
+
return logits
|
| 72 |
+
|
| 73 |
+
class AttentionPooling(nn.Module):
|
| 74 |
+
def __init__(self, hidden_size):
|
| 75 |
+
super().__init__()
|
| 76 |
+
self.attention = nn.Linear(hidden_size, 1)
|
| 77 |
+
|
| 78 |
+
def forward(self, hidden_states, attention_mask):
|
| 79 |
+
# hidden_states: [batch, seq_len, hidden]
|
| 80 |
+
# attention_mask: [batch, seq_len]
|
| 81 |
+
|
| 82 |
+
scores = self.attention(hidden_states).squeeze(-1) # [batch, seq_len]
|
| 83 |
+
scores = scores.masked_fill(attention_mask == 0, -1e9)
|
| 84 |
+
weights = torch.softmax(scores, dim=-1) # [batch, seq_len]
|
| 85 |
+
|
| 86 |
+
weighted_sum = torch.sum(hidden_states * weights.unsqueeze(-1), dim=1)
|
| 87 |
+
return weighted_sum
|
| 88 |
+
|
pytorch_model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d79284277477a674bd0e138cac2a088c77286b98a6316a2d9ec3d4ffb56354f8
|
| 3 |
+
size 736082987
|
special_tokens_map.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ed7c099c988dbb414b18a6980d20cb57b91b7cd119f6f6941eb364b0e892e712
|
| 3 |
+
size 301
|
spm.model
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c679fbf93643d19aab7ee10c0b99e460bdbc02fedf34b92b05af343b4af586fd
|
| 3 |
+
size 2464616
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5124ef2ead1a10a717703bc436de7f353da76d6340e4587719b42b1693707964
|
| 3 |
+
size 8656624
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:700dba386cc05b6b14e74add7fe9293a6cb3ab16f3aa2eb177c76e288592bf01
|
| 3 |
+
size 1374
|