UMCU commited on
Commit
2e88273
·
verified ·
1 Parent(s): 065e257

Upload modeling.py

Browse files
Files changed (1) hide show
  1. modeling.py +111 -0
modeling.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ from transformers import AutoModel, PreTrainedModel
5
+ from transformers.modeling_outputs import SequenceClassifierOutput
6
+
7
+
8
+ class CustomSequenceClassificationModel(PreTrainedModel):
9
+ """Sequence classification model with a configurable GELU + dropout dense head."""
10
+
11
+ def __init__(
12
+ self,
13
+ config,
14
+ head_layers: int = 1,
15
+ head_dropout: float = 0.1,
16
+ ):
17
+ super().__init__(config)
18
+ self.num_labels = config.num_labels
19
+ self.config = config
20
+ self.backbone = AutoModel.from_config(config)
21
+
22
+ hidden_size = getattr(config, "hidden_size", None)
23
+ if hidden_size is None:
24
+ raise ValueError(
25
+ "Backbone config is missing 'hidden_size'; cannot build custom head."
26
+ )
27
+
28
+ self.classifier = self._build_head(
29
+ input_dim=hidden_size,
30
+ output_dim=self.num_labels,
31
+ head_layers=head_layers,
32
+ head_dropout=head_dropout,
33
+ )
34
+ self.post_init()
35
+
36
+ @staticmethod
37
+ def _build_head(
38
+ input_dim: int, output_dim: int, head_layers: int, head_dropout: float
39
+ ) -> nn.Module:
40
+ if head_layers < 1:
41
+ raise ValueError("head_layers must be >= 1")
42
+
43
+ # head_layers includes the final projection layer.
44
+ # For head_layers=1 this is equivalent to a single linear classifier.
45
+ if head_layers == 1:
46
+ return nn.Linear(input_dim, output_dim)
47
+
48
+ layers = []
49
+ for _ in range(head_layers - 1):
50
+ layers.extend(
51
+ [
52
+ nn.Linear(input_dim, input_dim),
53
+ nn.GELU(),
54
+ nn.Dropout(head_dropout),
55
+ ]
56
+ )
57
+ layers.append(nn.Linear(input_dim, output_dim))
58
+ return nn.Sequential(*layers)
59
+
60
+ def _pooled_representation(self, outputs) -> torch.Tensor:
61
+ if hasattr(outputs, "pooler_output") and outputs.pooler_output is not None:
62
+ return outputs.pooler_output
63
+ return outputs.last_hidden_state[:, 0]
64
+
65
+ def forward(
66
+ self,
67
+ input_ids=None,
68
+ attention_mask=None,
69
+ token_type_ids=None,
70
+ labels=None,
71
+ **kwargs,
72
+ ):
73
+ backbone_inputs = {
74
+ "input_ids": input_ids,
75
+ "attention_mask": attention_mask,
76
+ **kwargs,
77
+ }
78
+ if token_type_ids is not None:
79
+ backbone_inputs["token_type_ids"] = token_type_ids
80
+
81
+ backbone_outputs = self.backbone(**backbone_inputs)
82
+
83
+ pooled = self._pooled_representation(backbone_outputs)
84
+ logits = self.classifier(pooled)
85
+
86
+ loss = None
87
+ if labels is not None:
88
+ if self.config.problem_type is None:
89
+ if self.num_labels == 1:
90
+ self.config.problem_type = "regression"
91
+ elif torch.is_floating_point(labels):
92
+ self.config.problem_type = "multi_label_classification"
93
+ else:
94
+ self.config.problem_type = "single_label_classification"
95
+
96
+ if self.config.problem_type == "regression":
97
+ loss_fct = nn.MSELoss()
98
+ loss = loss_fct(logits.squeeze(), labels.squeeze())
99
+ elif self.config.problem_type == "single_label_classification":
100
+ loss_fct = nn.CrossEntropyLoss()
101
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
102
+ else:
103
+ loss_fct = nn.BCEWithLogitsLoss()
104
+ loss = loss_fct(logits, labels)
105
+
106
+ return SequenceClassifierOutput(
107
+ loss=loss,
108
+ logits=logits,
109
+ hidden_states=backbone_outputs.hidden_states,
110
+ attentions=backbone_outputs.attentions,
111
+ )