Spaces:
Sleeping
Sleeping
custom bidirectional gru mode
Browse files
model.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.nn as nn
|
| 3 |
+
import torch.nn.functional as F
|
| 4 |
+
from huggingface_hub import PyTorchModelHubMixin
|
| 5 |
+
|
| 6 |
+
class CustomBiGRUMCQModel(nn.Module, PyTorchModelHubMixin):
|
| 7 |
+
"""
|
| 8 |
+
Bidirectional GRU model with custom global attention pooling
|
| 9 |
+
"""
|
| 10 |
+
#vocab_size, embedding_dim=256, hidden_dim=256, num_layers=2, dropout=0.1
|
| 11 |
+
def __init__(self, config:dict):
|
| 12 |
+
super().__init__()
|
| 13 |
+
self.config = config
|
| 14 |
+
self.vocab_size = config.get('vocab_size', 30000)
|
| 15 |
+
self.embedding_dim = config.get('embedding_dim',256)
|
| 16 |
+
self.hidden_dim = config.get('hidden_dim',256)
|
| 17 |
+
self.num_layers = config.get('num_layers',2)
|
| 18 |
+
|
| 19 |
+
self.embedding = nn.Embedding(self.vocab_size, self.embedding_dim, padding_idx=0)
|
| 20 |
+
self.embedding_dropout = nn.Dropout(config.get('dropout', 0.1))
|
| 21 |
+
|
| 22 |
+
self.gru = nn.GRU(
|
| 23 |
+
input_size = self.embedding_dim,
|
| 24 |
+
hidden_size = self.hidden_dim,
|
| 25 |
+
num_layers = self.num_layers,
|
| 26 |
+
bidirectional=True,
|
| 27 |
+
batch_first=True,
|
| 28 |
+
dropout = config.get('dropout',0.1) if self.num_layers > 1 else 0
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
# Dot product attention pooling head
|
| 32 |
+
self.attention_query = nn.Linear(self.hidden_dim * 2, 1, bias=False)
|
| 33 |
+
|
| 34 |
+
#Final classification layer
|
| 35 |
+
self.classifier = nn.Linear(self.hidden_dim*2, 1)
|
| 36 |
+
self.dropout = nn.Dropout(config.get('dropout',0.1))
|
| 37 |
+
|
| 38 |
+
def forward(self, input_ids, attention_mask=None, label=None, **kwargs):
|
| 39 |
+
input_idx = input_ids
|
| 40 |
+
#expected shape [batch_size, num_of_choice=5, seq_length]
|
| 41 |
+
batch_size, num_of_choices, seq_length = input_idx.shape
|
| 42 |
+
|
| 43 |
+
flat_input_idx = input_ids.view(batch_size * num_of_choices, seq_length)
|
| 44 |
+
|
| 45 |
+
embedded = self.embedding(flat_input_idx)
|
| 46 |
+
embedded = self.embedding_dropout(embedded)
|
| 47 |
+
|
| 48 |
+
gru_out, _ = self.gru(embedded) # Shape: [batch_size * 5, seq_length, hidden_dim * 2]
|
| 49 |
+
|
| 50 |
+
attentions_scores = self.attention_query(gru_out).squeeze(-1)
|
| 51 |
+
|
| 52 |
+
# Adapt Attentions mask to the choice dimension
|
| 53 |
+
flaten_mask = None
|
| 54 |
+
if attention_mask is not None:
|
| 55 |
+
flat_mask = attention_mask.view(batch_size * num_of_choices, seq_length)
|
| 56 |
+
attentions_scores = attentions_scores.masked_fill(flat_mask == 0, -1e9)
|
| 57 |
+
|
| 58 |
+
attention_weight = F.softmax(attentions_scores, dim=-1).unsqueeze(-1)
|
| 59 |
+
pooled_output = torch.sum(gru_out * attention_weight, dim=1)
|
| 60 |
+
pooled_output = self.dropout(pooled_output)
|
| 61 |
+
|
| 62 |
+
raw_scores = self.classifier(pooled_output).squeeze(-1) # Shape: [batch_size * 5]
|
| 63 |
+
reshape_logits = raw_scores.view(batch_size, num_of_choices) # Shape: [batch_size, 5]
|
| 64 |
+
|
| 65 |
+
loss = None
|
| 66 |
+
if label is not None:
|
| 67 |
+
loss_fct = nn.CrossEntropyLoss()
|
| 68 |
+
loss = loss_fct(reshape_logits, label)
|
| 69 |
+
|
| 70 |
+
return {
|
| 71 |
+
'loss': loss,
|
| 72 |
+
'logits': reshape_logits
|
| 73 |
+
}
|