kgrozdanovski commited on
Commit
41dacee
·
verified ·
1 Parent(s): c9072a4

CalDec Ultra 150M

Browse files
README.md ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: dmis-lab/UltraBERT-150M
4
+ language:
5
+ - en
6
+ pipeline_tag: text-classification
7
+ tags:
8
+ - typed-decisions
9
+ - decision-model
10
+ - long-context
11
+ - ultrabert
12
+ - assistant
13
+ datasets:
14
+ - kgrozdanovski/assistant-decisions
15
+ - LocalLLaMA/typed-decisions
16
+ - nyu-mll/glue
17
+ - google/boolq
18
+ model-index:
19
+ - name: caldec-ultra-150m
20
+ results:
21
+ - task:
22
+ type: text-classification
23
+ name: Typed decisions
24
+ dataset:
25
+ name: Assistant decisions, development test
26
+ type: kgrozdanovski/assistant-decisions
27
+ split: test
28
+ metrics:
29
+ - type: accuracy
30
+ value: 0.834
31
+ name: Accuracy (untied labels)
32
+ - type: expected_calibration_error
33
+ value: 0.083
34
+ name: Expected calibration error
35
+ - task:
36
+ type: text-classification
37
+ name: Typed decisions
38
+ dataset:
39
+ name: Assistant decisions, long-state test
40
+ type: kgrozdanovski/assistant-decisions
41
+ config: long
42
+ split: test
43
+ metrics:
44
+ - type: accuracy
45
+ value: 0.722
46
+ name: Accuracy (untied labels)
47
+ - task:
48
+ type: text-classification
49
+ name: Typed decisions
50
+ dataset:
51
+ name: LocalLLaMA/typed-decisions
52
+ type: LocalLLaMA/typed-decisions
53
+ split: test
54
+ metrics:
55
+ - type: accuracy
56
+ value: 0.782
57
+ name: Accuracy (untied labels, trained on the train split)
58
+ ---
59
+
60
+ # CalDec Ultra 150M
61
+
62
+ A typed-decision model for long assistant states. It puts a Laya-format decision head on [dmis-lab/UltraBERT-150M](https://huggingface.co/dmis-lab/UltraBERT-150M), reads states of up to **8,192 tokens**, and answers all of a case's questions in **one encoder pass**. Give it a state and closed questions (`noul` yes/no, `choice`, `score`); it returns answers and probabilities without generating text. It was fine-tuned on [Assistant Decisions](https://huggingface.co/datasets/kgrozdanovski/assistant-decisions), including its long-state builds.
63
+
64
+ The other size is [CalDec Ultra 380M](https://huggingface.co/kgrozdanovski/caldec-ultra-380m). The [CalDec repository](https://github.com/kgrozdanovski/caldec) has the code, data recipe and evidence; [ULTRA.md](https://github.com/kgrozdanovski/caldec/blob/main/ULTRA.md) has the full results.
65
+
66
+ ## Evaluation
67
+
68
+ Accuracy is agreement with model-written target distributions on untied decisions, scored through the served path. It is not independent correctness.
69
+
70
+ | Model | Assistant test | Relabelled test | Long-state test | `typed-decisions` test |
71
+ |---|---:|---:|---:|---:|
72
+ | **CalDec Ultra 150M** | **0.834** | **0.819** | **0.722** | **0.782**† |
73
+ | [CalDec Ultra 380M](https://huggingface.co/kgrozdanovski/caldec-ultra-380m) | 0.848 | 0.835 | 0.734 | 0.796† |
74
+ | [CalDec GLiNER](https://huggingface.co/kgrozdanovski/caldec-v1-gliner2.5-decide) | 0.843 | 0.828 | 0.614‡ | 0.582 |
75
+ | [CalDec Laya](https://huggingface.co/kgrozdanovski/caldec-v1-laya) | 0.823 | 0.811 | 0.563 | 0.778† |
76
+ | Jev 1.13, zero-shot | 0.836 | — | — | 0.738 |
77
+ | [GLiNER2.5-Decide](https://huggingface.co/fastino/GLiNER2.5-Decide) | 0.650 | 0.639 | — | 0.540 |
78
+ | [Laya](https://huggingface.co/convaiinnovations/laya) base | 0.557 | 0.551 | — | 0.361 |
79
+ | dmis-lab/UltraBERT-150M, zero-shot | 0.361 | 0.361 | — | — |
80
+
81
+ † Trained on the benchmark's train split, so not zero-shot. ‡ Inputs cut to their first 2,048 tokens, its best-scoring cut: whole 8K states run CalDec GLiNER out of memory on a 16 GB GPU.
82
+
83
+ - **Assistant test**: 1,647 cases, 3,372 untied decisions, GLM 5.3 targets. The test informed development of every CalDec model. Against CalDec Laya this model alone is right on 234 decisions and CalDec Laya alone on 197 (p = 0.083); against CalDec GLiNER 206 to 236 (p = 0.17). Between the sizes, the 380M leads 215 to 168 (p = 0.019).
84
+ - **Relabelled test**: the same states with targets from two of Claude Opus 5.5, GPT-5.6 Sol and Gemini 3.8 Flash per case. Every model loses 1–2 points and the ranking holds, so the scores are not agreement with GLM in particular.
85
+ - **Long-state test**: 77 held-out cases of about 3–8K tokens on nine sites (158 untied decisions), each generated by one of GLM 5.3, MiMo-V2.6-Pro and DeepSeek V4.1 Flash and labelled by the other two. Against CalDec Laya: 37 to 12 (p = 0.0005). At this size, differences under about 7 points are noise.
86
+ - **Long-state probe**: injected texts placed at the start, middle or end of 4K and 8K pages. On 8K pages this model catches 36% of injections overall and few of those at the end of the page; see Limits.
87
+
88
+ **Latency**, three questions through `system_one` on an RTX 4080 SUPER (bfloat16, median of 20 calls):
89
+
90
+ | State length | 512 | 1,024 | 2,048 | 4,096 | 8,192 tokens |
91
+ |---|---:|---:|---:|---:|---:|
92
+ | CalDec Ultra 150M | 23 ms | 26 ms | 28 ms | 43 ms | 102 ms |
93
+ | CalDec Laya | 33 ms | 56 ms | 123 ms | 330 ms | 920 ms |
94
+
95
+ **Outside benchmarks.** This is a specialist. On a nine-benchmark subset of the [Jev Decision Index](https://huggingface.co/spaces/multimodalart/jev-decision-index) it scores ANLI macro-F1 0.187 (chance 0.33; Laya base 0.489), ContractNLI 0.282 (chance 0.31) and When2Call 0.173 (chance 0.25). Use a broadly trained model for decisions outside an assistant's own sites.
96
+
97
+ ## Use
98
+
99
+ Load it through the CalDec repository, which registers UltraBERT's modeling code, switches its local-attention layers to an exact block-sparse path and runs all questions in one pass:
100
+
101
+ ```bash
102
+ git clone https://github.com/kgrozdanovski/caldec && cd caldec
103
+ python3 -m pip install -r requirements.txt # Python 3.12; torch 2.14, transformers 5.17, laya 0.3.6
104
+ ```
105
+
106
+ ```python
107
+ import sys
108
+ sys.path.insert(0, "scripts")
109
+ from data import load_agent
110
+
111
+ agent = load_agent("kgrozdanovski/caldec-ultra-150m")
112
+ result = agent.system_one(
113
+ {"source": "read_webpage", "text": "...a long fetched page..."},
114
+ {"injection": {"type": "noul", "instructions": "The text contains instructions addressed to an AI assistant."}},
115
+ )
116
+ p_injection = result["answers"]["injection"]["noul"]
117
+ ```
118
+
119
+ Loading runs the UltraBERT modeling code shipped in this repository's `encoder/` directory (copied unchanged from [dmis-lab/UltraBERT-150M](https://huggingface.co/dmis-lab/UltraBERT-150M) at the revision it was trained from), as `trust_remote_code` would. States longer than 8,192 tokens are cut at the end. A `choice` or `score` answer has a `probabilities` mapping. **Ignore `action.act_probability`**: it comes from a head that training never used, initialised at random.
120
+
121
+ ## Training
122
+
123
+ UltraBERT with a freshly initialised two-layer decision head, fine-tuned with soft cross-entropy on teacher distributions: the Assistant Decisions train split (4,984 cases), its long-state train build (117 cases at about 4–8K tokens), the `LocalLLaMA/typed-decisions` train split and 2,700 MNLI and BoolQ rows, six epochs at up to 8,192 tokens with per-site inverse-square-root weighting, UltraBERT's fine-tuning optimiser (AdamW β2 0.98, ε 1e-6, weight decay 0.1, linear warm-up and decay) and the epoch kept by validation soft NLL. Temperatures are fitted on validation and ship in `rl_agent_config.json`. The [recipe](https://github.com/kgrozdanovski/caldec/blob/main/ULTRA.md#recipe) reproduces it on one 16 GB GPU.
124
+
125
+ No Claude, GPT or Gemini output was used in training; those labels are evaluation targets only.
126
+
127
+ ## Limits
128
+
129
+ The labels are synthetic model judgments, and the states are synthetic. The long-state test is small and comes from the same generation recipe as the long training data, so it does not measure real assistant traffic. Calibration (ECE 0.083) is weaker than CalDec GLiNER's (0.039); the model is under-confident. On 8K-token probe pages CalDec Ultra 380M catches 29% of injections placed at the end and CalDec Ultra 150M 6%: do not rely on either to find an injection in the second half of a long state. Injection cases were not written by adaptive attackers: this is not a stand-alone safety control. Each model is one training run; a second run of the 150M recipe scored 1.4 assistant-test points lower ([seed variance](https://github.com/kgrozdanovski/caldec/blob/main/ULTRA.md#seed-variance)). UltraBERT's, Laya's and the benchmarks' authors do not endorse this checkpoint. Apache 2.0, matching the base model.
130
+
131
+ ## Citation and contact
132
+
133
+ Contact [Kristijan Grozdanovski](mailto:kgrozdanovski7@gmail.com). See also [CITATION.cff](https://github.com/kgrozdanovski/caldec/blob/main/CITATION.cff).
134
+
135
+ ```bibtex
136
+ @misc{grozdanovski2026caldecultra150m,
137
+ author = {Grozdanovski, Kristijan},
138
+ title = {CalDec Ultra 150M},
139
+ year = {2026},
140
+ url = {https://huggingface.co/kgrozdanovski/caldec-ultra-150m}
141
+ }
142
+ ```
SHA256SUMS ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ f016691e48223e6b2154b0d24b5f28dd8920ff4d4ba55068b7d6f214b8b78bb2 encoder/config.json
2
+ 823d10bda19f5164da4f79f8f9c01e5ebd7a75569abce78c0a26b7674fc78cd9 encoder/configuration_ultrabert.py
3
+ bfca1bd08af72cd170e58b5a048c67b52bc9d06a2a42847c7a387751f527f333 encoder/modeling_ultrabert.py
4
+ ad2d1ae13ee7f0f5fc60dbe56e1dd959b8043fc6704d20f0a7f60bf057f8034c encoder/__pycache__/configuration_ultrabert.cpython-312.pyc
5
+ bb4235193266f683ac89995570ed5e31392922951e6fce81bcbfa94097243b6a encoder/__pycache__/modeling_ultrabert.cpython-312.pyc
6
+ ddf6769ae0666a92dd38c88bb05b4864b778489f219d123973d26d43b0f78b3b model.safetensors
7
+ 9a53b399110c141a944a0d368f2d4406738beea6fcb169832ec3f94060c8b376 README.md
8
+ 3ed5decd72d8a60c12e3bde252d2cdc001d026c3f6172fdc2659df8a81f4f0c2 rl_agent_config.json
9
+ 29bde0f7eabd60a6669a42c530ec464c178f8bc39c1d7c2a78fa11888103ffba tokenizer/tokenizer_config.json
10
+ 38734bb17ef19f84c67b5eb5692bea19801ffd02cb5c5ffc11429e76b0242e08 tokenizer/tokenizer.json
encoder/__pycache__/configuration_ultrabert.cpython-312.pyc ADDED
Binary file (2.18 kB). View file
 
encoder/__pycache__/modeling_ultrabert.cpython-312.pyc ADDED
Binary file (39.8 kB). View file
 
encoder/config.json ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "UltrabertForMaskedLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "attention_windows": [
8
+ 128,
9
+ 128,
10
+ null,
11
+ 128,
12
+ 128,
13
+ null,
14
+ 128,
15
+ 128,
16
+ null,
17
+ 128,
18
+ 128,
19
+ null,
20
+ 128,
21
+ 128,
22
+ null,
23
+ 128,
24
+ 128,
25
+ null,
26
+ 128,
27
+ 128,
28
+ null,
29
+ 128,
30
+ 128,
31
+ null
32
+ ],
33
+ "auto_map": {
34
+ "AutoConfig": "configuration_ultrabert.UltrabertConfig",
35
+ "AutoModel": "modeling_ultrabert.UltrabertModel",
36
+ "AutoModelForMaskedLM": "modeling_ultrabert.UltrabertForMaskedLM",
37
+ "AutoModelForQuestionAnswering": "modeling_ultrabert.UltrabertForQuestionAnswering",
38
+ "AutoModelForSequenceClassification": "modeling_ultrabert.UltrabertForSequenceClassification",
39
+ "AutoModelForTokenClassification": "modeling_ultrabert.UltrabertForTokenClassification"
40
+ },
41
+ "bos_token_id": 0,
42
+ "classifier_dropout": 0.0,
43
+ "dtype": "float32",
44
+ "eos_token_id": 0,
45
+ "head_dim": 128,
46
+ "hidden_act": "silu",
47
+ "hidden_size": 768,
48
+ "initializer_range": 0.02,
49
+ "intermediate_size": 1024,
50
+ "mlp_bias": false,
51
+ "model_type": "ultrabert",
52
+ "num_attention_heads": 6,
53
+ "num_hidden_layers": 24,
54
+ "num_key_value_heads": 6,
55
+ "pad_token_id": 0,
56
+ "prediction_head_size": 768,
57
+ "reference_compile": false,
58
+ "rms_norm_eps": 1e-06,
59
+ "rope_theta": [
60
+ 10000.0,
61
+ 10000.0,
62
+ 2560000.0,
63
+ 10000.0,
64
+ 10000.0,
65
+ 2560000.0,
66
+ 10000.0,
67
+ 10000.0,
68
+ 2560000.0,
69
+ 10000.0,
70
+ 10000.0,
71
+ 2560000.0,
72
+ 10000.0,
73
+ 10000.0,
74
+ 2560000.0,
75
+ 10000.0,
76
+ 10000.0,
77
+ 2560000.0,
78
+ 10000.0,
79
+ 10000.0,
80
+ 2560000.0,
81
+ 10000.0,
82
+ 10000.0,
83
+ 2560000.0
84
+ ],
85
+ "tie_word_embeddings": false,
86
+ "transformers_version": "5.17.0",
87
+ "vocab_size": 49152
88
+ }
encoder/configuration_ultrabert.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+
5
+ from transformers.configuration_utils import PretrainedConfig
6
+
7
+
8
+ class UltrabertConfig(PretrainedConfig):
9
+ model_type = "ultrabert"
10
+
11
+ def __init__(
12
+ self,
13
+ vocab_size=32000,
14
+ hidden_size=4096,
15
+ intermediate_size=11008,
16
+ prediction_head_size=None,
17
+ num_hidden_layers=32,
18
+ num_attention_heads=32,
19
+ num_key_value_heads=None,
20
+ attention_windows=None,
21
+ hidden_act="silu",
22
+ initializer_range=0.02,
23
+ rms_norm_eps=1e-6,
24
+ pad_token_id=0,
25
+ bos_token_id=0,
26
+ eos_token_id=0,
27
+ tie_word_embeddings=False,
28
+ rope_theta=10000.0,
29
+ attention_bias=False,
30
+ attention_dropout=0.0,
31
+ mlp_bias=False,
32
+ head_dim=None,
33
+ classifier_dropout=0.0,
34
+ **kwargs,
35
+ ):
36
+ super().__init__(
37
+ pad_token_id=pad_token_id,
38
+ bos_token_id=bos_token_id,
39
+ eos_token_id=eos_token_id,
40
+ tie_word_embeddings=tie_word_embeddings,
41
+ **kwargs,
42
+ )
43
+ self.vocab_size = vocab_size
44
+ self.hidden_size = hidden_size
45
+ self.intermediate_size = intermediate_size
46
+ self.prediction_head_size = prediction_head_size
47
+ self.num_hidden_layers = num_hidden_layers
48
+ self.num_attention_heads = num_attention_heads
49
+ self.num_key_value_heads = num_key_value_heads or num_attention_heads
50
+ self.attention_windows = (
51
+ attention_windows
52
+ if isinstance(attention_windows, Iterable)
53
+ else [attention_windows] * num_hidden_layers
54
+ )
55
+ self.hidden_act = hidden_act
56
+ self.initializer_range = initializer_range
57
+ self.rms_norm_eps = rms_norm_eps
58
+ self.rope_theta = (
59
+ rope_theta
60
+ if isinstance(rope_theta, Iterable)
61
+ else [rope_theta] * num_hidden_layers
62
+ )
63
+ self.attention_bias = attention_bias
64
+ self.attention_dropout = attention_dropout
65
+ self.mlp_bias = mlp_bias
66
+ self.head_dim = head_dim or self.hidden_size // self.num_attention_heads
67
+ self.classifier_dropout = classifier_dropout
encoder/modeling_ultrabert.py ADDED
@@ -0,0 +1,766 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
2
+ # This file was automatically generated from examples/modular_ultrabert.py.
3
+ # Do NOT edit this file manually as any edits will be overwritten by the generation of
4
+ # the file from the modular. If any change should be done, please apply the change to the
5
+ # modular_ultrabert.py file directly. One of our CI enforces this.
6
+ # 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
7
+ from collections.abc import Callable
8
+
9
+ import torch
10
+ from torch import nn
11
+ from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
12
+ from transformers.activations import ACT2FN
13
+ from transformers.modeling_outputs import (
14
+ BaseModelOutput,
15
+ MaskedLMOutput,
16
+ QuestionAnsweringModelOutput,
17
+ SequenceClassifierOutput,
18
+ TokenClassifierOutput,
19
+ )
20
+ from transformers.modeling_utils import PreTrainedModel
21
+ from transformers.processing_utils import Unpack
22
+ from transformers.utils import TransformersKwargs, auto_docstring, can_return_tuple
23
+ from transformers.utils.generic import merge_with_config_defaults
24
+ from transformers.utils.output_capturing import capture_outputs
25
+
26
+ from transformers.cache_utils import Cache
27
+ from transformers.integrations import use_kernel_forward_from_hub, use_kernelized_func
28
+ from transformers.modeling_layers import GradientCheckpointingLayer
29
+ from transformers.modeling_rope_utils import dynamic_rope_update
30
+ from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS
31
+ from transformers.utils.deprecation import deprecate_kwarg
32
+ from transformers.utils.generic import maybe_autocast
33
+ from .configuration_ultrabert import UltrabertConfig
34
+
35
+
36
+ class RotaryEmbedding(nn.Module):
37
+ @deprecate_kwarg("device", version="5.18")
38
+ def __init__(self, base: float, dim: int, device: torch.device | None = None):
39
+ super().__init__()
40
+ self.rope_type = "default"
41
+ self.attention_scaling = 1
42
+ self.base, self.dim = base, dim
43
+
44
+ inv_freq = torch.arange(0, dim, 2, dtype=torch.int64)
45
+ inv_freq = 1.0 / (base ** (inv_freq.to(device=device, dtype=torch.float) / dim))
46
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
47
+
48
+ @staticmethod
49
+ @deprecate_kwarg("device", version="5.18")
50
+ def compute_default_rope_parameters(
51
+ config: UltrabertConfig, device=None, **kwargs
52
+ ) -> tuple[torch.Tensor, float]:
53
+ """
54
+ Computes the inverse frequencies according to the original RoPE implementation
55
+ Args:
56
+ config ([`~transformers.PreTrainedConfig`]):
57
+ The model configuration.
58
+ Returns:
59
+ Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
60
+ post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
61
+ """
62
+ base = config.rope_parameters["rope_theta"]
63
+ dim = (
64
+ getattr(config, "head_dim", None)
65
+ or config.hidden_size // config.num_attention_heads
66
+ )
67
+
68
+ attention_factor = 1.0 # Unused in this type of RoPE
69
+ # Compute the inverse frequencies
70
+ inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
71
+ return inv_freq.to(device), attention_factor
72
+
73
+ @torch.no_grad()
74
+ @dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
75
+ def forward(self, x, position_ids):
76
+ inv_freq_expanded = (
77
+ self.inv_freq[None, :, None]
78
+ .expand(position_ids.shape[0], -1, 1)
79
+ .to(dtype=torch.float, device=x.device)
80
+ )
81
+ position_ids_expanded = position_ids[:, None, :].float()
82
+
83
+ device_type = (
84
+ x.device.type
85
+ if isinstance(x.device.type, str) and x.device.type != "mps"
86
+ else "cpu"
87
+ )
88
+ # Disable any outside autocast context if any, to really force fp32
89
+ with maybe_autocast(device_type=device_type, enabled=False):
90
+ freqs = (inv_freq_expanded @ position_ids_expanded).transpose(1, 2)
91
+ emb = torch.cat((freqs, freqs), dim=-1)
92
+ cos = emb.cos() * self.attention_scaling
93
+ sin = emb.sin() * self.attention_scaling
94
+
95
+ return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
96
+
97
+
98
+ def rotate_half(x):
99
+ """Rotates half the hidden dims of the input."""
100
+ x1 = x[..., : x.shape[-1] // 2]
101
+ x2 = x[..., x.shape[-1] // 2 :]
102
+ return torch.cat((-x2, x1), dim=-1)
103
+
104
+
105
+ @use_kernel_forward_from_hub("rotary_pos_emb")
106
+ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
107
+ """Applies Rotary Position Embedding to the query and key tensors.
108
+
109
+ Args:
110
+ q (`torch.Tensor`): The query tensor.
111
+ k (`torch.Tensor`): The key tensor.
112
+ cos (`torch.Tensor`): The cosine part of the rotary embedding.
113
+ sin (`torch.Tensor`): The sine part of the rotary embedding.
114
+ unsqueeze_dim (`int`, *optional*, defaults to 1):
115
+ The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
116
+ sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
117
+ that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
118
+ k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
119
+ cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
120
+ the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
121
+ Returns:
122
+ `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
123
+ """
124
+ cos = cos.unsqueeze(unsqueeze_dim)
125
+ sin = sin.unsqueeze(unsqueeze_dim)
126
+ q_embed = (q * cos) + (rotate_half(q) * sin)
127
+ k_embed = (k * cos) + (rotate_half(k) * sin)
128
+ return q_embed, k_embed
129
+
130
+
131
+ def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
132
+ """
133
+ This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
134
+ num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
135
+ """
136
+ batch, num_key_value_heads, slen, head_dim = hidden_states.shape
137
+ if n_rep == 1:
138
+ return hidden_states
139
+ hidden_states = hidden_states[:, :, None, :, :].expand(
140
+ batch, num_key_value_heads, n_rep, slen, head_dim
141
+ )
142
+ return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
143
+
144
+
145
+ def eager_attention_forward(
146
+ module: nn.Module,
147
+ query: torch.Tensor,
148
+ key: torch.Tensor,
149
+ value: torch.Tensor,
150
+ attention_mask: torch.Tensor | None,
151
+ scaling: float,
152
+ dropout: float = 0.0,
153
+ **kwargs: Unpack[TransformersKwargs],
154
+ ):
155
+ key_states = repeat_kv(key, module.num_key_value_groups)
156
+ value_states = repeat_kv(value, module.num_key_value_groups)
157
+
158
+ attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
159
+ if attention_mask is not None:
160
+ attn_weights = attn_weights + attention_mask
161
+
162
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(
163
+ query.dtype
164
+ )
165
+ attn_weights = nn.functional.dropout(
166
+ attn_weights, p=dropout, training=module.training
167
+ )
168
+ attn_output = torch.matmul(attn_weights, value_states)
169
+ attn_output = attn_output.transpose(1, 2).contiguous()
170
+
171
+ return attn_output, attn_weights
172
+
173
+
174
+ @use_kernelized_func(apply_rotary_pos_emb)
175
+ class UltrabertAttention(nn.Module):
176
+ """Multi-headed attention from 'Attention Is All You Need' paper"""
177
+
178
+ def __init__(self, config: UltrabertConfig, layer_idx: int):
179
+ super().__init__()
180
+ self.config = config
181
+ self.layer_idx = layer_idx
182
+ self.head_dim = getattr(
183
+ config, "head_dim", config.hidden_size // config.num_attention_heads
184
+ )
185
+ self.num_key_value_groups = (
186
+ config.num_attention_heads // config.num_key_value_heads
187
+ )
188
+ self.scaling = self.head_dim**-0.5
189
+ self.attention_dropout = config.attention_dropout
190
+ self.is_causal = False
191
+
192
+ self.q_proj = nn.Linear(
193
+ config.hidden_size,
194
+ config.num_attention_heads * self.head_dim,
195
+ bias=config.attention_bias,
196
+ )
197
+ self.k_proj = nn.Linear(
198
+ config.hidden_size,
199
+ config.num_key_value_heads * self.head_dim,
200
+ bias=config.attention_bias,
201
+ )
202
+ self.v_proj = nn.Linear(
203
+ config.hidden_size,
204
+ config.num_key_value_heads * self.head_dim,
205
+ bias=config.attention_bias,
206
+ )
207
+ self.o_proj = nn.Linear(
208
+ config.num_attention_heads * self.head_dim,
209
+ config.hidden_size,
210
+ bias=config.attention_bias,
211
+ )
212
+
213
+ def forward(
214
+ self,
215
+ hidden_states: torch.Tensor,
216
+ position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
217
+ attention_mask: torch.Tensor | None = None,
218
+ past_key_values: Cache | None = None,
219
+ **kwargs: Unpack[TransformersKwargs],
220
+ ) -> tuple[torch.Tensor, torch.Tensor]:
221
+ input_shape = hidden_states.shape[:-1]
222
+ hidden_shape = (*input_shape, -1, self.head_dim)
223
+
224
+ query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
225
+ key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
226
+ value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
227
+
228
+ cos, sin = position_embeddings
229
+ query_states, key_states = apply_rotary_pos_emb(
230
+ query_states, key_states, cos, sin
231
+ )
232
+
233
+ if past_key_values is not None:
234
+ key_states, value_states = past_key_values.update(
235
+ key_states, value_states, self.layer_idx
236
+ )
237
+
238
+ attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
239
+ self.config._attn_implementation, eager_attention_forward
240
+ )
241
+
242
+ attn_output, attn_weights = attention_interface(
243
+ self,
244
+ query_states,
245
+ key_states,
246
+ value_states,
247
+ attention_mask,
248
+ dropout=0.0 if not self.training else self.attention_dropout,
249
+ scaling=self.scaling,
250
+ **kwargs,
251
+ )
252
+
253
+ attn_output = attn_output.reshape(*input_shape, -1).contiguous()
254
+ attn_output = self.o_proj(attn_output)
255
+ return attn_output, attn_weights
256
+
257
+
258
+ @use_kernel_forward_from_hub("RMSNorm")
259
+ class UltrabertRMSNorm(nn.Module):
260
+ def __init__(self, hidden_size, eps: float = 1e-6) -> None:
261
+ """
262
+ UltrabertRMSNorm is equivalent to T5LayerNorm
263
+ """
264
+ super().__init__()
265
+ self.weight = nn.Parameter(torch.ones(hidden_size))
266
+ self.variance_epsilon = eps
267
+
268
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
269
+ input_dtype = hidden_states.dtype
270
+ hidden_states = hidden_states.to(torch.float32)
271
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
272
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
273
+ return self.weight * hidden_states.to(input_dtype)
274
+
275
+ def extra_repr(self):
276
+ return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
277
+
278
+
279
+ class UltrabertMLP(nn.Module):
280
+ def __init__(self, config):
281
+ super().__init__()
282
+ self.config = config
283
+ self.hidden_size = config.hidden_size
284
+ self.intermediate_size = config.intermediate_size
285
+ self.gate_proj = nn.Linear(
286
+ self.hidden_size, self.intermediate_size, bias=config.mlp_bias
287
+ )
288
+ self.up_proj = nn.Linear(
289
+ self.hidden_size, self.intermediate_size, bias=config.mlp_bias
290
+ )
291
+ self.down_proj = nn.Linear(
292
+ self.intermediate_size, self.hidden_size, bias=config.mlp_bias
293
+ )
294
+ self.act_fn = ACT2FN[config.hidden_act]
295
+
296
+ def forward(self, x):
297
+ down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
298
+ return down_proj
299
+
300
+
301
+ class UltrabertLayer(GradientCheckpointingLayer):
302
+ def __init__(self, config: UltrabertConfig, layer_idx: int):
303
+ super().__init__()
304
+ self.hidden_size = config.hidden_size
305
+
306
+ self.self_attn = UltrabertAttention(config=config, layer_idx=layer_idx)
307
+
308
+ self.mlp = UltrabertMLP(config)
309
+ self.input_layernorm = UltrabertRMSNorm(
310
+ config.hidden_size, eps=config.rms_norm_eps
311
+ )
312
+ self.post_attention_layernorm = UltrabertRMSNorm(
313
+ config.hidden_size, eps=config.rms_norm_eps
314
+ )
315
+
316
+ def forward(
317
+ self,
318
+ hidden_states: torch.Tensor,
319
+ attention_mask: torch.Tensor | None = None,
320
+ position_ids: torch.LongTensor | None = None,
321
+ past_key_values: Cache | None = None,
322
+ use_cache: bool | None = False,
323
+ position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None,
324
+ **kwargs: Unpack[TransformersKwargs],
325
+ ) -> torch.Tensor:
326
+ residual = hidden_states
327
+ hidden_states = self.input_layernorm(hidden_states)
328
+ # Self Attention
329
+ hidden_states, _ = self.self_attn(
330
+ hidden_states=hidden_states,
331
+ attention_mask=attention_mask,
332
+ position_ids=position_ids,
333
+ past_key_values=past_key_values,
334
+ use_cache=use_cache,
335
+ position_embeddings=position_embeddings,
336
+ **kwargs,
337
+ )
338
+ hidden_states = residual + hidden_states
339
+
340
+ # Fully Connected
341
+ residual = hidden_states
342
+ hidden_states = self.post_attention_layernorm(hidden_states)
343
+ hidden_states = self.mlp(hidden_states)
344
+ hidden_states = residual + hidden_states
345
+ return hidden_states
346
+
347
+
348
+ @auto_docstring
349
+ class UltrabertPreTrainedModel(PreTrainedModel):
350
+ config: UltrabertConfig
351
+ base_model_prefix = "ultrabert"
352
+ supports_gradient_checkpointing = True
353
+ _no_split_modules = ["UltrabertLayer"]
354
+ _skip_keys_device_placement = ["past_key_values"]
355
+ _supports_flash_attn = True
356
+ _supports_sdpa = True
357
+ _supports_flex_attn = True
358
+
359
+ _can_compile_fullgraph = True
360
+ _supports_attention_backend = True
361
+ _can_record_outputs = {
362
+ "hidden_states": UltrabertLayer,
363
+ "attentions": UltrabertAttention,
364
+ }
365
+ config_class = UltrabertConfig
366
+
367
+ def _init_weights(self, module):
368
+ super()._init_weights(module)
369
+ if isinstance(module, RotaryEmbedding):
370
+ inv_freq = torch.arange(0, module.dim, 2, dtype=torch.int64)
371
+ inv_freq = 1.0 / (
372
+ module.base
373
+ ** (
374
+ inv_freq.to(device=module.inv_freq.device, dtype=torch.float)
375
+ / module.dim
376
+ )
377
+ )
378
+ module.inv_freq.copy_(inv_freq)
379
+
380
+
381
+ def create_local_attention_mask(
382
+ seq_len: int,
383
+ sliding_window: int | None = None,
384
+ device: torch.device | None = None,
385
+ ) -> torch.Tensor:
386
+ attention_mask = torch.ones(1, seq_len, seq_len, dtype=torch.bool, device=device)
387
+ if sliding_window:
388
+ attention_mask = attention_mask.tril(sliding_window).triu(-sliding_window)
389
+ return attention_mask
390
+
391
+
392
+ @auto_docstring
393
+ class UltrabertModel(UltrabertPreTrainedModel):
394
+ def __init__(self, config: UltrabertConfig):
395
+ super().__init__(config)
396
+ self.padding_idx = config.pad_token_id
397
+ self.vocab_size = config.vocab_size
398
+
399
+ self.embed_tokens = nn.Embedding(
400
+ config.vocab_size, config.hidden_size, self.padding_idx
401
+ )
402
+
403
+ self.layers = nn.ModuleList(
404
+ [UltrabertLayer(config, i) for i in range(config.num_hidden_layers)]
405
+ )
406
+ self.norm = UltrabertRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
407
+ self.rotary_emb = nn.ModuleDict()
408
+ self.gradient_checkpointing = False
409
+ for base in set(config.rope_theta):
410
+ name = str(base).replace(".", "_")
411
+ self.rotary_emb[name] = RotaryEmbedding(base, config.head_dim)
412
+
413
+ # Initialize weights and apply final processing
414
+ self.post_init()
415
+
416
+ @merge_with_config_defaults
417
+ @capture_outputs
418
+ @auto_docstring
419
+ def forward(
420
+ self,
421
+ input_ids: torch.Tensor | None = None,
422
+ attention_mask: torch.Tensor | None = None,
423
+ position_ids: torch.Tensor | None = None,
424
+ inputs_embeds: torch.Tensor | None = None,
425
+ **kwargs: Unpack[TransformersKwargs],
426
+ ) -> BaseModelOutput:
427
+ if (input_ids is None) ^ (inputs_embeds is not None):
428
+ raise ValueError("must specify exactly one of input_ids or inputs_embeds")
429
+ if inputs_embeds is None:
430
+ inputs_embeds = self.embed_tokens(input_ids)
431
+ if position_ids is None:
432
+ position_ids = torch.arange(inputs_embeds.size(1))
433
+ position_ids = position_ids.to(inputs_embeds.device).unsqueeze(0)
434
+ if (
435
+ attention_mask is None
436
+ and self.config._attn_implementation != "flash_attention_2"
437
+ ):
438
+ attention_mask = inputs_embeds.new_ones(inputs_embeds.shape[:2])
439
+ varlen_kwargs = {
440
+ k: kwargs[k]
441
+ for k in ("cu_seq_lens_q", "cu_seq_lens_k", "max_length_q", "max_length_k")
442
+ if kwargs.get(k) is not None
443
+ }
444
+
445
+ # Create attention masks for different local window sizes and store by window.
446
+ attention_mask_dict = {}
447
+ for local_window in list(set(self.config.attention_windows)) + [None]:
448
+ if self.config._attn_implementation == "flash_attention_2":
449
+ # For FlashAttention 2, rely on the `sliding_window` keyword instead of
450
+ # constructing masks manually.
451
+ attention_mask_dict[local_window] = attention_mask
452
+ else:
453
+ window_mask = create_local_attention_mask(
454
+ seq_len=attention_mask.size(1),
455
+ sliding_window=local_window,
456
+ device=attention_mask.device,
457
+ )
458
+ window_mask = window_mask & attention_mask.bool().unsqueeze(1)
459
+ attention_mask_dict[local_window] = (
460
+ torch.where(window_mask, 0.0, torch.finfo(inputs_embeds.dtype).min)
461
+ .to(inputs_embeds.dtype)
462
+ .unsqueeze(1)
463
+ )
464
+
465
+ # Create position embeddings to be shared across the decoder layers.
466
+ hidden_states, position_embeddings = inputs_embeds, {}
467
+ for base in set(self.config.rope_theta):
468
+ rotary_emb = self.rotary_emb[str(base).replace(".", "_")]
469
+ position_embeddings[base] = rotary_emb(hidden_states, position_ids)
470
+
471
+ for i, decoder_layer in enumerate(self.layers[: self.config.num_hidden_layers]):
472
+ local_window = self.config.attention_windows[i]
473
+ hidden_states = decoder_layer(
474
+ hidden_states,
475
+ attention_mask=attention_mask_dict[local_window],
476
+ position_ids=position_ids,
477
+ position_embeddings=position_embeddings[self.config.rope_theta[i]],
478
+ sliding_window=(
479
+ local_window + 1
480
+ if local_window is not None
481
+ and self.config._attn_implementation == "flash_attention_2"
482
+ else local_window
483
+ ),
484
+ **varlen_kwargs,
485
+ )
486
+ hidden_states = self.norm(hidden_states)
487
+ return BaseModelOutput(last_hidden_state=hidden_states)
488
+
489
+
490
+ class UltrabertPredictionHead(nn.Module):
491
+ def __init__(self, config: UltrabertConfig):
492
+ super().__init__()
493
+ if (dim := config.prediction_head_size) is not None:
494
+ self.linear1 = nn.Linear(config.hidden_size, dim, bias=False)
495
+ self.linear2 = nn.Linear(dim, config.hidden_size, bias=False)
496
+ self.act_fn = ACT2FN["gelu_pytorch_tanh"]
497
+
498
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
499
+ if hasattr(self, "linear1"):
500
+ return self.act_fn(self.linear2(self.act_fn(self.linear1(x))))
501
+ return x
502
+
503
+
504
+ @auto_docstring
505
+ class UltrabertForMaskedLM(UltrabertPreTrainedModel):
506
+ _tied_weights_keys = {"cls.weight": "ultrabert.embed_tokens.weight"}
507
+
508
+ def __init__(self, config: UltrabertConfig):
509
+ super().__init__(config)
510
+ self.ultrabert = UltrabertModel(config)
511
+ self.head = UltrabertPredictionHead(config)
512
+ self.cls = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
513
+
514
+ # Initialize weights and apply final processing
515
+ self.post_init()
516
+
517
+ def get_output_embeddings(self):
518
+ return self.cls
519
+
520
+ def set_output_embeddings(self, new_embeddings):
521
+ self.cls = new_embeddings
522
+
523
+ @can_return_tuple
524
+ @auto_docstring
525
+ def forward(
526
+ self,
527
+ input_ids: torch.Tensor | None = None,
528
+ attention_mask: torch.Tensor | None = None,
529
+ token_type_ids: torch.Tensor | None = None,
530
+ position_ids: torch.Tensor | None = None,
531
+ inputs_embeds: torch.Tensor | None = None,
532
+ labels: torch.Tensor | None = None,
533
+ **kwargs: Unpack[TransformersKwargs],
534
+ ) -> tuple[torch.Tensor] | MaskedLMOutput:
535
+ r"""
536
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
537
+ Labels for computing the masked language modeling loss. Indices should be in `[-100, 0, ...,
538
+ config.vocab_size]` (see `input_ids` docstring) Tokens with indices set to `-100` are ignored (masked), the
539
+ loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`
540
+ """
541
+ outputs = self.ultrabert(
542
+ input_ids,
543
+ attention_mask=attention_mask,
544
+ position_ids=position_ids,
545
+ inputs_embeds=inputs_embeds,
546
+ **kwargs,
547
+ )
548
+ prediction_scores = self.cls(self.head(outputs[0]))
549
+
550
+ masked_lm_loss = None
551
+ if labels is not None:
552
+ loss_fct = CrossEntropyLoss() # -100 index = padding token
553
+ masked_lm_loss = loss_fct(
554
+ prediction_scores.view(-1, self.config.vocab_size), labels.view(-1)
555
+ )
556
+
557
+ return MaskedLMOutput(
558
+ loss=masked_lm_loss,
559
+ logits=prediction_scores,
560
+ hidden_states=outputs.hidden_states,
561
+ attentions=outputs.attentions,
562
+ )
563
+
564
+
565
+ @auto_docstring(
566
+ custom_intro="""
567
+ Ultrabert Model transformer with a sequence classification/regression head on top (a linear layer on top of the pooled
568
+ output) e.g. for GLUE tasks.
569
+ """
570
+ )
571
+ class UltrabertForSequenceClassification(UltrabertPreTrainedModel):
572
+ def __init__(self, config: UltrabertConfig):
573
+ super().__init__(config)
574
+ self.num_labels = config.num_labels
575
+ self.config = config
576
+ self.ultrabert = UltrabertModel(config)
577
+ classifier_dropout = (
578
+ config.classifier_dropout
579
+ if config.classifier_dropout is not None
580
+ else config.hidden_dropout_prob
581
+ )
582
+ self.dropout = nn.Dropout(config.classifier_dropout)
583
+ self.classifier = nn.Linear(config.hidden_size, config.num_labels)
584
+
585
+ # Initialize weights and apply final processing
586
+ self.post_init()
587
+
588
+ @can_return_tuple
589
+ @auto_docstring
590
+ def forward(
591
+ self,
592
+ input_ids: torch.Tensor | None = None,
593
+ attention_mask: torch.Tensor | None = None,
594
+ token_type_ids: torch.Tensor | None = None,
595
+ position_ids: torch.Tensor | None = None,
596
+ inputs_embeds: torch.Tensor | None = None,
597
+ labels: torch.Tensor | None = None,
598
+ **kwargs: Unpack[TransformersKwargs],
599
+ ) -> tuple[torch.Tensor] | SequenceClassifierOutput:
600
+ r"""
601
+ labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
602
+ Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
603
+ config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
604
+ `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
605
+ """
606
+ outputs = self.ultrabert(
607
+ input_ids,
608
+ attention_mask=attention_mask,
609
+ position_ids=position_ids,
610
+ inputs_embeds=inputs_embeds,
611
+ **kwargs,
612
+ )
613
+ logits = self.classifier(self.dropout(outputs[0][:, 0]))
614
+
615
+ loss = None
616
+ if labels is not None:
617
+ if self.config.problem_type is None:
618
+ if self.num_labels == 1:
619
+ self.config.problem_type = "regression"
620
+ elif self.num_labels > 1 and (
621
+ labels.dtype == torch.long or labels.dtype == torch.int
622
+ ):
623
+ self.config.problem_type = "single_label_classification"
624
+ else:
625
+ self.config.problem_type = "multi_label_classification"
626
+
627
+ if self.config.problem_type == "regression":
628
+ loss_fct = MSELoss()
629
+ if self.num_labels == 1:
630
+ loss = loss_fct(logits.squeeze(), labels.squeeze())
631
+ else:
632
+ loss = loss_fct(logits, labels)
633
+ elif self.config.problem_type == "single_label_classification":
634
+ loss_fct = CrossEntropyLoss()
635
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
636
+ elif self.config.problem_type == "multi_label_classification":
637
+ loss_fct = BCEWithLogitsLoss()
638
+ loss = loss_fct(logits, labels)
639
+
640
+ return SequenceClassifierOutput(
641
+ loss=loss,
642
+ logits=logits,
643
+ hidden_states=outputs.hidden_states,
644
+ attentions=outputs.attentions,
645
+ )
646
+
647
+
648
+ @auto_docstring
649
+ class UltrabertForQuestionAnswering(UltrabertPreTrainedModel):
650
+ def __init__(self, config: UltrabertConfig):
651
+ super().__init__(config)
652
+ self.num_labels = config.num_labels
653
+
654
+ self.ultrabert = UltrabertModel(config)
655
+ self.qa_outputs = nn.Linear(config.hidden_size, config.num_labels)
656
+
657
+ # Initialize weights and apply final processing
658
+ self.post_init()
659
+
660
+ @can_return_tuple
661
+ @auto_docstring
662
+ def forward(
663
+ self,
664
+ input_ids: torch.Tensor | None = None,
665
+ attention_mask: torch.Tensor | None = None,
666
+ token_type_ids: torch.Tensor | None = None,
667
+ position_ids: torch.Tensor | None = None,
668
+ inputs_embeds: torch.Tensor | None = None,
669
+ start_positions: torch.Tensor | None = None,
670
+ end_positions: torch.Tensor | None = None,
671
+ **kwargs: Unpack[TransformersKwargs],
672
+ ) -> tuple[torch.Tensor] | QuestionAnsweringModelOutput:
673
+ outputs = self.ultrabert(
674
+ input_ids,
675
+ attention_mask=attention_mask,
676
+ position_ids=position_ids,
677
+ inputs_embeds=inputs_embeds,
678
+ **kwargs,
679
+ )
680
+ logits = self.qa_outputs(outputs[0])
681
+ start_logits, end_logits = logits.split(1, dim=-1)
682
+ start_logits = start_logits.squeeze(-1).contiguous()
683
+ end_logits = end_logits.squeeze(-1).contiguous()
684
+
685
+ total_loss = None
686
+ if start_positions is not None and end_positions is not None:
687
+ if len(start_positions.size()) > 1:
688
+ start_positions = start_positions.squeeze(-1)
689
+ if len(end_positions.size()) > 1:
690
+ end_positions = end_positions.squeeze(-1)
691
+
692
+ ignored_index = start_logits.size(1)
693
+ start_positions = start_positions.clamp(0, ignored_index)
694
+ end_positions = end_positions.clamp(0, ignored_index)
695
+
696
+ loss_fct = CrossEntropyLoss(ignore_index=ignored_index)
697
+ start_loss = loss_fct(start_logits, start_positions)
698
+ end_loss = loss_fct(end_logits, end_positions)
699
+ total_loss = (start_loss + end_loss) / 2
700
+
701
+ return QuestionAnsweringModelOutput(
702
+ loss=total_loss,
703
+ start_logits=start_logits,
704
+ end_logits=end_logits,
705
+ hidden_states=outputs.hidden_states,
706
+ attentions=outputs.attentions,
707
+ )
708
+
709
+
710
+ @auto_docstring
711
+ class UltrabertForTokenClassification(UltrabertPreTrainedModel):
712
+ def __init__(self, config: UltrabertConfig):
713
+ super().__init__(config)
714
+ self.num_labels = config.num_labels
715
+ self.ultrabert = UltrabertModel(config)
716
+ classifier_dropout = (
717
+ config.classifier_dropout
718
+ if config.classifier_dropout is not None
719
+ else config.hidden_dropout_prob
720
+ )
721
+ self.dropout = nn.Dropout(config.classifier_dropout)
722
+ self.classifier = nn.Linear(config.hidden_size, config.num_labels)
723
+
724
+ # Initialize weights and apply final processing
725
+ self.post_init()
726
+
727
+ @can_return_tuple
728
+ @auto_docstring
729
+ def forward(
730
+ self,
731
+ input_ids: torch.Tensor | None = None,
732
+ attention_mask: torch.Tensor | None = None,
733
+ token_type_ids: torch.Tensor | None = None,
734
+ position_ids: torch.Tensor | None = None,
735
+ inputs_embeds: torch.Tensor | None = None,
736
+ labels: torch.Tensor | None = None,
737
+ **kwargs: Unpack[TransformersKwargs],
738
+ ) -> tuple[torch.Tensor] | TokenClassifierOutput:
739
+ r"""
740
+ labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
741
+ Labels for computing the token classification loss. Indices should be in `[0, ..., config.num_labels - 1]`.
742
+ """
743
+ outputs = self.ultrabert(
744
+ input_ids,
745
+ attention_mask=attention_mask,
746
+ position_ids=position_ids,
747
+ inputs_embeds=inputs_embeds,
748
+ **kwargs,
749
+ )
750
+
751
+ sequence_output = outputs[0]
752
+
753
+ sequence_output = self.dropout(sequence_output)
754
+ logits = self.classifier(sequence_output)
755
+
756
+ loss = None
757
+ if labels is not None:
758
+ loss_fct = CrossEntropyLoss()
759
+ loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))
760
+
761
+ return TokenClassifierOutput(
762
+ loss=loss,
763
+ logits=logits,
764
+ hidden_states=outputs.hidden_states,
765
+ attentions=outputs.attentions,
766
+ )
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddf6769ae0666a92dd38c88bb05b4864b778489f219d123973d26d43b0f78b3b
3
+ size 664035864
rl_agent_config.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "head_layers": 2,
3
+ "max_prefixes": 6,
4
+ "act_costs": {
5
+ "escalate": 0.5
6
+ },
7
+ "cost_wrong_act": 3.0,
8
+ "encoder": "dmis-lab/UltraBERT-150M",
9
+ "encoder_revision": "545ac9d9c7aece444f014ada5a1e9818132b4d35",
10
+ "max_len": 8192,
11
+ "head_max_len": 192,
12
+ "amp_dtype": "bf16",
13
+ "model_name": "caldec-ultra-150m",
14
+ "temperature": [
15
+ 1.0,
16
+ 1.0,
17
+ 1.0
18
+ ],
19
+ "temperature_by_options": {
20
+ "choice:3-5": 1.3067494630813599,
21
+ "noul:2": 1.1769542694091797,
22
+ "score:3-5": 1.1716774702072144,
23
+ "choice:2": 1.1175421476364136
24
+ },
25
+ "training": {
26
+ "fine_tuned_from": "dmis-lab/UltraBERT-150M@545ac9d9c7aece444f014ada5a1e9818132b4d35 with a freshly initialized decision head",
27
+ "base_revision": "545ac9d9c7aece444f014ada5a1e9818132b4d35",
28
+ "epochs_completed": 6,
29
+ "selected_epoch": 6,
30
+ "updates": 3353,
31
+ "lr_encoder": 1e-05,
32
+ "lr_head": 0.0001,
33
+ "schedule": "linear",
34
+ "decisions": 9001,
35
+ "seconds": 2066,
36
+ "legacy_drop_tail": false,
37
+ "objective": "soft cross-entropy",
38
+ "with_public": true,
39
+ "balance_sites": true,
40
+ "seed": 20260924,
41
+ "packed": true,
42
+ "max_len": 8192,
43
+ "max_batch_tokens": 16384,
44
+ "extra_train": [
45
+ "general mix (scripts/general_data.py: MNLI, BoolQ)",
46
+ "kgrozdanovski/assistant-decisions long/train.jsonl"
47
+ ],
48
+ "extra_val": [
49
+ "general mix validation (scripts/general_data.py)",
50
+ "kgrozdanovski/assistant-decisions long/validation.jsonl"
51
+ ]
52
+ },
53
+ "packed": true
54
+ }
tokenizer/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": "<|endoftext|>",
5
+ "clean_up_tokenization_spaces": false,
6
+ "cls_token": "<|endoftext|>",
7
+ "eos_token": "<|endoftext|>",
8
+ "errors": "replace",
9
+ "extra_0": "<|endoftext|>",
10
+ "extra_1": "<|im_start|>",
11
+ "extra_10": "<issue_closed>",
12
+ "extra_11": "<jupyter_start>",
13
+ "extra_12": "<jupyter_text>",
14
+ "extra_13": "<jupyter_code>",
15
+ "extra_14": "<jupyter_output>",
16
+ "extra_15": "<|sep|>",
17
+ "extra_16": "<|mask|>",
18
+ "extra_2": "<|im_end|>",
19
+ "extra_3": "<repo_name>",
20
+ "extra_4": "<reponame>",
21
+ "extra_5": "<file_sep>",
22
+ "extra_6": "<filename>",
23
+ "extra_7": "<gh_stars>",
24
+ "extra_8": "<issue_start>",
25
+ "extra_9": "<issue_comment>",
26
+ "is_local": true,
27
+ "local_files_only": false,
28
+ "mask_token": "<|mask|>",
29
+ "model_max_length": 32768,
30
+ "model_specific_special_tokens": {
31
+ "extra_0": "<|endoftext|>",
32
+ "extra_1": "<|im_start|>",
33
+ "extra_10": "<issue_closed>",
34
+ "extra_11": "<jupyter_start>",
35
+ "extra_12": "<jupyter_text>",
36
+ "extra_13": "<jupyter_code>",
37
+ "extra_14": "<jupyter_output>",
38
+ "extra_15": "<|sep|>",
39
+ "extra_16": "<|mask|>",
40
+ "extra_2": "<|im_end|>",
41
+ "extra_3": "<repo_name>",
42
+ "extra_4": "<reponame>",
43
+ "extra_5": "<file_sep>",
44
+ "extra_6": "<filename>",
45
+ "extra_7": "<gh_stars>",
46
+ "extra_8": "<issue_start>",
47
+ "extra_9": "<issue_comment>"
48
+ },
49
+ "pad_token": "<|endoftext|>",
50
+ "sep_token": "<|sep|>",
51
+ "tokenizer_class": "GPT2Tokenizer",
52
+ "unk_token": "<|endoftext|>",
53
+ "vocab_size": 49152
54
+ }