riccorl commited on
Commit
38f3dfa
·
1 Parent(s): 7675939

Upload model

Browse files
Files changed (4) hide show
  1. config.json +22 -0
  2. configuration_relik.py +41 -0
  3. modeling_relik.py +976 -0
  4. pytorch_model.bin +3 -0
config.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "riccorl/relik-reader-aida-deberta-small",
3
+ "activation": "gelu",
4
+ "add_entity_embedding": null,
5
+ "additional_special_symbols": 101,
6
+ "architectures": [
7
+ "RelikReaderSpanModel"
8
+ ],
9
+ "auto_map": {
10
+ "AutoModel": "modeling_relik.RelikReaderSpanModel"
11
+ },
12
+ "default_reader_class": null,
13
+ "entity_type_loss": false,
14
+ "linears_hidden_size": 512,
15
+ "model_type": "relik-reader",
16
+ "num_layers": null,
17
+ "torch_dtype": "float32",
18
+ "training": false,
19
+ "transformer_model": "microsoft/deberta-v3-small",
20
+ "transformers_version": "4.33.3",
21
+ "use_last_k_layers": 1
22
+ }
configuration_relik.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ from transformers import AutoConfig
4
+ from transformers.configuration_utils import PretrainedConfig
5
+
6
+
7
+ class RelikReaderConfig(PretrainedConfig):
8
+ model_type = "relik-reader"
9
+
10
+ def __init__(
11
+ self,
12
+ transformer_model: str = "microsoft/deberta-v3-base",
13
+ additional_special_symbols: int = 101,
14
+ num_layers: Optional[int] = None,
15
+ activation: str = "gelu",
16
+ linears_hidden_size: Optional[int] = 512,
17
+ use_last_k_layers: int = 1,
18
+ entity_type_loss: bool = False,
19
+ add_entity_embedding: bool = None,
20
+ training: bool = False,
21
+ default_reader_class: Optional[str] = None,
22
+ **kwargs
23
+ ) -> None:
24
+ self.transformer_model = transformer_model
25
+ self.additional_special_symbols = additional_special_symbols
26
+ self.num_layers = num_layers
27
+ self.activation = activation
28
+ self.linears_hidden_size = linears_hidden_size
29
+ self.use_last_k_layers = use_last_k_layers
30
+ self.entity_type_loss = entity_type_loss
31
+ self.add_entity_embedding = (
32
+ True
33
+ if add_entity_embedding is None and entity_type_loss
34
+ else add_entity_embedding
35
+ )
36
+ self.training = training
37
+ self.default_reader_class = default_reader_class
38
+ super().__init__(**kwargs)
39
+
40
+
41
+ AutoConfig.register("relik-reader", RelikReaderConfig)
modeling_relik.py ADDED
@@ -0,0 +1,976 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Dict, Optional
2
+
3
+ import torch
4
+ from transformers import AutoModel, PreTrainedModel
5
+ from transformers.activations import ClippedGELUActivation, GELUActivation
6
+ from transformers.configuration_utils import PretrainedConfig
7
+ from transformers.modeling_utils import PoolerEndLogits
8
+
9
+ from .configuration_relik import RelikReaderConfig
10
+
11
+
12
+ class RelikReaderSample:
13
+ def __init__(self, **kwargs):
14
+ super().__setattr__("_d", {})
15
+ self._d = kwargs
16
+
17
+ def __getattribute__(self, item):
18
+ return super(RelikReaderSample, self).__getattribute__(item)
19
+
20
+ def __getattr__(self, item):
21
+ if item.startswith("__") and item.endswith("__"):
22
+ # this is likely some python library-specific variable (such as __deepcopy__ for copy)
23
+ # better follow standard behavior here
24
+ raise AttributeError(item)
25
+ elif item in self._d:
26
+ return self._d[item]
27
+ else:
28
+ return None
29
+
30
+ def __setattr__(self, key, value):
31
+ if key in self._d:
32
+ self._d[key] = value
33
+ else:
34
+ super().__setattr__(key, value)
35
+
36
+
37
+ activation2functions = {
38
+ "relu": torch.nn.ReLU(),
39
+ "gelu": GELUActivation(),
40
+ "gelu_10": ClippedGELUActivation(-10, 10),
41
+ }
42
+
43
+
44
+ class PoolerEndLogitsBi(PoolerEndLogits):
45
+ def __init__(self, config: PretrainedConfig):
46
+ super().__init__(config)
47
+ self.dense_1 = torch.nn.Linear(config.hidden_size, 2)
48
+
49
+ def forward(
50
+ self,
51
+ hidden_states: torch.FloatTensor,
52
+ start_states: Optional[torch.FloatTensor] = None,
53
+ start_positions: Optional[torch.LongTensor] = None,
54
+ p_mask: Optional[torch.FloatTensor] = None,
55
+ ) -> torch.FloatTensor:
56
+ if p_mask is not None:
57
+ p_mask = p_mask.unsqueeze(-1)
58
+ logits = super().forward(
59
+ hidden_states,
60
+ start_states,
61
+ start_positions,
62
+ p_mask,
63
+ )
64
+ return logits
65
+
66
+
67
+ class RelikReaderSpanModel(PreTrainedModel):
68
+ config_class = RelikReaderConfig
69
+
70
+ def __init__(self, config: RelikReaderConfig, *args, **kwargs):
71
+ super().__init__(config)
72
+ # Transformer model declaration
73
+ self.config = config
74
+ self.transformer_model = (
75
+ AutoModel.from_pretrained(self.config.transformer_model)
76
+ if self.config.num_layers is None
77
+ else AutoModel.from_pretrained(
78
+ self.config.transformer_model, num_hidden_layers=self.config.num_layers
79
+ )
80
+ )
81
+ self.transformer_model.resize_token_embeddings(
82
+ self.transformer_model.config.vocab_size
83
+ + self.config.additional_special_symbols
84
+ )
85
+
86
+ self.activation = self.config.activation
87
+ self.linears_hidden_size = self.config.linears_hidden_size
88
+ self.use_last_k_layers = self.config.use_last_k_layers
89
+
90
+ # named entity detection layers
91
+ self.ned_start_classifier = self._get_projection_layer(
92
+ self.activation, last_hidden=2, layer_norm=False
93
+ )
94
+ self.ned_end_classifier = PoolerEndLogits(self.transformer_model.config)
95
+
96
+ # END entity disambiguation layer
97
+ self.ed_start_projector = self._get_projection_layer(self.activation)
98
+ self.ed_end_projector = self._get_projection_layer(self.activation)
99
+
100
+ self.training = self.config.training
101
+
102
+ # criterion
103
+ self.criterion = torch.nn.CrossEntropyLoss()
104
+
105
+ def _get_projection_layer(
106
+ self,
107
+ activation: str,
108
+ last_hidden: Optional[int] = None,
109
+ input_hidden=None,
110
+ layer_norm: bool = True,
111
+ ) -> torch.nn.Sequential:
112
+ head_components = [
113
+ torch.nn.Dropout(0.1),
114
+ torch.nn.Linear(
115
+ self.transformer_model.config.hidden_size * self.use_last_k_layers
116
+ if input_hidden is None
117
+ else input_hidden,
118
+ self.linears_hidden_size,
119
+ ),
120
+ activation2functions[activation],
121
+ torch.nn.Dropout(0.1),
122
+ torch.nn.Linear(
123
+ self.linears_hidden_size,
124
+ self.linears_hidden_size if last_hidden is None else last_hidden,
125
+ ),
126
+ ]
127
+
128
+ if layer_norm:
129
+ head_components.append(
130
+ torch.nn.LayerNorm(
131
+ self.linears_hidden_size if last_hidden is None else last_hidden,
132
+ self.transformer_model.config.layer_norm_eps,
133
+ )
134
+ )
135
+
136
+ return torch.nn.Sequential(*head_components)
137
+
138
+ def _mask_logits(self, logits: torch.Tensor, mask: torch.Tensor) -> torch.Tensor:
139
+ mask = mask.unsqueeze(-1)
140
+ if next(self.parameters()).dtype == torch.float16:
141
+ logits = logits * (1 - mask) - 65500 * mask
142
+ else:
143
+ logits = logits * (1 - mask) - 1e30 * mask
144
+ return logits
145
+
146
+ def _get_model_features(
147
+ self,
148
+ input_ids: torch.Tensor,
149
+ attention_mask: torch.Tensor,
150
+ token_type_ids: Optional[torch.Tensor],
151
+ ):
152
+ model_input = {
153
+ "input_ids": input_ids,
154
+ "attention_mask": attention_mask,
155
+ "output_hidden_states": self.use_last_k_layers > 1,
156
+ }
157
+
158
+ if token_type_ids is not None:
159
+ model_input["token_type_ids"] = token_type_ids
160
+
161
+ model_output = self.transformer_model(**model_input)
162
+
163
+ if self.use_last_k_layers > 1:
164
+ model_features = torch.cat(
165
+ model_output[1][-self.use_last_k_layers :], dim=-1
166
+ )
167
+ else:
168
+ model_features = model_output[0]
169
+
170
+ return model_features
171
+
172
+ def compute_ned_end_logits(
173
+ self,
174
+ start_predictions,
175
+ start_labels,
176
+ model_features,
177
+ prediction_mask,
178
+ batch_size,
179
+ ) -> Optional[torch.Tensor]:
180
+ # todo: maybe when constraining on the spans,
181
+ # we should not use a prediction_mask for the end tokens.
182
+ # at least we should not during training imo
183
+ start_positions = start_labels if self.training else start_predictions
184
+ start_positions_indices = (
185
+ torch.arange(start_positions.size(1), device=start_positions.device)
186
+ .unsqueeze(0)
187
+ .expand(batch_size, -1)[start_positions > 0]
188
+ ).to(start_positions.device)
189
+
190
+ if len(start_positions_indices) > 0:
191
+ expanded_features = torch.cat(
192
+ [
193
+ model_features[i].unsqueeze(0).expand(x, -1, -1)
194
+ for i, x in enumerate(torch.sum(start_positions > 0, dim=-1))
195
+ if x > 0
196
+ ],
197
+ dim=0,
198
+ ).to(start_positions_indices.device)
199
+
200
+ expanded_prediction_mask = torch.cat(
201
+ [
202
+ prediction_mask[i].unsqueeze(0).expand(x, -1)
203
+ for i, x in enumerate(torch.sum(start_positions > 0, dim=-1))
204
+ if x > 0
205
+ ],
206
+ dim=0,
207
+ ).to(expanded_features.device)
208
+
209
+ end_logits = self.ned_end_classifier(
210
+ hidden_states=expanded_features,
211
+ start_positions=start_positions_indices,
212
+ p_mask=expanded_prediction_mask,
213
+ )
214
+
215
+ return end_logits
216
+
217
+ return None
218
+
219
+ def compute_classification_logits(
220
+ self,
221
+ model_features,
222
+ special_symbols_mask,
223
+ prediction_mask,
224
+ batch_size,
225
+ start_positions=None,
226
+ end_positions=None,
227
+ ) -> torch.Tensor:
228
+ if start_positions is None or end_positions is None:
229
+ start_positions = torch.zeros_like(prediction_mask)
230
+ end_positions = torch.zeros_like(prediction_mask)
231
+
232
+ model_start_features = self.ed_start_projector(model_features)
233
+ model_end_features = self.ed_end_projector(model_features)
234
+ model_end_features[start_positions > 0] = model_end_features[end_positions > 0]
235
+
236
+ model_ed_features = torch.cat(
237
+ [model_start_features, model_end_features], dim=-1
238
+ )
239
+
240
+ # computing ed features
241
+ classes_representations = torch.sum(special_symbols_mask, dim=1)[0].item()
242
+ special_symbols_representation = model_ed_features[special_symbols_mask].view(
243
+ batch_size, classes_representations, -1
244
+ )
245
+
246
+ logits = torch.bmm(
247
+ model_ed_features,
248
+ torch.permute(special_symbols_representation, (0, 2, 1)),
249
+ )
250
+
251
+ logits = self._mask_logits(logits, prediction_mask)
252
+
253
+ return logits
254
+
255
+ def forward(
256
+ self,
257
+ input_ids: torch.Tensor,
258
+ attention_mask: torch.Tensor,
259
+ token_type_ids: Optional[torch.Tensor] = None,
260
+ prediction_mask: Optional[torch.Tensor] = None,
261
+ special_symbols_mask: Optional[torch.Tensor] = None,
262
+ start_labels: Optional[torch.Tensor] = None,
263
+ end_labels: Optional[torch.Tensor] = None,
264
+ use_predefined_spans: bool = False,
265
+ *args,
266
+ **kwargs,
267
+ ) -> Dict[str, Any]:
268
+ batch_size, seq_len = input_ids.shape
269
+
270
+ model_features = self._get_model_features(
271
+ input_ids, attention_mask, token_type_ids
272
+ )
273
+
274
+ ned_start_labels = None
275
+
276
+ # named entity detection if required
277
+ if use_predefined_spans: # no need to compute spans
278
+ ned_start_logits, ned_start_probabilities, ned_start_predictions = (
279
+ None,
280
+ None,
281
+ torch.clone(start_labels)
282
+ if start_labels is not None
283
+ else torch.zeros_like(input_ids),
284
+ )
285
+ ned_end_logits, ned_end_probabilities, ned_end_predictions = (
286
+ None,
287
+ None,
288
+ torch.clone(end_labels)
289
+ if end_labels is not None
290
+ else torch.zeros_like(input_ids),
291
+ )
292
+
293
+ ned_start_predictions[ned_start_predictions > 0] = 1
294
+ ned_end_predictions[ned_end_predictions > 0] = 1
295
+
296
+ else: # compute spans
297
+ # start boundary prediction
298
+ ned_start_logits = self.ned_start_classifier(model_features)
299
+ ned_start_logits = self._mask_logits(ned_start_logits, prediction_mask)
300
+ ned_start_probabilities = torch.softmax(ned_start_logits, dim=-1)
301
+ ned_start_predictions = ned_start_probabilities.argmax(dim=-1)
302
+
303
+ # end boundary prediction
304
+ ned_start_labels = (
305
+ torch.zeros_like(start_labels) if start_labels is not None else None
306
+ )
307
+
308
+ if ned_start_labels is not None:
309
+ ned_start_labels[start_labels == -100] = -100
310
+ ned_start_labels[start_labels > 0] = 1
311
+
312
+ ned_end_logits = self.compute_ned_end_logits(
313
+ ned_start_predictions,
314
+ ned_start_labels,
315
+ model_features,
316
+ prediction_mask,
317
+ batch_size,
318
+ )
319
+
320
+ if ned_end_logits is not None:
321
+ ned_end_probabilities = torch.softmax(ned_end_logits, dim=-1)
322
+ ned_end_predictions = torch.argmax(ned_end_probabilities, dim=-1)
323
+ else:
324
+ ned_end_logits, ned_end_probabilities = None, None
325
+ ned_end_predictions = ned_start_predictions.new_zeros(batch_size)
326
+
327
+ # flattening end predictions
328
+ # (flattening can happen only if the
329
+ # end boundaries were not predicted using the gold labels)
330
+ if not self.training:
331
+ flattened_end_predictions = torch.clone(ned_start_predictions)
332
+ flattened_end_predictions[flattened_end_predictions > 0] = 0
333
+
334
+ batch_start_predictions = list()
335
+ for elem_idx in range(batch_size):
336
+ batch_start_predictions.append(
337
+ torch.where(ned_start_predictions[elem_idx] > 0)[0].tolist()
338
+ )
339
+
340
+ # check that the total number of start predictions
341
+ # is equal to the end predictions
342
+ total_start_predictions = sum(map(len, batch_start_predictions))
343
+ total_end_predictions = len(ned_end_predictions)
344
+ assert (
345
+ total_start_predictions == 0
346
+ or total_start_predictions == total_end_predictions
347
+ ), (
348
+ f"Total number of start predictions = {total_start_predictions}. "
349
+ f"Total number of end predictions = {total_end_predictions}"
350
+ )
351
+
352
+ curr_end_pred_num = 0
353
+ for elem_idx, bsp in enumerate(batch_start_predictions):
354
+ for sp in bsp:
355
+ ep = ned_end_predictions[curr_end_pred_num].item()
356
+ if ep < sp:
357
+ ep = sp
358
+
359
+ # if we already set this span throw it (no overlap)
360
+ if flattened_end_predictions[elem_idx, ep] == 1:
361
+ ned_start_predictions[elem_idx, sp] = 0
362
+ else:
363
+ flattened_end_predictions[elem_idx, ep] = 1
364
+
365
+ curr_end_pred_num += 1
366
+
367
+ ned_end_predictions = flattened_end_predictions
368
+
369
+ start_position, end_position = (
370
+ (start_labels, end_labels)
371
+ if self.training
372
+ else (ned_start_predictions, ned_end_predictions)
373
+ )
374
+
375
+ # Entity disambiguation
376
+ ed_logits = self.compute_classification_logits(
377
+ model_features,
378
+ special_symbols_mask,
379
+ prediction_mask,
380
+ batch_size,
381
+ start_position,
382
+ end_position,
383
+ )
384
+ ed_probabilities = torch.softmax(ed_logits, dim=-1)
385
+ ed_predictions = torch.argmax(ed_probabilities, dim=-1)
386
+
387
+ # output build
388
+ output_dict = dict(
389
+ batch_size=batch_size,
390
+ ned_start_logits=ned_start_logits,
391
+ ned_start_probabilities=ned_start_probabilities,
392
+ ned_start_predictions=ned_start_predictions,
393
+ ned_end_logits=ned_end_logits,
394
+ ned_end_probabilities=ned_end_probabilities,
395
+ ned_end_predictions=ned_end_predictions,
396
+ ed_logits=ed_logits,
397
+ ed_probabilities=ed_probabilities,
398
+ ed_predictions=ed_predictions,
399
+ )
400
+
401
+ # compute loss if labels
402
+ if start_labels is not None and end_labels is not None and self.training:
403
+ # named entity detection loss
404
+
405
+ # start
406
+ if ned_start_logits is not None:
407
+ ned_start_loss = self.criterion(
408
+ ned_start_logits.view(-1, ned_start_logits.shape[-1]),
409
+ ned_start_labels.view(-1),
410
+ )
411
+ else:
412
+ ned_start_loss = 0
413
+
414
+ # end
415
+ if ned_end_logits is not None:
416
+ ned_end_labels = torch.zeros_like(end_labels)
417
+ ned_end_labels[end_labels == -100] = -100
418
+ ned_end_labels[end_labels > 0] = 1
419
+
420
+ ned_end_loss = self.criterion(
421
+ ned_end_logits,
422
+ (
423
+ torch.arange(
424
+ ned_end_labels.size(1), device=ned_end_labels.device
425
+ )
426
+ .unsqueeze(0)
427
+ .expand(batch_size, -1)[ned_end_labels > 0]
428
+ ).to(ned_end_labels.device),
429
+ )
430
+
431
+ else:
432
+ ned_end_loss = 0
433
+
434
+ # entity disambiguation loss
435
+ start_labels[ned_start_labels != 1] = -100
436
+ ed_labels = torch.clone(start_labels)
437
+ ed_labels[end_labels > 0] = end_labels[end_labels > 0]
438
+ ed_loss = self.criterion(
439
+ ed_logits.view(-1, ed_logits.shape[-1]),
440
+ ed_labels.view(-1),
441
+ )
442
+
443
+ output_dict["ned_start_loss"] = ned_start_loss
444
+ output_dict["ned_end_loss"] = ned_end_loss
445
+ output_dict["ed_loss"] = ed_loss
446
+
447
+ output_dict["loss"] = ned_start_loss + ned_end_loss + ed_loss
448
+
449
+ return output_dict
450
+
451
+
452
+ class RelikReaderREModel(PreTrainedModel):
453
+ config_class = RelikReaderConfig
454
+
455
+ def __init__(self, config, *args, **kwargs):
456
+ super().__init__(config)
457
+ # Transformer model declaration
458
+ # self.transformer_model_name = transformer_model
459
+ self.config = config
460
+ self.transformer_model = (
461
+ AutoModel.from_pretrained(config.transformer_model)
462
+ if config.num_layers is None
463
+ else AutoModel.from_pretrained(
464
+ config.transformer_model, num_hidden_layers=config.num_layers
465
+ )
466
+ )
467
+ self.transformer_model.resize_token_embeddings(
468
+ self.transformer_model.config.vocab_size + config.additional_special_symbols
469
+ )
470
+
471
+ # named entity detection layers
472
+ self.ned_start_classifier = self._get_projection_layer(
473
+ config.activation, last_hidden=2, layer_norm=False
474
+ )
475
+
476
+ self.ned_end_classifier = PoolerEndLogitsBi(self.transformer_model.config)
477
+
478
+ self.relation_disambiguation_loss = (
479
+ config.relation_disambiguation_loss
480
+ if hasattr(config, "relation_disambiguation_loss")
481
+ else False
482
+ )
483
+
484
+ if self.config.entity_type_loss and self.config.add_entity_embedding:
485
+ input_hidden_ents = 3 * self.transformer_model.config.hidden_size
486
+ else:
487
+ input_hidden_ents = 2 * self.transformer_model.config.hidden_size
488
+
489
+ self.re_subject_projector = self._get_projection_layer(
490
+ config.activation, input_hidden=input_hidden_ents
491
+ )
492
+ self.re_object_projector = self._get_projection_layer(
493
+ config.activation, input_hidden=input_hidden_ents
494
+ )
495
+ self.re_relation_projector = self._get_projection_layer(config.activation)
496
+
497
+ if self.config.entity_type_loss or self.relation_disambiguation_loss:
498
+ self.re_entities_projector = self._get_projection_layer(
499
+ config.activation,
500
+ input_hidden=2 * self.transformer_model.config.hidden_size,
501
+ )
502
+ self.re_definition_projector = self._get_projection_layer(
503
+ config.activation,
504
+ )
505
+
506
+ self.re_classifier = self._get_projection_layer(
507
+ config.activation,
508
+ input_hidden=config.linears_hidden_size,
509
+ last_hidden=2,
510
+ layer_norm=False,
511
+ )
512
+
513
+ if self.config.entity_type_loss or self.relation_disambiguation_loss:
514
+ self.re_ed_classifier = self._get_projection_layer(
515
+ config.activation,
516
+ input_hidden=config.linears_hidden_size,
517
+ last_hidden=2,
518
+ layer_norm=False,
519
+ )
520
+
521
+ self.training = config.training
522
+
523
+ # criterion
524
+ self.criterion = torch.nn.CrossEntropyLoss()
525
+
526
+ def _get_projection_layer(
527
+ self,
528
+ activation: str,
529
+ last_hidden: Optional[int] = None,
530
+ input_hidden=None,
531
+ layer_norm: bool = True,
532
+ ) -> torch.nn.Sequential:
533
+ head_components = [
534
+ torch.nn.Dropout(0.1),
535
+ torch.nn.Linear(
536
+ self.transformer_model.config.hidden_size
537
+ * self.config.use_last_k_layers
538
+ if input_hidden is None
539
+ else input_hidden,
540
+ self.config.linears_hidden_size,
541
+ ),
542
+ activation2functions[activation],
543
+ torch.nn.Dropout(0.1),
544
+ torch.nn.Linear(
545
+ self.config.linears_hidden_size,
546
+ self.config.linears_hidden_size if last_hidden is None else last_hidden,
547
+ ),
548
+ ]
549
+
550
+ if layer_norm:
551
+ head_components.append(
552
+ torch.nn.LayerNorm(
553
+ self.config.linears_hidden_size
554
+ if last_hidden is None
555
+ else last_hidden,
556
+ self.transformer_model.config.layer_norm_eps,
557
+ )
558
+ )
559
+
560
+ return torch.nn.Sequential(*head_components)
561
+
562
+ def _mask_logits(self, logits: torch.Tensor, mask: torch.Tensor) -> torch.Tensor:
563
+ mask = mask.unsqueeze(-1)
564
+ if next(self.parameters()).dtype == torch.float16:
565
+ logits = logits * (1 - mask) - 65500 * mask
566
+ else:
567
+ logits = logits * (1 - mask) - 1e30 * mask
568
+ return logits
569
+
570
+ def _get_model_features(
571
+ self,
572
+ input_ids: torch.Tensor,
573
+ attention_mask: torch.Tensor,
574
+ token_type_ids: Optional[torch.Tensor],
575
+ ):
576
+ model_input = {
577
+ "input_ids": input_ids,
578
+ "attention_mask": attention_mask,
579
+ "output_hidden_states": self.config.use_last_k_layers > 1,
580
+ }
581
+
582
+ if token_type_ids is not None:
583
+ model_input["token_type_ids"] = token_type_ids
584
+
585
+ model_output = self.transformer_model(**model_input)
586
+
587
+ if self.config.use_last_k_layers > 1:
588
+ model_features = torch.cat(
589
+ model_output[1][-self.config.use_last_k_layers :], dim=-1
590
+ )
591
+ else:
592
+ model_features = model_output[0]
593
+
594
+ return model_features
595
+
596
+ def compute_ned_end_logits(
597
+ self,
598
+ start_predictions,
599
+ start_labels,
600
+ model_features,
601
+ prediction_mask,
602
+ batch_size,
603
+ mask_preceding: bool = False,
604
+ ) -> Optional[torch.Tensor]:
605
+ # todo: maybe when constraining on the spans,
606
+ # we should not use a prediction_mask for the end tokens.
607
+ # at least we should not during training imo
608
+ start_positions = start_labels if self.training else start_predictions
609
+ start_positions_indices = (
610
+ torch.arange(start_positions.size(1), device=start_positions.device)
611
+ .unsqueeze(0)
612
+ .expand(batch_size, -1)[start_positions > 0]
613
+ ).to(start_positions.device)
614
+
615
+ if len(start_positions_indices) > 0:
616
+ expanded_features = model_features.repeat_interleave(
617
+ torch.sum(start_positions > 0, dim=-1), dim=0
618
+ )
619
+ expanded_prediction_mask = prediction_mask.repeat_interleave(
620
+ torch.sum(start_positions > 0, dim=-1), dim=0
621
+ )
622
+ if mask_preceding:
623
+ expanded_prediction_mask[
624
+ torch.arange(
625
+ expanded_prediction_mask.shape[1],
626
+ device=expanded_prediction_mask.device,
627
+ )
628
+ < start_positions_indices.unsqueeze(1)
629
+ ] = 1
630
+ end_logits = self.ned_end_classifier(
631
+ hidden_states=expanded_features,
632
+ start_positions=start_positions_indices,
633
+ p_mask=expanded_prediction_mask,
634
+ )
635
+
636
+ return end_logits
637
+
638
+ return None
639
+
640
+ def compute_relation_logits(
641
+ self,
642
+ model_entity_features,
643
+ special_symbols_features,
644
+ ) -> torch.Tensor:
645
+ model_subject_features = self.re_subject_projector(model_entity_features)
646
+ model_object_features = self.re_object_projector(model_entity_features)
647
+ special_symbols_start_representation = self.re_relation_projector(
648
+ special_symbols_features
649
+ )
650
+ re_logits = torch.einsum(
651
+ "bse,bde,bfe->bsdfe",
652
+ model_subject_features,
653
+ model_object_features,
654
+ special_symbols_start_representation,
655
+ )
656
+ re_logits = self.re_classifier(re_logits)
657
+
658
+ return re_logits
659
+
660
+ def compute_entity_logits(
661
+ self,
662
+ model_entity_features,
663
+ special_symbols_features,
664
+ ) -> torch.Tensor:
665
+ model_ed_features = self.re_entities_projector(model_entity_features)
666
+ special_symbols_ed_representation = self.re_definition_projector(
667
+ special_symbols_features
668
+ )
669
+ logits = torch.einsum(
670
+ "bce,bde->bcde",
671
+ model_ed_features,
672
+ special_symbols_ed_representation,
673
+ )
674
+ logits = self.re_ed_classifier(logits)
675
+ start_logits = self._mask_logits(
676
+ logits,
677
+ (model_entity_features == -100)
678
+ .all(2)
679
+ .long()
680
+ .unsqueeze(2)
681
+ .repeat(1, 1, torch.sum(model_entity_features, dim=1)[0].item()),
682
+ )
683
+
684
+ return logits
685
+
686
+ def compute_loss(self, logits, labels, mask=None):
687
+ logits = logits.view(-1, logits.shape[-1])
688
+ labels = labels.view(-1).long()
689
+ if mask is not None:
690
+ return self.criterion(logits[mask], labels[mask])
691
+ return self.criterion(logits, labels)
692
+
693
+ def compute_ned_end_loss(self, ned_end_logits, end_labels):
694
+ if ned_end_logits is None:
695
+ return 0
696
+ ned_end_labels = torch.zeros_like(end_labels)
697
+ ned_end_labels[end_labels == -100] = -100
698
+ ned_end_labels[end_labels > 0] = 1
699
+ return self.compute_loss(ned_end_logits, ned_end_labels)
700
+
701
+ def compute_ned_type_loss(
702
+ self,
703
+ disambiguation_labels,
704
+ re_ned_entities_logits,
705
+ ned_type_logits,
706
+ re_entities_logits,
707
+ entity_types,
708
+ ):
709
+ if self.config.entity_type_loss and self.relation_disambiguation_loss:
710
+ return self.compute_loss(disambiguation_labels, re_ned_entities_logits)
711
+ if self.config.entity_type_loss:
712
+ return self.compute_loss(
713
+ disambiguation_labels[:, :, :entity_types], ned_type_logits
714
+ )
715
+ if self.relation_disambiguation_loss:
716
+ return self.compute_loss(disambiguation_labels, re_entities_logits)
717
+ return 0
718
+
719
+ def compute_relation_loss(self, relation_labels, re_logits):
720
+ return self.compute_loss(
721
+ re_logits, relation_labels, relation_labels.view(-1) != -100
722
+ )
723
+
724
+ def forward(
725
+ self,
726
+ input_ids: torch.Tensor,
727
+ attention_mask: torch.Tensor,
728
+ token_type_ids: torch.Tensor,
729
+ prediction_mask: Optional[torch.Tensor] = None,
730
+ special_symbols_mask: Optional[torch.Tensor] = None,
731
+ special_symbols_mask_entities: Optional[torch.Tensor] = None,
732
+ start_labels: Optional[torch.Tensor] = None,
733
+ end_labels: Optional[torch.Tensor] = None,
734
+ disambiguation_labels: Optional[torch.Tensor] = None,
735
+ relation_labels: Optional[torch.Tensor] = None,
736
+ is_validation: bool = False,
737
+ is_prediction: bool = False,
738
+ *args,
739
+ **kwargs,
740
+ ) -> Dict[str, Any]:
741
+ batch_size = input_ids.shape[0]
742
+
743
+ model_features = self._get_model_features(
744
+ input_ids, attention_mask, token_type_ids
745
+ )
746
+
747
+ # named entity detection
748
+ if is_prediction and start_labels is not None:
749
+ ned_start_logits, ned_start_probabilities, ned_start_predictions = (
750
+ None,
751
+ None,
752
+ torch.zeros_like(start_labels),
753
+ )
754
+ ned_end_logits, ned_end_probabilities, ned_end_predictions = (
755
+ None,
756
+ None,
757
+ torch.zeros_like(end_labels),
758
+ )
759
+
760
+ ned_start_predictions[start_labels > 0] = 1
761
+ ned_end_predictions[end_labels > 0] = 1
762
+ ned_end_predictions = ned_end_predictions[~(end_labels == -100).all(2)]
763
+ else:
764
+ # start boundary prediction
765
+ ned_start_logits = self.ned_start_classifier(model_features)
766
+ ned_start_logits = self._mask_logits(
767
+ ned_start_logits, prediction_mask
768
+ ) # why?
769
+ ned_start_probabilities = torch.softmax(ned_start_logits, dim=-1)
770
+ ned_start_predictions = ned_start_probabilities.argmax(dim=-1)
771
+
772
+ # end boundary prediction
773
+ ned_start_labels = (
774
+ torch.zeros_like(start_labels) if start_labels is not None else None
775
+ )
776
+
777
+ # start_labels contain entity id at their position, we just need 1 for start of entity
778
+ if ned_start_labels is not None:
779
+ ned_start_labels[start_labels == -100] = -100
780
+ ned_start_labels[start_labels > 0] = 1
781
+
782
+ # compute end logits only if there are any start predictions.
783
+ # For each start prediction, n end predictions are made
784
+ ned_end_logits = self.compute_ned_end_logits(
785
+ ned_start_predictions,
786
+ ned_start_labels,
787
+ model_features,
788
+ prediction_mask,
789
+ batch_size,
790
+ True,
791
+ )
792
+ # For each start prediction, n end predictions are made based on
793
+ # binary classification ie. argmax at each position.
794
+ ned_end_probabilities = torch.softmax(ned_end_logits, dim=-1)
795
+ ned_end_predictions = ned_end_probabilities.argmax(dim=-1)
796
+ if is_prediction or is_validation:
797
+ end_preds_count = ned_end_predictions.sum(1)
798
+ # If there are no end predictions for a start prediction, remove the start prediction
799
+ ned_start_predictions[ned_start_predictions == 1] = (
800
+ end_preds_count != 0
801
+ ).long()
802
+ ned_end_predictions = ned_end_predictions[end_preds_count != 0]
803
+
804
+ if end_labels is not None:
805
+ end_labels = end_labels[~(end_labels == -100).all(2)]
806
+
807
+ start_position, end_position = (
808
+ (start_labels, end_labels)
809
+ if (not is_prediction and not is_validation)
810
+ else (ned_start_predictions, ned_end_predictions)
811
+ )
812
+
813
+ start_counts = (start_position > 0).sum(1)
814
+ ned_end_predictions = ned_end_predictions.split(start_counts.tolist())
815
+
816
+ # We can only predict relations if we have start and end predictions
817
+ if (end_position > 0).sum() > 0:
818
+ ends_count = (end_position > 0).sum(1)
819
+ model_subject_features = torch.cat(
820
+ [
821
+ torch.repeat_interleave(
822
+ model_features[start_position > 0], ends_count, dim=0
823
+ ), # start position features
824
+ torch.repeat_interleave(model_features, start_counts, dim=0)[
825
+ end_position > 0
826
+ ], # end position features
827
+ ],
828
+ dim=-1,
829
+ )
830
+ ents_count = torch.nn.utils.rnn.pad_sequence(
831
+ torch.split(ends_count, start_counts.tolist()),
832
+ batch_first=True,
833
+ padding_value=0,
834
+ ).sum(1)
835
+ model_subject_features = torch.nn.utils.rnn.pad_sequence(
836
+ torch.split(model_subject_features, ents_count.tolist()),
837
+ batch_first=True,
838
+ padding_value=-100,
839
+ )
840
+
841
+ if is_validation or is_prediction:
842
+ model_subject_features = model_subject_features[:, :30, :]
843
+
844
+ # entity disambiguation. Here relation_disambiguation_loss would only be useful to
845
+ # reduce the number of candidate relations for the next step, but currently unused.
846
+ if self.config.entity_type_loss or self.relation_disambiguation_loss:
847
+ (re_ned_entities_logits) = self.compute_entity_logits(
848
+ model_subject_features,
849
+ model_features[
850
+ special_symbols_mask | special_symbols_mask_entities
851
+ ].view(batch_size, -1, model_features.shape[-1]),
852
+ )
853
+ entity_types = torch.sum(special_symbols_mask_entities, dim=1)[0].item()
854
+ ned_type_logits = re_ned_entities_logits[:, :, :entity_types]
855
+ re_entities_logits = re_ned_entities_logits[:, :, entity_types:]
856
+
857
+ if self.config.entity_type_loss:
858
+ ned_type_probabilities = torch.softmax(ned_type_logits, dim=-1)
859
+ ned_type_predictions = ned_type_probabilities.argmax(dim=-1)
860
+ ned_type_predictions = ned_type_predictions.argmax(dim=-1)
861
+ if self.config.add_entity_embedding:
862
+ special_symbols_representation = model_features[
863
+ special_symbols_mask
864
+ ].view(batch_size, entity_types, -1)
865
+
866
+ entities_representation = torch.einsum(
867
+ "bsp,bpe->bse",
868
+ ned_type_probabilities,
869
+ special_symbols_representation,
870
+ )
871
+ model_subject_features = torch.cat(
872
+ [model_subject_features, entities_representation], dim=-1
873
+ )
874
+ re_entities_probabilities = torch.softmax(re_entities_logits, dim=-1)
875
+ re_entities_predictions = re_entities_probabilities.argmax(dim=-1)
876
+ else:
877
+ (
878
+ ned_type_logits,
879
+ ned_type_probabilities,
880
+ re_entities_logits,
881
+ re_entities_probabilities,
882
+ ) = (None, None, None, None)
883
+ ned_type_predictions, re_entities_predictions = (
884
+ torch.zeros([batch_size, 1], dtype=torch.long).to(input_ids.device),
885
+ torch.zeros([batch_size, 1], dtype=torch.long).to(input_ids.device),
886
+ )
887
+
888
+ # Compute relation logits
889
+ re_logits = self.compute_relation_logits(
890
+ model_subject_features,
891
+ model_features[special_symbols_mask].view(
892
+ batch_size, -1, model_features.shape[-1]
893
+ ),
894
+ )
895
+
896
+ re_probabilities = torch.softmax(re_logits, dim=-1)
897
+ # we set a thresshold instead of argmax in cause it needs to be tweaked
898
+ re_predictions = re_probabilities[:, :, :, :, 1] > 0.5
899
+ # re_predictions = re_probabilities.argmax(dim=-1)
900
+ re_probabilities = re_probabilities[:, :, :, :, 1]
901
+
902
+ else:
903
+ (
904
+ ned_type_logits,
905
+ ned_type_probabilities,
906
+ re_entities_logits,
907
+ re_entities_probabilities,
908
+ ) = (None, None, None, None)
909
+ ned_type_predictions, re_entities_predictions = (
910
+ torch.zeros([batch_size, 1], dtype=torch.long).to(input_ids.device),
911
+ torch.zeros([batch_size, 1], dtype=torch.long).to(input_ids.device),
912
+ )
913
+ re_logits, re_probabilities, re_predictions = (
914
+ torch.zeros(
915
+ [batch_size, 1, 1, special_symbols_mask.sum(1)[0]], dtype=torch.long
916
+ ).to(input_ids.device),
917
+ torch.zeros(
918
+ [batch_size, 1, 1, special_symbols_mask.sum(1)[0]], dtype=torch.long
919
+ ).to(input_ids.device),
920
+ torch.zeros(
921
+ [batch_size, 1, 1, special_symbols_mask.sum(1)[0]], dtype=torch.long
922
+ ).to(input_ids.device),
923
+ )
924
+
925
+ # output build
926
+ output_dict = dict(
927
+ batch_size=batch_size,
928
+ ned_start_logits=ned_start_logits,
929
+ ned_start_probabilities=ned_start_probabilities,
930
+ ned_start_predictions=ned_start_predictions,
931
+ ned_end_logits=ned_end_logits,
932
+ ned_end_probabilities=ned_end_probabilities,
933
+ ned_end_predictions=ned_end_predictions,
934
+ ned_type_logits=ned_type_logits,
935
+ ned_type_probabilities=ned_type_probabilities,
936
+ ned_type_predictions=ned_type_predictions,
937
+ re_entities_logits=re_entities_logits,
938
+ re_entities_probabilities=re_entities_probabilities,
939
+ re_entities_predictions=re_entities_predictions,
940
+ re_logits=re_logits,
941
+ re_probabilities=re_probabilities,
942
+ re_predictions=re_predictions,
943
+ )
944
+
945
+ if (
946
+ start_labels is not None
947
+ and end_labels is not None
948
+ and relation_labels is not None
949
+ ):
950
+ ned_start_loss = self.compute_loss(ned_start_logits, ned_start_labels)
951
+ ned_end_loss = self.compute_ned_end_loss(ned_end_logits, end_labels)
952
+ if self.config.entity_type_loss or self.relation_disambiguation_loss:
953
+ ned_type_loss = self.compute_ned_type_loss(
954
+ disambiguation_labels,
955
+ re_ned_entities_logits,
956
+ ned_type_logits,
957
+ re_entities_logits,
958
+ entity_types,
959
+ )
960
+ relation_loss = self.compute_relation_loss(relation_labels, re_logits)
961
+ # compute loss. We can skip the relation loss if we are in the first epochs (optional)
962
+ if self.config.entity_type_loss or self.relation_disambiguation_loss:
963
+ output_dict["loss"] = (
964
+ ned_start_loss + ned_end_loss + relation_loss + ned_type_loss
965
+ ) / 4
966
+ output_dict["ned_type_loss"] = ned_type_loss
967
+ else:
968
+ output_dict["loss"] = (
969
+ ned_start_loss + ned_end_loss + relation_loss
970
+ ) / 3
971
+
972
+ output_dict["ned_start_loss"] = ned_start_loss
973
+ output_dict["ned_end_loss"] = ned_end_loss
974
+ output_dict["re_loss"] = relation_loss
975
+
976
+ return output_dict
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33939d8ecc8a9199a8ead78254dd3ed4e3dd40f4d50847979678f1c1465f289d
3
+ size 577138490