UMCU commited on
Commit
b2df892
·
verified ·
1 Parent(s): 76c1273

Upload 9 files

Browse files
Files changed (9) hide show
  1. config.json +166 -0
  2. merges.txt +0 -0
  3. model.safetensors +3 -0
  4. modeling.py +1495 -0
  5. special_tokens_map.json +51 -0
  6. split.json +0 -0
  7. tokenizer.json +0 -0
  8. tokenizer_config.json +60 -0
  9. vocab.json +0 -0
config.json ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens_ids": [],
3
+ "architectures": [
4
+ "TokenClassificationModel"
5
+ ],
6
+ "attention_probs_dropout_prob": 0.1,
7
+ "auto_map": {
8
+ "AutoModelForTokenClassification": "modeling.TokenClassificationModel"
9
+ },
10
+ "backbone_model_name": "DTAI-KULeuven/robbert-2023-dutch-large",
11
+ "bos_token_id": 0,
12
+ "class_weights": [
13
+ 1.0,
14
+ 50.0,
15
+ 50.0,
16
+ 50.0,
17
+ 50.0,
18
+ 50.0,
19
+ 50.0,
20
+ 50.0,
21
+ 50.0,
22
+ 50.0,
23
+ 10.665912628173828,
24
+ 50.0,
25
+ 50.0,
26
+ 50.0,
27
+ 29.357572555541992,
28
+ 50.0,
29
+ 50.0,
30
+ 30.548648834228516,
31
+ 11.926840782165527,
32
+ 50.0,
33
+ 50.0,
34
+ 50.0,
35
+ 50.0,
36
+ 50.0,
37
+ 50.0,
38
+ 50.0,
39
+ 50.0,
40
+ 50.0,
41
+ 50.0,
42
+ 33.347381591796875,
43
+ 10.019938468933105,
44
+ 50.0,
45
+ 50.0,
46
+ 50.0,
47
+ 50.0,
48
+ 47.132938385009766,
49
+ 50.0,
50
+ 50.0,
51
+ 50.0
52
+ ],
53
+ "classifier_dropout": 0.1,
54
+ "classifier_hidden_layers": [
55
+ 768,
56
+ 768,
57
+ 768
58
+ ],
59
+ "cls_token_id": 0,
60
+ "custom_model_type": "TokenClassificationModel",
61
+ "dtype": "bfloat16",
62
+ "eos_token_id": 3,
63
+ "hidden_act": "gelu",
64
+ "hidden_dropout_prob": 0.1,
65
+ "hidden_size": 1024,
66
+ "id2label": {
67
+ "0": "O",
68
+ "1": "B-AGE",
69
+ "2": "I-AGE",
70
+ "3": "B-BUILDINGNUM",
71
+ "4": "I-BUILDINGNUM",
72
+ "5": "B-CITY",
73
+ "6": "I-CITY",
74
+ "7": "B-CREDITCARDNUMBER",
75
+ "8": "I-CREDITCARDNUMBER",
76
+ "9": "B-DATE",
77
+ "10": "I-DATE",
78
+ "11": "B-DRIVERLICENSENUM",
79
+ "12": "I-DRIVERLICENSENUM",
80
+ "13": "B-EMAIL",
81
+ "14": "I-EMAIL",
82
+ "15": "B-GENDER",
83
+ "16": "I-GENDER",
84
+ "17": "B-GIVENNAME",
85
+ "18": "I-GIVENNAME",
86
+ "19": "B-IDCARDNUM",
87
+ "20": "I-IDCARDNUM",
88
+ "21": "B-PASSPORTNUM",
89
+ "22": "I-PASSPORTNUM",
90
+ "23": "B-SEX",
91
+ "24": "I-SEX",
92
+ "25": "B-SOCIALNUM",
93
+ "26": "I-SOCIALNUM",
94
+ "27": "B-STREET",
95
+ "28": "I-STREET",
96
+ "29": "B-SURNAME",
97
+ "30": "I-SURNAME",
98
+ "31": "B-TAXNUM",
99
+ "32": "I-TAXNUM",
100
+ "33": "B-TELEPHONENUM",
101
+ "34": "I-TELEPHONENUM",
102
+ "35": "B-TITLE",
103
+ "36": "I-TITLE",
104
+ "37": "B-ZIPCODE",
105
+ "38": "I-ZIPCODE"
106
+ },
107
+ "initializer_range": 0.02,
108
+ "intermediate_size": 4096,
109
+ "label2id": {
110
+ "B-AGE": 1,
111
+ "B-BUILDINGNUM": 3,
112
+ "B-CITY": 5,
113
+ "B-CREDITCARDNUMBER": 7,
114
+ "B-DATE": 9,
115
+ "B-DRIVERLICENSENUM": 11,
116
+ "B-EMAIL": 13,
117
+ "B-GENDER": 15,
118
+ "B-GIVENNAME": 17,
119
+ "B-IDCARDNUM": 19,
120
+ "B-PASSPORTNUM": 21,
121
+ "B-SEX": 23,
122
+ "B-SOCIALNUM": 25,
123
+ "B-STREET": 27,
124
+ "B-SURNAME": 29,
125
+ "B-TAXNUM": 31,
126
+ "B-TELEPHONENUM": 33,
127
+ "B-TITLE": 35,
128
+ "B-ZIPCODE": 37,
129
+ "I-AGE": 2,
130
+ "I-BUILDINGNUM": 4,
131
+ "I-CITY": 6,
132
+ "I-CREDITCARDNUMBER": 8,
133
+ "I-DATE": 10,
134
+ "I-DRIVERLICENSENUM": 12,
135
+ "I-EMAIL": 14,
136
+ "I-GENDER": 16,
137
+ "I-GIVENNAME": 18,
138
+ "I-IDCARDNUM": 20,
139
+ "I-PASSPORTNUM": 22,
140
+ "I-SEX": 24,
141
+ "I-SOCIALNUM": 26,
142
+ "I-STREET": 28,
143
+ "I-SURNAME": 30,
144
+ "I-TAXNUM": 32,
145
+ "I-TELEPHONENUM": 34,
146
+ "I-TITLE": 36,
147
+ "I-ZIPCODE": 38,
148
+ "O": 0
149
+ },
150
+ "layer_norm_eps": 1e-05,
151
+ "mask_token_id": 4,
152
+ "max_position_embeddings": 514,
153
+ "model_type": "roberta",
154
+ "num_attention_heads": 16,
155
+ "num_hidden_layers": 24,
156
+ "pad_token_id": 1,
157
+ "position_embedding_type": "absolute",
158
+ "requires_trust_remote_code": true,
159
+ "sep_token_id": 3,
160
+ "tokenizer_class": "RobertaTokenizerFast",
161
+ "transformers_version": "4.57.6",
162
+ "type_vocab_size": 1,
163
+ "unk_token_id": 2,
164
+ "use_cache": true,
165
+ "vocab_size": 50000
166
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:00e1aa055085f866f4a14ed8383ecfad1190f9de798d2519e7e6fae398acbd4c
3
+ size 714222406
modeling.py ADDED
@@ -0,0 +1,1495 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from itertools import islice
2
+ from typing import Dict, List, Optional, Tuple, Union
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ from torchcrf import CRF
7
+ from transformers import PretrainedConfig, PreTrainedModel
8
+ from transformers.modeling_outputs import TokenClassifierOutput
9
+
10
+ try:
11
+ from transformers.models.eurobert.modeling_eurobert import EuroBertModel
12
+ except Exception:
13
+ try:
14
+ from transformers import EuroBertModel
15
+ except Exception:
16
+ EuroBertModel = None
17
+ print("COULD NOT IMPORT EUROBERT MODEL")
18
+
19
+ # Large negative number for masking impossible transitions
20
+ LARGE_NEGATIVE_NUMBER = -1e9
21
+ NUM_PER_LAYER = 16
22
+
23
+
24
+ def _build_backbone_from_config(config):
25
+ """
26
+ Build a backbone model structure from config only.
27
+ Never call from_pretrained() here; outer model loading will restore weights.
28
+ """
29
+ from transformers import AutoConfig, AutoModel
30
+
31
+ backbone_name = getattr(config, "backbone_model_name", None)
32
+ if backbone_name is None:
33
+ backbone_name = getattr(config, "_name_or_path", None)
34
+
35
+ if backbone_name is None:
36
+ raise ValueError(
37
+ "config.backbone_model_name (or config._name_or_path) is required to load backbone"
38
+ )
39
+
40
+ backbone_config = AutoConfig.from_pretrained(
41
+ backbone_name,
42
+ trust_remote_code=True,
43
+ )
44
+
45
+ if hasattr(config, "hidden_dropout_prob"):
46
+ backbone_config.hidden_dropout_prob = getattr(
47
+ config, "hidden_dropout_prob", 0.1
48
+ )
49
+
50
+ if hasattr(config, "num_labels"):
51
+ backbone_config.num_labels = getattr(config, "num_labels")
52
+
53
+ if "eurobert" in backbone_name.lower() and EuroBertModel is not None:
54
+ backbone = EuroBertModel(backbone_config)
55
+ else:
56
+ backbone = AutoModel.from_config(
57
+ backbone_config,
58
+ trust_remote_code=True,
59
+ )
60
+
61
+ if getattr(config, "backbone_model_name", None) is None:
62
+ config.backbone_model_name = backbone_name
63
+
64
+ return backbone, backbone_name
65
+
66
+
67
+ class MultiHeadCRFConfig(PretrainedConfig):
68
+ """
69
+ Configuration class for Multi-Head CRF models.
70
+ """
71
+
72
+ model_type = "multihead-crf-tagger"
73
+
74
+ def __init__(
75
+ self,
76
+ entity_types: Optional[List[str]] = None,
77
+ number_of_layers_per_head: int = 1,
78
+ crf_reduction: str = "mean",
79
+ freeze_backbone: bool = False,
80
+ num_frozen_encoders: int = 0,
81
+ classifier_dropout: float = 0.1,
82
+ classifier_hidden_layers: Optional[Tuple] = None,
83
+ class_weights: Optional[List[float]] = None,
84
+ backbone_model_name: Optional[str] = None,
85
+ **kwargs,
86
+ ):
87
+ self.entity_types = entity_types or []
88
+ self.number_of_layers_per_head = number_of_layers_per_head
89
+ self.crf_reduction = crf_reduction
90
+ self.freeze_backbone = freeze_backbone
91
+ self.num_frozen_encoders = num_frozen_encoders
92
+ self.classifier_dropout = classifier_dropout
93
+ self.classifier_hidden_layers = classifier_hidden_layers
94
+ self.class_weights = class_weights
95
+ self.backbone_model_name = backbone_model_name
96
+ super().__init__(**kwargs)
97
+
98
+
99
+ class MultiHeadCRF(nn.Module):
100
+ """
101
+ Custom CRF implementation with BIO transition masking.
102
+ """
103
+
104
+ def __init__(self, num_tags: int, batch_first: bool = True) -> None:
105
+ if num_tags <= 0:
106
+ raise ValueError(f"invalid number of tags: {num_tags}")
107
+ super().__init__()
108
+ self.num_tags = num_tags
109
+ self.batch_first = batch_first
110
+ self.start_transitions = nn.Parameter(torch.empty(num_tags))
111
+ self.end_transitions = nn.Parameter(torch.empty(num_tags))
112
+ self.transitions = nn.Parameter(torch.empty(num_tags, num_tags))
113
+
114
+ self.reset_parameters()
115
+ self.mask_impossible_transitions()
116
+
117
+ def reset_parameters(self) -> None:
118
+ nn.init.uniform_(self.start_transitions, -0.1, 0.1)
119
+ nn.init.uniform_(self.end_transitions, -0.1, 0.1)
120
+ nn.init.uniform_(self.transitions, -0.1, 0.1)
121
+
122
+ def mask_impossible_transitions(self) -> None:
123
+ with torch.no_grad():
124
+ if self.num_tags > 2:
125
+ self.start_transitions[2] = LARGE_NEGATIVE_NUMBER
126
+ self.transitions[0][2] = LARGE_NEGATIVE_NUMBER
127
+
128
+ if self.num_tags > 3:
129
+ self.start_transitions[3] = LARGE_NEGATIVE_NUMBER
130
+ for i in range(3):
131
+ self.transitions[i][3] = LARGE_NEGATIVE_NUMBER
132
+ for i in range(3):
133
+ self.transitions[3][i] = LARGE_NEGATIVE_NUMBER
134
+
135
+ def __repr__(self) -> str:
136
+ return f"{self.__class__.__name__}(num_tags={self.num_tags})"
137
+
138
+ def forward(
139
+ self,
140
+ emissions: torch.Tensor,
141
+ tags: torch.Tensor,
142
+ mask: Optional[torch.Tensor] = None,
143
+ reduction: str = "mean",
144
+ ) -> torch.Tensor:
145
+ self._validate(emissions, tags=tags, mask=mask)
146
+ if reduction not in ("none", "sum", "mean", "token_mean"):
147
+ raise ValueError(f"invalid reduction: {reduction}")
148
+ if mask is None:
149
+ mask = torch.ones_like(tags, dtype=torch.uint8)
150
+
151
+ device = emissions.device
152
+ tags = tags.to(device)
153
+ mask = mask.to(device)
154
+
155
+ if self.batch_first:
156
+ emissions = emissions.transpose(0, 1)
157
+ tags = tags.transpose(0, 1)
158
+ mask = mask.transpose(0, 1)
159
+
160
+ numerator = self._compute_score(emissions, tags, mask)
161
+ denominator = self._compute_normalizer(emissions, mask)
162
+ llh = numerator - denominator
163
+ nllh = -llh
164
+
165
+ if reduction == "none":
166
+ return nllh
167
+ if reduction == "sum":
168
+ return nllh.sum()
169
+ if reduction == "mean":
170
+ return nllh.mean()
171
+ return nllh.sum() / mask.type_as(emissions).sum()
172
+
173
+ def decode(
174
+ self, emissions: torch.Tensor, mask: Optional[torch.Tensor] = None
175
+ ) -> List[List[int]]:
176
+ self._validate(emissions, mask=mask)
177
+ if mask is None:
178
+ mask = emissions.new_ones(emissions.shape[:2], dtype=torch.uint8)
179
+
180
+ if self.batch_first:
181
+ emissions = emissions.transpose(0, 1)
182
+ mask = mask.transpose(0, 1)
183
+
184
+ return self._viterbi_decode(emissions, mask)
185
+
186
+ def _validate(
187
+ self,
188
+ emissions: torch.Tensor,
189
+ tags: Optional[torch.Tensor] = None,
190
+ mask: Optional[torch.Tensor] = None,
191
+ ) -> None:
192
+ if emissions.dim() != 3:
193
+ raise ValueError(
194
+ f"emissions must have dimension of 3, got {emissions.dim()}"
195
+ )
196
+ if emissions.size(2) != self.num_tags:
197
+ raise ValueError(
198
+ f"expected last dimension of emissions is {self.num_tags}, "
199
+ f"got {emissions.size(2)}"
200
+ )
201
+
202
+ if tags is not None and emissions.shape[:2] != tags.shape:
203
+ raise ValueError(
204
+ "the first two dimensions of emissions and tags must match, "
205
+ f"got {tuple(emissions.shape[:2])} and {tuple(tags.shape)}"
206
+ )
207
+
208
+ if mask is not None:
209
+ if emissions.shape[:2] != mask.shape:
210
+ raise ValueError(
211
+ "the first two dimensions of emissions and mask must match, "
212
+ f"got {tuple(emissions.shape[:2])} and {tuple(mask.shape)}"
213
+ )
214
+ no_empty_seq = not self.batch_first and mask[0].all()
215
+ no_empty_seq_bf = self.batch_first and mask[:, 0].all()
216
+ if not no_empty_seq and not no_empty_seq_bf:
217
+ raise ValueError("mask of the first timestep must all be on")
218
+
219
+ def _compute_score(
220
+ self, emissions: torch.Tensor, tags: torch.Tensor, mask: torch.Tensor
221
+ ) -> torch.Tensor:
222
+ assert emissions.dim() == 3 and tags.dim() == 2
223
+ assert emissions.shape[:2] == tags.shape
224
+ assert emissions.size(2) == self.num_tags
225
+ assert mask.shape == tags.shape
226
+ assert mask[0].all()
227
+
228
+ device = emissions.device
229
+ tags = tags.to(device)
230
+ mask = mask.to(device)
231
+
232
+ seq_length, batch_size = tags.shape
233
+ mask = mask.type_as(emissions)
234
+
235
+ batch_indices = torch.arange(batch_size, device=device)
236
+ score = self.start_transitions[tags[0]]
237
+ score += emissions[0, batch_indices, tags[0]]
238
+
239
+ for i in range(1, seq_length):
240
+ score += self.transitions[tags[i - 1], tags[i]] * mask[i]
241
+ score += emissions[i, batch_indices, tags[i]] * mask[i]
242
+
243
+ seq_ends = mask.long().sum(dim=0) - 1
244
+ last_tags = tags[seq_ends, batch_indices]
245
+ score += self.end_transitions[last_tags]
246
+
247
+ return score
248
+
249
+ def _compute_normalizer(
250
+ self, emissions: torch.Tensor, mask: torch.Tensor
251
+ ) -> torch.Tensor:
252
+ assert emissions.dim() == 3 and mask.dim() == 2
253
+ assert emissions.shape[:2] == mask.shape
254
+ assert emissions.size(2) == self.num_tags
255
+ assert mask[0].all()
256
+
257
+ seq_length = emissions.size(0)
258
+ score = self.start_transitions + emissions[0]
259
+
260
+ for i in range(1, seq_length):
261
+ broadcast_score = score.unsqueeze(2)
262
+ broadcast_emissions = emissions[i].unsqueeze(1)
263
+ next_score = broadcast_score + self.transitions + broadcast_emissions
264
+ next_score = torch.logsumexp(next_score, dim=1)
265
+ score = torch.where(mask[i].unsqueeze(1).bool(), next_score, score)
266
+
267
+ score += self.end_transitions
268
+ return torch.logsumexp(score, dim=1)
269
+
270
+ def _viterbi_decode(
271
+ self, emissions: torch.Tensor, mask: torch.Tensor
272
+ ) -> List[List[int]]:
273
+ assert emissions.dim() == 3 and mask.dim() == 2
274
+ assert emissions.shape[:2] == mask.shape
275
+ assert emissions.size(2) == self.num_tags
276
+ assert mask[0].all()
277
+
278
+ seq_length, batch_size = mask.shape
279
+ score = self.start_transitions + emissions[0]
280
+ history = []
281
+
282
+ for i in range(1, seq_length):
283
+ broadcast_score = score.unsqueeze(2)
284
+ broadcast_emission = emissions[i].unsqueeze(1)
285
+ next_score = broadcast_score + self.transitions + broadcast_emission
286
+ next_score, indices = next_score.max(dim=1)
287
+ score = torch.where(mask[i].unsqueeze(1).bool(), next_score, score)
288
+ history.append(indices)
289
+
290
+ score += self.end_transitions
291
+
292
+ seq_ends = mask.long().sum(dim=0) - 1
293
+ best_tags_list = []
294
+
295
+ for idx in range(batch_size):
296
+ _, best_last_tag = score[idx].max(dim=0)
297
+ best_tags = [best_last_tag.item()]
298
+
299
+ for hist in reversed(history[: seq_ends[idx]]):
300
+ best_last_tag = hist[idx][best_tags[-1]]
301
+ best_tags.append(best_last_tag.item())
302
+
303
+ best_tags.reverse()
304
+ best_tags_list.append(best_tags)
305
+
306
+ return best_tags_list
307
+
308
+
309
+ class TokenClassificationModelCRF(PreTrainedModel):
310
+ """
311
+ Custom token classification model with CRF layer and configurable classifier head.
312
+ """
313
+
314
+ def __init__(
315
+ self,
316
+ config,
317
+ base_model=None,
318
+ freeze_backbone=False,
319
+ classifier_hidden_layers=None,
320
+ classifier_dropout=0.1,
321
+ ):
322
+ super().__init__(config)
323
+ self.config = config
324
+ self.num_labels = config.num_labels
325
+
326
+ if base_model is None:
327
+ self.roberta, backbone_name = _build_backbone_from_config(config)
328
+ else:
329
+ if hasattr(base_model, "roberta"):
330
+ self.roberta = base_model.roberta
331
+ else:
332
+ self.roberta = base_model
333
+ backbone_name = (
334
+ getattr(getattr(self.roberta, "config", None), "_name_or_path", None)
335
+ or getattr(config, "backbone_model_name", None)
336
+ or getattr(config, "_name_or_path", None)
337
+ )
338
+ if getattr(config, "backbone_model_name", None) is None:
339
+ config.backbone_model_name = backbone_name
340
+
341
+ self.lm_output_size = self.roberta.config.hidden_size
342
+
343
+ self.config.freeze_backbone = freeze_backbone
344
+ self.config.classifier_hidden_layers = classifier_hidden_layers
345
+ self.config.classifier_dropout = classifier_dropout
346
+
347
+ if freeze_backbone:
348
+ print("+" * 30, "\n\n", "Freezing backbone...", "+" * 30, "\n\n")
349
+ for param in self.roberta.parameters():
350
+ param.requires_grad = False
351
+ self.roberta.eval()
352
+ else:
353
+ print("+" * 30, "\n\n", "NOT Freezing backbone...", "+" * 30, "\n\n")
354
+ self.roberta.train(True)
355
+
356
+ self.dropout = nn.Dropout(getattr(config, "hidden_dropout_prob", 0.1))
357
+ self.crf = CRF(self.num_labels, batch_first=True)
358
+
359
+ self._build_classifier_head(classifier_hidden_layers, classifier_dropout)
360
+ self.post_init()
361
+
362
+ def _build_classifier_head(self, hidden_layers, dropout_rate):
363
+ layers = []
364
+ input_size = self.lm_output_size
365
+
366
+ if not hidden_layers:
367
+ self.classifier = nn.Sequential(
368
+ nn.Dropout(dropout_rate), nn.Linear(input_size, self.num_labels)
369
+ )
370
+ return
371
+
372
+ for hidden_size in hidden_layers:
373
+ layers.append(nn.Linear(input_size, hidden_size))
374
+ layers.append(nn.ReLU())
375
+ layers.append(nn.Dropout(dropout_rate))
376
+ input_size = hidden_size
377
+
378
+ layers.append(nn.Linear(input_size, self.num_labels))
379
+ self.classifier = nn.Sequential(*layers)
380
+
381
+ def forward(
382
+ self,
383
+ input_ids: Optional[torch.LongTensor] = None,
384
+ attention_mask: Optional[torch.FloatTensor] = None,
385
+ token_type_ids: Optional[torch.LongTensor] = None,
386
+ position_ids: Optional[torch.LongTensor] = None,
387
+ head_mask: Optional[torch.FloatTensor] = None,
388
+ inputs_embeds: Optional[torch.FloatTensor] = None,
389
+ labels: Optional[torch.LongTensor] = None,
390
+ output_attentions: Optional[bool] = None,
391
+ output_hidden_states: Optional[bool] = None,
392
+ return_dict: Optional[bool] = None,
393
+ **kwargs,
394
+ ) -> Union[Tuple[torch.Tensor], TokenClassifierOutput]:
395
+ return_dict = (
396
+ return_dict if return_dict is not None else self.config.use_return_dict
397
+ )
398
+
399
+ try:
400
+ outputs = self.roberta(
401
+ input_ids,
402
+ attention_mask=attention_mask,
403
+ token_type_ids=token_type_ids,
404
+ position_ids=position_ids,
405
+ head_mask=head_mask,
406
+ inputs_embeds=inputs_embeds,
407
+ output_attentions=output_attentions,
408
+ output_hidden_states=output_hidden_states,
409
+ return_dict=return_dict,
410
+ )
411
+ except TypeError:
412
+ outputs = self.roberta(
413
+ input_ids,
414
+ attention_mask=attention_mask,
415
+ position_ids=position_ids,
416
+ inputs_embeds=inputs_embeds,
417
+ output_attentions=output_attentions,
418
+ output_hidden_states=output_hidden_states,
419
+ return_dict=return_dict,
420
+ )
421
+
422
+ sequence_output = self.dropout(outputs.last_hidden_state)
423
+ logits = self.classifier(sequence_output)
424
+
425
+ loss = None
426
+ if labels is not None:
427
+ labels_long = labels.long()
428
+ if attention_mask is not None:
429
+ mask = attention_mask.bool()
430
+ loss = -self.crf(logits, labels_long, mask=mask, reduction="mean")
431
+ else:
432
+ if not getattr(self, "_warned_no_attention_mask", False):
433
+ print(
434
+ "WARNING: attention_mask is None; CRF loss will include padding tokens."
435
+ )
436
+ self._warned_no_attention_mask = True
437
+ loss = -self.crf(logits, labels_long, reduction="mean")
438
+
439
+ if not return_dict:
440
+ output = (logits,) + outputs[2:]
441
+ return ((loss,) + output) if loss is not None else output
442
+
443
+ return TokenClassifierOutput(
444
+ loss=loss,
445
+ logits=logits,
446
+ hidden_states=outputs.hidden_states,
447
+ attentions=outputs.attentions,
448
+ )
449
+
450
+ @property
451
+ def device_info(self):
452
+ return next(self.parameters()).device
453
+
454
+ def get_input_embeddings(self):
455
+ return self.roberta.get_input_embeddings()
456
+
457
+ def set_input_embeddings(self, value):
458
+ self.roberta.set_input_embeddings(value)
459
+
460
+ @classmethod
461
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
462
+ config = kwargs.pop("config", None)
463
+ if config is None:
464
+ from transformers import AutoConfig
465
+
466
+ config = AutoConfig.from_pretrained(pretrained_model_name_or_path, **kwargs)
467
+
468
+ freeze_backbone = getattr(config, "freeze_backbone", False)
469
+ classifier_hidden_layers = getattr(config, "classifier_hidden_layers", None)
470
+ classifier_dropout = getattr(config, "classifier_dropout", 0.1)
471
+
472
+ model = cls(
473
+ config=config,
474
+ freeze_backbone=freeze_backbone,
475
+ classifier_hidden_layers=classifier_hidden_layers,
476
+ classifier_dropout=classifier_dropout,
477
+ )
478
+
479
+ try:
480
+ state_dict = torch.load(
481
+ f"{pretrained_model_name_or_path}/pytorch_model.bin", map_location="cpu"
482
+ )
483
+ model.load_state_dict(state_dict)
484
+ except Exception:
485
+ print(
486
+ "Warning: Could not load pre-trained weights. Using randomly initialized model."
487
+ )
488
+
489
+ return model
490
+
491
+
492
+ class TokenClassificationModelMultiHeadCRF(PreTrainedModel):
493
+ """
494
+ Multi-Head CRF model for token classification with multiple entity types.
495
+ """
496
+
497
+ config_class = MultiHeadCRFConfig
498
+ base_model_prefix = "roberta"
499
+ _keys_to_ignore_on_load_unexpected = [r"pooler"]
500
+
501
+ def __init__(self, config, base_model=None, freeze_backbone=None):
502
+ super().__init__(config)
503
+ self.config = config
504
+
505
+ self.entity_types = getattr(config, "entity_types", [])
506
+ if not self.entity_types:
507
+ raise ValueError("entity_types must be provided in config")
508
+
509
+ self.num_labels = config.num_labels
510
+ self.number_of_layers_per_head = getattr(config, "number_of_layers_per_head", 1)
511
+ self.crf_reduction = getattr(config, "crf_reduction", "mean")
512
+ freeze_backbone = (
513
+ freeze_backbone
514
+ if freeze_backbone is not None
515
+ else getattr(config, "freeze_backbone", False)
516
+ )
517
+ self.num_frozen_encoders = getattr(config, "num_frozen_encoders", 0)
518
+ classifier_dropout = getattr(config, "classifier_dropout", 0.1)
519
+
520
+ if base_model is None:
521
+ self.roberta, backbone_name = _build_backbone_from_config(config)
522
+ else:
523
+ if hasattr(base_model, "roberta"):
524
+ self.roberta = base_model.roberta
525
+ else:
526
+ self.roberta = base_model
527
+ backbone_name = (
528
+ getattr(getattr(self.roberta, "config", None), "_name_or_path", None)
529
+ or getattr(config, "backbone_model_name", None)
530
+ or getattr(config, "_name_or_path", None)
531
+ )
532
+ if getattr(config, "backbone_model_name", None) is None:
533
+ config.backbone_model_name = backbone_name
534
+
535
+ self.hidden_size = self.roberta.config.hidden_size
536
+ self.dropout = nn.Dropout(getattr(config, "hidden_dropout_prob", 0.1))
537
+
538
+ print(f"Creating Multi-Head CRF with entity types: {sorted(self.entity_types)}")
539
+
540
+ for entity_type in self.entity_types:
541
+ for i in range(self.number_of_layers_per_head):
542
+ setattr(
543
+ self,
544
+ f"{entity_type}_dense_{i}",
545
+ nn.Linear(self.hidden_size, self.hidden_size),
546
+ )
547
+ setattr(
548
+ self,
549
+ f"{entity_type}_dense_activation_{i}",
550
+ nn.GELU(approximate="none"),
551
+ )
552
+ setattr(
553
+ self, f"{entity_type}_dropout_{i}", nn.Dropout(classifier_dropout)
554
+ )
555
+
556
+ setattr(
557
+ self,
558
+ f"{entity_type}_classifier",
559
+ nn.Linear(self.hidden_size, self.num_labels),
560
+ )
561
+ setattr(
562
+ self,
563
+ f"{entity_type}_crf",
564
+ MultiHeadCRF(num_tags=self.num_labels, batch_first=True),
565
+ )
566
+
567
+ if freeze_backbone:
568
+ self._freeze_backbone()
569
+
570
+ self.post_init()
571
+
572
+ def _freeze_backbone(self):
573
+ print("+" * 30, "\n\n", "Freezing backbone...", "+" * 30, "\n\n")
574
+
575
+ for param in self.roberta.embeddings.parameters():
576
+ param.requires_grad = False
577
+
578
+ if self.num_frozen_encoders > 0:
579
+ for _, param in islice(
580
+ self.roberta.encoder.named_parameters(),
581
+ self.num_frozen_encoders * NUM_PER_LAYER,
582
+ ):
583
+ param.requires_grad = False
584
+
585
+ def reset_head_parameters(self):
586
+ for entity_type in self.entity_types:
587
+ for i in range(self.number_of_layers_per_head):
588
+ getattr(self, f"{entity_type}_dense_{i}").reset_parameters()
589
+ getattr(self, f"{entity_type}_classifier").reset_parameters()
590
+ getattr(self, f"{entity_type}_crf").reset_parameters()
591
+ getattr(self, f"{entity_type}_crf").mask_impossible_transitions()
592
+
593
+ def forward(
594
+ self,
595
+ input_ids: Optional[torch.LongTensor] = None,
596
+ attention_mask: Optional[torch.FloatTensor] = None,
597
+ token_type_ids: Optional[torch.LongTensor] = None,
598
+ position_ids: Optional[torch.LongTensor] = None,
599
+ head_mask: Optional[torch.FloatTensor] = None,
600
+ inputs_embeds: Optional[torch.FloatTensor] = None,
601
+ labels: Optional[Dict[str, torch.LongTensor]] = None,
602
+ output_attentions: Optional[bool] = None,
603
+ output_hidden_states: Optional[bool] = None,
604
+ return_dict: Optional[bool] = None,
605
+ **kwargs,
606
+ ):
607
+ return_dict = (
608
+ return_dict if return_dict is not None else self.config.use_return_dict
609
+ )
610
+
611
+ try:
612
+ outputs = self.roberta(
613
+ input_ids,
614
+ attention_mask=attention_mask,
615
+ token_type_ids=token_type_ids,
616
+ position_ids=position_ids,
617
+ head_mask=head_mask,
618
+ inputs_embeds=inputs_embeds,
619
+ output_attentions=output_attentions,
620
+ output_hidden_states=output_hidden_states,
621
+ return_dict=return_dict,
622
+ )
623
+ except TypeError:
624
+ outputs = self.roberta(
625
+ input_ids,
626
+ attention_mask=attention_mask,
627
+ position_ids=position_ids,
628
+ inputs_embeds=inputs_embeds,
629
+ output_attentions=output_attentions,
630
+ output_hidden_states=output_hidden_states,
631
+ return_dict=return_dict,
632
+ )
633
+
634
+ sequence_output = outputs[0]
635
+ sequence_output = self.dropout(sequence_output)
636
+
637
+ logits = {}
638
+ for entity_type in self.entity_types:
639
+ head_output = sequence_output
640
+ for i in range(self.number_of_layers_per_head):
641
+ head_output = getattr(self, f"{entity_type}_dense_{i}")(head_output)
642
+ head_output = getattr(self, f"{entity_type}_dense_activation_{i}")(
643
+ head_output
644
+ )
645
+ head_output = getattr(self, f"{entity_type}_dropout_{i}")(head_output)
646
+ logits[entity_type] = getattr(self, f"{entity_type}_classifier")(
647
+ head_output
648
+ )
649
+
650
+ if labels is not None:
651
+ losses = {}
652
+ mask = attention_mask.bool() if attention_mask is not None else None
653
+
654
+ for entity_type in self.entity_types:
655
+ if entity_type in labels:
656
+ entity_labels = (
657
+ labels[entity_type].long().to(logits[entity_type].device)
658
+ )
659
+ crf = getattr(self, f"{entity_type}_crf")
660
+ if mask is not None:
661
+ losses[entity_type] = crf(
662
+ logits[entity_type],
663
+ entity_labels,
664
+ mask=mask,
665
+ reduction=self.crf_reduction,
666
+ )
667
+ else:
668
+ if not getattr(self, "_warned_no_attention_mask", False):
669
+ print(
670
+ "WARNING: attention_mask is None; CRF loss will include padding tokens."
671
+ )
672
+ self._warned_no_attention_mask = True
673
+ losses[entity_type] = crf(
674
+ logits[entity_type],
675
+ entity_labels,
676
+ reduction=self.crf_reduction,
677
+ )
678
+
679
+ total_loss = sum(losses.values())
680
+ return total_loss, logits
681
+
682
+ predictions = {}
683
+ mask = attention_mask.bool() if attention_mask is not None else None
684
+
685
+ for entity_type in self.entity_types:
686
+ crf = getattr(self, f"{entity_type}_crf")
687
+ if mask is not None:
688
+ decoded = crf.decode(logits[entity_type], mask=mask)
689
+ else:
690
+ decoded = crf.decode(logits[entity_type])
691
+ predictions[entity_type] = torch.tensor(decoded)
692
+
693
+ return [predictions[ent] for ent in sorted(self.entity_types)]
694
+
695
+ def get_input_embeddings(self):
696
+ return self.roberta.get_input_embeddings()
697
+
698
+ def set_input_embeddings(self, value):
699
+ self.roberta.set_input_embeddings(value)
700
+
701
+ @classmethod
702
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
703
+ import json
704
+ import os
705
+
706
+ config = kwargs.pop("config", None)
707
+
708
+ if config is None:
709
+ config_file = os.path.join(pretrained_model_name_or_path, "config.json")
710
+ if os.path.exists(config_file):
711
+ with open(config_file, "r") as f:
712
+ config_dict = json.load(f)
713
+ config = MultiHeadCRFConfig(**config_dict)
714
+ else:
715
+ from transformers import AutoConfig
716
+
717
+ config = AutoConfig.from_pretrained(
718
+ pretrained_model_name_or_path,
719
+ trust_remote_code=kwargs.get("trust_remote_code", True),
720
+ )
721
+
722
+ roberta_defaults = {
723
+ "layer_norm_eps": 1e-5,
724
+ "hidden_size": 768,
725
+ "num_hidden_layers": 12,
726
+ "num_attention_heads": 12,
727
+ "intermediate_size": 3072,
728
+ "hidden_act": "gelu",
729
+ "hidden_dropout_prob": 0.1,
730
+ "attention_probs_dropout_prob": 0.1,
731
+ "max_position_embeddings": 514,
732
+ "type_vocab_size": 1,
733
+ "initializer_range": 0.02,
734
+ "vocab_size": 52000,
735
+ "pad_token_id": 1,
736
+ "bos_token_id": 0,
737
+ "eos_token_id": 2,
738
+ "position_embedding_type": "absolute",
739
+ "use_cache": True,
740
+ "is_decoder": False,
741
+ "add_cross_attention": False,
742
+ "chunk_size_feed_forward": 0,
743
+ "output_hidden_states": False,
744
+ "output_attentions": False,
745
+ "torchscript": False,
746
+ "tie_word_embeddings": True,
747
+ "return_dict": True,
748
+ "gradient_checkpointing": False,
749
+ "pruned_heads": {},
750
+ "problem_type": None,
751
+ "embedding_size": None,
752
+ }
753
+
754
+ for key, default_value in roberta_defaults.items():
755
+ if not hasattr(config, key) or getattr(config, key) is None:
756
+ setattr(config, key, default_value)
757
+
758
+ freeze_backbone = getattr(config, "freeze_backbone", False)
759
+ model = cls(config=config, freeze_backbone=freeze_backbone)
760
+
761
+ weight_file = os.path.join(pretrained_model_name_or_path, "pytorch_model.bin")
762
+ safetensors_file = os.path.join(
763
+ pretrained_model_name_or_path, "model.safetensors"
764
+ )
765
+
766
+ try:
767
+ if os.path.exists(safetensors_file):
768
+ from safetensors.torch import load_file
769
+
770
+ state_dict = load_file(safetensors_file)
771
+ model.load_state_dict(state_dict)
772
+ elif os.path.exists(weight_file):
773
+ state_dict = torch.load(weight_file, map_location="cpu")
774
+ model.load_state_dict(state_dict)
775
+ else:
776
+ print(
777
+ "Warning: No pre-trained weights found. Using randomly initialized model."
778
+ )
779
+ except Exception as e:
780
+ print(f"Warning: Could not load pre-trained weights: {e}")
781
+
782
+ return model
783
+
784
+
785
+ class MultiHeadConfig(PretrainedConfig):
786
+ """
787
+ Configuration class for Multi-Head models (without CRF).
788
+ """
789
+
790
+ model_type = "multihead-tagger"
791
+
792
+ def __init__(
793
+ self,
794
+ entity_types: Optional[List[str]] = None,
795
+ number_of_layers_per_head: int = 1,
796
+ freeze_backbone: bool = False,
797
+ num_frozen_encoders: int = 0,
798
+ classifier_dropout: float = 0.1,
799
+ use_class_weights: bool = False,
800
+ class_weights: Optional[Dict[str, List[float]]] = None,
801
+ backbone_model_name: Optional[str] = None,
802
+ **kwargs,
803
+ ):
804
+ self.entity_types = entity_types or []
805
+ self.number_of_layers_per_head = number_of_layers_per_head
806
+ self.freeze_backbone = freeze_backbone
807
+ self.num_frozen_encoders = num_frozen_encoders
808
+ self.classifier_dropout = classifier_dropout
809
+ self.use_class_weights = use_class_weights
810
+ self.class_weights = class_weights
811
+ self.backbone_model_name = backbone_model_name
812
+ super().__init__(**kwargs)
813
+
814
+
815
+ class TokenClassificationModelMultiHead(PreTrainedModel):
816
+ """
817
+ Multi-Head model for token classification with multiple entity types (no CRF).
818
+ """
819
+
820
+ config_class = MultiHeadConfig
821
+ base_model_prefix = "roberta"
822
+ _keys_to_ignore_on_load_unexpected = [r"pooler"]
823
+
824
+ def __init__(self, config, base_model=None, freeze_backbone=None):
825
+ super().__init__(config)
826
+ self.config = config
827
+
828
+ self.entity_types = getattr(config, "entity_types", [])
829
+ if not self.entity_types:
830
+ raise ValueError("entity_types must be provided in config")
831
+
832
+ self.num_labels = config.num_labels
833
+ self.number_of_layers_per_head = getattr(config, "number_of_layers_per_head", 1)
834
+ freeze_backbone = (
835
+ freeze_backbone
836
+ if freeze_backbone is not None
837
+ else getattr(config, "freeze_backbone", False)
838
+ )
839
+ self.num_frozen_encoders = getattr(config, "num_frozen_encoders", 0)
840
+ classifier_dropout = getattr(config, "classifier_dropout", 0.1)
841
+
842
+ self.use_class_weights = getattr(config, "use_class_weights", False)
843
+ self.class_weights = getattr(config, "class_weights", None)
844
+
845
+ if base_model is None:
846
+ self.roberta, backbone_name = _build_backbone_from_config(config)
847
+ else:
848
+ if hasattr(base_model, "roberta"):
849
+ self.roberta = base_model.roberta
850
+ else:
851
+ self.roberta = base_model
852
+ backbone_name = (
853
+ getattr(getattr(self.roberta, "config", None), "_name_or_path", None)
854
+ or getattr(config, "backbone_model_name", None)
855
+ or getattr(config, "_name_or_path", None)
856
+ )
857
+ if getattr(config, "backbone_model_name", None) is None:
858
+ config.backbone_model_name = backbone_name
859
+
860
+ self.hidden_size = self.roberta.config.hidden_size
861
+ self.dropout = nn.Dropout(getattr(config, "hidden_dropout_prob", 0.1))
862
+
863
+ print(
864
+ f"Creating Multi-Head model with entity types: {sorted(self.entity_types)}"
865
+ )
866
+
867
+ for entity_type in self.entity_types:
868
+ for i in range(self.number_of_layers_per_head):
869
+ setattr(
870
+ self,
871
+ f"{entity_type}_dense_{i}",
872
+ nn.Linear(self.hidden_size, self.hidden_size),
873
+ )
874
+ setattr(
875
+ self,
876
+ f"{entity_type}_dense_activation_{i}",
877
+ nn.GELU(approximate="none"),
878
+ )
879
+ setattr(
880
+ self, f"{entity_type}_dropout_{i}", nn.Dropout(classifier_dropout)
881
+ )
882
+
883
+ setattr(
884
+ self,
885
+ f"{entity_type}_classifier",
886
+ nn.Linear(self.hidden_size, self.num_labels),
887
+ )
888
+
889
+ self.loss_fns = nn.ModuleDict()
890
+ for entity_type in self.entity_types:
891
+ if (
892
+ self.use_class_weights
893
+ and self.class_weights
894
+ and entity_type in self.class_weights
895
+ ):
896
+ weight = torch.tensor(
897
+ self.class_weights[entity_type], dtype=torch.float
898
+ )
899
+ self.loss_fns[entity_type] = nn.CrossEntropyLoss(
900
+ weight=weight, ignore_index=-100
901
+ )
902
+ else:
903
+ self.loss_fns[entity_type] = nn.CrossEntropyLoss(ignore_index=-100)
904
+
905
+ if freeze_backbone:
906
+ self._freeze_backbone()
907
+
908
+ self.post_init()
909
+
910
+ def _freeze_backbone(self):
911
+ print("+" * 30, "\n\n", "Freezing backbone...", "+" * 30, "\n\n")
912
+
913
+ for param in self.roberta.embeddings.parameters():
914
+ param.requires_grad = False
915
+
916
+ if self.num_frozen_encoders > 0:
917
+ for _, param in islice(
918
+ self.roberta.encoder.named_parameters(),
919
+ self.num_frozen_encoders * NUM_PER_LAYER,
920
+ ):
921
+ param.requires_grad = False
922
+
923
+ def reset_head_parameters(self):
924
+ for entity_type in self.entity_types:
925
+ for i in range(self.number_of_layers_per_head):
926
+ getattr(self, f"{entity_type}_dense_{i}").reset_parameters()
927
+ getattr(self, f"{entity_type}_classifier").reset_parameters()
928
+
929
+ def forward(
930
+ self,
931
+ input_ids: Optional[torch.LongTensor] = None,
932
+ attention_mask: Optional[torch.FloatTensor] = None,
933
+ token_type_ids: Optional[torch.LongTensor] = None,
934
+ position_ids: Optional[torch.LongTensor] = None,
935
+ head_mask: Optional[torch.FloatTensor] = None,
936
+ inputs_embeds: Optional[torch.FloatTensor] = None,
937
+ labels: Optional[Dict[str, torch.LongTensor]] = None,
938
+ output_attentions: Optional[bool] = None,
939
+ output_hidden_states: Optional[bool] = None,
940
+ return_dict: Optional[bool] = None,
941
+ **kwargs,
942
+ ):
943
+ return_dict = (
944
+ return_dict if return_dict is not None else self.config.use_return_dict
945
+ )
946
+
947
+ try:
948
+ outputs = self.roberta(
949
+ input_ids,
950
+ attention_mask=attention_mask,
951
+ token_type_ids=token_type_ids,
952
+ position_ids=position_ids,
953
+ head_mask=head_mask,
954
+ inputs_embeds=inputs_embeds,
955
+ output_attentions=output_attentions,
956
+ output_hidden_states=output_hidden_states,
957
+ return_dict=return_dict,
958
+ )
959
+ except TypeError:
960
+ outputs = self.roberta(
961
+ input_ids,
962
+ attention_mask=attention_mask,
963
+ position_ids=position_ids,
964
+ inputs_embeds=inputs_embeds,
965
+ output_attentions=output_attentions,
966
+ output_hidden_states=output_hidden_states,
967
+ return_dict=return_dict,
968
+ )
969
+
970
+ sequence_output = outputs[0]
971
+ sequence_output = self.dropout(sequence_output)
972
+
973
+ logits = {}
974
+ for entity_type in self.entity_types:
975
+ head_output = sequence_output
976
+ for i in range(self.number_of_layers_per_head):
977
+ head_output = getattr(self, f"{entity_type}_dense_{i}")(head_output)
978
+ head_output = getattr(self, f"{entity_type}_dense_activation_{i}")(
979
+ head_output
980
+ )
981
+ head_output = getattr(self, f"{entity_type}_dropout_{i}")(head_output)
982
+ logits[entity_type] = getattr(self, f"{entity_type}_classifier")(
983
+ head_output
984
+ )
985
+
986
+ if labels is not None:
987
+ losses = {}
988
+
989
+ for entity_type in self.entity_types:
990
+ if entity_type in labels:
991
+ entity_labels = (
992
+ labels[entity_type].long().to(logits[entity_type].device)
993
+ )
994
+ entity_logits = logits[entity_type]
995
+ loss_fct = self.loss_fns[entity_type]
996
+
997
+ if hasattr(loss_fct, "weight") and loss_fct.weight is not None:
998
+ loss_fct.weight = loss_fct.weight.to(entity_logits.device)
999
+
1000
+ losses[entity_type] = loss_fct(
1001
+ entity_logits.view(-1, self.num_labels),
1002
+ entity_labels.view(-1),
1003
+ )
1004
+
1005
+ total_loss = sum(losses.values())
1006
+ return total_loss, logits
1007
+
1008
+ predictions = {}
1009
+ for entity_type in self.entity_types:
1010
+ preds = torch.argmax(logits[entity_type], dim=-1)
1011
+ predictions[entity_type] = preds
1012
+
1013
+ return [predictions[ent] for ent in sorted(self.entity_types)]
1014
+
1015
+ def get_input_embeddings(self):
1016
+ return self.roberta.get_input_embeddings()
1017
+
1018
+ def set_input_embeddings(self, value):
1019
+ self.roberta.set_input_embeddings(value)
1020
+
1021
+ @classmethod
1022
+ def from_pretrained(cls, pretrained_model_name_or_path, *model_args, **kwargs):
1023
+ import json
1024
+ import os
1025
+
1026
+ config = kwargs.pop("config", None)
1027
+
1028
+ if config is None:
1029
+ config_file = os.path.join(pretrained_model_name_or_path, "config.json")
1030
+ if os.path.exists(config_file):
1031
+ with open(config_file, "r") as f:
1032
+ config_dict = json.load(f)
1033
+ config = MultiHeadConfig(**config_dict)
1034
+ else:
1035
+ from transformers import AutoConfig
1036
+
1037
+ config = AutoConfig.from_pretrained(
1038
+ pretrained_model_name_or_path,
1039
+ trust_remote_code=kwargs.get("trust_remote_code", True),
1040
+ )
1041
+
1042
+ roberta_defaults = {
1043
+ "layer_norm_eps": 1e-5,
1044
+ "hidden_size": 768,
1045
+ "num_hidden_layers": 12,
1046
+ "num_attention_heads": 12,
1047
+ "intermediate_size": 3072,
1048
+ "hidden_act": "gelu",
1049
+ "hidden_dropout_prob": 0.1,
1050
+ "attention_probs_dropout_prob": 0.1,
1051
+ "max_position_embeddings": 514,
1052
+ "type_vocab_size": 1,
1053
+ "initializer_range": 0.02,
1054
+ "vocab_size": 52000,
1055
+ "pad_token_id": 1,
1056
+ "bos_token_id": 0,
1057
+ "eos_token_id": 2,
1058
+ "position_embedding_type": "absolute",
1059
+ "use_cache": True,
1060
+ "is_decoder": False,
1061
+ "add_cross_attention": False,
1062
+ "chunk_size_feed_forward": 0,
1063
+ "output_hidden_states": False,
1064
+ "output_attentions": False,
1065
+ "torchscript": False,
1066
+ "tie_word_embeddings": True,
1067
+ "return_dict": True,
1068
+ "gradient_checkpointing": False,
1069
+ "pruned_heads": {},
1070
+ "problem_type": None,
1071
+ "embedding_size": None,
1072
+ }
1073
+
1074
+ for key, default_value in roberta_defaults.items():
1075
+ if not hasattr(config, key) or getattr(config, key) is None:
1076
+ setattr(config, key, default_value)
1077
+
1078
+ freeze_backbone = getattr(config, "freeze_backbone", False)
1079
+ model = cls(config=config, freeze_backbone=freeze_backbone)
1080
+
1081
+ weight_file = os.path.join(pretrained_model_name_or_path, "pytorch_model.bin")
1082
+ safetensors_file = os.path.join(
1083
+ pretrained_model_name_or_path, "model.safetensors"
1084
+ )
1085
+
1086
+ try:
1087
+ if os.path.exists(safetensors_file):
1088
+ from safetensors.torch import load_file
1089
+
1090
+ state_dict = load_file(safetensors_file)
1091
+ model.load_state_dict(state_dict)
1092
+ elif os.path.exists(weight_file):
1093
+ state_dict = torch.load(weight_file, map_location="cpu")
1094
+ model.load_state_dict(state_dict)
1095
+ else:
1096
+ print(
1097
+ "Warning: No pre-trained weights found. Using randomly initialized model."
1098
+ )
1099
+ except Exception as e:
1100
+ print(f"Warning: Could not load pre-trained weights: {e}")
1101
+
1102
+ return model
1103
+
1104
+
1105
+ class TokenClassificationModel(PreTrainedModel):
1106
+ """
1107
+ Custom token classification model with configurable classifier head (no CRF).
1108
+ """
1109
+
1110
+ def __init__(self, config, base_model=None):
1111
+ super().__init__(config)
1112
+ self.config = config
1113
+ self.num_labels = config.num_labels
1114
+
1115
+ if base_model is None:
1116
+ self.roberta, backbone_name = _build_backbone_from_config(config)
1117
+ else:
1118
+ if hasattr(base_model, "roberta"):
1119
+ self.roberta = base_model.roberta
1120
+ else:
1121
+ self.roberta = base_model
1122
+ backbone_name = (
1123
+ getattr(getattr(self.roberta, "config", None), "_name_or_path", None)
1124
+ or getattr(config, "backbone_model_name", None)
1125
+ or getattr(config, "_name_or_path", None)
1126
+ )
1127
+
1128
+ if getattr(config, "backbone_model_name", None) is None:
1129
+ config.backbone_model_name = backbone_name
1130
+
1131
+ self.dropout = nn.Dropout(getattr(config, "hidden_dropout_prob", 0.1))
1132
+
1133
+ classifier_hidden_layers = getattr(config, "classifier_hidden_layers", None)
1134
+ classifier_dropout = getattr(config, "classifier_dropout", 0.1)
1135
+
1136
+ if classifier_hidden_layers is not None:
1137
+ in_size = self.roberta.config.hidden_size
1138
+ layers = []
1139
+ if classifier_hidden_layers:
1140
+ for h in classifier_hidden_layers:
1141
+ layers += [
1142
+ nn.Linear(in_size, h),
1143
+ nn.ReLU(),
1144
+ nn.Dropout(classifier_dropout),
1145
+ ]
1146
+ in_size = h
1147
+ layers.append(nn.Linear(in_size, config.num_labels))
1148
+ self.classifier = nn.Sequential(*layers)
1149
+ else:
1150
+ self.classifier = nn.Linear(
1151
+ self.roberta.config.hidden_size, config.num_labels
1152
+ )
1153
+
1154
+ if isinstance(self.classifier, nn.Sequential):
1155
+ for module in self.classifier:
1156
+ if isinstance(module, nn.Linear):
1157
+ self._init_weights(module)
1158
+ elif isinstance(self.classifier, nn.Linear):
1159
+ self._init_weights(self.classifier)
1160
+
1161
+ self.post_init()
1162
+
1163
+ def forward(
1164
+ self,
1165
+ input_ids: Optional[torch.LongTensor] = None,
1166
+ attention_mask: Optional[torch.FloatTensor] = None,
1167
+ token_type_ids: Optional[torch.LongTensor] = None,
1168
+ position_ids: Optional[torch.LongTensor] = None,
1169
+ head_mask: Optional[torch.FloatTensor] = None,
1170
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1171
+ labels: Optional[torch.LongTensor] = None,
1172
+ output_attentions: Optional[bool] = None,
1173
+ output_hidden_states: Optional[bool] = None,
1174
+ return_dict: Optional[bool] = None,
1175
+ **kwargs,
1176
+ ) -> Union[Tuple[torch.Tensor], TokenClassifierOutput]:
1177
+ return_dict = (
1178
+ return_dict if return_dict is not None else self.config.use_return_dict
1179
+ )
1180
+
1181
+ try:
1182
+ outputs = self.roberta(
1183
+ input_ids,
1184
+ attention_mask=attention_mask,
1185
+ token_type_ids=token_type_ids,
1186
+ position_ids=position_ids,
1187
+ head_mask=head_mask,
1188
+ inputs_embeds=inputs_embeds,
1189
+ output_attentions=output_attentions,
1190
+ output_hidden_states=output_hidden_states,
1191
+ return_dict=return_dict,
1192
+ )
1193
+ except TypeError:
1194
+ outputs = self.roberta(
1195
+ input_ids,
1196
+ attention_mask=attention_mask,
1197
+ position_ids=position_ids,
1198
+ inputs_embeds=inputs_embeds,
1199
+ output_attentions=output_attentions,
1200
+ output_hidden_states=output_hidden_states,
1201
+ return_dict=return_dict,
1202
+ )
1203
+
1204
+ sequence_output = outputs.last_hidden_state
1205
+ sequence_output = self.dropout(sequence_output)
1206
+ logits = self.classifier(sequence_output)
1207
+
1208
+ loss = None
1209
+ if labels is not None:
1210
+ loss_fct = nn.CrossEntropyLoss()
1211
+ if attention_mask is not None:
1212
+ active_loss = attention_mask.view(-1) == 1
1213
+ active_logits = logits.view(-1, self.num_labels)[active_loss]
1214
+ active_labels = labels.view(-1)[active_loss]
1215
+ loss = loss_fct(active_logits, active_labels)
1216
+ else:
1217
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
1218
+
1219
+ if not return_dict:
1220
+ output = (logits,) + outputs[2:]
1221
+ return ((loss,) + output) if loss is not None else output
1222
+
1223
+ return TokenClassifierOutput(
1224
+ loss=loss,
1225
+ logits=logits,
1226
+ hidden_states=outputs.hidden_states,
1227
+ attentions=outputs.attentions,
1228
+ )
1229
+
1230
+ def get_input_embeddings(self):
1231
+ return self.roberta.get_input_embeddings()
1232
+
1233
+ def set_input_embeddings(self, value):
1234
+ self.roberta.set_input_embeddings(value)
1235
+
1236
+
1237
+ def load_custom_cardioner_multiclass_model(model_path: str, device: str = "auto"):
1238
+ import os
1239
+
1240
+ import torch
1241
+ from transformers import AutoModelForTokenClassification, AutoTokenizer
1242
+
1243
+ required_files = ["config.json", "modeling.py", "pytorch_model.bin"]
1244
+ missing_files = [
1245
+ f for f in required_files if not os.path.exists(os.path.join(model_path, f))
1246
+ ]
1247
+
1248
+ if missing_files:
1249
+ raise FileNotFoundError(
1250
+ f"Missing required files in {model_path}: {missing_files}"
1251
+ )
1252
+
1253
+ print(f"Loading custom CardioNER multiclass model from: {model_path}")
1254
+
1255
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
1256
+
1257
+ model = AutoModelForTokenClassification.from_pretrained(
1258
+ model_path,
1259
+ trust_remote_code=True,
1260
+ use_safetensors=True,
1261
+ )
1262
+
1263
+ if device == "auto":
1264
+ device = "cuda" if torch.cuda.is_available() else "cpu"
1265
+
1266
+ model = model.to(device)
1267
+
1268
+ print(f"Model loaded successfully on {device}")
1269
+ print(f"Model type: {type(model).__name__}")
1270
+ print(f"Number of labels: {model.num_labels}")
1271
+
1272
+ return model, tokenizer, model.config
1273
+
1274
+
1275
+ def load_custom_multihead_crf_model(model_path: str, device: str = "auto"):
1276
+ import json
1277
+ import os
1278
+
1279
+ from transformers import AutoTokenizer
1280
+
1281
+ required_files = ["config.json", "modeling.py"]
1282
+ missing_files = [
1283
+ f for f in required_files if not os.path.exists(os.path.join(model_path, f))
1284
+ ]
1285
+
1286
+ if missing_files:
1287
+ raise FileNotFoundError(
1288
+ f"Missing required files in {model_path}: {missing_files}"
1289
+ )
1290
+
1291
+ print(f"Loading Multi-Head CRF model from: {model_path}")
1292
+
1293
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
1294
+
1295
+ with open(os.path.join(model_path, "config.json"), "r") as f:
1296
+ config_dict = json.load(f)
1297
+
1298
+ config = MultiHeadCRFConfig(**config_dict)
1299
+
1300
+ model = TokenClassificationModelMultiHeadCRF.from_pretrained(
1301
+ model_path, config=config
1302
+ )
1303
+
1304
+ if device == "auto":
1305
+ device = "cuda" if torch.cuda.is_available() else "cpu"
1306
+
1307
+ model = model.to(device)
1308
+
1309
+ print(f"Model loaded successfully on {device}")
1310
+ print(f"Model type: {type(model).__name__}")
1311
+ print(f"Entity types: {model.entity_types}")
1312
+ print(f"Number of labels per head: {model.num_labels}")
1313
+
1314
+ return model, tokenizer, model.config
1315
+
1316
+
1317
+ def validate_custom_multiclass_model_directory(model_path: str) -> dict:
1318
+ import json
1319
+ import os
1320
+
1321
+ validation_results = {
1322
+ "valid": True,
1323
+ "errors": [],
1324
+ "warnings": [],
1325
+ "files_found": [],
1326
+ "model_info": {},
1327
+ }
1328
+
1329
+ required_files = {
1330
+ "config.json": "Model configuration",
1331
+ "modeling.py": "Custom model class definition",
1332
+ "pytorch_model.bin": "Model weights",
1333
+ }
1334
+
1335
+ optional_files = {
1336
+ "tokenizer.json": "Tokenizer vocabulary",
1337
+ "tokenizer_config.json": "Tokenizer configuration",
1338
+ "training_args.json": "Training arguments",
1339
+ }
1340
+
1341
+ for filename, description in required_files.items():
1342
+ filepath = os.path.join(model_path, filename)
1343
+ if os.path.exists(filepath):
1344
+ validation_results["files_found"].append(f"{filename} ({description})")
1345
+ else:
1346
+ validation_results["valid"] = False
1347
+ validation_results["errors"].append(
1348
+ f"Missing required file: {filename} - {description}"
1349
+ )
1350
+
1351
+ for filename, description in optional_files.items():
1352
+ filepath = os.path.join(model_path, filename)
1353
+ if os.path.exists(filepath):
1354
+ validation_results["files_found"].append(f"{filename} ({description})")
1355
+ else:
1356
+ validation_results["warnings"].append(
1357
+ f"Missing optional file: {filename} - {description}"
1358
+ )
1359
+
1360
+ config_path = os.path.join(model_path, "config.json")
1361
+ if os.path.exists(config_path):
1362
+ try:
1363
+ with open(config_path, "r") as f:
1364
+ config = json.load(f)
1365
+
1366
+ validation_results["model_info"]["num_labels"] = config.get(
1367
+ "num_labels", "Unknown"
1368
+ )
1369
+ validation_results["model_info"]["model_type"] = config.get(
1370
+ "model_type", "Unknown"
1371
+ )
1372
+ validation_results["model_info"]["has_auto_map"] = "auto_map" in config
1373
+ validation_results["model_info"]["classifier_hidden_layers"] = config.get(
1374
+ "classifier_hidden_layers", None
1375
+ )
1376
+ validation_results["model_info"]["freeze_backbone"] = config.get(
1377
+ "freeze_backbone", None
1378
+ )
1379
+ validation_results["model_info"]["use_crf"] = (
1380
+ "TokenClassificationModelCRF" in str(config.get("architectures", []))
1381
+ )
1382
+
1383
+ if not config.get("auto_map"):
1384
+ validation_results["warnings"].append(
1385
+ "No auto_map found in config - may not load correctly with trust_remote_code=True"
1386
+ )
1387
+
1388
+ except json.JSONDecodeError as e:
1389
+ validation_results["valid"] = False
1390
+ validation_results["errors"].append(f"Invalid config.json: {str(e)}")
1391
+
1392
+ modeling_path = os.path.join(model_path, "modeling.py")
1393
+ if os.path.exists(modeling_path):
1394
+ try:
1395
+ with open(modeling_path, "r") as f:
1396
+ content = f.read()
1397
+
1398
+ required_classes = [
1399
+ "TokenClassificationModel",
1400
+ "TokenClassificationModelCRF",
1401
+ ]
1402
+ missing_classes = [cls for cls in required_classes if cls not in content]
1403
+
1404
+ if missing_classes:
1405
+ validation_results["valid"] = False
1406
+ validation_results["errors"].append(
1407
+ f"modeling.py missing required classes: {missing_classes}"
1408
+ )
1409
+
1410
+ except Exception as e:
1411
+ validation_results["warnings"].append(
1412
+ f"Could not read modeling.py: {str(e)}"
1413
+ )
1414
+
1415
+ return validation_results
1416
+
1417
+
1418
+ try:
1419
+ from transformers import AutoConfig
1420
+
1421
+ AutoConfig.register("multihead-crf-tagger", MultiHeadCRFConfig)
1422
+ except Exception:
1423
+ pass
1424
+
1425
+
1426
+ def patch_legacy_model(
1427
+ model_path: str, backbone_model_name: str, dry_run: bool = True
1428
+ ) -> bool:
1429
+ import json
1430
+ import os
1431
+ import shutil
1432
+
1433
+ config_path = os.path.join(model_path, "config.json")
1434
+
1435
+ if not os.path.exists(config_path):
1436
+ print(f"ERROR: config.json not found at {config_path}")
1437
+ return False
1438
+
1439
+ with open(config_path, "r") as f:
1440
+ config = json.load(f)
1441
+
1442
+ if "backbone_model_name" in config:
1443
+ print(f"Model already has backbone_model_name: {config['backbone_model_name']}")
1444
+ if config["backbone_model_name"] == backbone_model_name:
1445
+ print("No changes needed.")
1446
+ return True
1447
+ else:
1448
+ print(f"WARNING: Existing backbone_model_name differs from provided value!")
1449
+ print(f" Existing: {config['backbone_model_name']}")
1450
+ print(f" Provided: {backbone_model_name}")
1451
+ if dry_run:
1452
+ print("Would update to new value (dry_run=True)")
1453
+ else:
1454
+ print("Updating to new value...")
1455
+
1456
+ config["backbone_model_name"] = backbone_model_name
1457
+
1458
+ if dry_run:
1459
+ print(f"\n[DRY RUN] Would patch {config_path}:")
1460
+ print(f' Adding: backbone_model_name = "{backbone_model_name}"')
1461
+ print("\nTo apply this patch, run with dry_run=False")
1462
+ return True
1463
+
1464
+ backup_path = config_path + ".backup"
1465
+ shutil.copy2(config_path, backup_path)
1466
+ print(f"Created backup at {backup_path}")
1467
+
1468
+ with open(config_path, "w") as f:
1469
+ json.dump(config, f, indent=2)
1470
+
1471
+ print(f"Successfully patched {config_path}")
1472
+ print(f' Added: backbone_model_name = "{backbone_model_name}"')
1473
+
1474
+ return True
1475
+
1476
+
1477
+ def patch_multiple_models(
1478
+ model_paths: list, backbone_model_name: str, dry_run: bool = True
1479
+ ) -> dict:
1480
+ results = {}
1481
+ for path in model_paths:
1482
+ print(f"\n{'=' * 60}")
1483
+ print(f"Processing: {path}")
1484
+ print("=" * 60)
1485
+ results[path] = patch_legacy_model(path, backbone_model_name, dry_run)
1486
+
1487
+ print(f"\n{'=' * 60}")
1488
+ print("SUMMARY")
1489
+ print("=" * 60)
1490
+ success = sum(1 for v in results.values() if v)
1491
+ print(
1492
+ f"Successfully {'would patch' if dry_run else 'patched'}: {success}/{len(model_paths)}"
1493
+ )
1494
+
1495
+ return results
special_tokens_map.json ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<s>",
4
+ "lstrip": false,
5
+ "normalized": true,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "cls_token": {
10
+ "content": "<s>",
11
+ "lstrip": false,
12
+ "normalized": true,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "eos_token": {
17
+ "content": "</s>",
18
+ "lstrip": false,
19
+ "normalized": true,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "mask_token": {
24
+ "content": "<mask>",
25
+ "lstrip": true,
26
+ "normalized": true,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "pad_token": {
31
+ "content": "<pad>",
32
+ "lstrip": false,
33
+ "normalized": true,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ },
37
+ "sep_token": {
38
+ "content": "</s>",
39
+ "lstrip": false,
40
+ "normalized": true,
41
+ "rstrip": false,
42
+ "single_word": false
43
+ },
44
+ "unk_token": {
45
+ "content": "<unk>",
46
+ "lstrip": false,
47
+ "normalized": true,
48
+ "rstrip": false,
49
+ "single_word": false
50
+ }
51
+ }
split.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": true,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<s>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "<pad>",
14
+ "lstrip": false,
15
+ "normalized": true,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "<unk>",
22
+ "lstrip": false,
23
+ "normalized": true,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "3": {
29
+ "content": "</s>",
30
+ "lstrip": false,
31
+ "normalized": true,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "4": {
37
+ "content": "<mask>",
38
+ "lstrip": true,
39
+ "normalized": true,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ }
44
+ },
45
+ "bos_token": "<s>",
46
+ "clean_up_tokenization_spaces": true,
47
+ "cls_token": "<s>",
48
+ "eos_token": "</s>",
49
+ "errors": "replace",
50
+ "extra_special_tokens": {},
51
+ "mask_token": "<mask>",
52
+ "model_max_length": 32,
53
+ "pad_token": "<pad>",
54
+ "padding": false,
55
+ "sep_token": "</s>",
56
+ "tokenizer_class": "RobertaTokenizer",
57
+ "trim_offsets": true,
58
+ "truncation": true,
59
+ "unk_token": "<unk>"
60
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff