Text Classification
Transformers
Safetensors
English
modernbert
commitment-detection
decision-detection
experimental
vela
text-embeddings-inference
Instructions to use TwilightTechie/vela-commitment-classifier-307m with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use TwilightTechie/vela-commitment-classifier-307m with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="TwilightTechie/vela-commitment-classifier-307m")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("TwilightTechie/vela-commitment-classifier-307m") model = AutoModelForSequenceClassification.from_pretrained("TwilightTechie/vela-commitment-classifier-307m", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Publish experimental commitment-classifier pilot
Browse files- .gitattributes +1 -0
- LICENSE +17 -0
- README.md +152 -0
- UPSTREAM_LICENSES.md +27 -0
- config.json +63 -0
- label-contract.json +11 -0
- model.safetensors +3 -0
- reproducibility/LICENSE +201 -0
- reproducibility/README.md +37 -0
- reproducibility/environment.txt +64 -0
- reproducibility/sequence_repair/__init__.py +1 -0
- reproducibility/sequence_repair/complete_adapter.py +94 -0
- reproducibility/sequence_repair/context.py +85 -0
- reproducibility/sequence_repair/corpus.py +55 -0
- reproducibility/sequence_repair/data.py +107 -0
- reproducibility/sequence_repair/evaluate.py +147 -0
- reproducibility/sequence_repair/export.py +172 -0
- reproducibility/sequence_repair/fetch_sources.py +48 -0
- reproducibility/sequence_repair/hydrate_annotations.py +95 -0
- reproducibility/sequence_repair/initialize.py +76 -0
- reproducibility/sequence_repair/model.py +94 -0
- reproducibility/sequence_repair/optimization.py +220 -0
- reproducibility/sequence_repair/prepare_context.py +158 -0
- reproducibility/sequence_repair/prepare_retention.py +87 -0
- reproducibility/sequence_repair/retention.py +410 -0
- reproducibility/sequence_repair/runtime_mapping.py +58 -0
- reproducibility/sequence_repair/selection.py +158 -0
- reproducibility/sequence_repair/task_head.py +102 -0
- reproducibility/sequence_repair/train.py +791 -0
- reproducibility/sequence_repair/training_order.py +134 -0
- reproducibility/source-files.json +22 -0
- reproducibility/training.json +26 -0
- special_tokens_map.json +55 -0
- task-head.json +49 -0
- tokenizer.json +3 -0
- tokenizer_config.json +2018 -0
- training-origin.json +5 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
| 5 |
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
| 6 |
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 7 |
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
| 8 |
+
following conditions:
|
| 9 |
+
|
| 10 |
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
| 11 |
+
portions of the Software.
|
| 12 |
+
|
| 13 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
| 14 |
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
| 15 |
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
| 16 |
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
| 17 |
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
library_name: transformers
|
| 6 |
+
pipeline_tag: text-classification
|
| 7 |
+
base_model: vllm-sr/Vela-1.0-Encoder-307M
|
| 8 |
+
base_model_relation: finetune
|
| 9 |
+
datasets:
|
| 10 |
+
- TwilightTechie/commitment-statements-pilot
|
| 11 |
+
tags:
|
| 12 |
+
- commitment-detection
|
| 13 |
+
- decision-detection
|
| 14 |
+
- experimental
|
| 15 |
+
- vela
|
| 16 |
+
widget:
|
| 17 |
+
- text: We have decided to update the document today.
|
| 18 |
+
- text: I like mountains.
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# Vela commitment classifier — experimental pilot
|
| 22 |
+
|
| 23 |
+
A short English statement classifier that detects an **expressed decision, firm
|
| 24 |
+
intention, or commitment**. This is a personal fine-tuning experiment derived from
|
| 25 |
+
Vela, not an official vLLM Semantic Router release or an endorsed product.
|
| 26 |
+
|
| 27 |
+
| Label | Meaning |
|
| 28 |
+
| --- | --- |
|
| 29 |
+
| `DECISION_EXPRESSED` | An affirmed chosen action, firm intention, commitment, explicit rejection or chosen inaction. Explicitly reported past choices also count. |
|
| 30 |
+
| `NO_DECISION_EXPRESSED` | Preferences, questions, requests, possibilities, predictions, example quotations, or completed-action reports without an expressed choice. |
|
| 31 |
+
|
| 32 |
+
It does not determine whether a promise was fulfilled, infer an unspoken mental
|
| 33 |
+
state, extract tasks, or decide whether a statement deserves a decision-log entry.
|
| 34 |
+
Routine firm process commitments count as positive under this broad contract.
|
| 35 |
+
|
| 36 |
+
## Quick start
|
| 37 |
+
|
| 38 |
+
```bash
|
| 39 |
+
pip install torch transformers==4.57.6
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
```python
|
| 43 |
+
from transformers import pipeline
|
| 44 |
+
|
| 45 |
+
classifier = pipeline(
|
| 46 |
+
"text-classification",
|
| 47 |
+
model="TwilightTechie/vela-commitment-classifier-307m",
|
| 48 |
+
tokenizer="TwilightTechie/vela-commitment-classifier-307m",
|
| 49 |
+
device=-1, # CPU
|
| 50 |
+
)
|
| 51 |
+
print(classifier("We have decided to update the document today."))
|
| 52 |
+
print(classifier("I like mountains."))
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
The first example was classified as `DECISION_EXPRESSED`; the second as
|
| 56 |
+
`NO_DECISION_EXPRESSED`. A GPU or hosted endpoint is not required for inference.
|
| 57 |
+
Scores are model softmax outputs, **not calibrated certainty**. Run only trusted
|
| 58 |
+
standard library code; this model requires no `trust_remote_code=True`.
|
| 59 |
+
|
| 60 |
+
Keep inputs to **256 tokens including special tokens**. You can enforce this
|
| 61 |
+
before classification:
|
| 62 |
+
|
| 63 |
+
```python
|
| 64 |
+
text = "We agreed to postpone the rollout until the pilot finishes."
|
| 65 |
+
if len(classifier.tokenizer(text)["input_ids"]) > 256:
|
| 66 |
+
raise ValueError("This pilot's input budget is 256 tokens")
|
| 67 |
+
print(classifier(text))
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
The foundation has a larger architectural context capacity; this fine-tuned
|
| 71 |
+
pilot has not established quality on long documents or conversations.
|
| 72 |
+
|
| 73 |
+
## Training and provenance
|
| 74 |
+
|
| 75 |
+
- Foundation: [`vllm-sr/Vela-1.0-Encoder-307M`](https://huggingface.co/vllm-sr/Vela-1.0-Encoder-307M).
|
| 76 |
+
- Exact foundation revision: `720ab37904ce15054068d429381bfae7549f00f6`.
|
| 77 |
+
- Architecture: ModernBERT sequence classifier with a fresh two-label task head.
|
| 78 |
+
- Method: complete checkpoint, updating the final two encoder layers and task
|
| 79 |
+
head; other encoder parameters stayed frozen and passed preservation checks.
|
| 80 |
+
- Trainable parameters: 10,622,210.
|
| 81 |
+
- Training data: 118 short, synthetic English examples. Development data: 14.
|
| 82 |
+
Assistant-authored examples were accepted by the user for this pilot; this
|
| 83 |
+
does not constitute independent expert annotation. Original row review and
|
| 84 |
+
provenance fields remain unchanged in the dataset.
|
| 85 |
+
- 100 optimizer steps, seed 42, batch size 2, gradient accumulation 2.
|
| 86 |
+
- Encoder learning rate 0.00002; head learning rate 0.0001; maximum length 256.
|
| 87 |
+
- BF16 forward autocast, FP32 parameters; FP32 development evaluation.
|
| 88 |
+
- Hardware: one NVIDIA L4 on Modal; peak allocated training memory 1.3697 GiB.
|
| 89 |
+
- Selection: development macro F1 at steps 0, 25, 50, 75, 100. Step 75 selected.
|
| 90 |
+
- Remote environment: Python 3.12, Torch 2.8.0+cu128, Transformers 4.57.6,
|
| 91 |
+
PEFT 0.18.1, Accelerate 1.10.1, scikit-learn 1.7.2.
|
| 92 |
+
|
| 93 |
+
The training recipe and environment are included under `reproducibility/`.
|
| 94 |
+
The training code comes from the public
|
| 95 |
+
[vLLM Semantic Router repository](https://github.com/vllm-project/semantic-router).
|
| 96 |
+
`source-files.json` captures hashes of the exact trainer modules used; the
|
| 97 |
+
experiment was made in a local checkout, not claimed as an upstream release.
|
| 98 |
+
No private source document or credentials are included.
|
| 99 |
+
|
| 100 |
+
## Development results — not independent testing
|
| 101 |
+
|
| 102 |
+
All rows below use the same **14-example development set**:
|
| 103 |
+
|
| 104 |
+
| Classifier | Correct | Macro F1 |
|
| 105 |
+
| --- | --- | --- |
|
| 106 |
+
| Fixed keyword rule | 12/14 | 0.8542 |
|
| 107 |
+
| TF-IDF + logistic regression | 13/14 | 0.9282 |
|
| 108 |
+
| Decision 2.0 Kai, fixed yes/no question | 11/14 | 0.7754 |
|
| 109 |
+
| This selected Vela checkpoint | 14/14 | 1.0000 |
|
| 110 |
+
|
| 111 |
+
The neural checkpoint was selected using this development set. Additional
|
| 112 |
+
training examples were authored after inspecting earlier development errors.
|
| 113 |
+
Therefore, **14/14 does not imply general accuracy or enterprise readiness**.
|
| 114 |
+
FP32 GPU and local CPU reload produced the same class predictions; maximum
|
| 115 |
+
probability difference was about 0.00000185. This is artifact verification,
|
| 116 |
+
not independent quality evaluation.
|
| 117 |
+
|
| 118 |
+
A 16-example same-author synthetic test set remains unpublished and unevaluated.
|
| 119 |
+
A fresh, realistic, independently annotated evaluation set is still needed.
|
| 120 |
+
|
| 121 |
+
## Intended use and limitations
|
| 122 |
+
|
| 123 |
+
Use this for learning, local experimentation, and a candidate classifier in
|
| 124 |
+
human-reviewed workflows. It has not been qualified for automatic authoritative
|
| 125 |
+
logging, production routing, or consequential decisions.
|
| 126 |
+
|
| 127 |
+
- English-only evaluated scope despite the multilingual foundation.
|
| 128 |
+
- Very small authored dataset; wording and topic bias are likely.
|
| 129 |
+
- Standalone short statements only; multi-turn reference resolution is not tested.
|
| 130 |
+
- Conditional, canceled, sarcastic and context-dependent statements need a
|
| 131 |
+
separately reviewed contract; predictions may be unreliable there.
|
| 132 |
+
- A past decision may be superseded; this classifier does not identify current
|
| 133 |
+
policy, author authority, or supersession links.
|
| 134 |
+
- High scores can be overconfident. Calibration and realistic false-positive
|
| 135 |
+
rates have not been measured.
|
| 136 |
+
- Transformers 4.57.6 emitted a known class of Mistral regex warnings when loading
|
| 137 |
+
this non-Mistral tokenizer locally. No tokenizer patch was applied. Basic
|
| 138 |
+
reload checks passed; a broader tokenizer audit has not been performed.
|
| 139 |
+
|
| 140 |
+
## License and attribution
|
| 141 |
+
|
| 142 |
+
The pinned Vela model card declares MIT; it identifies
|
| 143 |
+
[`jhu-clsp/mmBERT-base`](https://huggingface.co/jhu-clsp/mmBERT-base) as its upstream
|
| 144 |
+
foundation, whose model card also declares MIT. The fine-tuned model is shared
|
| 145 |
+
under MIT with those upstream declarations retained. See `LICENSE` and
|
| 146 |
+
`UPSTREAM_LICENSES.md` for the recorded absence of separate upstream notice files.
|
| 147 |
+
No upstream copyright owner or year has been invented.
|
| 148 |
+
|
| 149 |
+
The reproducibility code and synthetic dataset are distributed separately under
|
| 150 |
+
Apache-2.0, following the Semantic Router repository's code/data context. See
|
| 151 |
+
`reproducibility/LICENSE` and the dataset card. This model license does not
|
| 152 |
+
relicense upstream training corpora or unrelated dependencies.
|
UPSTREAM_LICENSES.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Upstream license declarations and provenance
|
| 2 |
+
|
| 3 |
+
This distribution contains a fine-tuned derivative of
|
| 4 |
+
[`vllm-sr/Vela-1.0-Encoder-307M`](https://huggingface.co/vllm-sr/Vela-1.0-Encoder-307M),
|
| 5 |
+
using revision `720ab37904ce15054068d429381bfae7549f00f6`.
|
| 6 |
+
That revision's model card declares `license: mit`. Its upstream model is
|
| 7 |
+
[`jhu-clsp/mmBERT-base`](https://huggingface.co/jhu-clsp/mmBERT-base), whose queried
|
| 8 |
+
model card also declares MIT.
|
| 9 |
+
|
| 10 |
+
The queried pinned Vela files and upstream mmBERT files provide no separate
|
| 11 |
+
LICENSE or NOTICE file. This omission is recorded rather than manufacturing
|
| 12 |
+
an upstream copyright notice or assigning ownership of their weights to the
|
| 13 |
+
fine-tuning author. The model license file contains the standard MIT permission
|
| 14 |
+
and warranty terms, sourced from the
|
| 15 |
+
[SPDX MIT license text](https://github.com/spdx/license-list-data/blob/main/text/MIT.txt).
|
| 16 |
+
Any authoritative upstream copyright notices subsequently supplied should be
|
| 17 |
+
preserved with this distribution. These statements reflect published license
|
| 18 |
+
declarations rather than a comprehensive audit of upstream training corpora.
|
| 19 |
+
|
| 20 |
+
The new classifier head and final two encoder layers were updated in a personal
|
| 21 |
+
training experiment. This derivative is not an official upstream release and
|
| 22 |
+
does not imply endorsement by vLLM Semantic Router or JHU.
|
| 23 |
+
|
| 24 |
+
The accompanying reproduction source and synthetic dataset retain Apache-2.0
|
| 25 |
+
licensing from the Semantic Router experiment's source/data context. Their
|
| 26 |
+
license copies are separate from the MIT model license. No private reference
|
| 27 |
+
document, original test examples or credentials are distributed.
|
config.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"ModernBertForSequenceClassification"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": false,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"bos_token_id": 2,
|
| 8 |
+
"classifier_activation": "gelu",
|
| 9 |
+
"classifier_bias": false,
|
| 10 |
+
"classifier_dropout": 0.0,
|
| 11 |
+
"classifier_pooling": "mean",
|
| 12 |
+
"cls_token_id": 1,
|
| 13 |
+
"decoder_bias": true,
|
| 14 |
+
"deterministic_flash_attn": false,
|
| 15 |
+
"dtype": "float32",
|
| 16 |
+
"embedding_dropout": 0.0,
|
| 17 |
+
"eos_token_id": 1,
|
| 18 |
+
"global_attn_every_n_layers": 3,
|
| 19 |
+
"global_rope_theta": 160000,
|
| 20 |
+
"gradient_checkpointing": false,
|
| 21 |
+
"hidden_activation": "gelu",
|
| 22 |
+
"hidden_size": 768,
|
| 23 |
+
"id2label": {
|
| 24 |
+
"0": "NO_DECISION_EXPRESSED",
|
| 25 |
+
"1": "DECISION_EXPRESSED"
|
| 26 |
+
},
|
| 27 |
+
"initializer_cutoff_factor": 2.0,
|
| 28 |
+
"initializer_range": 0.02,
|
| 29 |
+
"intermediate_size": 1152,
|
| 30 |
+
"label2id": {
|
| 31 |
+
"DECISION_EXPRESSED": 1,
|
| 32 |
+
"NO_DECISION_EXPRESSED": 0
|
| 33 |
+
},
|
| 34 |
+
"layer_norm_eps": 1e-05,
|
| 35 |
+
"local_attention": 128,
|
| 36 |
+
"local_rope_theta": 160000,
|
| 37 |
+
"mask_token_id": 4,
|
| 38 |
+
"max_position_embeddings": 32768,
|
| 39 |
+
"mlp_bias": false,
|
| 40 |
+
"mlp_dropout": 0.0,
|
| 41 |
+
"model_type": "modernbert",
|
| 42 |
+
"norm_bias": false,
|
| 43 |
+
"norm_eps": 1e-05,
|
| 44 |
+
"num_attention_heads": 12,
|
| 45 |
+
"num_hidden_layers": 22,
|
| 46 |
+
"pad_token_id": 0,
|
| 47 |
+
"position_embedding_type": "sans_pos",
|
| 48 |
+
"problem_type": "single_label_classification",
|
| 49 |
+
"repad_logits_with_grad": false,
|
| 50 |
+
"rope_scaling": {
|
| 51 |
+
"beta_fast": 32.0,
|
| 52 |
+
"beta_slow": 1.0,
|
| 53 |
+
"factor": 4.0,
|
| 54 |
+
"original_max_position_embeddings": 8192,
|
| 55 |
+
"rope_type": "yarn",
|
| 56 |
+
"truncate": true
|
| 57 |
+
},
|
| 58 |
+
"sep_token_id": 1,
|
| 59 |
+
"sparse_pred_ignore_index": -100,
|
| 60 |
+
"sparse_prediction": false,
|
| 61 |
+
"transformers_version": "4.57.6",
|
| 62 |
+
"vocab_size": 256000
|
| 63 |
+
}
|
label-contract.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"problem_type": "single_label_classification",
|
| 3 |
+
"label2id": {
|
| 4 |
+
"NO_DECISION_EXPRESSED": 0,
|
| 5 |
+
"DECISION_EXPRESSED": 1
|
| 6 |
+
},
|
| 7 |
+
"id2label": {
|
| 8 |
+
"0": "NO_DECISION_EXPRESSED",
|
| 9 |
+
"1": "DECISION_EXPRESSED"
|
| 10 |
+
}
|
| 11 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fcadfb68f0ea218ca6b015a9517af234049e3953cb4376d2c2ffc3803917dcb4
|
| 3 |
+
size 1230141424
|
reproducibility/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
reproducibility/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Reproduce the pilot
|
| 2 |
+
|
| 3 |
+
Use a Linux GPU environment matching `environment.txt`. This is the exact
|
| 4 |
+
training source; dependency versions and data hashes are in `training.json`.
|
| 5 |
+
Hardware and numerical differences can change the selected checkpoint.
|
| 6 |
+
|
| 7 |
+
Download the foundation at its pinned revision and this release's synthetic
|
| 8 |
+
train/validation data. Run from this directory; choose a new output directory.
|
| 9 |
+
|
| 10 |
+
```python
|
| 11 |
+
from huggingface_hub import snapshot_download
|
| 12 |
+
|
| 13 |
+
snapshot_download(
|
| 14 |
+
"vllm-sr/Vela-1.0-Encoder-307M",
|
| 15 |
+
revision="720ab37904ce15054068d429381bfae7549f00f6",
|
| 16 |
+
local_dir="base",
|
| 17 |
+
)
|
| 18 |
+
snapshot_download(
|
| 19 |
+
"TwilightTechie/commitment-statements-pilot", repo_type="dataset", local_dir="dataset"
|
| 20 |
+
)
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
```bash
|
| 24 |
+
python -m sequence_repair.train \
|
| 25 |
+
--method full --fresh-head --trainable-last-layers 2 \
|
| 26 |
+
--base base --base-id vllm-sr/Vela-1.0-Encoder-307M \
|
| 27 |
+
--base-revision 720ab37904ce15054068d429381bfae7549f00f6 \
|
| 28 |
+
--contract ../label-contract.json \
|
| 29 |
+
--train dataset/data/train.jsonl --dev dataset/data/validation.jsonl \
|
| 30 |
+
--output rerun --steps 100 --batch-size 2 --accumulate 2 \
|
| 31 |
+
--max-length 256 --learning-rate 0.00002 --head-learning-rate 0.0001 \
|
| 32 |
+
--eval-every 25 --evaluation-dtype float32 --selection macro-f1 --seed 42
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
The original run selected step 75 using development macro F1. No reserved test
|
| 36 |
+
examples are distributed or used by this command. Before running, verify the
|
| 37 |
+
training and validation file hashes against `training.json`.
|
reproducibility/environment.txt
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
accelerate==1.10.1
|
| 2 |
+
aiohappyeyeballs==2.6.1
|
| 3 |
+
aiohttp==3.12.7
|
| 4 |
+
aiosignal==1.3.2
|
| 5 |
+
attrs==25.3.0
|
| 6 |
+
cbor2==5.7.0
|
| 7 |
+
certifi==2026.7.22
|
| 8 |
+
charset-normalizer==3.5.2
|
| 9 |
+
cloudpickle==3.1.2
|
| 10 |
+
filelock==4.0.12
|
| 11 |
+
frozenlist==1.6.0
|
| 12 |
+
fsspec==2026.9.0
|
| 13 |
+
grpclib==0.4.8
|
| 14 |
+
h2==4.2.0
|
| 15 |
+
hf-xet==1.7.0
|
| 16 |
+
hpack==4.1.0
|
| 17 |
+
huggingface_hub==0.36.2
|
| 18 |
+
hyperframe==6.1.0
|
| 19 |
+
idna==3.20
|
| 20 |
+
Jinja2==3.1.6
|
| 21 |
+
joblib==1.6.0
|
| 22 |
+
MarkupSafe==3.0.4
|
| 23 |
+
mpmath==1.3.0
|
| 24 |
+
multidict==6.4.4
|
| 25 |
+
networkx==3.7
|
| 26 |
+
numpy==2.5.3
|
| 27 |
+
nvidia-cublas-cu12==12.8.4.1
|
| 28 |
+
nvidia-cuda-cupti-cu12==12.8.90
|
| 29 |
+
nvidia-cuda-nvrtc-cu12==12.8.93
|
| 30 |
+
nvidia-cuda-runtime-cu12==12.8.90
|
| 31 |
+
nvidia-cudnn-cu12==9.10.2.21
|
| 32 |
+
nvidia-cufft-cu12==11.3.3.83
|
| 33 |
+
nvidia-cufile-cu12==1.13.1.3
|
| 34 |
+
nvidia-curand-cu12==10.3.9.90
|
| 35 |
+
nvidia-cusolver-cu12==11.7.3.90
|
| 36 |
+
nvidia-cusparse-cu12==12.5.8.93
|
| 37 |
+
nvidia-cusparselt-cu12==0.7.1
|
| 38 |
+
nvidia-nccl-cu12==2.27.3
|
| 39 |
+
nvidia-nvjitlink-cu12==12.8.93
|
| 40 |
+
nvidia-nvtx-cu12==12.8.90
|
| 41 |
+
packaging==26.3
|
| 42 |
+
peft==0.18.1
|
| 43 |
+
propcache==0.3.1
|
| 44 |
+
protobuf==6.31.1
|
| 45 |
+
psutil==7.2.2
|
| 46 |
+
PyYAML==6.0.3
|
| 47 |
+
regex==2026.9.29
|
| 48 |
+
requests==2.34.2
|
| 49 |
+
safetensors==0.8.0
|
| 50 |
+
scikit-learn==1.7.2
|
| 51 |
+
scipy==1.18.1
|
| 52 |
+
setuptools==84.0.0
|
| 53 |
+
sympy==1.14.0
|
| 54 |
+
threadpoolctl==3.7.0
|
| 55 |
+
tokenizers==0.22.2
|
| 56 |
+
torch==2.8.0
|
| 57 |
+
tqdm==4.70.1
|
| 58 |
+
transformers==4.57.6
|
| 59 |
+
triton==3.4.0
|
| 60 |
+
typing_extensions==4.16.0
|
| 61 |
+
urllib3==2.8.0
|
| 62 |
+
uv==0.7.19
|
| 63 |
+
wheel==0.45.1
|
| 64 |
+
yarl==1.20.0
|
reproducibility/sequence_repair/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""Reproducible continuation of fixed-label sequence classifiers."""
|
reproducibility/sequence_repair/complete_adapter.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Make a legacy sequence adapter self-contained with its original task head."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
import shutil
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
from .model import load_model
|
| 11 |
+
from .task_head import verify_saved_task_head
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def main():
|
| 15 |
+
import torch
|
| 16 |
+
from safetensors.torch import load_file, save_file
|
| 17 |
+
|
| 18 |
+
parser = argparse.ArgumentParser()
|
| 19 |
+
parser.add_argument("--base", required=True)
|
| 20 |
+
parser.add_argument("--adapter", type=Path, required=True)
|
| 21 |
+
parser.add_argument("--contract", required=True)
|
| 22 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 23 |
+
args = parser.parse_args()
|
| 24 |
+
if args.output.exists():
|
| 25 |
+
raise ValueError("Refusing to overwrite a completed adapter")
|
| 26 |
+
config = json.loads((args.adapter / "adapter_config.json").read_text())
|
| 27 |
+
if "head" in (config.get("modules_to_save") or []):
|
| 28 |
+
raise ValueError("Adapter already owns its task head")
|
| 29 |
+
torch.set_num_threads(8)
|
| 30 |
+
model, tokenizer, _labels, _ids = load_model(args.base, args.contract, args.adapter)
|
| 31 |
+
model.eval()
|
| 32 |
+
tokens = tokenizer(
|
| 33 |
+
["A task head parity probe.", "核对分类头参数是否保持不变。"],
|
| 34 |
+
padding=True,
|
| 35 |
+
return_tensors="pt",
|
| 36 |
+
)
|
| 37 |
+
with torch.inference_mode():
|
| 38 |
+
before = model(**tokens).logits
|
| 39 |
+
head = model.get_base_model().head.state_dict()
|
| 40 |
+
weights = load_file(args.adapter / "adapter_model.safetensors", device="cpu")
|
| 41 |
+
for name, tensor in head.items():
|
| 42 |
+
key = "base_model.model.head." + name
|
| 43 |
+
if key in weights:
|
| 44 |
+
raise ValueError("Unexpected existing head tensor in legacy adapter")
|
| 45 |
+
weights[key] = tensor.detach().cpu().contiguous()
|
| 46 |
+
args.output.mkdir(parents=True)
|
| 47 |
+
for path in args.adapter.iterdir():
|
| 48 |
+
if path.is_file() and path.name not in {
|
| 49 |
+
"adapter_config.json",
|
| 50 |
+
"adapter_model.safetensors",
|
| 51 |
+
"task-head.json",
|
| 52 |
+
}:
|
| 53 |
+
shutil.copy2(path, args.output / path.name)
|
| 54 |
+
config["modules_to_save"] = [*(config.get("modules_to_save") or []), "head"]
|
| 55 |
+
(args.output / "adapter_config.json").write_text(
|
| 56 |
+
json.dumps(config, indent=2) + "\n"
|
| 57 |
+
)
|
| 58 |
+
save_file(
|
| 59 |
+
weights, args.output / "adapter_model.safetensors", metadata={"format": "pt"}
|
| 60 |
+
)
|
| 61 |
+
restored, _tokenizer, _labels, _ids = load_model(
|
| 62 |
+
args.base, args.contract, args.output
|
| 63 |
+
)
|
| 64 |
+
restored.eval()
|
| 65 |
+
with torch.inference_mode():
|
| 66 |
+
after = restored(**tokens).logits
|
| 67 |
+
if not bool(torch.isfinite(before).all() and torch.isfinite(after).all()):
|
| 68 |
+
raise ValueError("Task-head completion produced non-finite logits")
|
| 69 |
+
torch.testing.assert_close(before, after, rtol=1e-6, atol=1e-6)
|
| 70 |
+
scope = verify_saved_task_head(restored, args.output / "adapter_model.safetensors")
|
| 71 |
+
(args.output / "task-head.json").write_text(json.dumps(scope, indent=2) + "\n")
|
| 72 |
+
receipt = {
|
| 73 |
+
"operation": "Preserve the existing sequence task head in a legacy adapter; no training or encoder change",
|
| 74 |
+
"source_adapter_sha256": hashlib.sha256(
|
| 75 |
+
(args.adapter / "adapter_model.safetensors").read_bytes()
|
| 76 |
+
).hexdigest(),
|
| 77 |
+
"completed_adapter_sha256": hashlib.sha256(
|
| 78 |
+
(args.output / "adapter_model.safetensors").read_bytes()
|
| 79 |
+
).hexdigest(),
|
| 80 |
+
"base_model": config["base_model_name_or_path"],
|
| 81 |
+
"base_revision": config.get("revision"),
|
| 82 |
+
"head_tensors": list(head),
|
| 83 |
+
"task_head": scope,
|
| 84 |
+
"maximum_absolute_logit_difference": float((before - after).abs().max()),
|
| 85 |
+
"quality_evaluation": False,
|
| 86 |
+
}
|
| 87 |
+
(args.output / "task-head-completion.json").write_text(
|
| 88 |
+
json.dumps(receipt, indent=2) + "\n"
|
| 89 |
+
)
|
| 90 |
+
print(json.dumps(receipt))
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
if __name__ == "__main__":
|
| 94 |
+
main()
|
reproducibility/sequence_repair/context.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Construct measured context probes without truncating the task-bearing payload."""
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def insert_payload(
|
| 5 |
+
payload,
|
| 6 |
+
background,
|
| 7 |
+
position,
|
| 8 |
+
budget,
|
| 9 |
+
count_tokens,
|
| 10 |
+
*,
|
| 11 |
+
fill_to_budget=True,
|
| 12 |
+
neutral_suffix=" note"
|
| 13 |
+
):
|
| 14 |
+
if position not in {"head", "middle", "tail"}:
|
| 15 |
+
raise ValueError("Unknown payload position")
|
| 16 |
+
if not payload or not background.strip() or budget <= 0:
|
| 17 |
+
raise ValueError("Payload, background and token budget must be nonempty")
|
| 18 |
+
if count_tokens(payload) > budget:
|
| 19 |
+
raise ValueError("Payload itself exceeds the token budget")
|
| 20 |
+
if count_tokens(background) <= count_tokens(""):
|
| 21 |
+
raise ValueError("Background must contribute actual tokens")
|
| 22 |
+
|
| 23 |
+
def build(repetitions):
|
| 24 |
+
left = {"head": 0, "middle": repetitions // 2, "tail": repetitions}[position]
|
| 25 |
+
prefix = "\n".join([background] * left)
|
| 26 |
+
suffix = "\n".join([background] * (repetitions - left))
|
| 27 |
+
text = (
|
| 28 |
+
(prefix + "\n" if prefix else "")
|
| 29 |
+
+ payload
|
| 30 |
+
+ ("\n" + suffix if suffix else "")
|
| 31 |
+
)
|
| 32 |
+
start = len(prefix) + 1 if prefix else 0
|
| 33 |
+
return text, start
|
| 34 |
+
|
| 35 |
+
measured = {}
|
| 36 |
+
|
| 37 |
+
def measure(repetitions):
|
| 38 |
+
if repetitions not in measured:
|
| 39 |
+
measured[repetitions] = count_tokens(build(repetitions)[0])
|
| 40 |
+
return measured[repetitions]
|
| 41 |
+
|
| 42 |
+
# Repeated complete paragraphs usually have a constant token increment.
|
| 43 |
+
# Use that only to find a close starting point; exact measurements still
|
| 44 |
+
# bracket and determine the result, including boundary-token differences.
|
| 45 |
+
increment = max(1, measure(2) - measure(1))
|
| 46 |
+
estimate = min(budget, max(0, 1 + (budget - measure(1)) // increment))
|
| 47 |
+
if measure(estimate) <= budget:
|
| 48 |
+
low, high, distance = estimate, estimate, 1
|
| 49 |
+
while high < budget:
|
| 50 |
+
high = min(budget, estimate + distance)
|
| 51 |
+
if measure(high) > budget:
|
| 52 |
+
break
|
| 53 |
+
low, distance = high, distance * 2
|
| 54 |
+
else:
|
| 55 |
+
low, high, distance = estimate, estimate, 1
|
| 56 |
+
while low > 0:
|
| 57 |
+
low = max(0, estimate - distance)
|
| 58 |
+
if measure(low) <= budget:
|
| 59 |
+
break
|
| 60 |
+
high, distance = low, distance * 2
|
| 61 |
+
while low < high:
|
| 62 |
+
middle = (low + high + 1) // 2
|
| 63 |
+
if measure(middle) <= budget:
|
| 64 |
+
low = middle
|
| 65 |
+
else:
|
| 66 |
+
high = middle - 1
|
| 67 |
+
text, start = build(low)
|
| 68 |
+
actual = measure(low)
|
| 69 |
+
if fill_to_budget:
|
| 70 |
+
text += neutral_suffix * (budget - actual)
|
| 71 |
+
actual = count_tokens(text)
|
| 72 |
+
if actual != budget:
|
| 73 |
+
raise ValueError(
|
| 74 |
+
"Neutral suffix does not fill this tokenizer's exact budget"
|
| 75 |
+
)
|
| 76 |
+
if actual > budget or text[start : start + len(payload)] != payload:
|
| 77 |
+
raise ValueError(
|
| 78 |
+
"Context construction corrupted its payload or exceeded budget"
|
| 79 |
+
)
|
| 80 |
+
return {
|
| 81 |
+
"text": text,
|
| 82 |
+
"payload_start": start,
|
| 83 |
+
"payload_end": start + len(payload),
|
| 84 |
+
"actual_tokens": actual,
|
| 85 |
+
}
|
reproducibility/sequence_repair/corpus.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Frozen task corpus receipts and source-group partitioning."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
from .data import assert_disjoint, normalized_text
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def group_split(group, seed=20260913):
|
| 11 |
+
bucket = int(hashlib.sha256(f"{seed}:{group}".encode()).hexdigest()[:8], 16) % 100
|
| 12 |
+
return "train" if bucket < 70 else "dev" if bucket < 85 else "test" # noqa: PLR2004
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def write_corpus(output, splits, contract, provenance):
|
| 16 |
+
output = Path(output)
|
| 17 |
+
if output.exists() and any(output.iterdir()):
|
| 18 |
+
raise ValueError("Refusing to overwrite a frozen corpus")
|
| 19 |
+
unique = {}
|
| 20 |
+
for split, rows in splits.items():
|
| 21 |
+
seen, retained, retained_keys = {}, [], set()
|
| 22 |
+
for row in rows:
|
| 23 |
+
key = normalized_text(row["text"])
|
| 24 |
+
previous = seen.setdefault(key, row["label"])
|
| 25 |
+
if previous != row["label"]:
|
| 26 |
+
raise ValueError("Contradictory labels for identical normalized text")
|
| 27 |
+
if key in unique and unique[key] != split:
|
| 28 |
+
raise ValueError("Duplicate text crosses corpus splits")
|
| 29 |
+
unique[key] = split
|
| 30 |
+
if key not in retained_keys:
|
| 31 |
+
retained.append(row)
|
| 32 |
+
retained_keys.add(key)
|
| 33 |
+
splits[split] = retained
|
| 34 |
+
for first, second in [("train", "dev"), ("train", "test"), ("dev", "test")]:
|
| 35 |
+
assert_disjoint(splits[first], splits[second])
|
| 36 |
+
output.mkdir(parents=True, exist_ok=True)
|
| 37 |
+
files = {}
|
| 38 |
+
for split, rows in splits.items():
|
| 39 |
+
content = "".join(
|
| 40 |
+
json.dumps(row, ensure_ascii=False, sort_keys=True) + "\n" for row in rows
|
| 41 |
+
)
|
| 42 |
+
(output / f"{split}.jsonl").write_text(content)
|
| 43 |
+
files[split] = {
|
| 44 |
+
"rows": len(rows),
|
| 45 |
+
"sha256": hashlib.sha256(content.encode()).hexdigest(),
|
| 46 |
+
}
|
| 47 |
+
(output / "contract.json").write_text(json.dumps(contract, indent=2) + "\n")
|
| 48 |
+
manifest = {
|
| 49 |
+
"files": files,
|
| 50 |
+
"provenance": provenance,
|
| 51 |
+
"test_used_for_selection": False,
|
| 52 |
+
"split_policy": "Group-disjoint before sampling; exact NFKC/case/whitespace overlap rejected",
|
| 53 |
+
}
|
| 54 |
+
(output / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n")
|
| 55 |
+
return manifest
|
reproducibility/sequence_repair/data.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dependency-light sequence data contracts and classification metrics."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
import unicodedata
|
| 6 |
+
from collections import Counter
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def normalized_text(text):
|
| 11 |
+
return " ".join(unicodedata.normalize("NFKC", text).casefold().split())
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def load_contract(path):
|
| 15 |
+
config = json.loads(Path(path).read_text())
|
| 16 |
+
id_to_label = {int(index): label for index, label in config["id2label"].items()}
|
| 17 |
+
if set(id_to_label) != set(range(len(id_to_label))):
|
| 18 |
+
raise ValueError("Label IDs must be contiguous from zero")
|
| 19 |
+
if config["label2id"] != {label: index for index, label in id_to_label.items()}:
|
| 20 |
+
raise ValueError("id2label and label2id must be a bijection")
|
| 21 |
+
return config["label2id"], id_to_label
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def read_records(paths, label_to_id):
|
| 25 |
+
records, ids, texts = [], set(), {}
|
| 26 |
+
for path in paths:
|
| 27 |
+
for line in Path(path).read_text().split("\n"):
|
| 28 |
+
if not line.strip():
|
| 29 |
+
continue
|
| 30 |
+
row = json.loads(line)
|
| 31 |
+
if not isinstance(row.get("text"), str) or not row["text"].strip():
|
| 32 |
+
raise ValueError("A classification row needs nonempty text")
|
| 33 |
+
if not row.get("id") or row["id"] in ids:
|
| 34 |
+
raise ValueError("Missing or duplicate row ID")
|
| 35 |
+
if not row.get("group_id"):
|
| 36 |
+
raise ValueError("Each row needs a source/translation/template group")
|
| 37 |
+
if row.get("label") not in label_to_id:
|
| 38 |
+
raise ValueError("Unknown classification label")
|
| 39 |
+
normalized = normalized_text(row["text"])
|
| 40 |
+
previous = texts.setdefault(normalized, row["label"])
|
| 41 |
+
if previous != row["label"]:
|
| 42 |
+
raise ValueError("Identical text has contradictory labels")
|
| 43 |
+
ids.add(row["id"])
|
| 44 |
+
records.append(row)
|
| 45 |
+
if not records:
|
| 46 |
+
raise ValueError(
|
| 47 |
+
"Empty datasets cannot produce training or evaluation evidence"
|
| 48 |
+
)
|
| 49 |
+
return records
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def assert_disjoint(train, dev):
|
| 53 |
+
for key, transform in [("group_id", str), ("text", normalized_text), ("id", str)]:
|
| 54 |
+
overlap = {transform(row[key]) for row in train} & {
|
| 55 |
+
transform(row[key]) for row in dev
|
| 56 |
+
}
|
| 57 |
+
if overlap:
|
| 58 |
+
raise ValueError(f"Training/development overlap in {key}: {len(overlap)}")
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def file_receipts(paths):
|
| 62 |
+
return [
|
| 63 |
+
{
|
| 64 |
+
"file": Path(path).name,
|
| 65 |
+
"sha256": hashlib.sha256(Path(path).read_bytes()).hexdigest(),
|
| 66 |
+
}
|
| 67 |
+
for path in paths
|
| 68 |
+
]
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def classification_metrics(gold, predicted, id_to_label):
|
| 72 |
+
if not gold or len(gold) != len(predicted):
|
| 73 |
+
raise ValueError("Empty or mismatched prediction evidence")
|
| 74 |
+
count = len(id_to_label)
|
| 75 |
+
confusion = [[0] * count for _ in range(count)]
|
| 76 |
+
for index, expected in enumerate(gold):
|
| 77 |
+
actual = predicted[index]
|
| 78 |
+
if expected not in id_to_label or actual not in id_to_label:
|
| 79 |
+
raise ValueError("Prediction outside the frozen label contract")
|
| 80 |
+
confusion[expected][actual] += 1
|
| 81 |
+
per_label = {}
|
| 82 |
+
for index, label in id_to_label.items():
|
| 83 |
+
tp = confusion[index][index]
|
| 84 |
+
support = sum(confusion[index])
|
| 85 |
+
selected = sum(row[index] for row in confusion)
|
| 86 |
+
per_label[label] = {
|
| 87 |
+
"support": support,
|
| 88 |
+
"tp": tp,
|
| 89 |
+
"fp": selected - tp,
|
| 90 |
+
"fn": support - tp,
|
| 91 |
+
"precision": tp / selected if selected else 0.0,
|
| 92 |
+
"recall": tp / support if support else 0.0,
|
| 93 |
+
"f1": 2 * tp / (selected + support) if selected + support else 0.0,
|
| 94 |
+
}
|
| 95 |
+
present = [row for row in per_label.values() if row["support"]]
|
| 96 |
+
return {
|
| 97 |
+
"rows": len(gold),
|
| 98 |
+
"accuracy": sum(confusion[index][index] for index in range(count)) / len(gold),
|
| 99 |
+
"macro_f1": sum(row["f1"] for row in per_label.values()) / count,
|
| 100 |
+
"macro_f1_present_labels": sum(row["f1"] for row in present) / len(present),
|
| 101 |
+
"per_label": per_label,
|
| 102 |
+
"confusion": confusion,
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def label_counts(records):
|
| 107 |
+
return dict(Counter(row["label"] for row in records))
|
reproducibility/sequence_repair/evaluate.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Explicit streaming evaluation; never invoked on test data during training."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import json
|
| 7 |
+
import time
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
from .data import classification_metrics, file_receipts, read_records
|
| 11 |
+
from .model import load_model
|
| 12 |
+
|
| 13 |
+
LONG_BATCH_THRESHOLD = 2048
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def evaluate_records(
|
| 17 |
+
model,
|
| 18 |
+
tokenizer,
|
| 19 |
+
records,
|
| 20 |
+
label_to_id,
|
| 21 |
+
id_to_label,
|
| 22 |
+
max_length,
|
| 23 |
+
batch_size=16,
|
| 24 |
+
dtype="bfloat16",
|
| 25 |
+
):
|
| 26 |
+
import torch
|
| 27 |
+
|
| 28 |
+
device = next(model.parameters()).device
|
| 29 |
+
if model.config.problem_type != "single_label_classification":
|
| 30 |
+
raise ValueError("Softmax evaluation requires a single-label classifier")
|
| 31 |
+
was_training = model.training
|
| 32 |
+
model.eval()
|
| 33 |
+
encoded = [
|
| 34 |
+
tokenizer(row["text"], truncation=False, padding=False) for row in records
|
| 35 |
+
]
|
| 36 |
+
lengths = [len(row["input_ids"]) for row in encoded]
|
| 37 |
+
if max(lengths) > max_length:
|
| 38 |
+
raise ValueError(
|
| 39 |
+
"Evaluation input exceeds the explicit budget; truncation is forbidden"
|
| 40 |
+
)
|
| 41 |
+
order = sorted(range(len(records)), key=lengths.__getitem__)
|
| 42 |
+
results, timings, cursor = [None] * len(records), [], 0
|
| 43 |
+
while cursor < len(order):
|
| 44 |
+
size = 1 if lengths[order[cursor]] > LONG_BATCH_THRESHOLD else batch_size
|
| 45 |
+
indices = order[cursor : cursor + size]
|
| 46 |
+
if any(lengths[index] > LONG_BATCH_THRESHOLD for index in indices):
|
| 47 |
+
indices = indices[:1]
|
| 48 |
+
cursor += len(indices)
|
| 49 |
+
batch = tokenizer.pad(
|
| 50 |
+
[encoded[index] for index in indices], padding=True, return_tensors="pt"
|
| 51 |
+
)
|
| 52 |
+
batch = {key: value.to(device) for key, value in batch.items()}
|
| 53 |
+
if device.type == "cuda":
|
| 54 |
+
torch.cuda.synchronize()
|
| 55 |
+
start = time.perf_counter()
|
| 56 |
+
with torch.inference_mode(), torch.autocast(
|
| 57 |
+
device_type=device.type,
|
| 58 |
+
dtype=getattr(torch, dtype),
|
| 59 |
+
enabled=device.type == "cuda" and dtype != "float32",
|
| 60 |
+
):
|
| 61 |
+
logits = model(**batch).logits.float()
|
| 62 |
+
if not bool(torch.isfinite(logits).all()):
|
| 63 |
+
raise ValueError("Non-finite evaluation logits")
|
| 64 |
+
probabilities = logits.softmax(-1).cpu().tolist()
|
| 65 |
+
if device.type == "cuda":
|
| 66 |
+
torch.cuda.synchronize()
|
| 67 |
+
timings.append((time.perf_counter() - start) * 1000)
|
| 68 |
+
for position, index in enumerate(indices):
|
| 69 |
+
scores = probabilities[position]
|
| 70 |
+
results[index] = {
|
| 71 |
+
"id": records[index]["id"],
|
| 72 |
+
"prediction": max(range(len(scores)), key=scores.__getitem__),
|
| 73 |
+
"probabilities": scores,
|
| 74 |
+
"tokens": lengths[index],
|
| 75 |
+
}
|
| 76 |
+
gold = [label_to_id[row["label"]] for row in records]
|
| 77 |
+
predicted = [row["prediction"] for row in results]
|
| 78 |
+
metrics = classification_metrics(gold, predicted, id_to_label)
|
| 79 |
+
metrics["breakdowns"] = {}
|
| 80 |
+
for field in ["source", "language", "length_bucket", "position"]:
|
| 81 |
+
metrics["breakdowns"][field] = {}
|
| 82 |
+
for group in sorted({str(row.get(field, "unspecified")) for row in records}):
|
| 83 |
+
indices = [
|
| 84 |
+
i
|
| 85 |
+
for i, row in enumerate(records)
|
| 86 |
+
if str(row.get(field, "unspecified")) == group
|
| 87 |
+
]
|
| 88 |
+
metrics["breakdowns"][field][group] = classification_metrics(
|
| 89 |
+
[gold[i] for i in indices], [predicted[i] for i in indices], id_to_label
|
| 90 |
+
)
|
| 91 |
+
metrics["actual_tokens"] = {"min": min(lengths), "max": max(lengths)}
|
| 92 |
+
metrics["forward_batches_ms"] = timings
|
| 93 |
+
metrics["precision"] = {
|
| 94 |
+
"parameters": "float32",
|
| 95 |
+
"forward_autocast": (
|
| 96 |
+
dtype if device.type == "cuda" and dtype != "float32" else None
|
| 97 |
+
),
|
| 98 |
+
"device_type": device.type,
|
| 99 |
+
}
|
| 100 |
+
if was_training:
|
| 101 |
+
model.train()
|
| 102 |
+
return metrics, results
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def main():
|
| 106 |
+
import torch
|
| 107 |
+
|
| 108 |
+
torch.set_num_threads(8)
|
| 109 |
+
parser = argparse.ArgumentParser()
|
| 110 |
+
parser.add_argument("--base", required=True)
|
| 111 |
+
parser.add_argument("--adapter")
|
| 112 |
+
parser.add_argument("--contract", required=True)
|
| 113 |
+
parser.add_argument("--data", nargs="+", required=True)
|
| 114 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 115 |
+
parser.add_argument("--max-length", type=int, default=32768)
|
| 116 |
+
parser.add_argument("--device", default="cuda")
|
| 117 |
+
parser.add_argument("--dtype", choices=["float32", "bfloat16"], default="bfloat16")
|
| 118 |
+
args = parser.parse_args()
|
| 119 |
+
if args.output.exists():
|
| 120 |
+
raise ValueError("Refusing to overwrite evaluation evidence")
|
| 121 |
+
model, tokenizer, labels, ids = load_model(args.base, args.contract, args.adapter)
|
| 122 |
+
if args.max_length > model.config.max_position_embeddings:
|
| 123 |
+
raise ValueError("Evaluation budget exceeds checkpoint position capacity")
|
| 124 |
+
model.to(args.device)
|
| 125 |
+
rows = read_records(args.data, labels)
|
| 126 |
+
metrics, predictions = evaluate_records(
|
| 127 |
+
model, tokenizer, rows, labels, ids, args.max_length, dtype=args.dtype
|
| 128 |
+
)
|
| 129 |
+
metrics["data_files"] = file_receipts(args.data)
|
| 130 |
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
| 131 |
+
args.output.write_text(json.dumps(metrics, indent=2) + "\n")
|
| 132 |
+
args.output.with_suffix(".predictions.jsonl").write_text(
|
| 133 |
+
"".join(json.dumps(row) + "\n" for row in predictions)
|
| 134 |
+
)
|
| 135 |
+
print(
|
| 136 |
+
json.dumps(
|
| 137 |
+
{
|
| 138 |
+
key: metrics[key]
|
| 139 |
+
for key in ["rows", "accuracy", "macro_f1", "actual_tokens"]
|
| 140 |
+
}
|
| 141 |
+
),
|
| 142 |
+
flush=True,
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
if __name__ == "__main__":
|
| 147 |
+
main()
|
reproducibility/sequence_repair/export.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Freeze a selected adapter or full model as a standard HF sequence checkpoint."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
from .data import load_contract
|
| 11 |
+
from .model import configuration_overrides, load_model, load_task_config
|
| 12 |
+
from .optimization import validate_method, verify_full_checkpoint
|
| 13 |
+
from .runtime_mapping import RUNTIME_TASKS, write_runtime_mappings
|
| 14 |
+
from .task_head import (
|
| 15 |
+
assert_task_head_preserved,
|
| 16 |
+
task_head_scope,
|
| 17 |
+
verify_saved_task_head,
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def validate_provenance(args):
|
| 22 |
+
validate_method(args.method, args.adapter, False)
|
| 23 |
+
run = json.loads(args.run_manifest.read_text())
|
| 24 |
+
if run.get("test_used") is not False:
|
| 25 |
+
raise ValueError("Candidate provenance must explicitly exclude test selection")
|
| 26 |
+
if run.get("base_revision") != args.base_revision:
|
| 27 |
+
raise ValueError("Export base revision differs from the training receipt")
|
| 28 |
+
if run.get("base_model", args.base_id) != args.base_id:
|
| 29 |
+
raise ValueError("Export base model differs from the training receipt")
|
| 30 |
+
if run.get("method", "lora") != args.method:
|
| 31 |
+
raise ValueError("Export method differs from the training receipt")
|
| 32 |
+
if args.method == "full":
|
| 33 |
+
origin = json.loads((Path(args.base) / "training-origin.json").read_text())
|
| 34 |
+
expected = {
|
| 35 |
+
"method": "full",
|
| 36 |
+
"base_model": args.base_id,
|
| 37 |
+
"base_revision": args.base_revision,
|
| 38 |
+
}
|
| 39 |
+
if origin != expected:
|
| 40 |
+
raise ValueError("Full checkpoint origin differs from the training receipt")
|
| 41 |
+
config = json.loads((Path(args.base) / "config.json").read_text())
|
| 42 |
+
labels, ids = load_contract(args.contract)
|
| 43 |
+
contract = configuration_overrides(args.contract)
|
| 44 |
+
contract.update(label2id=labels, id2label={str(k): v for k, v in ids.items()})
|
| 45 |
+
if any(config.get(key) != value for key, value in contract.items()):
|
| 46 |
+
raise ValueError("Export contract differs from the trained full checkpoint")
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def main():
|
| 50 |
+
import torch
|
| 51 |
+
|
| 52 |
+
parser = argparse.ArgumentParser()
|
| 53 |
+
parser.add_argument("--base", required=True)
|
| 54 |
+
parser.add_argument("--base-id", required=True)
|
| 55 |
+
parser.add_argument("--base-revision", required=True)
|
| 56 |
+
parser.add_argument("--method", choices=["lora", "full"], default="lora")
|
| 57 |
+
parser.add_argument("--adapter", type=Path)
|
| 58 |
+
parser.add_argument("--contract", required=True)
|
| 59 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 60 |
+
parser.add_argument("--run-manifest", type=Path, required=True)
|
| 61 |
+
parser.add_argument("--runtime-task", choices=RUNTIME_TASKS, required=True)
|
| 62 |
+
args = parser.parse_args()
|
| 63 |
+
if args.output.exists() and any(args.output.iterdir()):
|
| 64 |
+
raise ValueError("Refusing to overwrite a frozen candidate")
|
| 65 |
+
validate_provenance(args)
|
| 66 |
+
torch.set_num_threads(8)
|
| 67 |
+
model, tokenizer, labels, _ = load_model(args.base, args.contract, args.adapter)
|
| 68 |
+
model.eval()
|
| 69 |
+
if args.method == "full":
|
| 70 |
+
verify_full_checkpoint(model, args.base)
|
| 71 |
+
head = task_head_scope(model)
|
| 72 |
+
else:
|
| 73 |
+
head = verify_saved_task_head(model, args.adapter / "adapter_model.safetensors")
|
| 74 |
+
tokens = tokenizer(
|
| 75 |
+
["Numerical checkpoint equivalence probe.", "用于核对模型数值的输入。"],
|
| 76 |
+
padding=True,
|
| 77 |
+
return_tensors="pt",
|
| 78 |
+
)
|
| 79 |
+
with torch.inference_mode():
|
| 80 |
+
before = model(**tokens).logits
|
| 81 |
+
exported = (
|
| 82 |
+
model.merge_and_unload(safe_merge=True) if args.method == "lora" else model
|
| 83 |
+
)
|
| 84 |
+
after = exported(**tokens).logits
|
| 85 |
+
assert_task_head_preserved(head, exported)
|
| 86 |
+
torch.testing.assert_close(before, after, atol=2e-4, rtol=2e-4)
|
| 87 |
+
if type(exported).__name__ != "ModernBertForSequenceClassification":
|
| 88 |
+
raise ValueError(
|
| 89 |
+
"Export must preserve the standard supported HF sequence architecture"
|
| 90 |
+
)
|
| 91 |
+
if exported.config.label2id != labels:
|
| 92 |
+
raise ValueError("Export changed label IDs")
|
| 93 |
+
exported.config._name_or_path = args.base_id
|
| 94 |
+
args.output.mkdir(parents=True, exist_ok=True)
|
| 95 |
+
exported.save_pretrained(args.output, safe_serialization=True)
|
| 96 |
+
verify_full_checkpoint(exported, args.output)
|
| 97 |
+
tokenizer.save_pretrained(args.output)
|
| 98 |
+
restored = (
|
| 99 |
+
type(exported)
|
| 100 |
+
.from_pretrained(
|
| 101 |
+
args.output,
|
| 102 |
+
config=load_task_config(args.output),
|
| 103 |
+
torch_dtype=torch.float32,
|
| 104 |
+
attn_implementation="sdpa",
|
| 105 |
+
)
|
| 106 |
+
.eval()
|
| 107 |
+
)
|
| 108 |
+
verify_full_checkpoint(restored, args.output)
|
| 109 |
+
assert_task_head_preserved(head, restored)
|
| 110 |
+
with torch.inference_mode():
|
| 111 |
+
reloaded_logits = restored(**tokens).logits
|
| 112 |
+
torch.testing.assert_close(after, reloaded_logits, atol=0, rtol=0)
|
| 113 |
+
mapping_files = write_runtime_mappings(args.output, labels, args.runtime_task)
|
| 114 |
+
receipt = {
|
| 115 |
+
"method": args.method,
|
| 116 |
+
"base_model": args.base_id,
|
| 117 |
+
"base_revision": args.base_revision,
|
| 118 |
+
"run_manifest_sha256": hashlib.sha256(
|
| 119 |
+
args.run_manifest.read_bytes()
|
| 120 |
+
).hexdigest(),
|
| 121 |
+
"parameter_count": sum(
|
| 122 |
+
parameter.numel() for parameter in exported.parameters()
|
| 123 |
+
),
|
| 124 |
+
"encoder_parameter_count": sum(
|
| 125 |
+
parameter.numel() for parameter in exported.model.parameters()
|
| 126 |
+
),
|
| 127 |
+
"label2id": labels,
|
| 128 |
+
"runtime_task": args.runtime_task,
|
| 129 |
+
"runtime_mapping_files": mapping_files,
|
| 130 |
+
"task": exported.config.problem_type,
|
| 131 |
+
"classifier_pooling": exported.config.classifier_pooling,
|
| 132 |
+
"max_position_embeddings": exported.config.max_position_embeddings,
|
| 133 |
+
"position_capacity_is_quality_evidence": False,
|
| 134 |
+
"weight_dtype": "float32",
|
| 135 |
+
"task_head": head,
|
| 136 |
+
"task_head_preserved_after_reload": True,
|
| 137 |
+
"all_tensors_preserved_after_reload": True,
|
| 138 |
+
"test_used_for_selection": False,
|
| 139 |
+
"files": {
|
| 140 |
+
path.name: hashlib.sha256(path.read_bytes()).hexdigest()
|
| 141 |
+
for path in sorted(args.output.iterdir())
|
| 142 |
+
if path.is_file()
|
| 143 |
+
},
|
| 144 |
+
}
|
| 145 |
+
if args.method == "lora":
|
| 146 |
+
receipt.update(
|
| 147 |
+
adapter_sha256=hashlib.sha256(
|
| 148 |
+
(args.adapter / "adapter_model.safetensors").read_bytes()
|
| 149 |
+
).hexdigest(),
|
| 150 |
+
task_head_preserved_after_merge_and_reload=True,
|
| 151 |
+
merge_probe_max_absolute_difference=float((before - after).abs().max()),
|
| 152 |
+
)
|
| 153 |
+
(args.output / "candidate-lock.json").write_text(
|
| 154 |
+
json.dumps(receipt, indent=2) + "\n"
|
| 155 |
+
)
|
| 156 |
+
print(
|
| 157 |
+
json.dumps(
|
| 158 |
+
{
|
| 159 |
+
key: receipt[key]
|
| 160 |
+
for key in (
|
| 161 |
+
"method",
|
| 162 |
+
"parameter_count",
|
| 163 |
+
"all_tensors_preserved_after_reload",
|
| 164 |
+
)
|
| 165 |
+
}
|
| 166 |
+
),
|
| 167 |
+
flush=True,
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
if __name__ == "__main__":
|
| 172 |
+
main()
|
reproducibility/sequence_repair/fetch_sources.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Fetch only the pinned public dataset files used by the repair recipes."""
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import hashlib
|
| 5 |
+
import json
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
from huggingface_hub import hf_hub_download # noqa: PLC0415
|
| 11 |
+
|
| 12 |
+
parser = argparse.ArgumentParser()
|
| 13 |
+
parser.add_argument(
|
| 14 |
+
"--manifest",
|
| 15 |
+
type=Path,
|
| 16 |
+
default=Path(__file__).parent / "data/source-files.json",
|
| 17 |
+
)
|
| 18 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 19 |
+
args = parser.parse_args()
|
| 20 |
+
receipts = []
|
| 21 |
+
for item in json.loads(args.manifest.read_text()):
|
| 22 |
+
directory = args.output / item["repo"].replace("/", "--")
|
| 23 |
+
path = Path(
|
| 24 |
+
hf_hub_download(
|
| 25 |
+
repo_id=item["repo"],
|
| 26 |
+
repo_type="dataset",
|
| 27 |
+
filename=item["file"],
|
| 28 |
+
revision=item["revision"],
|
| 29 |
+
local_dir=directory,
|
| 30 |
+
)
|
| 31 |
+
)
|
| 32 |
+
digest = hashlib.sha256(path.read_bytes()).hexdigest()
|
| 33 |
+
if digest != item["sha256"]:
|
| 34 |
+
raise ValueError(
|
| 35 |
+
f"Pinned dataset file hash differs: {item['repo']}/{item['file']}"
|
| 36 |
+
)
|
| 37 |
+
receipts.append({**item, "verified_sha256": digest})
|
| 38 |
+
print(
|
| 39 |
+
json.dumps({"repo": item["repo"], "file": item["file"], "verified": True}),
|
| 40 |
+
flush=True,
|
| 41 |
+
)
|
| 42 |
+
(args.output / "verified-source-files.json").write_text(
|
| 43 |
+
json.dumps(receipts, indent=2) + "\n"
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
if __name__ == "__main__":
|
| 48 |
+
main()
|
reproducibility/sequence_repair/hydrate_annotations.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Reconstruct reviewed requests from pinned source data and text-free label sidecars."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def sha256_text(text):
|
| 11 |
+
return hashlib.sha256(text.encode()).hexdigest()
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def hydrate_records(sidecar, sources):
|
| 15 |
+
repository = sidecar["source"]["repository"]
|
| 16 |
+
result = []
|
| 17 |
+
if repository == "CohereLabs/aya_dataset":
|
| 18 |
+
lookup = {}
|
| 19 |
+
for row in sources:
|
| 20 |
+
if not row.get("user_id"):
|
| 21 |
+
continue
|
| 22 |
+
key = (
|
| 23 |
+
sha256_text(row["inputs"]),
|
| 24 |
+
row["language_code"],
|
| 25 |
+
"aya-author-" + sha256_text(row["user_id"]),
|
| 26 |
+
)
|
| 27 |
+
lookup[key] = row["inputs"]
|
| 28 |
+
for row in sidecar["records"]:
|
| 29 |
+
key = (row["source_text_sha256"], row["language"], row["group_id"])
|
| 30 |
+
if key not in lookup:
|
| 31 |
+
raise ValueError(
|
| 32 |
+
"Reviewed Aya request or author differs from the pinned source"
|
| 33 |
+
)
|
| 34 |
+
result.append({**row, "text": lookup[key]})
|
| 35 |
+
elif repository == "databricks/databricks-dolly-15k":
|
| 36 |
+
for row in sidecar["records"]:
|
| 37 |
+
source = sources[row["source_row"]]
|
| 38 |
+
instruction, context = (
|
| 39 |
+
source["instruction"].strip(),
|
| 40 |
+
source["context"].strip(),
|
| 41 |
+
)
|
| 42 |
+
text = instruction + ("\n\n" + context if context else "")
|
| 43 |
+
if sha256_text(text) != row["source_text_sha256"]:
|
| 44 |
+
raise ValueError(
|
| 45 |
+
"Reviewed Dolly request differs from the pinned source"
|
| 46 |
+
)
|
| 47 |
+
result.append(
|
| 48 |
+
{**row, "text": text, "instruction": instruction, "context": context}
|
| 49 |
+
)
|
| 50 |
+
else:
|
| 51 |
+
raise ValueError("Unknown reviewed source")
|
| 52 |
+
return result
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def main():
|
| 56 |
+
parser = argparse.ArgumentParser()
|
| 57 |
+
parser.add_argument("--sidecar", type=Path, required=True)
|
| 58 |
+
parser.add_argument("--source", type=Path, required=True)
|
| 59 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 60 |
+
args = parser.parse_args()
|
| 61 |
+
if args.output.exists():
|
| 62 |
+
raise ValueError("Refusing to overwrite reviewed annotations")
|
| 63 |
+
sidecar = json.loads(args.sidecar.read_text())
|
| 64 |
+
if (
|
| 65 |
+
hashlib.sha256(args.source.read_bytes()).hexdigest()
|
| 66 |
+
!= sidecar["source"]["file_sha256"]
|
| 67 |
+
):
|
| 68 |
+
raise ValueError("Source file hash differs from the reviewed revision")
|
| 69 |
+
if sidecar["source"]["repository"] == "CohereLabs/aya_dataset":
|
| 70 |
+
from pyarrow import parquet
|
| 71 |
+
|
| 72 |
+
sources = parquet.read_table(
|
| 73 |
+
args.source, columns=["inputs", "language_code", "user_id"]
|
| 74 |
+
).to_pylist()
|
| 75 |
+
else:
|
| 76 |
+
sources = [
|
| 77 |
+
json.loads(line)
|
| 78 |
+
for line in args.source.read_text().split("\n")
|
| 79 |
+
if line.strip()
|
| 80 |
+
]
|
| 81 |
+
rows = hydrate_records(sidecar, sources)
|
| 82 |
+
content = "".join(
|
| 83 |
+
json.dumps(row, ensure_ascii=False, sort_keys=True) + "\n" for row in rows
|
| 84 |
+
)
|
| 85 |
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
| 86 |
+
args.output.write_text(content)
|
| 87 |
+
print(
|
| 88 |
+
json.dumps(
|
| 89 |
+
{"rows": len(rows), "sha256": hashlib.sha256(content.encode()).hexdigest()}
|
| 90 |
+
)
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
if __name__ == "__main__":
|
| 95 |
+
main()
|
reproducibility/sequence_repair/initialize.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Initialize a fresh task adapter and trainable head from a fixed encoder base."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
import argparse
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from .model import save_adapter
|
| 10 |
+
from .optimization import load_trainable_model
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def main():
|
| 14 |
+
import torch
|
| 15 |
+
from peft import LoraConfig, TaskType, get_peft_model
|
| 16 |
+
|
| 17 |
+
parser = argparse.ArgumentParser()
|
| 18 |
+
parser.add_argument("--base", required=True)
|
| 19 |
+
parser.add_argument("--base-id", required=True)
|
| 20 |
+
parser.add_argument("--base-revision", required=True)
|
| 21 |
+
parser.add_argument("--contract", type=Path, required=True)
|
| 22 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 23 |
+
parser.add_argument("--seed", type=int, default=20260913)
|
| 24 |
+
parser.add_argument("--rank", type=int, default=32)
|
| 25 |
+
parser.add_argument("--alpha", type=int, default=64)
|
| 26 |
+
parser.add_argument("--dropout", type=float, default=0.05)
|
| 27 |
+
args = parser.parse_args()
|
| 28 |
+
if args.output.exists():
|
| 29 |
+
raise ValueError("Refusing to overwrite an initialized adapter")
|
| 30 |
+
if min(args.rank, args.alpha) <= 0 or not 0 <= args.dropout < 1:
|
| 31 |
+
raise ValueError("Invalid LoRA dimensions or dropout")
|
| 32 |
+
torch.set_num_threads(8)
|
| 33 |
+
torch.manual_seed(args.seed)
|
| 34 |
+
model, tokenizer, _labels, _ids = load_trainable_model(
|
| 35 |
+
args.base, args.contract, None, "full", fresh_head=True
|
| 36 |
+
)
|
| 37 |
+
model = get_peft_model(
|
| 38 |
+
model,
|
| 39 |
+
LoraConfig(
|
| 40 |
+
task_type=TaskType.SEQ_CLS,
|
| 41 |
+
r=args.rank,
|
| 42 |
+
lora_alpha=args.alpha,
|
| 43 |
+
lora_dropout=args.dropout,
|
| 44 |
+
target_modules=["attn.Wqkv", "attn.Wo", "mlp.Wi", "mlp.Wo"],
|
| 45 |
+
modules_to_save=["head", "classifier"],
|
| 46 |
+
bias="none",
|
| 47 |
+
revision=args.base_revision,
|
| 48 |
+
),
|
| 49 |
+
)
|
| 50 |
+
save_adapter(model, tokenizer, args.output, args.base_id, args.base_revision)
|
| 51 |
+
(args.output / "contract.json").write_bytes(args.contract.read_bytes())
|
| 52 |
+
receipt = {
|
| 53 |
+
"base_model": args.base_id,
|
| 54 |
+
"base_revision": args.base_revision,
|
| 55 |
+
"seed": args.seed,
|
| 56 |
+
"rank": args.rank,
|
| 57 |
+
"alpha": args.alpha,
|
| 58 |
+
"dropout": args.dropout,
|
| 59 |
+
"classifier_pooling": model.config.classifier_pooling,
|
| 60 |
+
"adapter_sha256": hashlib.sha256(
|
| 61 |
+
(args.output / "adapter_model.safetensors").read_bytes()
|
| 62 |
+
).hexdigest(),
|
| 63 |
+
"trainable_parameters": sum(
|
| 64 |
+
parameter.numel()
|
| 65 |
+
for parameter in model.parameters()
|
| 66 |
+
if parameter.requires_grad
|
| 67 |
+
),
|
| 68 |
+
}
|
| 69 |
+
(args.output / "initialization.json").write_text(
|
| 70 |
+
json.dumps(receipt, indent=2) + "\n"
|
| 71 |
+
)
|
| 72 |
+
print(json.dumps(receipt))
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if __name__ == "__main__":
|
| 76 |
+
main()
|
reproducibility/sequence_repair/model.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""HF standard sequence checkpoints with an unchanged label contract."""
|
| 2 |
+
|
| 3 |
+
# Heavy imports stay optional for data-contract tests.
|
| 4 |
+
# ruff: noqa: PLC0415
|
| 5 |
+
|
| 6 |
+
import json
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from .data import load_contract
|
| 10 |
+
from .task_head import verify_saved_task_head
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def configuration_overrides(contract):
|
| 14 |
+
"""Validate optional standard HF task settings without guessing a pooling mode."""
|
| 15 |
+
content = json.loads(Path(contract).read_text())
|
| 16 |
+
problem_type = content.get("problem_type", "single_label_classification")
|
| 17 |
+
if problem_type not in {
|
| 18 |
+
"single_label_classification",
|
| 19 |
+
"multi_label_classification",
|
| 20 |
+
}:
|
| 21 |
+
raise ValueError("Unsupported classification problem type")
|
| 22 |
+
overrides = {"problem_type": problem_type}
|
| 23 |
+
if "classifier_pooling" in content:
|
| 24 |
+
pooling = content["classifier_pooling"]
|
| 25 |
+
if pooling not in {"mean", "cls"}:
|
| 26 |
+
raise ValueError("Sequence pooling must be explicitly mean or cls")
|
| 27 |
+
overrides["classifier_pooling"] = pooling
|
| 28 |
+
return overrides
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def load_task_config(base, **overrides):
|
| 32 |
+
"""Keep optional execution settings on the configuration that owns them."""
|
| 33 |
+
from transformers import AutoConfig
|
| 34 |
+
|
| 35 |
+
config = AutoConfig.from_pretrained(base, **overrides)
|
| 36 |
+
if hasattr(config, "reference_compile"):
|
| 37 |
+
config.reference_compile = False
|
| 38 |
+
return config
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def load_model(base, contract, adapter=None, trainable=False):
|
| 42 |
+
import torch
|
| 43 |
+
from transformers import AutoModelForSequenceClassification, AutoTokenizer
|
| 44 |
+
|
| 45 |
+
label_to_id, id_to_label = load_contract(contract)
|
| 46 |
+
overrides = configuration_overrides(contract)
|
| 47 |
+
tokenizer = AutoTokenizer.from_pretrained(base)
|
| 48 |
+
config = load_task_config(
|
| 49 |
+
base,
|
| 50 |
+
num_labels=len(label_to_id),
|
| 51 |
+
label2id=label_to_id,
|
| 52 |
+
id2label=id_to_label,
|
| 53 |
+
**overrides,
|
| 54 |
+
)
|
| 55 |
+
model, loading = AutoModelForSequenceClassification.from_pretrained(
|
| 56 |
+
base,
|
| 57 |
+
config=config,
|
| 58 |
+
torch_dtype=torch.float32,
|
| 59 |
+
attn_implementation="sdpa",
|
| 60 |
+
output_loading_info=True,
|
| 61 |
+
)
|
| 62 |
+
missing_encoder = [
|
| 63 |
+
name for name in loading["missing_keys"] if name.startswith("model.")
|
| 64 |
+
]
|
| 65 |
+
if missing_encoder:
|
| 66 |
+
raise ValueError(f"Checkpoint is missing encoder tensors: {missing_encoder}")
|
| 67 |
+
if adapter:
|
| 68 |
+
from peft import PeftModel
|
| 69 |
+
|
| 70 |
+
model = PeftModel.from_pretrained(model, adapter, is_trainable=trainable)
|
| 71 |
+
elif trainable:
|
| 72 |
+
raise ValueError("Continuation requires an explicit initial adapter")
|
| 73 |
+
if model.config.label2id != label_to_id:
|
| 74 |
+
raise ValueError("The loaded classifier changed the label contract")
|
| 75 |
+
return model, tokenizer, label_to_id, id_to_label
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def save_adapter(model, tokenizer, destination, base_id, base_revision):
|
| 79 |
+
import json
|
| 80 |
+
|
| 81 |
+
destination.mkdir(parents=True, exist_ok=True)
|
| 82 |
+
model.peft_config["default"].base_model_name_or_path = base_id
|
| 83 |
+
model.peft_config["default"].revision = base_revision
|
| 84 |
+
model.save_pretrained(destination)
|
| 85 |
+
scope = verify_saved_task_head(model, destination / "adapter_model.safetensors")
|
| 86 |
+
(destination / "task-head.json").write_text(json.dumps(scope, indent=2) + "\n")
|
| 87 |
+
tokenizer.save_pretrained(destination)
|
| 88 |
+
(destination / "label_mapping.json").write_text(
|
| 89 |
+
json.dumps(
|
| 90 |
+
{"label2id": model.config.label2id, "id2label": model.config.id2label},
|
| 91 |
+
indent=2,
|
| 92 |
+
)
|
| 93 |
+
+ "\n"
|
| 94 |
+
)
|
reproducibility/sequence_repair/optimization.py
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Explicit adapter or full-encoder optimization and checkpoint ownership."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import hashlib
|
| 6 |
+
import json
|
| 7 |
+
import math
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
from .model import load_model, save_adapter
|
| 11 |
+
from .task_head import task_head_scope, tensor_digest
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def configure_trainable_tail(model, last_layers):
|
| 15 |
+
"""Restrict a complete ModernBERT checkpoint to its tail and entire task head."""
|
| 16 |
+
if (
|
| 17 |
+
type(model).__name__ != "ModernBertForSequenceClassification"
|
| 18 |
+
or hasattr(model, "peft_config")
|
| 19 |
+
or hasattr(model, "get_base_model")
|
| 20 |
+
):
|
| 21 |
+
raise ValueError("Tail training requires a complete ModernBERT classifier")
|
| 22 |
+
layers = model.model.layers
|
| 23 |
+
if type(last_layers) is not int or not 1 <= last_layers <= len(layers):
|
| 24 |
+
raise ValueError("Trainable tail must contain one through all encoder layers")
|
| 25 |
+
start = len(layers) - last_layers
|
| 26 |
+
modules = [*layers[start:], model.head, model.classifier]
|
| 27 |
+
selected = {
|
| 28 |
+
id(parameter) for module in modules for parameter in module.parameters()
|
| 29 |
+
}
|
| 30 |
+
named = dict(model.named_parameters())
|
| 31 |
+
if not selected or not selected <= {id(parameter) for parameter in named.values()}:
|
| 32 |
+
raise ValueError("Trainable modules do not belong to the classifier")
|
| 33 |
+
if any(
|
| 34 |
+
id(parameter) in selected for parameter in model.model.final_norm.parameters()
|
| 35 |
+
):
|
| 36 |
+
raise ValueError("Encoder final normalization must remain frozen")
|
| 37 |
+
model.requires_grad_(False)
|
| 38 |
+
for module in modules:
|
| 39 |
+
module.requires_grad_(True)
|
| 40 |
+
tensors = {
|
| 41 |
+
name: {"shape": list(parameter.shape), "numel": parameter.numel()}
|
| 42 |
+
for name, parameter in named.items()
|
| 43 |
+
if parameter.requires_grad
|
| 44 |
+
}
|
| 45 |
+
return {
|
| 46 |
+
"architecture": type(model).__name__,
|
| 47 |
+
"layer_indices": list(range(start, len(layers))),
|
| 48 |
+
"trainable_tensors": tensors,
|
| 49 |
+
"trainable_parameters": sum(item["numel"] for item in tensors.values()),
|
| 50 |
+
"encoder_final_norm_trainable": False,
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def frozen_parameter_receipt(model):
|
| 55 |
+
"""Hash frozen parameters once so an optional restricted update is auditable."""
|
| 56 |
+
return {
|
| 57 |
+
name: {
|
| 58 |
+
"shape": list(parameter.shape),
|
| 59 |
+
"dtype": str(parameter.dtype),
|
| 60 |
+
"sha256": tensor_digest(parameter),
|
| 61 |
+
}
|
| 62 |
+
for name, parameter in model.named_parameters()
|
| 63 |
+
if not parameter.requires_grad
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def assert_frozen_parameters_preserved(expected, model):
|
| 68 |
+
if frozen_parameter_receipt(model) != expected:
|
| 69 |
+
raise ValueError("Frozen parameter scope or tensor values changed")
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def validate_method(method, adapter, fresh_head):
|
| 73 |
+
if method not in {"lora", "full"}:
|
| 74 |
+
raise ValueError("Training method must be lora or full")
|
| 75 |
+
if method == "lora" and (adapter is None or fresh_head):
|
| 76 |
+
raise ValueError("LoRA continuation requires its initialized adapter")
|
| 77 |
+
if method == "full" and adapter is not None:
|
| 78 |
+
raise ValueError(
|
| 79 |
+
"Full training starts from a complete checkpoint, not an adapter"
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def load_trainable_model(base, contract, adapter, method, fresh_head=False):
|
| 84 |
+
validate_method(method, adapter, fresh_head)
|
| 85 |
+
model, tokenizer, labels, ids = load_model(
|
| 86 |
+
base, contract, adapter, trainable=method == "lora"
|
| 87 |
+
)
|
| 88 |
+
if method == "full":
|
| 89 |
+
if type(model).__name__ != "ModernBertForSequenceClassification":
|
| 90 |
+
raise ValueError("Full sequence training requires a ModernBERT classifier")
|
| 91 |
+
model.requires_grad_(True)
|
| 92 |
+
if fresh_head:
|
| 93 |
+
from torch import nn
|
| 94 |
+
|
| 95 |
+
head_parameter = next(model.head.parameters())
|
| 96 |
+
model.head = type(model.head)(model.config).to(
|
| 97 |
+
device=head_parameter.device, dtype=head_parameter.dtype
|
| 98 |
+
)
|
| 99 |
+
classifier = model.classifier
|
| 100 |
+
model.classifier = nn.Linear(
|
| 101 |
+
classifier.in_features,
|
| 102 |
+
classifier.out_features,
|
| 103 |
+
bias=classifier.bias is not None,
|
| 104 |
+
device=classifier.weight.device,
|
| 105 |
+
dtype=classifier.weight.dtype,
|
| 106 |
+
)
|
| 107 |
+
# Fresh modules let HF apply its native initialization without
|
| 108 |
+
# mutating the initialization guards on loaded checkpoint tensors.
|
| 109 |
+
model.head.apply(model._init_weights)
|
| 110 |
+
# ModernBERT initializes the final classifier on its owning task
|
| 111 |
+
# module, not when visiting the bare Linear child.
|
| 112 |
+
model._init_weights(model)
|
| 113 |
+
return model, tokenizer, labels, ids
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def optimizer_groups(model, learning_rate, head_learning_rate=None):
|
| 117 |
+
rates = [learning_rate]
|
| 118 |
+
if head_learning_rate is not None:
|
| 119 |
+
rates.append(head_learning_rate)
|
| 120 |
+
if any(not math.isfinite(rate) or rate <= 0 for rate in rates):
|
| 121 |
+
raise ValueError("Learning rates must be finite and positive")
|
| 122 |
+
base = model.get_base_model() if hasattr(model, "get_base_model") else model
|
| 123 |
+
head_ids = {
|
| 124 |
+
id(parameter)
|
| 125 |
+
for module in (base.head, base.classifier)
|
| 126 |
+
for parameter in module.parameters()
|
| 127 |
+
if parameter.requires_grad
|
| 128 |
+
}
|
| 129 |
+
encoder, head = [], []
|
| 130 |
+
for parameter in model.parameters():
|
| 131 |
+
if parameter.requires_grad:
|
| 132 |
+
(head if id(parameter) in head_ids else encoder).append(parameter)
|
| 133 |
+
groups = []
|
| 134 |
+
for name, parameters, rate in (
|
| 135 |
+
("encoder", encoder, learning_rate),
|
| 136 |
+
("task_head", head, head_learning_rate or learning_rate),
|
| 137 |
+
):
|
| 138 |
+
if parameters:
|
| 139 |
+
groups.append(
|
| 140 |
+
{"name": name, "params": parameters, "lr": rate, "initial_lr": rate}
|
| 141 |
+
)
|
| 142 |
+
if not groups:
|
| 143 |
+
raise ValueError("No trainable parameters")
|
| 144 |
+
return groups
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def initial_artifact_receipt(base, adapter):
|
| 148 |
+
"""Hash the actual local initialization, including every weight shard."""
|
| 149 |
+
root = Path(base)
|
| 150 |
+
if not root.is_dir():
|
| 151 |
+
raise ValueError("Training requires a downloaded local base checkpoint")
|
| 152 |
+
names = {"config.json", "tokenizer.json", "tokenizer_config.json"}
|
| 153 |
+
for path in root.iterdir():
|
| 154 |
+
if (
|
| 155 |
+
path.suffix == ".safetensors"
|
| 156 |
+
or path.name
|
| 157 |
+
in {
|
| 158 |
+
"model.safetensors.index.json",
|
| 159 |
+
"pytorch_model.bin",
|
| 160 |
+
"pytorch_model.bin.index.json",
|
| 161 |
+
}
|
| 162 |
+
or path.name.startswith("pytorch_model-")
|
| 163 |
+
):
|
| 164 |
+
names.add(path.name)
|
| 165 |
+
files = {}
|
| 166 |
+
for name in sorted(names):
|
| 167 |
+
path = root / name
|
| 168 |
+
if path.is_file():
|
| 169 |
+
with path.open("rb") as stream:
|
| 170 |
+
files[name] = hashlib.file_digest(stream, "sha256").hexdigest()
|
| 171 |
+
result = {"base_files": files}
|
| 172 |
+
if adapter is not None:
|
| 173 |
+
for filename in ("adapter_model.safetensors", "adapter_config.json"):
|
| 174 |
+
path = Path(adapter) / filename
|
| 175 |
+
if filename == "adapter_config.json" and not path.is_file():
|
| 176 |
+
result[filename] = None
|
| 177 |
+
continue
|
| 178 |
+
with path.open("rb") as stream:
|
| 179 |
+
result[filename] = hashlib.file_digest(stream, "sha256").hexdigest()
|
| 180 |
+
return result
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def verify_full_checkpoint(model, checkpoint):
|
| 184 |
+
"""Require every tensor of a complete sequence checkpoint to be preserved."""
|
| 185 |
+
if type(model).__name__ != "ModernBertForSequenceClassification":
|
| 186 |
+
raise ValueError("Full checkpoints must own the actual encoder weights")
|
| 187 |
+
from safetensors.torch import load_file
|
| 188 |
+
|
| 189 |
+
saved = load_file(str(Path(checkpoint) / "model.safetensors"), device="cpu")
|
| 190 |
+
state = model.state_dict()
|
| 191 |
+
if saved.keys() != state.keys():
|
| 192 |
+
raise ValueError("Full checkpoint omitted or introduced model tensors")
|
| 193 |
+
import torch
|
| 194 |
+
|
| 195 |
+
for name, value in state.items():
|
| 196 |
+
if saved[name].dtype != value.dtype or not torch.equal(
|
| 197 |
+
saved[name], value.detach().cpu()
|
| 198 |
+
):
|
| 199 |
+
raise ValueError(f"Full checkpoint changed tensor: {name}")
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def save_training_checkpoint(model, tokenizer, destination, method, base_id, revision):
|
| 203 |
+
if method == "lora":
|
| 204 |
+
save_adapter(model, tokenizer, destination, base_id, revision)
|
| 205 |
+
return
|
| 206 |
+
if method != "full" or hasattr(model, "peft_config"):
|
| 207 |
+
raise ValueError("Full checkpoints must own the actual encoder weights")
|
| 208 |
+
destination.mkdir(parents=True, exist_ok=True)
|
| 209 |
+
expected = task_head_scope(model)
|
| 210 |
+
model.save_pretrained(destination, safe_serialization=True)
|
| 211 |
+
verify_full_checkpoint(model, destination)
|
| 212 |
+
tokenizer.save_pretrained(destination)
|
| 213 |
+
(destination / "task-head.json").write_text(json.dumps(expected, indent=2) + "\n")
|
| 214 |
+
(destination / "training-origin.json").write_text(
|
| 215 |
+
json.dumps(
|
| 216 |
+
{"method": method, "base_model": base_id, "base_revision": revision},
|
| 217 |
+
indent=2,
|
| 218 |
+
)
|
| 219 |
+
+ "\n"
|
| 220 |
+
)
|
reproducibility/sequence_repair/prepare_context.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Frozen context curriculum and held-out stress variants from task source groups."""
|
| 2 |
+
|
| 3 |
+
# Chinese punctuation is intentional in language-specific task markers.
|
| 4 |
+
# ruff: noqa: PLC0415, RUF001
|
| 5 |
+
import argparse
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
from collections import defaultdict
|
| 9 |
+
from pathlib import Path
|
| 10 |
+
|
| 11 |
+
from .context import insert_payload
|
| 12 |
+
from .corpus import write_corpus
|
| 13 |
+
from .data import read_records
|
| 14 |
+
|
| 15 |
+
LANGUAGE_ALIASES = {
|
| 16 |
+
"ara": "ar",
|
| 17 |
+
"eng": "en",
|
| 18 |
+
"zho": "zh",
|
| 19 |
+
"spa": "es",
|
| 20 |
+
"fra": "fr",
|
| 21 |
+
"deu": "de",
|
| 22 |
+
"jpn": "ja",
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
TASK_MARKERS = {
|
| 26 |
+
"ar": "المهمة المطلوبة:\n",
|
| 27 |
+
"de": "Angefragte Aufgabe:\n",
|
| 28 |
+
"en": "Requested task:\n",
|
| 29 |
+
"es": "Tarea solicitada:\n",
|
| 30 |
+
"fr": "Tâche demandée :\n",
|
| 31 |
+
"ja": "依頼されたタスク:\n",
|
| 32 |
+
"zh": "需要完成的任务:\n",
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def task_payload(row):
|
| 37 |
+
"""Mark a task in its declared language without rewriting its source text."""
|
| 38 |
+
language = LANGUAGE_ALIASES.get(row["language"], row["language"])
|
| 39 |
+
if language not in TASK_MARKERS:
|
| 40 |
+
raise ValueError(f"No context task marker for language: {language}")
|
| 41 |
+
return TASK_MARKERS[language] + row["text"]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def choose_payloads(rows, languages, per_label):
|
| 45 |
+
pools = defaultdict(list)
|
| 46 |
+
for row in rows:
|
| 47 |
+
language = LANGUAGE_ALIASES.get(row.get("language"), row.get("language"))
|
| 48 |
+
if language in languages:
|
| 49 |
+
pools[(language, row["label"])].append(row)
|
| 50 |
+
result = []
|
| 51 |
+
for (language, _label), pool in sorted(pools.items()):
|
| 52 |
+
seen = set()
|
| 53 |
+
for row in sorted(
|
| 54 |
+
pool, key=lambda item: hashlib.sha256(item["id"].encode()).hexdigest()
|
| 55 |
+
):
|
| 56 |
+
if row["group_id"] in seen:
|
| 57 |
+
continue
|
| 58 |
+
seen.add(row["group_id"])
|
| 59 |
+
result.append({**row, "language": language})
|
| 60 |
+
if len(seen) >= per_label:
|
| 61 |
+
break
|
| 62 |
+
return result
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def main():
|
| 66 |
+
from transformers import AutoTokenizer
|
| 67 |
+
|
| 68 |
+
parser = argparse.ArgumentParser()
|
| 69 |
+
parser.add_argument("--corpus", type=Path, required=True)
|
| 70 |
+
parser.add_argument("--tokenizer", required=True)
|
| 71 |
+
parser.add_argument("--backgrounds", type=Path, required=True)
|
| 72 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 73 |
+
parser.add_argument("--train-per-label", type=int, default=3)
|
| 74 |
+
parser.add_argument("--eval-per-label", type=int, default=1)
|
| 75 |
+
parser.add_argument(
|
| 76 |
+
"--budgets", type=int, nargs="+", default=[4096, 8192, 16384, 32768]
|
| 77 |
+
)
|
| 78 |
+
parser.add_argument(
|
| 79 |
+
"--languages", nargs="+", choices=sorted(TASK_MARKERS), default=["en", "zh"]
|
| 80 |
+
)
|
| 81 |
+
parser.add_argument("--payload-sources", nargs="+")
|
| 82 |
+
args = parser.parse_args()
|
| 83 |
+
if min(args.train_per_label, args.eval_per_label, *args.budgets) <= 0:
|
| 84 |
+
raise ValueError("Context budgets and sample counts must be positive")
|
| 85 |
+
backgrounds = json.loads(args.backgrounds.read_text())
|
| 86 |
+
if len({text for group in backgrounds.values() for text in group.values()}) != sum(
|
| 87 |
+
len(group) for group in backgrounds.values()
|
| 88 |
+
):
|
| 89 |
+
raise ValueError("Background text must differ across languages and partitions")
|
| 90 |
+
tokenizer = AutoTokenizer.from_pretrained(args.tokenizer)
|
| 91 |
+
contract = json.loads((args.corpus / "contract.json").read_text())
|
| 92 |
+
|
| 93 |
+
def count(text):
|
| 94 |
+
return len(tokenizer(text, truncation=False, padding=False)["input_ids"])
|
| 95 |
+
|
| 96 |
+
splits = {}
|
| 97 |
+
for split in ["train", "dev", "test"]:
|
| 98 |
+
rows = read_records([args.corpus / f"{split}.jsonl"], contract["label2id"])
|
| 99 |
+
if args.payload_sources:
|
| 100 |
+
rows = [row for row in rows if row.get("source") in args.payload_sources]
|
| 101 |
+
chosen = choose_payloads(
|
| 102 |
+
rows,
|
| 103 |
+
args.languages,
|
| 104 |
+
args.train_per_label if split == "train" else args.eval_per_label,
|
| 105 |
+
)
|
| 106 |
+
if not chosen:
|
| 107 |
+
raise ValueError(f"No eligible {split} source groups")
|
| 108 |
+
output = []
|
| 109 |
+
for row in chosen:
|
| 110 |
+
language = row["language"]
|
| 111 |
+
payload = task_payload(row)
|
| 112 |
+
for budget in args.budgets:
|
| 113 |
+
for position in ["head", "middle", "tail"]:
|
| 114 |
+
built = insert_payload(
|
| 115 |
+
payload, backgrounds[split][language], position, budget, count
|
| 116 |
+
)
|
| 117 |
+
output.append(
|
| 118 |
+
{
|
| 119 |
+
**row,
|
| 120 |
+
"id": f"context:{row['id']}:{budget}:{position}",
|
| 121 |
+
"text": built["text"],
|
| 122 |
+
"source": "authored-context-on-frozen-source",
|
| 123 |
+
"parent_source": row["source"],
|
| 124 |
+
"parent_id": row["id"],
|
| 125 |
+
"length_bucket": str(budget),
|
| 126 |
+
"position": position,
|
| 127 |
+
"actual_tokens": built["actual_tokens"],
|
| 128 |
+
"payload_start": built["payload_start"],
|
| 129 |
+
"payload_end": built["payload_end"],
|
| 130 |
+
}
|
| 131 |
+
)
|
| 132 |
+
splits[split] = output
|
| 133 |
+
print(
|
| 134 |
+
json.dumps(
|
| 135 |
+
{"split": split, "payloads": len(chosen), "variants": len(output)}
|
| 136 |
+
),
|
| 137 |
+
flush=True,
|
| 138 |
+
)
|
| 139 |
+
provenance = {
|
| 140 |
+
"parent_manifest_sha256": hashlib.sha256(
|
| 141 |
+
(args.corpus / "manifest.json").read_bytes()
|
| 142 |
+
).hexdigest(),
|
| 143 |
+
"backgrounds_sha256": hashlib.sha256(args.backgrounds.read_bytes()).hexdigest(),
|
| 144 |
+
"tokenizer_sha256": hashlib.sha256(
|
| 145 |
+
(Path(args.tokenizer) / "tokenizer.json").read_bytes()
|
| 146 |
+
).hexdigest(),
|
| 147 |
+
"train_payloads_per_label_language": args.train_per_label,
|
| 148 |
+
"eval_payloads_per_label_language": args.eval_per_label,
|
| 149 |
+
"budgets": args.budgets,
|
| 150 |
+
"languages": args.languages,
|
| 151 |
+
"scope": "Authored repeated multi-paragraph context around frozen source requests, not natural long-document accuracy. Label is the explicitly marked requested task. Paired length/position variants retain the parent source group and partition.",
|
| 152 |
+
"test_used": False,
|
| 153 |
+
}
|
| 154 |
+
print(json.dumps(write_corpus(args.output, splits, contract, provenance), indent=2))
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
if __name__ == "__main__":
|
| 158 |
+
main()
|
reproducibility/sequence_repair/prepare_retention.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Cache complete FP32 teacher outputs for explicitly marked replay TRAIN rows."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
|
| 10 |
+
from .data import read_records
|
| 11 |
+
from .model import load_model
|
| 12 |
+
from .optimization import initial_artifact_receipt, verify_full_checkpoint
|
| 13 |
+
from .retention import row_identity, tokenizer_file_receipt, write_retention_cache
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def main():
|
| 17 |
+
import torch
|
| 18 |
+
|
| 19 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 20 |
+
parser.add_argument("--base", required=True)
|
| 21 |
+
parser.add_argument("--contract", required=True)
|
| 22 |
+
parser.add_argument("--train", nargs="+", required=True)
|
| 23 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 24 |
+
parser.add_argument("--max-length", type=int, default=32768)
|
| 25 |
+
parser.add_argument("--device", default="cuda")
|
| 26 |
+
args = parser.parse_args()
|
| 27 |
+
if args.output.exists():
|
| 28 |
+
raise ValueError("Refusing to overwrite retention targets")
|
| 29 |
+
if args.max_length <= 0:
|
| 30 |
+
raise ValueError("The teacher input budget must be positive")
|
| 31 |
+
initialization = initial_artifact_receipt(args.base, None)
|
| 32 |
+
model, tokenizer, labels, _ = load_model(args.base, args.contract)
|
| 33 |
+
if model.config.problem_type != "single_label_classification":
|
| 34 |
+
raise ValueError("Retention targets require single-label classification")
|
| 35 |
+
verify_full_checkpoint(model, args.base)
|
| 36 |
+
if args.max_length > model.config.max_position_embeddings:
|
| 37 |
+
raise ValueError("Teacher input budget exceeds checkpoint capacity")
|
| 38 |
+
rows = read_records(args.train, labels)
|
| 39 |
+
if any(row.get("split", "train") != "train" for row in rows):
|
| 40 |
+
raise ValueError("Teacher targets must not use development or test rows")
|
| 41 |
+
if any(not isinstance(row.get("retention_replay", False), bool) for row in rows):
|
| 42 |
+
raise ValueError("retention_replay must be a boolean TRAIN annotation")
|
| 43 |
+
replay = [row for row in rows if row.get("retention_replay", False)]
|
| 44 |
+
if not replay:
|
| 45 |
+
raise ValueError("Mark the old TRAIN rows with retention_replay: true")
|
| 46 |
+
encoded = [
|
| 47 |
+
tokenizer(row["text"], truncation=False, padding=False) for row in replay
|
| 48 |
+
]
|
| 49 |
+
if any(len(value["input_ids"]) > args.max_length for value in encoded):
|
| 50 |
+
raise ValueError(
|
| 51 |
+
"A replay row exceeds the teacher budget; truncation is forbidden"
|
| 52 |
+
)
|
| 53 |
+
torch.set_num_threads(8)
|
| 54 |
+
torch.set_float32_matmul_precision("highest")
|
| 55 |
+
torch.backends.cuda.matmul.allow_tf32 = False
|
| 56 |
+
torch.backends.cudnn.allow_tf32 = False
|
| 57 |
+
model = model.to(args.device).eval()
|
| 58 |
+
records = []
|
| 59 |
+
with torch.inference_mode():
|
| 60 |
+
for row, value in zip(replay, encoded, strict=True):
|
| 61 |
+
batch = {
|
| 62 |
+
name: torch.tensor([ids], device=args.device)
|
| 63 |
+
for name, ids in value.items()
|
| 64 |
+
}
|
| 65 |
+
logits = model(**batch).logits
|
| 66 |
+
if logits.dtype != torch.float32 or not bool(torch.isfinite(logits).all()):
|
| 67 |
+
raise ValueError("Teacher outputs must be finite native FP32 logits")
|
| 68 |
+
records.append(
|
| 69 |
+
{**row_identity(row, value), "logits": logits[0].cpu().tolist()}
|
| 70 |
+
)
|
| 71 |
+
manifest = write_retention_cache(
|
| 72 |
+
args.output,
|
| 73 |
+
initialization=initialization,
|
| 74 |
+
contract_sha256=hashlib.sha256(Path(args.contract).read_bytes()).hexdigest(),
|
| 75 |
+
tokenizer_files=tokenizer_file_receipt(args.base),
|
| 76 |
+
label_to_id=labels,
|
| 77 |
+
records=records,
|
| 78 |
+
)
|
| 79 |
+
print(
|
| 80 |
+
json.dumps(
|
| 81 |
+
{"manifest": str(manifest), "rows": len(records), "dtype": "float32"}
|
| 82 |
+
)
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
if __name__ == "__main__":
|
| 87 |
+
main()
|
reproducibility/sequence_repair/retention.py
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Optional, identity-bound TRAIN replay targets and categorical retention loss."""
|
| 2 |
+
|
| 3 |
+
# Torch stays optional for cache identity and data checks.
|
| 4 |
+
# ruff: noqa: PLC0415
|
| 5 |
+
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
import math
|
| 9 |
+
import re
|
| 10 |
+
import struct
|
| 11 |
+
from collections.abc import Mapping
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
_LOGIT_RANK = 2
|
| 15 |
+
_MINIMUM_LABELS = 2
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def masked_teacher_kl(
|
| 19 |
+
logits, teacher_logits, eligible, *, examples_per_step, temperature=2.0
|
| 20 |
+
):
|
| 21 |
+
"""Return detached T² KL(teacher || student), summed over a logical batch."""
|
| 22 |
+
import torch
|
| 23 |
+
from torch.nn import functional
|
| 24 |
+
|
| 25 |
+
if type(examples_per_step) is not int or examples_per_step <= 0:
|
| 26 |
+
raise ValueError("Logical example count must be a positive integer")
|
| 27 |
+
if (
|
| 28 |
+
isinstance(temperature, bool)
|
| 29 |
+
or not isinstance(temperature, (int, float))
|
| 30 |
+
or not math.isfinite(temperature)
|
| 31 |
+
or temperature <= 0
|
| 32 |
+
):
|
| 33 |
+
raise ValueError("Retention temperature must be finite and positive")
|
| 34 |
+
if (
|
| 35 |
+
logits.ndim != _LOGIT_RANK
|
| 36 |
+
or logits.shape[1] < _MINIMUM_LABELS
|
| 37 |
+
or logits.shape[0] > examples_per_step
|
| 38 |
+
or teacher_logits.shape != logits.shape
|
| 39 |
+
or eligible.shape != logits.shape[:1]
|
| 40 |
+
or eligible.dtype != torch.bool
|
| 41 |
+
or not logits.is_floating_point()
|
| 42 |
+
or not teacher_logits.is_floating_point()
|
| 43 |
+
or teacher_logits.device != logits.device
|
| 44 |
+
or eligible.device != logits.device
|
| 45 |
+
or not torch.isfinite(logits).all()
|
| 46 |
+
):
|
| 47 |
+
raise ValueError(
|
| 48 |
+
"Retention logits and mask must have compatible finite geometry"
|
| 49 |
+
)
|
| 50 |
+
if not eligible.any():
|
| 51 |
+
# Connected zero without summing possibly huge finite masked logits.
|
| 52 |
+
return logits.float()[:0].sum()
|
| 53 |
+
student = logits[eligible].float() / temperature
|
| 54 |
+
teacher = teacher_logits.detach()[eligible].float() / temperature
|
| 55 |
+
if not torch.isfinite(teacher).all():
|
| 56 |
+
raise ValueError("Eligible teacher logits must be finite")
|
| 57 |
+
student_logp = functional.log_softmax(student, dim=-1)
|
| 58 |
+
teacher_logp = functional.log_softmax(teacher, dim=-1)
|
| 59 |
+
loss = functional.kl_div(
|
| 60 |
+
student_logp, teacher_logp, log_target=True, reduction="sum"
|
| 61 |
+
) * (temperature**2 / examples_per_step)
|
| 62 |
+
if not torch.isfinite(loss):
|
| 63 |
+
raise ValueError("Retention loss must be finite")
|
| 64 |
+
return loss
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def _sha(path):
|
| 68 |
+
with Path(path).open("rb") as stream:
|
| 69 |
+
return hashlib.file_digest(stream, "sha256").hexdigest()
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def _digest_map(value):
|
| 73 |
+
if not isinstance(value, dict) or not value:
|
| 74 |
+
raise ValueError("Artifact receipts must contain file digests")
|
| 75 |
+
for name, digest in value.items():
|
| 76 |
+
if (
|
| 77 |
+
not isinstance(name, str)
|
| 78 |
+
or not name
|
| 79 |
+
or Path(name).is_absolute()
|
| 80 |
+
or ".." in Path(name).parts
|
| 81 |
+
or not isinstance(digest, str)
|
| 82 |
+
or re.fullmatch(r"[0-9a-f]{64}", digest) is None
|
| 83 |
+
):
|
| 84 |
+
raise ValueError(
|
| 85 |
+
"Artifact receipt contains an invalid relative name or SHA"
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def tokenizer_file_receipt(base):
|
| 90 |
+
"""Bind the complete local fast-tokenizer files used by ModernBERT."""
|
| 91 |
+
base = Path(base)
|
| 92 |
+
names = {
|
| 93 |
+
"tokenizer.json",
|
| 94 |
+
"tokenizer_config.json",
|
| 95 |
+
"special_tokens_map.json",
|
| 96 |
+
"added_tokens.json",
|
| 97 |
+
"vocab.json",
|
| 98 |
+
"vocab.txt",
|
| 99 |
+
"merges.txt",
|
| 100 |
+
"tokenizer.model",
|
| 101 |
+
"spiece.model",
|
| 102 |
+
"sentencepiece.bpe.model",
|
| 103 |
+
"chat_template.jinja",
|
| 104 |
+
}
|
| 105 |
+
names.update(
|
| 106 |
+
str(path.relative_to(base))
|
| 107 |
+
for path in (base / "chat_templates").glob("*.jinja")
|
| 108 |
+
)
|
| 109 |
+
result = {
|
| 110 |
+
name: _sha(base / name) for name in sorted(names) if (base / name).is_file()
|
| 111 |
+
}
|
| 112 |
+
if not {"tokenizer.json", "tokenizer_config.json"} <= result.keys():
|
| 113 |
+
raise ValueError("Retention requires the complete local fast tokenizer")
|
| 114 |
+
return result
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def row_identity(row, encoded):
|
| 118 |
+
"""Bind raw text and every unpadded model input, without storing text in targets."""
|
| 119 |
+
if any(
|
| 120 |
+
not isinstance(row.get(key), str) or not row[key]
|
| 121 |
+
for key in ("id", "group_id", "text", "label")
|
| 122 |
+
):
|
| 123 |
+
raise ValueError("Retention rows require string ID, group, text and label")
|
| 124 |
+
if (
|
| 125 |
+
not isinstance(encoded, Mapping)
|
| 126 |
+
or not {"input_ids", "attention_mask"} <= encoded.keys()
|
| 127 |
+
):
|
| 128 |
+
raise ValueError("Retention requires complete unpadded tokenizer inputs")
|
| 129 |
+
encoded = dict(encoded)
|
| 130 |
+
if not encoded.keys() <= {
|
| 131 |
+
"input_ids",
|
| 132 |
+
"attention_mask",
|
| 133 |
+
"token_type_ids",
|
| 134 |
+
"position_ids",
|
| 135 |
+
}:
|
| 136 |
+
raise ValueError("Unexpected tokenizer input in retention identity")
|
| 137 |
+
if not isinstance(encoded["input_ids"], list):
|
| 138 |
+
raise ValueError("Retention input IDs must be an unpadded integer list")
|
| 139 |
+
size = len(encoded["input_ids"])
|
| 140 |
+
if (
|
| 141 |
+
not size
|
| 142 |
+
or any(
|
| 143 |
+
not isinstance(values, list)
|
| 144 |
+
or len(values) != size
|
| 145 |
+
or any(type(value) is not int or value < 0 for value in values)
|
| 146 |
+
for values in encoded.values()
|
| 147 |
+
)
|
| 148 |
+
or any(value != 1 for value in encoded["attention_mask"])
|
| 149 |
+
):
|
| 150 |
+
raise ValueError("Retention inputs must be complete unpadded integer sequences")
|
| 151 |
+
token_bytes = json.dumps(encoded, sort_keys=True, separators=(",", ":")).encode()
|
| 152 |
+
return {
|
| 153 |
+
"id": row["id"],
|
| 154 |
+
"group_id": row["group_id"],
|
| 155 |
+
"label": row["label"],
|
| 156 |
+
"text_sha256": hashlib.sha256(row["text"].encode()).hexdigest(),
|
| 157 |
+
"tokens_sha256": hashlib.sha256(token_bytes).hexdigest(),
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def _labels(value):
|
| 162 |
+
if (
|
| 163 |
+
not isinstance(value, dict)
|
| 164 |
+
or len(value) < _MINIMUM_LABELS
|
| 165 |
+
or any(
|
| 166 |
+
not isinstance(name, str) or not name or type(index) is not int
|
| 167 |
+
for name, index in value.items()
|
| 168 |
+
)
|
| 169 |
+
or sorted(value.values()) != list(range(len(value)))
|
| 170 |
+
):
|
| 171 |
+
raise ValueError("Retention labels must be a contiguous bijection")
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def _record(record, labels):
|
| 175 |
+
expected = {"id", "group_id", "label", "text_sha256", "tokens_sha256", "logits"}
|
| 176 |
+
if not isinstance(record, dict) or set(record) != expected:
|
| 177 |
+
raise ValueError("Retention target fields differ from the schema")
|
| 178 |
+
if any(
|
| 179 |
+
not isinstance(record[key], str) or not record[key]
|
| 180 |
+
for key in ("id", "group_id", "label")
|
| 181 |
+
):
|
| 182 |
+
raise ValueError("Invalid retention target identity")
|
| 183 |
+
_digest_map({key: record[key] for key in ("text_sha256", "tokens_sha256")})
|
| 184 |
+
values = record["logits"]
|
| 185 |
+
if (
|
| 186 |
+
record["label"] not in labels
|
| 187 |
+
or not isinstance(values, list)
|
| 188 |
+
or len(values) != len(labels)
|
| 189 |
+
):
|
| 190 |
+
raise ValueError("Retention logits differ from the label geometry")
|
| 191 |
+
for value in values:
|
| 192 |
+
if (
|
| 193 |
+
isinstance(value, bool)
|
| 194 |
+
or not isinstance(value, (int, float))
|
| 195 |
+
or not math.isfinite(value)
|
| 196 |
+
):
|
| 197 |
+
raise ValueError("Cached teacher logits must be finite float32 values")
|
| 198 |
+
try:
|
| 199 |
+
exact = struct.unpack("f", struct.pack("f", value))[0]
|
| 200 |
+
except (OverflowError, struct.error) as error:
|
| 201 |
+
raise ValueError("Cached teacher logit exceeds float32") from error
|
| 202 |
+
if exact != value:
|
| 203 |
+
raise ValueError("Cached teacher logit was not serialized from float32")
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def _metadata(initialization, contract_sha256, tokenizer_files, label_to_id):
|
| 207 |
+
if not isinstance(initialization, dict) or set(initialization) != {"base_files"}:
|
| 208 |
+
raise ValueError("Retention requires an exact complete-checkpoint receipt")
|
| 209 |
+
_digest_map(initialization["base_files"])
|
| 210 |
+
_digest_map({"contract": contract_sha256})
|
| 211 |
+
_digest_map(tokenizer_files)
|
| 212 |
+
_labels(label_to_id)
|
| 213 |
+
for name, digest in tokenizer_files.items():
|
| 214 |
+
if (
|
| 215 |
+
name in initialization["base_files"]
|
| 216 |
+
and initialization["base_files"][name] != digest
|
| 217 |
+
):
|
| 218 |
+
raise ValueError("Tokenizer and initialization receipts disagree")
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def write_retention_cache(
|
| 222 |
+
destination,
|
| 223 |
+
*,
|
| 224 |
+
initialization,
|
| 225 |
+
contract_sha256,
|
| 226 |
+
tokenizer_files,
|
| 227 |
+
label_to_id,
|
| 228 |
+
records,
|
| 229 |
+
):
|
| 230 |
+
"""Write a new portable cache; the loader separately verifies admitted TRAIN scope."""
|
| 231 |
+
_metadata(initialization, contract_sha256, tokenizer_files, label_to_id)
|
| 232 |
+
records = list(records)
|
| 233 |
+
for record in records:
|
| 234 |
+
_record(record, label_to_id)
|
| 235 |
+
records.sort(key=lambda record: record["id"])
|
| 236 |
+
ids = [record["id"] for record in records]
|
| 237 |
+
if not ids or len(ids) != len(set(ids)):
|
| 238 |
+
raise ValueError("Retention targets must be nonempty with unique IDs")
|
| 239 |
+
destination = Path(destination)
|
| 240 |
+
destination.mkdir(parents=True, exist_ok=False)
|
| 241 |
+
targets = destination / "targets.jsonl"
|
| 242 |
+
with targets.open("w") as stream:
|
| 243 |
+
for record in records:
|
| 244 |
+
stream.write(json.dumps(record, sort_keys=True, allow_nan=False) + "\n")
|
| 245 |
+
manifest = {
|
| 246 |
+
"version": 1,
|
| 247 |
+
"split": "train",
|
| 248 |
+
"dtype": "float32",
|
| 249 |
+
"initialization": initialization,
|
| 250 |
+
"contract_sha256": contract_sha256,
|
| 251 |
+
"tokenizer_files": tokenizer_files,
|
| 252 |
+
"label_to_id": label_to_id,
|
| 253 |
+
"replay_ids": ids,
|
| 254 |
+
"rows": len(records),
|
| 255 |
+
"records_file": targets.name,
|
| 256 |
+
"records_sha256": _sha(targets),
|
| 257 |
+
}
|
| 258 |
+
path = destination / "manifest.json"
|
| 259 |
+
path.write_text(json.dumps(manifest, indent=2, allow_nan=False) + "\n")
|
| 260 |
+
return path
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
class RetentionCache:
|
| 264 |
+
"""Targets for explicitly designated old TRAIN rows; unknown rows are rejected."""
|
| 265 |
+
|
| 266 |
+
@classmethod
|
| 267 |
+
def load(
|
| 268 |
+
cls,
|
| 269 |
+
path,
|
| 270 |
+
*,
|
| 271 |
+
initialization,
|
| 272 |
+
contract_sha256,
|
| 273 |
+
tokenizer_files,
|
| 274 |
+
train_rows,
|
| 275 |
+
tokenized_rows,
|
| 276 |
+
label_to_id,
|
| 277 |
+
replay_ids,
|
| 278 |
+
):
|
| 279 |
+
_metadata(initialization, contract_sha256, tokenizer_files, label_to_id)
|
| 280 |
+
path = Path(path)
|
| 281 |
+
raw = path.read_bytes()
|
| 282 |
+
manifest = json.loads(raw)
|
| 283 |
+
expected = {
|
| 284 |
+
"version",
|
| 285 |
+
"split",
|
| 286 |
+
"dtype",
|
| 287 |
+
"initialization",
|
| 288 |
+
"contract_sha256",
|
| 289 |
+
"tokenizer_files",
|
| 290 |
+
"label_to_id",
|
| 291 |
+
"replay_ids",
|
| 292 |
+
"rows",
|
| 293 |
+
"records_file",
|
| 294 |
+
"records_sha256",
|
| 295 |
+
}
|
| 296 |
+
if not isinstance(manifest, dict) or set(manifest) != expected:
|
| 297 |
+
raise ValueError("Retention manifest fields differ from the schema")
|
| 298 |
+
if (
|
| 299 |
+
type(manifest["version"]) is not int
|
| 300 |
+
or manifest["version"] != 1
|
| 301 |
+
or manifest["split"] != "train"
|
| 302 |
+
or manifest["dtype"] != "float32"
|
| 303 |
+
):
|
| 304 |
+
raise ValueError("Retention requires version1 float32 TRAIN targets")
|
| 305 |
+
for key, value in (
|
| 306 |
+
("initialization", initialization),
|
| 307 |
+
("contract_sha256", contract_sha256),
|
| 308 |
+
("tokenizer_files", tokenizer_files),
|
| 309 |
+
("label_to_id", label_to_id),
|
| 310 |
+
):
|
| 311 |
+
if manifest[key] != value:
|
| 312 |
+
raise ValueError(f"Retention cache differs from the actual {key}")
|
| 313 |
+
identities, marked = {}, set()
|
| 314 |
+
for row in train_rows:
|
| 315 |
+
if row.get("split", "train") != "train":
|
| 316 |
+
raise ValueError(
|
| 317 |
+
"Retention targets cannot include development or test rows"
|
| 318 |
+
)
|
| 319 |
+
if type(row.get("retention_replay", False)) is not bool:
|
| 320 |
+
raise ValueError("TRAIN retention_replay designation must be boolean")
|
| 321 |
+
if row["id"] in identities or row["id"] not in tokenized_rows:
|
| 322 |
+
raise ValueError("Missing tokens or duplicate TRAIN retention ID")
|
| 323 |
+
identities[row["id"]] = row_identity(row, tokenized_rows[row["id"]])
|
| 324 |
+
if row["label"] not in label_to_id:
|
| 325 |
+
raise ValueError("Unknown TRAIN retention label")
|
| 326 |
+
if row.get("retention_replay", False):
|
| 327 |
+
marked.add(row["id"])
|
| 328 |
+
replay_ids = list(replay_ids)
|
| 329 |
+
if (
|
| 330 |
+
not marked
|
| 331 |
+
or len(replay_ids) != len(set(replay_ids))
|
| 332 |
+
or set(replay_ids) != marked
|
| 333 |
+
or manifest["replay_ids"] != sorted(marked)
|
| 334 |
+
):
|
| 335 |
+
raise ValueError("Cache must cover exactly the designated old TRAIN subset")
|
| 336 |
+
filename = manifest["records_file"]
|
| 337 |
+
if (
|
| 338 |
+
not isinstance(filename, str)
|
| 339 |
+
or Path(filename).name != filename
|
| 340 |
+
or filename in {"", ".", ".."}
|
| 341 |
+
):
|
| 342 |
+
raise ValueError("Retention records must use a relative filename")
|
| 343 |
+
targets = path.parent / filename
|
| 344 |
+
data = targets.read_bytes()
|
| 345 |
+
if hashlib.sha256(data).hexdigest() != manifest["records_sha256"]:
|
| 346 |
+
raise ValueError("Retention target bytes changed")
|
| 347 |
+
records = [json.loads(line) for line in data.splitlines() if line.strip()]
|
| 348 |
+
if (
|
| 349 |
+
type(manifest["rows"]) is not int
|
| 350 |
+
or len(records) != manifest["rows"]
|
| 351 |
+
or len(records) != len(marked)
|
| 352 |
+
):
|
| 353 |
+
raise ValueError("Retention target coverage is incomplete")
|
| 354 |
+
cached = {}
|
| 355 |
+
for record in records:
|
| 356 |
+
_record(record, label_to_id)
|
| 357 |
+
identity = {key: value for key, value in record.items() if key != "logits"}
|
| 358 |
+
if (
|
| 359 |
+
record["id"] not in marked
|
| 360 |
+
or record["id"] in cached
|
| 361 |
+
or identity != identities[record["id"]]
|
| 362 |
+
):
|
| 363 |
+
raise ValueError(
|
| 364 |
+
"Retention target does not match its old TRAIN identity"
|
| 365 |
+
)
|
| 366 |
+
values = record["logits"]
|
| 367 |
+
maximum = max(values)
|
| 368 |
+
eligible = (
|
| 369 |
+
values.count(maximum) == 1
|
| 370 |
+
and values.index(maximum) == label_to_id[record["label"]]
|
| 371 |
+
)
|
| 372 |
+
cached[record["id"]] = (values, eligible)
|
| 373 |
+
result = cls()
|
| 374 |
+
result._identities, result._cached, result._width = (
|
| 375 |
+
identities,
|
| 376 |
+
cached,
|
| 377 |
+
len(label_to_id),
|
| 378 |
+
)
|
| 379 |
+
result.receipt = {
|
| 380 |
+
"manifest_sha256": hashlib.sha256(raw).hexdigest(),
|
| 381 |
+
"records_sha256": manifest["records_sha256"],
|
| 382 |
+
"replay_rows": len(cached),
|
| 383 |
+
"eligible_rows": sum(eligible for _, eligible in cached.values()),
|
| 384 |
+
}
|
| 385 |
+
return result
|
| 386 |
+
|
| 387 |
+
def targets(self, rows, device):
|
| 388 |
+
import torch
|
| 389 |
+
|
| 390 |
+
values, masks = [], []
|
| 391 |
+
for row in rows:
|
| 392 |
+
identity = self._identities.get(row["id"])
|
| 393 |
+
if (
|
| 394 |
+
identity is None
|
| 395 |
+
or any(row[key] != identity[key] for key in ("id", "group_id", "label"))
|
| 396 |
+
or hashlib.sha256(row["text"].encode()).hexdigest()
|
| 397 |
+
!= identity["text_sha256"]
|
| 398 |
+
):
|
| 399 |
+
raise ValueError(
|
| 400 |
+
"Retention batch is not part of the validated TRAIN corpus"
|
| 401 |
+
)
|
| 402 |
+
logits, eligible = self._cached.get(row["id"], ([0.0] * self._width, False))
|
| 403 |
+
values.append(logits)
|
| 404 |
+
masks.append(eligible)
|
| 405 |
+
return (
|
| 406 |
+
torch.tensor(values, dtype=torch.float32, device=device).reshape(
|
| 407 |
+
len(rows), self._width
|
| 408 |
+
),
|
| 409 |
+
torch.tensor(masks, dtype=torch.bool, device=device),
|
| 410 |
+
)
|
reproducibility/sequence_repair/runtime_mapping.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Serialize classifier label sidecars consumed by the router's Go loaders."""
|
| 2 |
+
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
RUNTIME_TASKS = (
|
| 7 |
+
"domain",
|
| 8 |
+
"fact-check",
|
| 9 |
+
"modality",
|
| 10 |
+
"feedback",
|
| 11 |
+
"prompt-guard",
|
| 12 |
+
"safety",
|
| 13 |
+
"hazard",
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def write_runtime_mappings(destination, labels, task):
|
| 18 |
+
"""Write both HF and router layouts from one contiguous label bijection."""
|
| 19 |
+
if task not in RUNTIME_TASKS:
|
| 20 |
+
raise ValueError("Unknown runtime classifier task")
|
| 21 |
+
if not labels or set(labels.values()) != set(range(len(labels))):
|
| 22 |
+
raise ValueError("Runtime label IDs must be a contiguous bijection")
|
| 23 |
+
if task == "modality" and labels != {"AR": 0, "DIFFUSION": 1, "BOTH": 2}:
|
| 24 |
+
raise ValueError("Modality must preserve the native AR/DIFFUSION/BOTH IDs")
|
| 25 |
+
if task == "fact-check" and set(labels) != {
|
| 26 |
+
"NO_FACT_CHECK_NEEDED",
|
| 27 |
+
"FACT_CHECK_NEEDED",
|
| 28 |
+
}:
|
| 29 |
+
raise ValueError("FactCheck requires the router's two semantic labels")
|
| 30 |
+
reverse = {str(index): label for label, index in labels.items()}
|
| 31 |
+
generic = {
|
| 32 |
+
"label2id": labels,
|
| 33 |
+
"id2label": reverse,
|
| 34 |
+
"label_to_idx": labels,
|
| 35 |
+
"idx_to_label": reverse,
|
| 36 |
+
}
|
| 37 |
+
files = {"label_mapping.json": generic}
|
| 38 |
+
if task == "domain":
|
| 39 |
+
files["category_mapping.json"] = {
|
| 40 |
+
"category_to_idx": labels,
|
| 41 |
+
"idx_to_category": reverse,
|
| 42 |
+
}
|
| 43 |
+
sidecars = {
|
| 44 |
+
"fact-check": "fact_check_mapping.json",
|
| 45 |
+
"modality": "modality_mapping.json",
|
| 46 |
+
"prompt-guard": "jailbreak_type_mapping.json",
|
| 47 |
+
}
|
| 48 |
+
if task in sidecars:
|
| 49 |
+
files[sidecars[task]] = {
|
| 50 |
+
"label_to_idx": labels,
|
| 51 |
+
"idx_to_label": reverse,
|
| 52 |
+
}
|
| 53 |
+
for name, data in files.items():
|
| 54 |
+
path = Path(destination) / name
|
| 55 |
+
if path.exists():
|
| 56 |
+
raise ValueError("Refusing to overwrite an existing runtime mapping")
|
| 57 |
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
| 58 |
+
return sorted(files)
|
reproducibility/sequence_repair/selection.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Development-only binary operating points under an explicit false-positive budget."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
import math
|
| 6 |
+
from collections import Counter, defaultdict
|
| 7 |
+
from fractions import Fraction
|
| 8 |
+
|
| 9 |
+
BINARY_FP_SELECTION = "binary-fp-budget-recall"
|
| 10 |
+
BINARY_LABEL_COUNT = 2
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def validate_binary_selection(label_to_id, positive_label, budget):
|
| 14 |
+
"""Require an unambiguous binary ontology and a finite, explicit FP budget."""
|
| 15 |
+
if (
|
| 16 |
+
len(label_to_id) != BINARY_LABEL_COUNT
|
| 17 |
+
or set(label_to_id.values()) != {0, 1}
|
| 18 |
+
or any(type(index) is not int for index in label_to_id.values())
|
| 19 |
+
):
|
| 20 |
+
raise ValueError("FP-budget selection requires exactly two label IDs: 0 and 1")
|
| 21 |
+
if positive_label not in label_to_id:
|
| 22 |
+
raise ValueError("FP-budget selection requires an exact positive label")
|
| 23 |
+
if (
|
| 24 |
+
isinstance(budget, bool)
|
| 25 |
+
or not isinstance(budget, (int, float))
|
| 26 |
+
or not math.isfinite(budget)
|
| 27 |
+
or not 0 <= budget <= 1
|
| 28 |
+
):
|
| 29 |
+
raise ValueError("Selection false-positive budget must be finite in [0, 1]")
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def validate_selection_options(selection, label_to_id, positive_label, budget):
|
| 33 |
+
if selection == BINARY_FP_SELECTION:
|
| 34 |
+
validate_binary_selection(label_to_id, positive_label, budget)
|
| 35 |
+
elif positive_label is not None or budget is not None:
|
| 36 |
+
raise ValueError("Binary selection options require binary-fp-budget-recall")
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def binary_selection_support(records, label_to_id, positive_label):
|
| 40 |
+
counts = Counter(row["label"] for row in records)
|
| 41 |
+
if set(counts) != set(label_to_id):
|
| 42 |
+
raise ValueError("FP-budget development data must observe both binary labels")
|
| 43 |
+
if any(not row.get("id") for row in records) or len(
|
| 44 |
+
{row["id"] for row in records}
|
| 45 |
+
) != len(records):
|
| 46 |
+
raise ValueError("Development IDs must be nonempty and unique")
|
| 47 |
+
return {
|
| 48 |
+
"positive": counts[positive_label],
|
| 49 |
+
"negative": len(records) - counts[positive_label],
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def binary_checkpoint_key(operating_point):
|
| 54 |
+
"""Tie policy also applies across checkpoints; exact ties keep the earlier step."""
|
| 55 |
+
if not operating_point["feasible"]:
|
| 56 |
+
return None
|
| 57 |
+
return (
|
| 58 |
+
operating_point["recall"],
|
| 59 |
+
-operating_point["confusion"]["fp"],
|
| 60 |
+
operating_point["threshold"],
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def fit_binary_operating_point(
|
| 65 |
+
records, predictions, label_to_id, positive_label, budget
|
| 66 |
+
):
|
| 67 |
+
"""Sweep complete tied-score groups with p(positive) >= threshold in [0, 1]."""
|
| 68 |
+
validate_binary_selection(label_to_id, positive_label, budget)
|
| 69 |
+
support = binary_selection_support(records, label_to_id, positive_label)
|
| 70 |
+
by_id = {row["id"]: row for row in predictions}
|
| 71 |
+
if len(by_id) != len(predictions) or set(by_id) != {row["id"] for row in records}:
|
| 72 |
+
raise ValueError("Development prediction IDs must match each row exactly once")
|
| 73 |
+
positive_id = label_to_id[positive_label]
|
| 74 |
+
grouped = defaultdict(lambda: [0, 0])
|
| 75 |
+
evidence = []
|
| 76 |
+
for row in records:
|
| 77 |
+
scores = by_id[row["id"]]["probabilities"]
|
| 78 |
+
if (
|
| 79 |
+
len(scores) != BINARY_LABEL_COUNT
|
| 80 |
+
or any(
|
| 81 |
+
isinstance(score, bool)
|
| 82 |
+
or not isinstance(score, (int, float))
|
| 83 |
+
or not math.isfinite(score)
|
| 84 |
+
or not 0 <= score <= 1
|
| 85 |
+
for score in scores
|
| 86 |
+
)
|
| 87 |
+
or not math.isclose(sum(scores), 1.0, rel_tol=0, abs_tol=1e-5)
|
| 88 |
+
):
|
| 89 |
+
raise ValueError("Expected finite normalized binary probabilities")
|
| 90 |
+
score = scores[positive_id]
|
| 91 |
+
is_positive = row["label"] == positive_label
|
| 92 |
+
grouped[score][0 if is_positive else 1] += 1
|
| 93 |
+
evidence.append(
|
| 94 |
+
{"id": row["id"], "label": row["label"], "probabilities": scores}
|
| 95 |
+
)
|
| 96 |
+
# Decimal budget arithmetic avoids floor(0.3 * 10) rounding surprises without
|
| 97 |
+
# an epsilon that could admit an extra false positive.
|
| 98 |
+
maximum_fp = math.floor(Fraction(str(budget)) * support["negative"])
|
| 99 |
+
receipt = {
|
| 100 |
+
"metric": BINARY_FP_SELECTION,
|
| 101 |
+
"positive_label": positive_label,
|
| 102 |
+
"positive_label_id": positive_id,
|
| 103 |
+
"negative_label": next(
|
| 104 |
+
label for label in label_to_id if label != positive_label
|
| 105 |
+
),
|
| 106 |
+
"false_positive_budget": budget,
|
| 107 |
+
"maximum_false_positives": maximum_fp,
|
| 108 |
+
"support": support,
|
| 109 |
+
"comparison": "positive_probability >= threshold",
|
| 110 |
+
"threshold_range": [0, 1],
|
| 111 |
+
"tie_break": ["maximum_recall", "fewer_false_positives", "higher_threshold"],
|
| 112 |
+
"evidence_sha256": hashlib.sha256(
|
| 113 |
+
json.dumps(
|
| 114 |
+
sorted(evidence, key=lambda row: row["id"]),
|
| 115 |
+
sort_keys=True,
|
| 116 |
+
separators=(",", ":"),
|
| 117 |
+
allow_nan=False,
|
| 118 |
+
).encode()
|
| 119 |
+
).hexdigest(),
|
| 120 |
+
"test_used": False,
|
| 121 |
+
"feasible": False,
|
| 122 |
+
"threshold": None,
|
| 123 |
+
"recall": None,
|
| 124 |
+
"precision": None,
|
| 125 |
+
"false_positive_rate": None,
|
| 126 |
+
"confusion": None,
|
| 127 |
+
}
|
| 128 |
+
best_key, tp, fp = None, 0, 0
|
| 129 |
+
for threshold in sorted({0.0, 1.0, *grouped}, reverse=True):
|
| 130 |
+
positive_count, negative_count = grouped[threshold]
|
| 131 |
+
tp += positive_count
|
| 132 |
+
fp += negative_count
|
| 133 |
+
if fp > maximum_fp:
|
| 134 |
+
continue
|
| 135 |
+
key = (tp, -fp, threshold)
|
| 136 |
+
if best_key is not None and key <= best_key:
|
| 137 |
+
continue
|
| 138 |
+
best_key = key
|
| 139 |
+
receipt.update(
|
| 140 |
+
{
|
| 141 |
+
"feasible": True,
|
| 142 |
+
"threshold": threshold,
|
| 143 |
+
"recall": tp / support["positive"],
|
| 144 |
+
"precision": tp / (tp + fp) if tp + fp else 0.0,
|
| 145 |
+
"false_positive_rate": fp / support["negative"],
|
| 146 |
+
"confusion": {
|
| 147 |
+
"tp": tp,
|
| 148 |
+
"fp": fp,
|
| 149 |
+
"fn": support["positive"] - tp,
|
| 150 |
+
"tn": support["negative"] - fp,
|
| 151 |
+
},
|
| 152 |
+
}
|
| 153 |
+
)
|
| 154 |
+
if not receipt["feasible"]:
|
| 155 |
+
receipt["infeasible_reason"] = (
|
| 156 |
+
"Negative examples at probability 1 exceed the budget even at threshold 1"
|
| 157 |
+
)
|
| 158 |
+
return receipt
|
reproducibility/sequence_repair/task_head.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Inspect the effective task head and verify its adapter/merged storage."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import hashlib
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _modules(model):
|
| 9 |
+
base = model.get_base_model() if hasattr(model, "get_base_model") else model
|
| 10 |
+
if type(base).__name__ not in {
|
| 11 |
+
"ModernBertForSequenceClassification",
|
| 12 |
+
"ModernBertForTokenClassification",
|
| 13 |
+
}:
|
| 14 |
+
raise ValueError(
|
| 15 |
+
"Task-head auditing requires a supported ModernBERT task model"
|
| 16 |
+
)
|
| 17 |
+
for name in ("head", "classifier"):
|
| 18 |
+
module = getattr(base, name)
|
| 19 |
+
owned = hasattr(module, "modules_to_save")
|
| 20 |
+
if owned:
|
| 21 |
+
active = module.active_adapter
|
| 22 |
+
if isinstance(active, list):
|
| 23 |
+
if len(active) != 1:
|
| 24 |
+
raise ValueError("Task-head auditing requires one active adapter")
|
| 25 |
+
active = active[0]
|
| 26 |
+
module = module.modules_to_save[active]
|
| 27 |
+
yield name, module, owned
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def tensor_digest(tensor):
|
| 31 |
+
import torch
|
| 32 |
+
|
| 33 |
+
value = tensor.detach().cpu().contiguous()
|
| 34 |
+
if not bool(torch.isfinite(value).all()):
|
| 35 |
+
raise ValueError("Task head contains non-finite tensors")
|
| 36 |
+
return hashlib.sha256(value.view(torch.uint8).numpy().tobytes()).hexdigest()
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def task_head_scope(model):
|
| 40 |
+
"""Describe actual effective tensors, including deliberately inherited heads."""
|
| 41 |
+
tensors = {}
|
| 42 |
+
for name, module, owned in _modules(model):
|
| 43 |
+
trainable = dict(module.named_parameters())
|
| 44 |
+
for key, tensor in module.state_dict().items():
|
| 45 |
+
parameter = trainable.get(key)
|
| 46 |
+
tensors[f"{name}.{key}"] = {
|
| 47 |
+
"shape": list(tensor.shape),
|
| 48 |
+
"dtype": str(tensor.dtype),
|
| 49 |
+
"numel": tensor.numel(),
|
| 50 |
+
"trainable": parameter is not None and parameter.requires_grad,
|
| 51 |
+
"adapter_owned": owned,
|
| 52 |
+
"sha256": tensor_digest(tensor),
|
| 53 |
+
}
|
| 54 |
+
base = model.get_base_model() if hasattr(model, "get_base_model") else model
|
| 55 |
+
return {
|
| 56 |
+
"architecture": type(base).__name__,
|
| 57 |
+
"modules_to_save": (
|
| 58 |
+
model.peft_config["default"].modules_to_save
|
| 59 |
+
if hasattr(model, "get_base_model")
|
| 60 |
+
else None
|
| 61 |
+
),
|
| 62 |
+
"trainable_task_head_parameters": sum(
|
| 63 |
+
item["numel"] for item in tensors.values() if item["trainable"]
|
| 64 |
+
),
|
| 65 |
+
"tensors": tensors,
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def verify_saved_task_head(model, adapter_path):
|
| 70 |
+
"""Reject an adapter that omits or changes an effective trainable task tensor."""
|
| 71 |
+
from safetensors.torch import load_file
|
| 72 |
+
|
| 73 |
+
saved = load_file(str(adapter_path), device="cpu")
|
| 74 |
+
scope = task_head_scope(model)
|
| 75 |
+
for name, item in scope["tensors"].items():
|
| 76 |
+
key = f"base_model.model.{name}"
|
| 77 |
+
value = saved.get(key)
|
| 78 |
+
item["saved_key"] = key if value is not None else None
|
| 79 |
+
if value is None:
|
| 80 |
+
if item["trainable"] or item["adapter_owned"]:
|
| 81 |
+
raise ValueError(f"Adapter omitted effective task tensor: {name}")
|
| 82 |
+
continue
|
| 83 |
+
if (
|
| 84 |
+
list(value.shape) != item["shape"]
|
| 85 |
+
or str(value.dtype) != item["dtype"]
|
| 86 |
+
or tensor_digest(value) != item["sha256"]
|
| 87 |
+
):
|
| 88 |
+
raise ValueError(f"Adapter changed effective task tensor: {name}")
|
| 89 |
+
return scope
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def assert_task_head_preserved(expected, model):
|
| 93 |
+
"""Compare tensor identity across PEFT merge and serialized model reload."""
|
| 94 |
+
observed = task_head_scope(model)
|
| 95 |
+
identity = ("shape", "dtype", "sha256")
|
| 96 |
+
expected_tensors = expected["tensors"]
|
| 97 |
+
if expected_tensors.keys() != observed["tensors"].keys():
|
| 98 |
+
raise ValueError("Task-head tensor names changed")
|
| 99 |
+
for name, item in expected_tensors.items():
|
| 100 |
+
if any(item[key] != observed["tensors"][name][key] for key in identity):
|
| 101 |
+
raise ValueError(f"Task-head tensor changed: {name}")
|
| 102 |
+
return observed
|
reproducibility/sequence_repair/train.py
ADDED
|
@@ -0,0 +1,791 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Explicit single-GPU classifier training with optional development selection."""
|
| 2 |
+
|
| 3 |
+
# ruff: noqa: PLC0415
|
| 4 |
+
|
| 5 |
+
import argparse
|
| 6 |
+
import hashlib
|
| 7 |
+
import json
|
| 8 |
+
import math
|
| 9 |
+
import random
|
| 10 |
+
import time
|
| 11 |
+
from collections import Counter, defaultdict
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
|
| 14 |
+
from .data import assert_disjoint, file_receipts, label_counts, read_records
|
| 15 |
+
from .evaluate import evaluate_records
|
| 16 |
+
from .optimization import (
|
| 17 |
+
assert_frozen_parameters_preserved,
|
| 18 |
+
configure_trainable_tail,
|
| 19 |
+
frozen_parameter_receipt,
|
| 20 |
+
initial_artifact_receipt,
|
| 21 |
+
load_trainable_model,
|
| 22 |
+
optimizer_groups,
|
| 23 |
+
save_training_checkpoint,
|
| 24 |
+
validate_method,
|
| 25 |
+
verify_full_checkpoint,
|
| 26 |
+
)
|
| 27 |
+
from .retention import RetentionCache, masked_teacher_kl, tokenizer_file_receipt
|
| 28 |
+
from .selection import (
|
| 29 |
+
BINARY_FP_SELECTION,
|
| 30 |
+
binary_checkpoint_key,
|
| 31 |
+
binary_selection_support,
|
| 32 |
+
fit_binary_operating_point,
|
| 33 |
+
validate_selection_options,
|
| 34 |
+
)
|
| 35 |
+
from .task_head import task_head_scope
|
| 36 |
+
from .training_order import load_training_order
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def microbatch_loss(logits, labels, accumulation_steps):
|
| 40 |
+
from torch.nn import functional
|
| 41 |
+
|
| 42 |
+
if accumulation_steps <= 0:
|
| 43 |
+
raise ValueError("Gradient accumulation must be positive")
|
| 44 |
+
# Each microbatch has the same number of examples. HF Trainer loss-kwargs
|
| 45 |
+
# normalization is intentionally not involved in this explicit loop.
|
| 46 |
+
return (
|
| 47 |
+
functional.cross_entropy(logits.float(), labels, reduction="mean")
|
| 48 |
+
/ accumulation_steps
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def global_batch_loss(logits, labels, examples_per_step):
|
| 53 |
+
"""Normalize variable microbatches by the same sampled optimizer-step size."""
|
| 54 |
+
from torch.nn import functional
|
| 55 |
+
|
| 56 |
+
if examples_per_step <= 0:
|
| 57 |
+
raise ValueError("Optimizer-step example count must be positive")
|
| 58 |
+
return (
|
| 59 |
+
functional.cross_entropy(logits.float(), labels, reduction="sum")
|
| 60 |
+
/ examples_per_step
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def token_budget_microbatches(indices, lengths, token_budget):
|
| 65 |
+
"""Stable length ordering without dropping or duplicating sampled examples."""
|
| 66 |
+
if token_budget <= 0:
|
| 67 |
+
raise ValueError("Microbatch token budget must be positive")
|
| 68 |
+
batches, current = [], []
|
| 69 |
+
for index in sorted(indices, key=lengths.__getitem__):
|
| 70 |
+
length = lengths[index]
|
| 71 |
+
if length > token_budget:
|
| 72 |
+
raise ValueError("A sampled example exceeds the microbatch token budget")
|
| 73 |
+
if current and length * (len(current) + 1) > token_budget:
|
| 74 |
+
batches.append(current)
|
| 75 |
+
current = []
|
| 76 |
+
current.append(index)
|
| 77 |
+
if current:
|
| 78 |
+
batches.append(current)
|
| 79 |
+
return batches
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def selection_score(metrics, selection):
|
| 83 |
+
if selection == "macro-f1":
|
| 84 |
+
return metrics["macro_f1"]
|
| 85 |
+
if selection in {
|
| 86 |
+
"length-macro-f1",
|
| 87 |
+
"source-macro-f1",
|
| 88 |
+
"source-present-macro-f1",
|
| 89 |
+
}:
|
| 90 |
+
field = "length_bucket" if selection == "length-macro-f1" else "source"
|
| 91 |
+
metric = (
|
| 92 |
+
"macro_f1_present_labels"
|
| 93 |
+
if selection == "source-present-macro-f1"
|
| 94 |
+
else "macro_f1"
|
| 95 |
+
)
|
| 96 |
+
groups = list(metrics["breakdowns"][field].values())
|
| 97 |
+
if not groups:
|
| 98 |
+
raise ValueError("Grouped selection requires measured groups")
|
| 99 |
+
return sum(group[metric] for group in groups) / len(groups)
|
| 100 |
+
raise ValueError("Unknown development selection metric")
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def length_sampling_pools(rows):
|
| 104 |
+
buckets = defaultdict(lambda: defaultdict(list))
|
| 105 |
+
for index, row in enumerate(rows):
|
| 106 |
+
buckets[str(row.get("length_bucket", "unspecified"))][row["label"]].append(
|
| 107 |
+
index
|
| 108 |
+
)
|
| 109 |
+
return [list(labels.values()) for labels in buckets.values()]
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def sample_length_balanced(pools, rng, balance_labels):
|
| 113 |
+
bucket = rng.choice(pools)
|
| 114 |
+
pool = (
|
| 115 |
+
rng.choice(bucket)
|
| 116 |
+
if balance_labels
|
| 117 |
+
else [index for label in bucket for index in label]
|
| 118 |
+
)
|
| 119 |
+
return rng.choice(pool)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def source_sampling_pools(rows, balance_lengths):
|
| 123 |
+
sources = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
|
| 124 |
+
for index, row in enumerate(rows):
|
| 125 |
+
if not row.get("source"):
|
| 126 |
+
raise ValueError("Source-balanced sampling requires explicit sources")
|
| 127 |
+
length = (
|
| 128 |
+
str(row.get("length_bucket", "unspecified")) if balance_lengths else "all"
|
| 129 |
+
)
|
| 130 |
+
sources[row["source"]][length][row["label"]].append(index)
|
| 131 |
+
return [
|
| 132 |
+
[list(labels.values()) for labels in lengths.values()]
|
| 133 |
+
for lengths in sources.values()
|
| 134 |
+
]
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def source_sampling_weights(rows, specification):
|
| 138 |
+
"""Resolve explicit probabilities in the same order as source pools."""
|
| 139 |
+
if specification is None:
|
| 140 |
+
return None
|
| 141 |
+
weights = json.loads(specification)
|
| 142 |
+
sources = list(dict.fromkeys(row.get("source") for row in rows))
|
| 143 |
+
if (
|
| 144 |
+
not sources
|
| 145 |
+
or not all(sources)
|
| 146 |
+
or not isinstance(weights, dict)
|
| 147 |
+
or set(weights) != set(sources)
|
| 148 |
+
):
|
| 149 |
+
raise ValueError("Source weights must name every eligible source exactly")
|
| 150 |
+
values = [weights[source] for source in sources]
|
| 151 |
+
if any(
|
| 152 |
+
isinstance(value, bool)
|
| 153 |
+
or not isinstance(value, (int, float))
|
| 154 |
+
or not math.isfinite(value)
|
| 155 |
+
or value <= 0
|
| 156 |
+
for value in values
|
| 157 |
+
):
|
| 158 |
+
raise ValueError("Source weights must be finite positive numbers")
|
| 159 |
+
total = sum(values)
|
| 160 |
+
if not math.isfinite(total):
|
| 161 |
+
raise ValueError("Total source weight must be finite")
|
| 162 |
+
return [value / total for value in values]
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def sample_source_balanced(pools, rng, balance_labels, source_weights=None):
|
| 166 |
+
source = (
|
| 167 |
+
rng.choice(pools)
|
| 168 |
+
if source_weights is None
|
| 169 |
+
else rng.choices(pools, weights=source_weights, k=1)[0]
|
| 170 |
+
)
|
| 171 |
+
return sample_length_balanced(source, rng, balance_labels)
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def sampling_exposure(rows, drawn):
|
| 175 |
+
"""Report sampling counts separately from class/length selection metrics."""
|
| 176 |
+
sources = defaultdict(
|
| 177 |
+
lambda: {"rows": 0, "draws": 0, "unique_rows": 0, "label_draws": Counter()}
|
| 178 |
+
)
|
| 179 |
+
for index, row in enumerate(rows):
|
| 180 |
+
item = sources[row.get("source", "unspecified")]
|
| 181 |
+
count = drawn[index]
|
| 182 |
+
item["rows"] += 1
|
| 183 |
+
item["draws"] += count
|
| 184 |
+
item["unique_rows"] += int(count > 0)
|
| 185 |
+
item["label_draws"][row["label"]] += count
|
| 186 |
+
return dict(sources)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def main():
|
| 190 |
+
import torch
|
| 191 |
+
|
| 192 |
+
parser = argparse.ArgumentParser()
|
| 193 |
+
parser.add_argument("--base", required=True)
|
| 194 |
+
parser.add_argument("--base-id", required=True)
|
| 195 |
+
parser.add_argument("--base-revision", required=True)
|
| 196 |
+
parser.add_argument("--adapter", type=Path)
|
| 197 |
+
parser.add_argument("--method", choices=["lora", "full"], default="lora")
|
| 198 |
+
parser.add_argument("--fresh-head", action="store_true")
|
| 199 |
+
parser.add_argument("--contract", required=True)
|
| 200 |
+
parser.add_argument("--train", nargs="+", required=True)
|
| 201 |
+
parser.add_argument("--dev", nargs="+")
|
| 202 |
+
parser.add_argument("--output", type=Path, required=True)
|
| 203 |
+
parser.add_argument("--steps", type=int, default=400)
|
| 204 |
+
parser.add_argument("--batch-size", type=int, default=8)
|
| 205 |
+
parser.add_argument("--accumulate", type=int, default=2)
|
| 206 |
+
parser.add_argument("--max-length", type=int, default=2048)
|
| 207 |
+
parser.add_argument("--learning-rate", type=float, default=2e-5)
|
| 208 |
+
parser.add_argument("--head-learning-rate", type=float)
|
| 209 |
+
parser.add_argument("--trainable-last-layers", type=int)
|
| 210 |
+
parser.add_argument("--retention-targets", type=Path)
|
| 211 |
+
parser.add_argument("--retention-weight", type=float)
|
| 212 |
+
parser.add_argument("--retention-temperature", type=float)
|
| 213 |
+
parser.add_argument("--eval-every", type=int, default=100)
|
| 214 |
+
parser.add_argument(
|
| 215 |
+
"--evaluation-dtype", choices=["bfloat16", "float32"], default="bfloat16"
|
| 216 |
+
)
|
| 217 |
+
parser.add_argument(
|
| 218 |
+
"--selection",
|
| 219 |
+
choices=[
|
| 220 |
+
"macro-f1",
|
| 221 |
+
"length-macro-f1",
|
| 222 |
+
"source-macro-f1",
|
| 223 |
+
"source-present-macro-f1",
|
| 224 |
+
BINARY_FP_SELECTION,
|
| 225 |
+
],
|
| 226 |
+
default="macro-f1",
|
| 227 |
+
)
|
| 228 |
+
parser.add_argument("--positive-label")
|
| 229 |
+
parser.add_argument("--selection-false-positive-budget", type=float)
|
| 230 |
+
parser.add_argument("--balanced-sampling", action="store_true")
|
| 231 |
+
parser.add_argument("--length-balanced-sampling", action="store_true")
|
| 232 |
+
parser.add_argument("--source-balanced-sampling", action="store_true")
|
| 233 |
+
parser.add_argument(
|
| 234 |
+
"--source-weights", help="JSON object of explicit source weights"
|
| 235 |
+
)
|
| 236 |
+
parser.add_argument("--microbatch-token-budget", type=int)
|
| 237 |
+
parser.add_argument("--training-order", type=Path)
|
| 238 |
+
mode = parser.add_mutually_exclusive_group()
|
| 239 |
+
mode.add_argument("--probe-only", action="store_true")
|
| 240 |
+
mode.add_argument(
|
| 241 |
+
"--train-only",
|
| 242 |
+
action="store_true",
|
| 243 |
+
help="Skip development data and selection; save only the final checkpoint",
|
| 244 |
+
)
|
| 245 |
+
parser.add_argument("--seed", type=int, default=20260913)
|
| 246 |
+
args = parser.parse_args()
|
| 247 |
+
if args.train_only:
|
| 248 |
+
if args.dev:
|
| 249 |
+
parser.error("--train-only must not receive development data")
|
| 250 |
+
if (
|
| 251 |
+
args.selection != "macro-f1"
|
| 252 |
+
or args.positive_label is not None
|
| 253 |
+
or args.selection_false_positive_budget is not None
|
| 254 |
+
):
|
| 255 |
+
parser.error("--train-only does not select a development operating point")
|
| 256 |
+
elif not args.dev:
|
| 257 |
+
parser.error("--dev is required unless --train-only is set")
|
| 258 |
+
validate_method(args.method, args.adapter, args.fresh_head)
|
| 259 |
+
if args.trainable_last_layers is not None and args.method != "full":
|
| 260 |
+
raise ValueError("A trainable encoder tail requires full checkpoint training")
|
| 261 |
+
if args.retention_targets is None:
|
| 262 |
+
if args.retention_weight is not None or args.retention_temperature is not None:
|
| 263 |
+
raise ValueError("Retention settings require explicit TRAIN targets")
|
| 264 |
+
else:
|
| 265 |
+
if args.method != "full" or args.fresh_head:
|
| 266 |
+
raise ValueError("Retention requires the unchanged complete initial head")
|
| 267 |
+
args.retention_weight = (
|
| 268 |
+
0.5 if args.retention_weight is None else args.retention_weight
|
| 269 |
+
)
|
| 270 |
+
args.retention_temperature = (
|
| 271 |
+
2.0 if args.retention_temperature is None else args.retention_temperature
|
| 272 |
+
)
|
| 273 |
+
if any(
|
| 274 |
+
not math.isfinite(value) or value <= 0
|
| 275 |
+
for value in (args.retention_weight, args.retention_temperature)
|
| 276 |
+
):
|
| 277 |
+
raise ValueError(
|
| 278 |
+
"Retention weight and temperature must be finite and positive"
|
| 279 |
+
)
|
| 280 |
+
if args.training_order and (
|
| 281 |
+
args.balanced_sampling
|
| 282 |
+
or args.length_balanced_sampling
|
| 283 |
+
or args.source_balanced_sampling
|
| 284 |
+
or args.source_weights is not None
|
| 285 |
+
):
|
| 286 |
+
raise ValueError("An explicit training order cannot also configure sampling")
|
| 287 |
+
if (
|
| 288 |
+
min(
|
| 289 |
+
args.steps,
|
| 290 |
+
args.batch_size,
|
| 291 |
+
args.accumulate,
|
| 292 |
+
args.max_length,
|
| 293 |
+
args.eval_every,
|
| 294 |
+
)
|
| 295 |
+
<= 0
|
| 296 |
+
or args.learning_rate <= 0
|
| 297 |
+
or (
|
| 298 |
+
args.microbatch_token_budget is not None
|
| 299 |
+
and args.microbatch_token_budget <= 0
|
| 300 |
+
)
|
| 301 |
+
):
|
| 302 |
+
raise ValueError("Training budgets and learning rate must be positive")
|
| 303 |
+
if args.output.exists() and any(args.output.iterdir()):
|
| 304 |
+
raise ValueError("Refusing to overwrite a training run")
|
| 305 |
+
torch.set_num_threads(8)
|
| 306 |
+
torch.manual_seed(args.seed)
|
| 307 |
+
rng = random.Random(args.seed)
|
| 308 |
+
initial_artifacts = initial_artifact_receipt(args.base, args.adapter)
|
| 309 |
+
model, tokenizer, label_to_id, id_to_label = load_trainable_model(
|
| 310 |
+
args.base, args.contract, args.adapter, args.method, args.fresh_head
|
| 311 |
+
)
|
| 312 |
+
if model.config.problem_type != "single_label_classification":
|
| 313 |
+
raise ValueError("This training loop requires single-label targets")
|
| 314 |
+
if args.retention_targets is not None:
|
| 315 |
+
verify_full_checkpoint(model, args.base)
|
| 316 |
+
trainable_scope = (
|
| 317 |
+
configure_trainable_tail(model, args.trainable_last_layers)
|
| 318 |
+
if args.trainable_last_layers is not None
|
| 319 |
+
else None
|
| 320 |
+
)
|
| 321 |
+
frozen_parameters = (
|
| 322 |
+
frozen_parameter_receipt(model) if trainable_scope is not None else None
|
| 323 |
+
)
|
| 324 |
+
if not args.train_only:
|
| 325 |
+
validate_selection_options(
|
| 326 |
+
args.selection,
|
| 327 |
+
label_to_id,
|
| 328 |
+
args.positive_label,
|
| 329 |
+
args.selection_false_positive_budget,
|
| 330 |
+
)
|
| 331 |
+
if args.max_length > model.config.max_position_embeddings:
|
| 332 |
+
raise ValueError("Training budget exceeds checkpoint position capacity")
|
| 333 |
+
rows, dev = (
|
| 334 |
+
read_records(args.train, label_to_id),
|
| 335 |
+
[] if args.train_only else read_records(args.dev, label_to_id),
|
| 336 |
+
)
|
| 337 |
+
assert_disjoint(rows, dev)
|
| 338 |
+
if args.selection == BINARY_FP_SELECTION:
|
| 339 |
+
binary_selection_support(dev, label_to_id, args.positive_label)
|
| 340 |
+
train, rejected, pools = [], [], defaultdict(list)
|
| 341 |
+
for row in rows:
|
| 342 |
+
encoded = tokenizer(row["text"], truncation=False, padding=False)
|
| 343 |
+
if len(encoded["input_ids"]) > args.max_length:
|
| 344 |
+
rejected.append(
|
| 345 |
+
{
|
| 346 |
+
"id": row["id"],
|
| 347 |
+
"reason": "explicit context budget",
|
| 348 |
+
"tokens": len(encoded["input_ids"]),
|
| 349 |
+
}
|
| 350 |
+
)
|
| 351 |
+
continue
|
| 352 |
+
index = len(train)
|
| 353 |
+
train.append((row, encoded))
|
| 354 |
+
pools[row["label"]].append(index)
|
| 355 |
+
if not train:
|
| 356 |
+
raise ValueError("No training rows fit the explicit budget")
|
| 357 |
+
retention = None
|
| 358 |
+
if args.retention_targets is not None:
|
| 359 |
+
if any(
|
| 360 |
+
not isinstance(row.get("retention_replay", False), bool) for row, _ in train
|
| 361 |
+
):
|
| 362 |
+
raise ValueError("retention_replay must be a boolean TRAIN annotation")
|
| 363 |
+
retention = RetentionCache.load(
|
| 364 |
+
args.retention_targets,
|
| 365 |
+
initialization=initial_artifacts,
|
| 366 |
+
contract_sha256=hashlib.sha256(
|
| 367 |
+
Path(args.contract).read_bytes()
|
| 368 |
+
).hexdigest(),
|
| 369 |
+
tokenizer_files=tokenizer_file_receipt(args.base),
|
| 370 |
+
train_rows=[row for row, _ in train],
|
| 371 |
+
tokenized_rows={row["id"]: encoded for row, encoded in train},
|
| 372 |
+
label_to_id=label_to_id,
|
| 373 |
+
replay_ids=[
|
| 374 |
+
row["id"] for row, _ in train if row.get("retention_replay", False)
|
| 375 |
+
],
|
| 376 |
+
)
|
| 377 |
+
train_lengths = [len(encoded["input_ids"]) for _, encoded in train]
|
| 378 |
+
if (
|
| 379 |
+
args.microbatch_token_budget is not None
|
| 380 |
+
and max(train_lengths) > args.microbatch_token_budget
|
| 381 |
+
):
|
| 382 |
+
raise ValueError(
|
| 383 |
+
"Microbatch token budget cannot fit the longest eligible example"
|
| 384 |
+
)
|
| 385 |
+
training_order = (
|
| 386 |
+
load_training_order(
|
| 387 |
+
args.training_order,
|
| 388 |
+
[row for row, _ in train],
|
| 389 |
+
args.train,
|
| 390 |
+
steps=args.steps,
|
| 391 |
+
global_batch=args.batch_size * args.accumulate,
|
| 392 |
+
)
|
| 393 |
+
if args.training_order
|
| 394 |
+
else None
|
| 395 |
+
)
|
| 396 |
+
pool_values = list(pools.values())
|
| 397 |
+
length_pools = length_sampling_pools([row for row, _encoded in train])
|
| 398 |
+
balance_sources = args.source_balanced_sampling or args.source_weights is not None
|
| 399 |
+
source_weights = source_sampling_weights(
|
| 400 |
+
[row for row, _encoded in train], args.source_weights
|
| 401 |
+
)
|
| 402 |
+
source_pools = (
|
| 403 |
+
source_sampling_pools(
|
| 404 |
+
[row for row, _encoded in train], args.length_balanced_sampling
|
| 405 |
+
)
|
| 406 |
+
if balance_sources
|
| 407 |
+
else None
|
| 408 |
+
)
|
| 409 |
+
model.gradient_checkpointing_enable(
|
| 410 |
+
gradient_checkpointing_kwargs={"use_reentrant": False}
|
| 411 |
+
)
|
| 412 |
+
model.to("cuda")
|
| 413 |
+
model.train()
|
| 414 |
+
parameters = [
|
| 415 |
+
parameter for parameter in model.parameters() if parameter.requires_grad
|
| 416 |
+
]
|
| 417 |
+
groups = optimizer_groups(model, args.learning_rate, args.head_learning_rate)
|
| 418 |
+
optimizer = torch.optim.AdamW(groups, weight_decay=0.01)
|
| 419 |
+
args.output.mkdir(parents=True, exist_ok=True)
|
| 420 |
+
metadata = {
|
| 421 |
+
"base_model": args.base_id,
|
| 422 |
+
"base_revision": args.base_revision,
|
| 423 |
+
"method": args.method,
|
| 424 |
+
"fresh_head": args.fresh_head,
|
| 425 |
+
"trainable_scope": trainable_scope,
|
| 426 |
+
"frozen_parameters": frozen_parameters,
|
| 427 |
+
"retention": (
|
| 428 |
+
{
|
| 429 |
+
"targets": retention.receipt,
|
| 430 |
+
"weight": args.retention_weight,
|
| 431 |
+
"temperature": args.retention_temperature,
|
| 432 |
+
"normalization": "all examples in the optimizer step",
|
| 433 |
+
}
|
| 434 |
+
if retention is not None
|
| 435 |
+
else None
|
| 436 |
+
),
|
| 437 |
+
"initial_artifacts": initial_artifacts,
|
| 438 |
+
"initial_adapter_sha256": initial_artifacts.get("adapter_model.safetensors"),
|
| 439 |
+
"initial_adapter_config_sha256": initial_artifacts.get("adapter_config.json"),
|
| 440 |
+
"contract_sha256": hashlib.sha256(Path(args.contract).read_bytes()).hexdigest(),
|
| 441 |
+
"classifier_pooling": model.config.classifier_pooling,
|
| 442 |
+
"task_head": task_head_scope(model),
|
| 443 |
+
"problem_type": model.config.problem_type,
|
| 444 |
+
"train_files": file_receipts(args.train),
|
| 445 |
+
"dev_files": file_receipts(args.dev or []),
|
| 446 |
+
"train_only": args.train_only,
|
| 447 |
+
"checkpoint_policy": (
|
| 448 |
+
"final-only" if args.train_only else "development-and-final"
|
| 449 |
+
),
|
| 450 |
+
"label2id": label_to_id,
|
| 451 |
+
"train_rows": len(train),
|
| 452 |
+
"dev_rows": len(dev),
|
| 453 |
+
"train_label_counts": label_counts([row for row, _ in train]),
|
| 454 |
+
"rejected": rejected,
|
| 455 |
+
"seed": args.seed,
|
| 456 |
+
"steps": args.steps,
|
| 457 |
+
"batch_size": args.batch_size,
|
| 458 |
+
"accumulate": args.accumulate,
|
| 459 |
+
"examples_per_optimizer_step": args.batch_size * args.accumulate,
|
| 460 |
+
"microbatch_token_budget": args.microbatch_token_budget,
|
| 461 |
+
"dropout_trajectory_equivalence": args.microbatch_token_budget is None,
|
| 462 |
+
"max_length": args.max_length,
|
| 463 |
+
"learning_rate": args.learning_rate,
|
| 464 |
+
"optimizer_groups": [
|
| 465 |
+
{
|
| 466 |
+
"name": group["name"],
|
| 467 |
+
"learning_rate": group["initial_lr"],
|
| 468 |
+
"parameters": sum(parameter.numel() for parameter in group["params"]),
|
| 469 |
+
}
|
| 470 |
+
for group in groups
|
| 471 |
+
],
|
| 472 |
+
"balanced_sampling": args.balanced_sampling,
|
| 473 |
+
"training_order": training_order.receipt if training_order else None,
|
| 474 |
+
"length_balanced_sampling": args.length_balanced_sampling,
|
| 475 |
+
"source_balanced_sampling": balance_sources,
|
| 476 |
+
"source_sampling_probabilities": (
|
| 477 |
+
dict(
|
| 478 |
+
zip(
|
| 479 |
+
dict.fromkeys(row["source"] for row, _ in train),
|
| 480 |
+
source_weights,
|
| 481 |
+
strict=True,
|
| 482 |
+
)
|
| 483 |
+
)
|
| 484 |
+
if source_weights is not None
|
| 485 |
+
else None
|
| 486 |
+
),
|
| 487 |
+
"implementation_sha256": hashlib.sha256(
|
| 488 |
+
Path(__file__).read_bytes()
|
| 489 |
+
).hexdigest(),
|
| 490 |
+
"selection": None if args.train_only else args.selection,
|
| 491 |
+
"evaluation_dtype": None if args.train_only else args.evaluation_dtype,
|
| 492 |
+
"test_used": False,
|
| 493 |
+
"precision": "FP32 parameters and explicit FP32 mean CE / BF16 autocast",
|
| 494 |
+
"attention": "sdpa",
|
| 495 |
+
"checkpointing": "non-reentrant",
|
| 496 |
+
"parameters": sum(parameter.numel() for parameter in model.parameters()),
|
| 497 |
+
"trainable_parameters": sum(parameter.numel() for parameter in parameters),
|
| 498 |
+
}
|
| 499 |
+
if args.selection == BINARY_FP_SELECTION:
|
| 500 |
+
metadata["binary_selection"] = {
|
| 501 |
+
"positive_label": args.positive_label,
|
| 502 |
+
"false_positive_budget": args.selection_false_positive_budget,
|
| 503 |
+
"support": binary_selection_support(dev, label_to_id, args.positive_label),
|
| 504 |
+
"implementation_sha256": hashlib.sha256(
|
| 505 |
+
Path(__file__).with_name("selection.py").read_bytes()
|
| 506 |
+
).hexdigest(),
|
| 507 |
+
}
|
| 508 |
+
(args.output / "run.json").write_text(json.dumps(metadata, indent=2) + "\n")
|
| 509 |
+
print(
|
| 510 |
+
json.dumps(
|
| 511 |
+
{
|
| 512 |
+
"event": "ready",
|
| 513 |
+
"train_rows": len(train),
|
| 514 |
+
"rejected_rows": len(rejected),
|
| 515 |
+
"trainable_parameters": metadata["trainable_parameters"],
|
| 516 |
+
}
|
| 517 |
+
),
|
| 518 |
+
flush=True,
|
| 519 |
+
)
|
| 520 |
+
best = -1.0
|
| 521 |
+
best_key = None
|
| 522 |
+
drawn = Counter()
|
| 523 |
+
|
| 524 |
+
def evaluate_checkpoint(step):
|
| 525 |
+
nonlocal best, best_key
|
| 526 |
+
metrics, predictions = evaluate_records(
|
| 527 |
+
model,
|
| 528 |
+
tokenizer,
|
| 529 |
+
dev,
|
| 530 |
+
label_to_id,
|
| 531 |
+
id_to_label,
|
| 532 |
+
args.max_length,
|
| 533 |
+
dtype=args.evaluation_dtype,
|
| 534 |
+
)
|
| 535 |
+
operating_point = None
|
| 536 |
+
if args.selection == BINARY_FP_SELECTION:
|
| 537 |
+
operating_point = fit_binary_operating_point(
|
| 538 |
+
dev,
|
| 539 |
+
predictions,
|
| 540 |
+
label_to_id,
|
| 541 |
+
args.positive_label,
|
| 542 |
+
args.selection_false_positive_budget,
|
| 543 |
+
)
|
| 544 |
+
metrics["binary_fp_budget"] = operating_point
|
| 545 |
+
key = binary_checkpoint_key(operating_point)
|
| 546 |
+
score = operating_point["recall"] if key is not None else -1.0
|
| 547 |
+
(args.output / f"dev-predictions-step-{step}.jsonl").write_text(
|
| 548 |
+
"".join(json.dumps(row) + "\n" for row in predictions)
|
| 549 |
+
)
|
| 550 |
+
else:
|
| 551 |
+
score = selection_score(metrics, args.selection)
|
| 552 |
+
key = (score,)
|
| 553 |
+
(args.output / f"sampling-step-{step}.json").write_text(
|
| 554 |
+
json.dumps(sampling_exposure([row for row, _ in train], drawn), indent=2)
|
| 555 |
+
+ "\n"
|
| 556 |
+
)
|
| 557 |
+
(args.output / f"dev-step-{step}.json").write_text(
|
| 558 |
+
json.dumps(metrics, indent=2) + "\n"
|
| 559 |
+
)
|
| 560 |
+
print(
|
| 561 |
+
json.dumps(
|
| 562 |
+
{
|
| 563 |
+
"event": "dev",
|
| 564 |
+
"step": step,
|
| 565 |
+
"score": score,
|
| 566 |
+
"accuracy": metrics["accuracy"],
|
| 567 |
+
"macro_f1": metrics["macro_f1"],
|
| 568 |
+
}
|
| 569 |
+
),
|
| 570 |
+
flush=True,
|
| 571 |
+
)
|
| 572 |
+
if key is not None and (best_key is None or key > best_key):
|
| 573 |
+
best = score
|
| 574 |
+
best_key = key
|
| 575 |
+
if frozen_parameters is not None:
|
| 576 |
+
assert_frozen_parameters_preserved(frozen_parameters, model)
|
| 577 |
+
save_training_checkpoint(
|
| 578 |
+
model,
|
| 579 |
+
tokenizer,
|
| 580 |
+
args.output
|
| 581 |
+
/ ("best-adapter" if args.method == "lora" else "best-model"),
|
| 582 |
+
args.method,
|
| 583 |
+
args.base_id,
|
| 584 |
+
args.base_revision,
|
| 585 |
+
)
|
| 586 |
+
(args.output / "selection.json").write_text(
|
| 587 |
+
json.dumps(
|
| 588 |
+
{
|
| 589 |
+
"step": step,
|
| 590 |
+
"score": score,
|
| 591 |
+
"metric": args.selection,
|
| 592 |
+
"test_used": False,
|
| 593 |
+
**(
|
| 594 |
+
{"operating_point": operating_point}
|
| 595 |
+
if operating_point is not None
|
| 596 |
+
else {}
|
| 597 |
+
),
|
| 598 |
+
},
|
| 599 |
+
indent=2,
|
| 600 |
+
)
|
| 601 |
+
+ "\n"
|
| 602 |
+
)
|
| 603 |
+
|
| 604 |
+
def draw_microbatch_indices():
|
| 605 |
+
return [
|
| 606 |
+
(
|
| 607 |
+
sample_source_balanced(
|
| 608 |
+
source_pools, rng, args.balanced_sampling, source_weights
|
| 609 |
+
)
|
| 610 |
+
if balance_sources
|
| 611 |
+
else (
|
| 612 |
+
sample_length_balanced(length_pools, rng, args.balanced_sampling)
|
| 613 |
+
if args.length_balanced_sampling
|
| 614 |
+
else (
|
| 615 |
+
rng.choice(rng.choice(pool_values))
|
| 616 |
+
if args.balanced_sampling
|
| 617 |
+
else rng.randrange(len(train))
|
| 618 |
+
)
|
| 619 |
+
)
|
| 620 |
+
)
|
| 621 |
+
for _ in range(args.batch_size)
|
| 622 |
+
]
|
| 623 |
+
|
| 624 |
+
if not args.probe_only and not args.train_only:
|
| 625 |
+
evaluate_checkpoint(0)
|
| 626 |
+
for step in range(1, args.steps + 1):
|
| 627 |
+
optimizer.zero_grad(set_to_none=True)
|
| 628 |
+
torch.cuda.reset_peak_memory_stats()
|
| 629 |
+
torch.cuda.synchronize()
|
| 630 |
+
start, step_loss, lengths = time.perf_counter(), 0.0, []
|
| 631 |
+
step_ce_loss, step_retention_loss, retention_examples = 0.0, 0.0, 0
|
| 632 |
+
if training_order:
|
| 633 |
+
planned = training_order.indices_for_step(step)
|
| 634 |
+
microbatches = (
|
| 635 |
+
token_budget_microbatches(
|
| 636 |
+
planned, train_lengths, args.microbatch_token_budget
|
| 637 |
+
)
|
| 638 |
+
if args.microbatch_token_budget is not None
|
| 639 |
+
else [
|
| 640 |
+
planned[start : start + args.batch_size]
|
| 641 |
+
for start in range(0, len(planned), args.batch_size)
|
| 642 |
+
]
|
| 643 |
+
)
|
| 644 |
+
elif args.microbatch_token_budget is None:
|
| 645 |
+
microbatches = (draw_microbatch_indices() for _ in range(args.accumulate))
|
| 646 |
+
else:
|
| 647 |
+
sampled = [
|
| 648 |
+
index
|
| 649 |
+
for _ in range(args.accumulate)
|
| 650 |
+
for index in draw_microbatch_indices()
|
| 651 |
+
]
|
| 652 |
+
microbatches = token_budget_microbatches(
|
| 653 |
+
sampled, train_lengths, args.microbatch_token_budget
|
| 654 |
+
)
|
| 655 |
+
microbatch_count, max_padded_tokens = 0, 0
|
| 656 |
+
for indices in microbatches:
|
| 657 |
+
microbatch_count += 1
|
| 658 |
+
max_padded_tokens = max(
|
| 659 |
+
max_padded_tokens, max(train_lengths[i] for i in indices) * len(indices)
|
| 660 |
+
)
|
| 661 |
+
drawn.update(indices)
|
| 662 |
+
selected = [train[index] for index in indices]
|
| 663 |
+
lengths.extend(len(encoded["input_ids"]) for _, encoded in selected)
|
| 664 |
+
batch = tokenizer.pad(
|
| 665 |
+
[encoded for _, encoded in selected], padding=True, return_tensors="pt"
|
| 666 |
+
)
|
| 667 |
+
batch = {key: value.to("cuda") for key, value in batch.items()}
|
| 668 |
+
gold = torch.tensor(
|
| 669 |
+
[label_to_id[row["label"]] for row, _ in selected], device="cuda"
|
| 670 |
+
)
|
| 671 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 672 |
+
logits = model(**batch).logits
|
| 673 |
+
loss = (
|
| 674 |
+
microbatch_loss(logits, gold, args.accumulate)
|
| 675 |
+
if args.microbatch_token_budget is None
|
| 676 |
+
else global_batch_loss(
|
| 677 |
+
logits, gold, args.batch_size * args.accumulate
|
| 678 |
+
)
|
| 679 |
+
)
|
| 680 |
+
step_ce_loss += float(loss.detach())
|
| 681 |
+
if retention is not None:
|
| 682 |
+
teacher_logits, eligible = retention.targets(
|
| 683 |
+
[row for row, _ in selected], device=logits.device
|
| 684 |
+
)
|
| 685 |
+
preservation = args.retention_weight * masked_teacher_kl(
|
| 686 |
+
logits,
|
| 687 |
+
teacher_logits,
|
| 688 |
+
eligible,
|
| 689 |
+
examples_per_step=args.batch_size * args.accumulate,
|
| 690 |
+
temperature=args.retention_temperature,
|
| 691 |
+
)
|
| 692 |
+
loss = loss + preservation
|
| 693 |
+
step_retention_loss += float(preservation.detach())
|
| 694 |
+
retention_examples += int(eligible.sum())
|
| 695 |
+
if not bool(torch.isfinite(loss)):
|
| 696 |
+
raise ValueError(f"Non-finite loss at step {step}")
|
| 697 |
+
loss.backward()
|
| 698 |
+
step_loss += float(loss.detach())
|
| 699 |
+
del logits, loss, batch
|
| 700 |
+
gradients = [
|
| 701 |
+
parameter.grad for parameter in parameters if parameter.grad is not None
|
| 702 |
+
]
|
| 703 |
+
if not gradients or not all(
|
| 704 |
+
bool(torch.isfinite(gradient).all()) for gradient in gradients
|
| 705 |
+
):
|
| 706 |
+
raise ValueError(f"Missing or non-finite gradients at step {step}")
|
| 707 |
+
norm = torch.nn.utils.clip_grad_norm_(parameters, 1.0)
|
| 708 |
+
warmup = max(1, round(args.steps * 0.06))
|
| 709 |
+
rate = (
|
| 710 |
+
step / warmup
|
| 711 |
+
if step <= warmup
|
| 712 |
+
else 0.5
|
| 713 |
+
* (1 + math.cos(math.pi * (step - warmup) / max(1, args.steps - warmup)))
|
| 714 |
+
)
|
| 715 |
+
for group in optimizer.param_groups:
|
| 716 |
+
group["lr"] = group["initial_lr"] * rate
|
| 717 |
+
optimizer.step()
|
| 718 |
+
if training_order:
|
| 719 |
+
trace = training_order.record_step(step, microbatches)
|
| 720 |
+
with (args.output / "actual-training-order.jsonl").open("a") as stream:
|
| 721 |
+
stream.write(json.dumps(trace) + "\n")
|
| 722 |
+
torch.cuda.synchronize()
|
| 723 |
+
log = {
|
| 724 |
+
"step": step,
|
| 725 |
+
"loss": step_loss,
|
| 726 |
+
"cross_entropy_loss": step_ce_loss,
|
| 727 |
+
"retention_loss": step_retention_loss,
|
| 728 |
+
"retention_examples": retention_examples,
|
| 729 |
+
"grad_norm": float(norm),
|
| 730 |
+
"finite": True,
|
| 731 |
+
"gradient_tensors": len(gradients),
|
| 732 |
+
"max_tokens": max(lengths),
|
| 733 |
+
"mean_tokens": sum(lengths) / len(lengths),
|
| 734 |
+
"microbatches": microbatch_count,
|
| 735 |
+
"max_padded_tokens": max_padded_tokens,
|
| 736 |
+
"step_seconds": time.perf_counter() - start,
|
| 737 |
+
"peak_allocated_gib": torch.cuda.max_memory_allocated() / 2**30,
|
| 738 |
+
"peak_reserved_gib": torch.cuda.max_memory_reserved() / 2**30,
|
| 739 |
+
}
|
| 740 |
+
with (args.output / "steps.jsonl").open("a") as stream:
|
| 741 |
+
stream.write(json.dumps(log) + "\n")
|
| 742 |
+
if step == 1 or step % 10 == 0 or args.probe_only:
|
| 743 |
+
print(json.dumps(log), flush=True)
|
| 744 |
+
if (
|
| 745 |
+
not args.probe_only
|
| 746 |
+
and not args.train_only
|
| 747 |
+
and (step % args.eval_every == 0 or step == args.steps)
|
| 748 |
+
):
|
| 749 |
+
evaluate_checkpoint(step)
|
| 750 |
+
if training_order:
|
| 751 |
+
order_receipt = training_order.finish()
|
| 752 |
+
order_receipt["actual_trace_sha256"] = hashlib.sha256(
|
| 753 |
+
(args.output / "actual-training-order.jsonl").read_bytes()
|
| 754 |
+
).hexdigest()
|
| 755 |
+
(args.output / "training-order-completed.json").write_text(
|
| 756 |
+
json.dumps(order_receipt, indent=2) + "\n"
|
| 757 |
+
)
|
| 758 |
+
(args.output / "sampling-final.json").write_text(
|
| 759 |
+
json.dumps(sampling_exposure([row for row, _ in train], drawn), indent=2) + "\n"
|
| 760 |
+
)
|
| 761 |
+
if frozen_parameters is not None:
|
| 762 |
+
assert_frozen_parameters_preserved(frozen_parameters, model)
|
| 763 |
+
if not args.probe_only:
|
| 764 |
+
save_training_checkpoint(
|
| 765 |
+
model,
|
| 766 |
+
tokenizer,
|
| 767 |
+
args.output / ("last-adapter" if args.method == "lora" else "last-model"),
|
| 768 |
+
args.method,
|
| 769 |
+
args.base_id,
|
| 770 |
+
args.base_revision,
|
| 771 |
+
)
|
| 772 |
+
if best_key is None and not args.train_only:
|
| 773 |
+
raise ValueError(
|
| 774 |
+
"No checkpoint met the development FP budget; last checkpoint and "
|
| 775 |
+
"infeasibility receipts were retained without selecting a best checkpoint"
|
| 776 |
+
)
|
| 777 |
+
print(
|
| 778 |
+
json.dumps(
|
| 779 |
+
{
|
| 780 |
+
"event": "complete",
|
| 781 |
+
"best_dev_score": (
|
| 782 |
+
best if not (args.probe_only or args.train_only) else None
|
| 783 |
+
),
|
| 784 |
+
}
|
| 785 |
+
),
|
| 786 |
+
flush=True,
|
| 787 |
+
)
|
| 788 |
+
|
| 789 |
+
|
| 790 |
+
if __name__ == "__main__":
|
| 791 |
+
main()
|
reproducibility/sequence_repair/training_order.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Replay a complete, content-bound training order without changing optimization."""
|
| 2 |
+
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from collections import Counter
|
| 6 |
+
from dataclasses import dataclass, field
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
+
from .data import file_receipts
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def ordered_ids_sha256(ids):
|
| 13 |
+
"""Canonical identity preserves UTF-8 IDs, duplicates, and their full order."""
|
| 14 |
+
return hashlib.sha256(
|
| 15 |
+
json.dumps(ids, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
|
| 16 |
+
).hexdigest()
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def _unique_object(pairs):
|
| 20 |
+
result = {}
|
| 21 |
+
for key, value in pairs:
|
| 22 |
+
if key in result:
|
| 23 |
+
raise ValueError("Duplicate training-order field")
|
| 24 |
+
result[key] = value
|
| 25 |
+
return result
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@dataclass
|
| 29 |
+
class TrainingOrder:
|
| 30 |
+
"""A step can only complete once, with every planned example accounted for."""
|
| 31 |
+
|
| 32 |
+
indices: tuple[int, ...]
|
| 33 |
+
eligible_ids: tuple[str, ...]
|
| 34 |
+
steps: int
|
| 35 |
+
global_batch: int
|
| 36 |
+
receipt: dict
|
| 37 |
+
completed_steps: int = field(default=0, init=False)
|
| 38 |
+
|
| 39 |
+
def indices_for_step(self, step):
|
| 40 |
+
if (
|
| 41 |
+
type(step) is not int
|
| 42 |
+
or step != self.completed_steps + 1
|
| 43 |
+
or step > self.steps
|
| 44 |
+
):
|
| 45 |
+
raise ValueError("Training order requires the next unconsumed step")
|
| 46 |
+
start = (step - 1) * self.global_batch
|
| 47 |
+
return list(self.indices[start : start + self.global_batch])
|
| 48 |
+
|
| 49 |
+
def record_step(self, step, microbatches):
|
| 50 |
+
planned = self.indices_for_step(step)
|
| 51 |
+
actual = [index for batch in microbatches for index in batch]
|
| 52 |
+
if Counter(planned) != Counter(actual):
|
| 53 |
+
raise ValueError("Microbatches dropped or duplicated planned examples")
|
| 54 |
+
self.completed_steps = step
|
| 55 |
+
return {
|
| 56 |
+
"step": step,
|
| 57 |
+
"planned_ids": [self.eligible_ids[index] for index in planned],
|
| 58 |
+
"microbatch_ids": [
|
| 59 |
+
[self.eligible_ids[index] for index in batch] for batch in microbatches
|
| 60 |
+
],
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
def finish(self):
|
| 64 |
+
if self.completed_steps != self.steps:
|
| 65 |
+
raise ValueError("Training ended before consuming the complete order")
|
| 66 |
+
return {
|
| 67 |
+
**self.receipt,
|
| 68 |
+
"completed_steps": self.completed_steps,
|
| 69 |
+
"completed_draws": self.completed_steps * self.global_batch,
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def load_training_order(path, rows, train_paths, *, steps, global_batch):
|
| 74 |
+
"""Validate exact source bytes, eligible IDs, budgets, and planned draws."""
|
| 75 |
+
raw = Path(path).read_bytes()
|
| 76 |
+
value = json.loads(raw, object_pairs_hook=_unique_object)
|
| 77 |
+
required = {
|
| 78 |
+
"version",
|
| 79 |
+
"train_files",
|
| 80 |
+
"eligible_ids_sha256",
|
| 81 |
+
"steps",
|
| 82 |
+
"global_batch",
|
| 83 |
+
"ids",
|
| 84 |
+
"ids_sha256",
|
| 85 |
+
}
|
| 86 |
+
if not isinstance(value, dict) or set(value) != required:
|
| 87 |
+
raise ValueError("Training order has unknown or missing fields")
|
| 88 |
+
if type(value["version"]) is not int or value["version"] != 1:
|
| 89 |
+
raise ValueError("Unsupported training-order version")
|
| 90 |
+
for name, expected in (("steps", steps), ("global_batch", global_batch)):
|
| 91 |
+
if (
|
| 92 |
+
type(expected) is not int
|
| 93 |
+
or expected <= 0
|
| 94 |
+
or type(value[name]) is not int
|
| 95 |
+
or value[name] != expected
|
| 96 |
+
):
|
| 97 |
+
raise ValueError("Training order does not match the optimizer budget")
|
| 98 |
+
if value["train_files"] != file_receipts(train_paths):
|
| 99 |
+
raise ValueError("Training order does not match TRAIN file contents")
|
| 100 |
+
eligible = [row.get("id") for row in rows]
|
| 101 |
+
if (
|
| 102 |
+
not eligible
|
| 103 |
+
or any(not isinstance(key, str) or not key for key in eligible)
|
| 104 |
+
or len(set(eligible)) != len(eligible)
|
| 105 |
+
):
|
| 106 |
+
raise ValueError("Eligible TRAIN IDs must be nonempty unique strings")
|
| 107 |
+
if value["eligible_ids_sha256"] != ordered_ids_sha256(eligible):
|
| 108 |
+
raise ValueError("Training order does not match eligible TRAIN IDs")
|
| 109 |
+
ids = value["ids"]
|
| 110 |
+
if (
|
| 111 |
+
not isinstance(ids, list)
|
| 112 |
+
or len(ids) != steps * global_batch
|
| 113 |
+
or any(not isinstance(key, str) or not key for key in ids)
|
| 114 |
+
):
|
| 115 |
+
raise ValueError("Training order needs exactly steps times global-batch IDs")
|
| 116 |
+
if value["ids_sha256"] != ordered_ids_sha256(ids):
|
| 117 |
+
raise ValueError("Training-order ID sequence hash mismatch")
|
| 118 |
+
positions = {key: index for index, key in enumerate(eligible)}
|
| 119 |
+
if any(key not in positions for key in ids):
|
| 120 |
+
raise ValueError("Training order references unknown or filtered TRAIN IDs")
|
| 121 |
+
receipt = {
|
| 122 |
+
"file": Path(path).name,
|
| 123 |
+
"sha256": hashlib.sha256(raw).hexdigest(),
|
| 124 |
+
**{key: value[key] for key in sorted(required - {"ids"})},
|
| 125 |
+
"draws": len(ids),
|
| 126 |
+
"unique_rows": len(set(ids)),
|
| 127 |
+
}
|
| 128 |
+
return TrainingOrder(
|
| 129 |
+
tuple(positions[key] for key in ids),
|
| 130 |
+
tuple(eligible),
|
| 131 |
+
steps,
|
| 132 |
+
global_batch,
|
| 133 |
+
receipt,
|
| 134 |
+
)
|
reproducibility/source-files.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"runtime_mapping.py": "ec0c553ef625001c09c53a27659cc5162629e303bdef6a93c6091767f49b7fd9",
|
| 3 |
+
"retention.py": "3c8bc8aa60388508bc400bd68a6de2ed6ac18b48a24d3acd66d8e591223736eb",
|
| 4 |
+
"complete_adapter.py": "bc9a9365b1740b18d9cbe59d5250d8b5d214a0e133850c4921857c8e870ea13a",
|
| 5 |
+
"hydrate_annotations.py": "ea0c44b51afddbeb7dabf084db006eed545022ed819fa40682f4be846b207d62",
|
| 6 |
+
"export.py": "2f3ec1b038eae154ad32b28dc3cdc465e57e8d8b6fa842c2b67b0a66d3938fa9",
|
| 7 |
+
"task_head.py": "9d2a19743980c35e224c752a35e1e91a7e82dee3430f83b9008a4d01270a5a42",
|
| 8 |
+
"prepare_context.py": "9f9fe1ebd52e97d3e6901dc42bbf81f7e0703b7f2293703eabd89acd900a254a",
|
| 9 |
+
"corpus.py": "ba3d4f91607db085e55ae1c76701b9b1319fea5ee7dece9851d4ee7375bca108",
|
| 10 |
+
"prepare_retention.py": "56f48cc26b4889f93b43734e66ad8aaccd0046701519278b6b446d495f605ff4",
|
| 11 |
+
"initialize.py": "ade17c61ba94231a83e124e368bda4f468574cbb77689b6f71694c6489bb94a6",
|
| 12 |
+
"evaluate.py": "41617631838a1f72e33d402470a9bebd1ab0d7b42b80ac7e8c424a487068c562",
|
| 13 |
+
"selection.py": "764150454d150ad8971956faa2198d84380c8ee28f23ea63a650b07d045fc735",
|
| 14 |
+
"data.py": "84f922c20a2f3b029f7d363cf7f96f98cd239669f7777de099c63cfa1a1ef199",
|
| 15 |
+
"model.py": "c85ca12237e8735e20289e6e630803c59a6919dd473021d42291956c4b32f434",
|
| 16 |
+
"optimization.py": "71dde43dbe288cd8fab636a9266905f7898bac66ae155ded5158e37786492082",
|
| 17 |
+
"__init__.py": "04cd2a4c037dd1cc2070d57bea979cacb76d4660313a190fdf612007cb33b88e",
|
| 18 |
+
"context.py": "8e51031478aca4a825a77d057b2a66a9d09d80e42fb66ccbec3c527f3a891303",
|
| 19 |
+
"fetch_sources.py": "1abd30d33f456357553facdbde11116134835a087009c63c433faeccf8214638",
|
| 20 |
+
"train.py": "8b91020b3fcf93ae5925e9d15597d6f37ea3ca5d5c03745a2096b76be246e038",
|
| 21 |
+
"training_order.py": "88492bbb97b93743d637474595cffbc82e79d18bd115245adf60ffadea3bef44"
|
| 22 |
+
}
|
reproducibility/training.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"steps": 100,
|
| 3 |
+
"gpu": "NVIDIA L4",
|
| 4 |
+
"torch": "2.8.0+cu128",
|
| 5 |
+
"cuda": "12.8",
|
| 6 |
+
"python": "3.12.10",
|
| 7 |
+
"selection": {
|
| 8 |
+
"step": 75,
|
| 9 |
+
"score": 1.0,
|
| 10 |
+
"metric": "macro-f1",
|
| 11 |
+
"test_used": false
|
| 12 |
+
},
|
| 13 |
+
"base_model": "vllm-sr/Vela-1.0-Encoder-307M",
|
| 14 |
+
"base_revision": "720ab37904ce15054068d429381bfae7549f00f6",
|
| 15 |
+
"method": "full; fresh head; final two encoder layers",
|
| 16 |
+
"batch_size": 2,
|
| 17 |
+
"accumulation": 2,
|
| 18 |
+
"max_length": 256,
|
| 19 |
+
"seed": 42,
|
| 20 |
+
"learning_rate": 2e-05,
|
| 21 |
+
"head_learning_rate": 0.0001,
|
| 22 |
+
"dataset_files": {
|
| 23 |
+
"train.jsonl": "69022836ee506922a74b3583088a242fcbedc5fd181c4dd7bcea4e7eca60f814",
|
| 24 |
+
"dev.jsonl": "5909fe10961b0c6500a5e7d6ac9efd99b114c16f3545d45cd04036a070dbd1c3"
|
| 25 |
+
}
|
| 26 |
+
}
|
special_tokens_map.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"additional_special_tokens": [
|
| 3 |
+
"<start_of_turn>",
|
| 4 |
+
"<end_of_turn>"
|
| 5 |
+
],
|
| 6 |
+
"bos_token": {
|
| 7 |
+
"content": "<bos>",
|
| 8 |
+
"lstrip": false,
|
| 9 |
+
"normalized": false,
|
| 10 |
+
"rstrip": false,
|
| 11 |
+
"single_word": false
|
| 12 |
+
},
|
| 13 |
+
"cls_token": {
|
| 14 |
+
"content": "<bos>",
|
| 15 |
+
"lstrip": false,
|
| 16 |
+
"normalized": false,
|
| 17 |
+
"rstrip": false,
|
| 18 |
+
"single_word": false
|
| 19 |
+
},
|
| 20 |
+
"eos_token": {
|
| 21 |
+
"content": "<eos>",
|
| 22 |
+
"lstrip": false,
|
| 23 |
+
"normalized": false,
|
| 24 |
+
"rstrip": false,
|
| 25 |
+
"single_word": false
|
| 26 |
+
},
|
| 27 |
+
"mask_token": {
|
| 28 |
+
"content": "<mask>",
|
| 29 |
+
"lstrip": true,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false
|
| 33 |
+
},
|
| 34 |
+
"pad_token": {
|
| 35 |
+
"content": "<pad>",
|
| 36 |
+
"lstrip": false,
|
| 37 |
+
"normalized": false,
|
| 38 |
+
"rstrip": false,
|
| 39 |
+
"single_word": false
|
| 40 |
+
},
|
| 41 |
+
"sep_token": {
|
| 42 |
+
"content": "<eos>",
|
| 43 |
+
"lstrip": false,
|
| 44 |
+
"normalized": false,
|
| 45 |
+
"rstrip": false,
|
| 46 |
+
"single_word": false
|
| 47 |
+
},
|
| 48 |
+
"unk_token": {
|
| 49 |
+
"content": "<unk>",
|
| 50 |
+
"lstrip": false,
|
| 51 |
+
"normalized": false,
|
| 52 |
+
"rstrip": false,
|
| 53 |
+
"single_word": false
|
| 54 |
+
}
|
| 55 |
+
}
|
task-head.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architecture": "ModernBertForSequenceClassification",
|
| 3 |
+
"modules_to_save": null,
|
| 4 |
+
"trainable_task_head_parameters": 592130,
|
| 5 |
+
"tensors": {
|
| 6 |
+
"head.dense.weight": {
|
| 7 |
+
"shape": [
|
| 8 |
+
768,
|
| 9 |
+
768
|
| 10 |
+
],
|
| 11 |
+
"dtype": "torch.float32",
|
| 12 |
+
"numel": 589824,
|
| 13 |
+
"trainable": true,
|
| 14 |
+
"adapter_owned": false,
|
| 15 |
+
"sha256": "01a8bfc3e8af91a9901f5088ec0fb1cdb1f1b8c47526a5d5e2fe5a94d7383003"
|
| 16 |
+
},
|
| 17 |
+
"head.norm.weight": {
|
| 18 |
+
"shape": [
|
| 19 |
+
768
|
| 20 |
+
],
|
| 21 |
+
"dtype": "torch.float32",
|
| 22 |
+
"numel": 768,
|
| 23 |
+
"trainable": true,
|
| 24 |
+
"adapter_owned": false,
|
| 25 |
+
"sha256": "fd989126d90b0d85ba4e8863c791567d526c8d6bed155fc05672489c906a91b5"
|
| 26 |
+
},
|
| 27 |
+
"classifier.weight": {
|
| 28 |
+
"shape": [
|
| 29 |
+
2,
|
| 30 |
+
768
|
| 31 |
+
],
|
| 32 |
+
"dtype": "torch.float32",
|
| 33 |
+
"numel": 1536,
|
| 34 |
+
"trainable": true,
|
| 35 |
+
"adapter_owned": false,
|
| 36 |
+
"sha256": "84ca652ca12370d26a59fc4039312c112dd5079c834a04f43cc48c568b0873ee"
|
| 37 |
+
},
|
| 38 |
+
"classifier.bias": {
|
| 39 |
+
"shape": [
|
| 40 |
+
2
|
| 41 |
+
],
|
| 42 |
+
"dtype": "torch.float32",
|
| 43 |
+
"numel": 2,
|
| 44 |
+
"trainable": true,
|
| 45 |
+
"adapter_owned": false,
|
| 46 |
+
"sha256": "eace58362ea99f963002fb0ba0a36ab6d2ddfc1a504668108853dd5dbf1cba92"
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
}
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:609d8f4c067cd3950f88594c5a802616cea245823836ef5848ee4fc40aab5b6f
|
| 3 |
+
size 34363188
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,2018 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_bos_token": true,
|
| 3 |
+
"added_tokens_decoder": {
|
| 4 |
+
"0": {
|
| 5 |
+
"content": "<pad>",
|
| 6 |
+
"lstrip": false,
|
| 7 |
+
"normalized": false,
|
| 8 |
+
"rstrip": false,
|
| 9 |
+
"single_word": false,
|
| 10 |
+
"special": true
|
| 11 |
+
},
|
| 12 |
+
"1": {
|
| 13 |
+
"content": "<eos>",
|
| 14 |
+
"lstrip": false,
|
| 15 |
+
"normalized": false,
|
| 16 |
+
"rstrip": false,
|
| 17 |
+
"single_word": false,
|
| 18 |
+
"special": true
|
| 19 |
+
},
|
| 20 |
+
"2": {
|
| 21 |
+
"content": "<bos>",
|
| 22 |
+
"lstrip": false,
|
| 23 |
+
"normalized": false,
|
| 24 |
+
"rstrip": false,
|
| 25 |
+
"single_word": false,
|
| 26 |
+
"special": true
|
| 27 |
+
},
|
| 28 |
+
"3": {
|
| 29 |
+
"content": "<unk>",
|
| 30 |
+
"lstrip": false,
|
| 31 |
+
"normalized": false,
|
| 32 |
+
"rstrip": false,
|
| 33 |
+
"single_word": false,
|
| 34 |
+
"special": true
|
| 35 |
+
},
|
| 36 |
+
"4": {
|
| 37 |
+
"content": "<mask>",
|
| 38 |
+
"lstrip": true,
|
| 39 |
+
"normalized": false,
|
| 40 |
+
"rstrip": false,
|
| 41 |
+
"single_word": false,
|
| 42 |
+
"special": true
|
| 43 |
+
},
|
| 44 |
+
"5": {
|
| 45 |
+
"content": "<2mass>",
|
| 46 |
+
"lstrip": false,
|
| 47 |
+
"normalized": false,
|
| 48 |
+
"rstrip": false,
|
| 49 |
+
"single_word": false,
|
| 50 |
+
"special": false
|
| 51 |
+
},
|
| 52 |
+
"6": {
|
| 53 |
+
"content": "[@BOS@]",
|
| 54 |
+
"lstrip": false,
|
| 55 |
+
"normalized": false,
|
| 56 |
+
"rstrip": false,
|
| 57 |
+
"single_word": false,
|
| 58 |
+
"special": false
|
| 59 |
+
},
|
| 60 |
+
"7": {
|
| 61 |
+
"content": "<unused0>",
|
| 62 |
+
"lstrip": false,
|
| 63 |
+
"normalized": false,
|
| 64 |
+
"rstrip": false,
|
| 65 |
+
"single_word": false,
|
| 66 |
+
"special": false
|
| 67 |
+
},
|
| 68 |
+
"8": {
|
| 69 |
+
"content": "<unused1>",
|
| 70 |
+
"lstrip": false,
|
| 71 |
+
"normalized": false,
|
| 72 |
+
"rstrip": false,
|
| 73 |
+
"single_word": false,
|
| 74 |
+
"special": false
|
| 75 |
+
},
|
| 76 |
+
"9": {
|
| 77 |
+
"content": "<unused2>",
|
| 78 |
+
"lstrip": false,
|
| 79 |
+
"normalized": false,
|
| 80 |
+
"rstrip": false,
|
| 81 |
+
"single_word": false,
|
| 82 |
+
"special": false
|
| 83 |
+
},
|
| 84 |
+
"10": {
|
| 85 |
+
"content": "<unused3>",
|
| 86 |
+
"lstrip": false,
|
| 87 |
+
"normalized": false,
|
| 88 |
+
"rstrip": false,
|
| 89 |
+
"single_word": false,
|
| 90 |
+
"special": false
|
| 91 |
+
},
|
| 92 |
+
"11": {
|
| 93 |
+
"content": "<unused4>",
|
| 94 |
+
"lstrip": false,
|
| 95 |
+
"normalized": false,
|
| 96 |
+
"rstrip": false,
|
| 97 |
+
"single_word": false,
|
| 98 |
+
"special": false
|
| 99 |
+
},
|
| 100 |
+
"12": {
|
| 101 |
+
"content": "<unused5>",
|
| 102 |
+
"lstrip": false,
|
| 103 |
+
"normalized": false,
|
| 104 |
+
"rstrip": false,
|
| 105 |
+
"single_word": false,
|
| 106 |
+
"special": false
|
| 107 |
+
},
|
| 108 |
+
"13": {
|
| 109 |
+
"content": "<unused6>",
|
| 110 |
+
"lstrip": false,
|
| 111 |
+
"normalized": false,
|
| 112 |
+
"rstrip": false,
|
| 113 |
+
"single_word": false,
|
| 114 |
+
"special": false
|
| 115 |
+
},
|
| 116 |
+
"14": {
|
| 117 |
+
"content": "<unused7>",
|
| 118 |
+
"lstrip": false,
|
| 119 |
+
"normalized": false,
|
| 120 |
+
"rstrip": false,
|
| 121 |
+
"single_word": false,
|
| 122 |
+
"special": false
|
| 123 |
+
},
|
| 124 |
+
"15": {
|
| 125 |
+
"content": "<unused8>",
|
| 126 |
+
"lstrip": false,
|
| 127 |
+
"normalized": false,
|
| 128 |
+
"rstrip": false,
|
| 129 |
+
"single_word": false,
|
| 130 |
+
"special": false
|
| 131 |
+
},
|
| 132 |
+
"16": {
|
| 133 |
+
"content": "<unused9>",
|
| 134 |
+
"lstrip": false,
|
| 135 |
+
"normalized": false,
|
| 136 |
+
"rstrip": false,
|
| 137 |
+
"single_word": false,
|
| 138 |
+
"special": false
|
| 139 |
+
},
|
| 140 |
+
"17": {
|
| 141 |
+
"content": "<unused10>",
|
| 142 |
+
"lstrip": false,
|
| 143 |
+
"normalized": false,
|
| 144 |
+
"rstrip": false,
|
| 145 |
+
"single_word": false,
|
| 146 |
+
"special": false
|
| 147 |
+
},
|
| 148 |
+
"18": {
|
| 149 |
+
"content": "<unused11>",
|
| 150 |
+
"lstrip": false,
|
| 151 |
+
"normalized": false,
|
| 152 |
+
"rstrip": false,
|
| 153 |
+
"single_word": false,
|
| 154 |
+
"special": false
|
| 155 |
+
},
|
| 156 |
+
"19": {
|
| 157 |
+
"content": "<unused12>",
|
| 158 |
+
"lstrip": false,
|
| 159 |
+
"normalized": false,
|
| 160 |
+
"rstrip": false,
|
| 161 |
+
"single_word": false,
|
| 162 |
+
"special": false
|
| 163 |
+
},
|
| 164 |
+
"20": {
|
| 165 |
+
"content": "<unused13>",
|
| 166 |
+
"lstrip": false,
|
| 167 |
+
"normalized": false,
|
| 168 |
+
"rstrip": false,
|
| 169 |
+
"single_word": false,
|
| 170 |
+
"special": false
|
| 171 |
+
},
|
| 172 |
+
"21": {
|
| 173 |
+
"content": "<unused14>",
|
| 174 |
+
"lstrip": false,
|
| 175 |
+
"normalized": false,
|
| 176 |
+
"rstrip": false,
|
| 177 |
+
"single_word": false,
|
| 178 |
+
"special": false
|
| 179 |
+
},
|
| 180 |
+
"22": {
|
| 181 |
+
"content": "<unused15>",
|
| 182 |
+
"lstrip": false,
|
| 183 |
+
"normalized": false,
|
| 184 |
+
"rstrip": false,
|
| 185 |
+
"single_word": false,
|
| 186 |
+
"special": false
|
| 187 |
+
},
|
| 188 |
+
"23": {
|
| 189 |
+
"content": "<unused16>",
|
| 190 |
+
"lstrip": false,
|
| 191 |
+
"normalized": false,
|
| 192 |
+
"rstrip": false,
|
| 193 |
+
"single_word": false,
|
| 194 |
+
"special": false
|
| 195 |
+
},
|
| 196 |
+
"24": {
|
| 197 |
+
"content": "<unused17>",
|
| 198 |
+
"lstrip": false,
|
| 199 |
+
"normalized": false,
|
| 200 |
+
"rstrip": false,
|
| 201 |
+
"single_word": false,
|
| 202 |
+
"special": false
|
| 203 |
+
},
|
| 204 |
+
"25": {
|
| 205 |
+
"content": "<unused18>",
|
| 206 |
+
"lstrip": false,
|
| 207 |
+
"normalized": false,
|
| 208 |
+
"rstrip": false,
|
| 209 |
+
"single_word": false,
|
| 210 |
+
"special": false
|
| 211 |
+
},
|
| 212 |
+
"26": {
|
| 213 |
+
"content": "<unused19>",
|
| 214 |
+
"lstrip": false,
|
| 215 |
+
"normalized": false,
|
| 216 |
+
"rstrip": false,
|
| 217 |
+
"single_word": false,
|
| 218 |
+
"special": false
|
| 219 |
+
},
|
| 220 |
+
"27": {
|
| 221 |
+
"content": "<unused20>",
|
| 222 |
+
"lstrip": false,
|
| 223 |
+
"normalized": false,
|
| 224 |
+
"rstrip": false,
|
| 225 |
+
"single_word": false,
|
| 226 |
+
"special": false
|
| 227 |
+
},
|
| 228 |
+
"28": {
|
| 229 |
+
"content": "<unused21>",
|
| 230 |
+
"lstrip": false,
|
| 231 |
+
"normalized": false,
|
| 232 |
+
"rstrip": false,
|
| 233 |
+
"single_word": false,
|
| 234 |
+
"special": false
|
| 235 |
+
},
|
| 236 |
+
"29": {
|
| 237 |
+
"content": "<unused22>",
|
| 238 |
+
"lstrip": false,
|
| 239 |
+
"normalized": false,
|
| 240 |
+
"rstrip": false,
|
| 241 |
+
"single_word": false,
|
| 242 |
+
"special": false
|
| 243 |
+
},
|
| 244 |
+
"30": {
|
| 245 |
+
"content": "<unused23>",
|
| 246 |
+
"lstrip": false,
|
| 247 |
+
"normalized": false,
|
| 248 |
+
"rstrip": false,
|
| 249 |
+
"single_word": false,
|
| 250 |
+
"special": false
|
| 251 |
+
},
|
| 252 |
+
"31": {
|
| 253 |
+
"content": "<unused24>",
|
| 254 |
+
"lstrip": false,
|
| 255 |
+
"normalized": false,
|
| 256 |
+
"rstrip": false,
|
| 257 |
+
"single_word": false,
|
| 258 |
+
"special": false
|
| 259 |
+
},
|
| 260 |
+
"32": {
|
| 261 |
+
"content": "<unused25>",
|
| 262 |
+
"lstrip": false,
|
| 263 |
+
"normalized": false,
|
| 264 |
+
"rstrip": false,
|
| 265 |
+
"single_word": false,
|
| 266 |
+
"special": false
|
| 267 |
+
},
|
| 268 |
+
"33": {
|
| 269 |
+
"content": "<unused26>",
|
| 270 |
+
"lstrip": false,
|
| 271 |
+
"normalized": false,
|
| 272 |
+
"rstrip": false,
|
| 273 |
+
"single_word": false,
|
| 274 |
+
"special": false
|
| 275 |
+
},
|
| 276 |
+
"34": {
|
| 277 |
+
"content": "<unused27>",
|
| 278 |
+
"lstrip": false,
|
| 279 |
+
"normalized": false,
|
| 280 |
+
"rstrip": false,
|
| 281 |
+
"single_word": false,
|
| 282 |
+
"special": false
|
| 283 |
+
},
|
| 284 |
+
"35": {
|
| 285 |
+
"content": "<unused28>",
|
| 286 |
+
"lstrip": false,
|
| 287 |
+
"normalized": false,
|
| 288 |
+
"rstrip": false,
|
| 289 |
+
"single_word": false,
|
| 290 |
+
"special": false
|
| 291 |
+
},
|
| 292 |
+
"36": {
|
| 293 |
+
"content": "<unused29>",
|
| 294 |
+
"lstrip": false,
|
| 295 |
+
"normalized": false,
|
| 296 |
+
"rstrip": false,
|
| 297 |
+
"single_word": false,
|
| 298 |
+
"special": false
|
| 299 |
+
},
|
| 300 |
+
"37": {
|
| 301 |
+
"content": "<unused30>",
|
| 302 |
+
"lstrip": false,
|
| 303 |
+
"normalized": false,
|
| 304 |
+
"rstrip": false,
|
| 305 |
+
"single_word": false,
|
| 306 |
+
"special": false
|
| 307 |
+
},
|
| 308 |
+
"38": {
|
| 309 |
+
"content": "<unused31>",
|
| 310 |
+
"lstrip": false,
|
| 311 |
+
"normalized": false,
|
| 312 |
+
"rstrip": false,
|
| 313 |
+
"single_word": false,
|
| 314 |
+
"special": false
|
| 315 |
+
},
|
| 316 |
+
"39": {
|
| 317 |
+
"content": "<unused32>",
|
| 318 |
+
"lstrip": false,
|
| 319 |
+
"normalized": false,
|
| 320 |
+
"rstrip": false,
|
| 321 |
+
"single_word": false,
|
| 322 |
+
"special": false
|
| 323 |
+
},
|
| 324 |
+
"40": {
|
| 325 |
+
"content": "<unused33>",
|
| 326 |
+
"lstrip": false,
|
| 327 |
+
"normalized": false,
|
| 328 |
+
"rstrip": false,
|
| 329 |
+
"single_word": false,
|
| 330 |
+
"special": false
|
| 331 |
+
},
|
| 332 |
+
"41": {
|
| 333 |
+
"content": "<unused34>",
|
| 334 |
+
"lstrip": false,
|
| 335 |
+
"normalized": false,
|
| 336 |
+
"rstrip": false,
|
| 337 |
+
"single_word": false,
|
| 338 |
+
"special": false
|
| 339 |
+
},
|
| 340 |
+
"42": {
|
| 341 |
+
"content": "<unused35>",
|
| 342 |
+
"lstrip": false,
|
| 343 |
+
"normalized": false,
|
| 344 |
+
"rstrip": false,
|
| 345 |
+
"single_word": false,
|
| 346 |
+
"special": false
|
| 347 |
+
},
|
| 348 |
+
"43": {
|
| 349 |
+
"content": "<unused36>",
|
| 350 |
+
"lstrip": false,
|
| 351 |
+
"normalized": false,
|
| 352 |
+
"rstrip": false,
|
| 353 |
+
"single_word": false,
|
| 354 |
+
"special": false
|
| 355 |
+
},
|
| 356 |
+
"44": {
|
| 357 |
+
"content": "<unused37>",
|
| 358 |
+
"lstrip": false,
|
| 359 |
+
"normalized": false,
|
| 360 |
+
"rstrip": false,
|
| 361 |
+
"single_word": false,
|
| 362 |
+
"special": false
|
| 363 |
+
},
|
| 364 |
+
"45": {
|
| 365 |
+
"content": "<unused38>",
|
| 366 |
+
"lstrip": false,
|
| 367 |
+
"normalized": false,
|
| 368 |
+
"rstrip": false,
|
| 369 |
+
"single_word": false,
|
| 370 |
+
"special": false
|
| 371 |
+
},
|
| 372 |
+
"46": {
|
| 373 |
+
"content": "<unused39>",
|
| 374 |
+
"lstrip": false,
|
| 375 |
+
"normalized": false,
|
| 376 |
+
"rstrip": false,
|
| 377 |
+
"single_word": false,
|
| 378 |
+
"special": false
|
| 379 |
+
},
|
| 380 |
+
"47": {
|
| 381 |
+
"content": "<unused40>",
|
| 382 |
+
"lstrip": false,
|
| 383 |
+
"normalized": false,
|
| 384 |
+
"rstrip": false,
|
| 385 |
+
"single_word": false,
|
| 386 |
+
"special": false
|
| 387 |
+
},
|
| 388 |
+
"48": {
|
| 389 |
+
"content": "<unused41>",
|
| 390 |
+
"lstrip": false,
|
| 391 |
+
"normalized": false,
|
| 392 |
+
"rstrip": false,
|
| 393 |
+
"single_word": false,
|
| 394 |
+
"special": false
|
| 395 |
+
},
|
| 396 |
+
"49": {
|
| 397 |
+
"content": "<unused42>",
|
| 398 |
+
"lstrip": false,
|
| 399 |
+
"normalized": false,
|
| 400 |
+
"rstrip": false,
|
| 401 |
+
"single_word": false,
|
| 402 |
+
"special": false
|
| 403 |
+
},
|
| 404 |
+
"50": {
|
| 405 |
+
"content": "<unused43>",
|
| 406 |
+
"lstrip": false,
|
| 407 |
+
"normalized": false,
|
| 408 |
+
"rstrip": false,
|
| 409 |
+
"single_word": false,
|
| 410 |
+
"special": false
|
| 411 |
+
},
|
| 412 |
+
"51": {
|
| 413 |
+
"content": "<unused44>",
|
| 414 |
+
"lstrip": false,
|
| 415 |
+
"normalized": false,
|
| 416 |
+
"rstrip": false,
|
| 417 |
+
"single_word": false,
|
| 418 |
+
"special": false
|
| 419 |
+
},
|
| 420 |
+
"52": {
|
| 421 |
+
"content": "<unused45>",
|
| 422 |
+
"lstrip": false,
|
| 423 |
+
"normalized": false,
|
| 424 |
+
"rstrip": false,
|
| 425 |
+
"single_word": false,
|
| 426 |
+
"special": false
|
| 427 |
+
},
|
| 428 |
+
"53": {
|
| 429 |
+
"content": "<unused46>",
|
| 430 |
+
"lstrip": false,
|
| 431 |
+
"normalized": false,
|
| 432 |
+
"rstrip": false,
|
| 433 |
+
"single_word": false,
|
| 434 |
+
"special": false
|
| 435 |
+
},
|
| 436 |
+
"54": {
|
| 437 |
+
"content": "<unused47>",
|
| 438 |
+
"lstrip": false,
|
| 439 |
+
"normalized": false,
|
| 440 |
+
"rstrip": false,
|
| 441 |
+
"single_word": false,
|
| 442 |
+
"special": false
|
| 443 |
+
},
|
| 444 |
+
"55": {
|
| 445 |
+
"content": "<unused48>",
|
| 446 |
+
"lstrip": false,
|
| 447 |
+
"normalized": false,
|
| 448 |
+
"rstrip": false,
|
| 449 |
+
"single_word": false,
|
| 450 |
+
"special": false
|
| 451 |
+
},
|
| 452 |
+
"56": {
|
| 453 |
+
"content": "<unused49>",
|
| 454 |
+
"lstrip": false,
|
| 455 |
+
"normalized": false,
|
| 456 |
+
"rstrip": false,
|
| 457 |
+
"single_word": false,
|
| 458 |
+
"special": false
|
| 459 |
+
},
|
| 460 |
+
"57": {
|
| 461 |
+
"content": "<unused50>",
|
| 462 |
+
"lstrip": false,
|
| 463 |
+
"normalized": false,
|
| 464 |
+
"rstrip": false,
|
| 465 |
+
"single_word": false,
|
| 466 |
+
"special": false
|
| 467 |
+
},
|
| 468 |
+
"58": {
|
| 469 |
+
"content": "<unused51>",
|
| 470 |
+
"lstrip": false,
|
| 471 |
+
"normalized": false,
|
| 472 |
+
"rstrip": false,
|
| 473 |
+
"single_word": false,
|
| 474 |
+
"special": false
|
| 475 |
+
},
|
| 476 |
+
"59": {
|
| 477 |
+
"content": "<unused52>",
|
| 478 |
+
"lstrip": false,
|
| 479 |
+
"normalized": false,
|
| 480 |
+
"rstrip": false,
|
| 481 |
+
"single_word": false,
|
| 482 |
+
"special": false
|
| 483 |
+
},
|
| 484 |
+
"60": {
|
| 485 |
+
"content": "<unused53>",
|
| 486 |
+
"lstrip": false,
|
| 487 |
+
"normalized": false,
|
| 488 |
+
"rstrip": false,
|
| 489 |
+
"single_word": false,
|
| 490 |
+
"special": false
|
| 491 |
+
},
|
| 492 |
+
"61": {
|
| 493 |
+
"content": "<unused54>",
|
| 494 |
+
"lstrip": false,
|
| 495 |
+
"normalized": false,
|
| 496 |
+
"rstrip": false,
|
| 497 |
+
"single_word": false,
|
| 498 |
+
"special": false
|
| 499 |
+
},
|
| 500 |
+
"62": {
|
| 501 |
+
"content": "<unused55>",
|
| 502 |
+
"lstrip": false,
|
| 503 |
+
"normalized": false,
|
| 504 |
+
"rstrip": false,
|
| 505 |
+
"single_word": false,
|
| 506 |
+
"special": false
|
| 507 |
+
},
|
| 508 |
+
"63": {
|
| 509 |
+
"content": "<unused56>",
|
| 510 |
+
"lstrip": false,
|
| 511 |
+
"normalized": false,
|
| 512 |
+
"rstrip": false,
|
| 513 |
+
"single_word": false,
|
| 514 |
+
"special": false
|
| 515 |
+
},
|
| 516 |
+
"64": {
|
| 517 |
+
"content": "<unused57>",
|
| 518 |
+
"lstrip": false,
|
| 519 |
+
"normalized": false,
|
| 520 |
+
"rstrip": false,
|
| 521 |
+
"single_word": false,
|
| 522 |
+
"special": false
|
| 523 |
+
},
|
| 524 |
+
"65": {
|
| 525 |
+
"content": "<unused58>",
|
| 526 |
+
"lstrip": false,
|
| 527 |
+
"normalized": false,
|
| 528 |
+
"rstrip": false,
|
| 529 |
+
"single_word": false,
|
| 530 |
+
"special": false
|
| 531 |
+
},
|
| 532 |
+
"66": {
|
| 533 |
+
"content": "<unused59>",
|
| 534 |
+
"lstrip": false,
|
| 535 |
+
"normalized": false,
|
| 536 |
+
"rstrip": false,
|
| 537 |
+
"single_word": false,
|
| 538 |
+
"special": false
|
| 539 |
+
},
|
| 540 |
+
"67": {
|
| 541 |
+
"content": "<unused60>",
|
| 542 |
+
"lstrip": false,
|
| 543 |
+
"normalized": false,
|
| 544 |
+
"rstrip": false,
|
| 545 |
+
"single_word": false,
|
| 546 |
+
"special": false
|
| 547 |
+
},
|
| 548 |
+
"68": {
|
| 549 |
+
"content": "<unused61>",
|
| 550 |
+
"lstrip": false,
|
| 551 |
+
"normalized": false,
|
| 552 |
+
"rstrip": false,
|
| 553 |
+
"single_word": false,
|
| 554 |
+
"special": false
|
| 555 |
+
},
|
| 556 |
+
"69": {
|
| 557 |
+
"content": "<unused62>",
|
| 558 |
+
"lstrip": false,
|
| 559 |
+
"normalized": false,
|
| 560 |
+
"rstrip": false,
|
| 561 |
+
"single_word": false,
|
| 562 |
+
"special": false
|
| 563 |
+
},
|
| 564 |
+
"70": {
|
| 565 |
+
"content": "<unused63>",
|
| 566 |
+
"lstrip": false,
|
| 567 |
+
"normalized": false,
|
| 568 |
+
"rstrip": false,
|
| 569 |
+
"single_word": false,
|
| 570 |
+
"special": false
|
| 571 |
+
},
|
| 572 |
+
"71": {
|
| 573 |
+
"content": "<unused64>",
|
| 574 |
+
"lstrip": false,
|
| 575 |
+
"normalized": false,
|
| 576 |
+
"rstrip": false,
|
| 577 |
+
"single_word": false,
|
| 578 |
+
"special": false
|
| 579 |
+
},
|
| 580 |
+
"72": {
|
| 581 |
+
"content": "<unused65>",
|
| 582 |
+
"lstrip": false,
|
| 583 |
+
"normalized": false,
|
| 584 |
+
"rstrip": false,
|
| 585 |
+
"single_word": false,
|
| 586 |
+
"special": false
|
| 587 |
+
},
|
| 588 |
+
"73": {
|
| 589 |
+
"content": "<unused66>",
|
| 590 |
+
"lstrip": false,
|
| 591 |
+
"normalized": false,
|
| 592 |
+
"rstrip": false,
|
| 593 |
+
"single_word": false,
|
| 594 |
+
"special": false
|
| 595 |
+
},
|
| 596 |
+
"74": {
|
| 597 |
+
"content": "<unused67>",
|
| 598 |
+
"lstrip": false,
|
| 599 |
+
"normalized": false,
|
| 600 |
+
"rstrip": false,
|
| 601 |
+
"single_word": false,
|
| 602 |
+
"special": false
|
| 603 |
+
},
|
| 604 |
+
"75": {
|
| 605 |
+
"content": "<unused68>",
|
| 606 |
+
"lstrip": false,
|
| 607 |
+
"normalized": false,
|
| 608 |
+
"rstrip": false,
|
| 609 |
+
"single_word": false,
|
| 610 |
+
"special": false
|
| 611 |
+
},
|
| 612 |
+
"76": {
|
| 613 |
+
"content": "<unused69>",
|
| 614 |
+
"lstrip": false,
|
| 615 |
+
"normalized": false,
|
| 616 |
+
"rstrip": false,
|
| 617 |
+
"single_word": false,
|
| 618 |
+
"special": false
|
| 619 |
+
},
|
| 620 |
+
"77": {
|
| 621 |
+
"content": "<unused70>",
|
| 622 |
+
"lstrip": false,
|
| 623 |
+
"normalized": false,
|
| 624 |
+
"rstrip": false,
|
| 625 |
+
"single_word": false,
|
| 626 |
+
"special": false
|
| 627 |
+
},
|
| 628 |
+
"78": {
|
| 629 |
+
"content": "<unused71>",
|
| 630 |
+
"lstrip": false,
|
| 631 |
+
"normalized": false,
|
| 632 |
+
"rstrip": false,
|
| 633 |
+
"single_word": false,
|
| 634 |
+
"special": false
|
| 635 |
+
},
|
| 636 |
+
"79": {
|
| 637 |
+
"content": "<unused72>",
|
| 638 |
+
"lstrip": false,
|
| 639 |
+
"normalized": false,
|
| 640 |
+
"rstrip": false,
|
| 641 |
+
"single_word": false,
|
| 642 |
+
"special": false
|
| 643 |
+
},
|
| 644 |
+
"80": {
|
| 645 |
+
"content": "<unused73>",
|
| 646 |
+
"lstrip": false,
|
| 647 |
+
"normalized": false,
|
| 648 |
+
"rstrip": false,
|
| 649 |
+
"single_word": false,
|
| 650 |
+
"special": false
|
| 651 |
+
},
|
| 652 |
+
"81": {
|
| 653 |
+
"content": "<unused74>",
|
| 654 |
+
"lstrip": false,
|
| 655 |
+
"normalized": false,
|
| 656 |
+
"rstrip": false,
|
| 657 |
+
"single_word": false,
|
| 658 |
+
"special": false
|
| 659 |
+
},
|
| 660 |
+
"82": {
|
| 661 |
+
"content": "<unused75>",
|
| 662 |
+
"lstrip": false,
|
| 663 |
+
"normalized": false,
|
| 664 |
+
"rstrip": false,
|
| 665 |
+
"single_word": false,
|
| 666 |
+
"special": false
|
| 667 |
+
},
|
| 668 |
+
"83": {
|
| 669 |
+
"content": "<unused76>",
|
| 670 |
+
"lstrip": false,
|
| 671 |
+
"normalized": false,
|
| 672 |
+
"rstrip": false,
|
| 673 |
+
"single_word": false,
|
| 674 |
+
"special": false
|
| 675 |
+
},
|
| 676 |
+
"84": {
|
| 677 |
+
"content": "<unused77>",
|
| 678 |
+
"lstrip": false,
|
| 679 |
+
"normalized": false,
|
| 680 |
+
"rstrip": false,
|
| 681 |
+
"single_word": false,
|
| 682 |
+
"special": false
|
| 683 |
+
},
|
| 684 |
+
"85": {
|
| 685 |
+
"content": "<unused78>",
|
| 686 |
+
"lstrip": false,
|
| 687 |
+
"normalized": false,
|
| 688 |
+
"rstrip": false,
|
| 689 |
+
"single_word": false,
|
| 690 |
+
"special": false
|
| 691 |
+
},
|
| 692 |
+
"86": {
|
| 693 |
+
"content": "<unused79>",
|
| 694 |
+
"lstrip": false,
|
| 695 |
+
"normalized": false,
|
| 696 |
+
"rstrip": false,
|
| 697 |
+
"single_word": false,
|
| 698 |
+
"special": false
|
| 699 |
+
},
|
| 700 |
+
"87": {
|
| 701 |
+
"content": "<unused80>",
|
| 702 |
+
"lstrip": false,
|
| 703 |
+
"normalized": false,
|
| 704 |
+
"rstrip": false,
|
| 705 |
+
"single_word": false,
|
| 706 |
+
"special": false
|
| 707 |
+
},
|
| 708 |
+
"88": {
|
| 709 |
+
"content": "<unused81>",
|
| 710 |
+
"lstrip": false,
|
| 711 |
+
"normalized": false,
|
| 712 |
+
"rstrip": false,
|
| 713 |
+
"single_word": false,
|
| 714 |
+
"special": false
|
| 715 |
+
},
|
| 716 |
+
"89": {
|
| 717 |
+
"content": "<unused82>",
|
| 718 |
+
"lstrip": false,
|
| 719 |
+
"normalized": false,
|
| 720 |
+
"rstrip": false,
|
| 721 |
+
"single_word": false,
|
| 722 |
+
"special": false
|
| 723 |
+
},
|
| 724 |
+
"90": {
|
| 725 |
+
"content": "<unused83>",
|
| 726 |
+
"lstrip": false,
|
| 727 |
+
"normalized": false,
|
| 728 |
+
"rstrip": false,
|
| 729 |
+
"single_word": false,
|
| 730 |
+
"special": false
|
| 731 |
+
},
|
| 732 |
+
"91": {
|
| 733 |
+
"content": "<unused84>",
|
| 734 |
+
"lstrip": false,
|
| 735 |
+
"normalized": false,
|
| 736 |
+
"rstrip": false,
|
| 737 |
+
"single_word": false,
|
| 738 |
+
"special": false
|
| 739 |
+
},
|
| 740 |
+
"92": {
|
| 741 |
+
"content": "<unused85>",
|
| 742 |
+
"lstrip": false,
|
| 743 |
+
"normalized": false,
|
| 744 |
+
"rstrip": false,
|
| 745 |
+
"single_word": false,
|
| 746 |
+
"special": false
|
| 747 |
+
},
|
| 748 |
+
"93": {
|
| 749 |
+
"content": "<unused86>",
|
| 750 |
+
"lstrip": false,
|
| 751 |
+
"normalized": false,
|
| 752 |
+
"rstrip": false,
|
| 753 |
+
"single_word": false,
|
| 754 |
+
"special": false
|
| 755 |
+
},
|
| 756 |
+
"94": {
|
| 757 |
+
"content": "<unused87>",
|
| 758 |
+
"lstrip": false,
|
| 759 |
+
"normalized": false,
|
| 760 |
+
"rstrip": false,
|
| 761 |
+
"single_word": false,
|
| 762 |
+
"special": false
|
| 763 |
+
},
|
| 764 |
+
"95": {
|
| 765 |
+
"content": "<unused88>",
|
| 766 |
+
"lstrip": false,
|
| 767 |
+
"normalized": false,
|
| 768 |
+
"rstrip": false,
|
| 769 |
+
"single_word": false,
|
| 770 |
+
"special": false
|
| 771 |
+
},
|
| 772 |
+
"96": {
|
| 773 |
+
"content": "<unused89>",
|
| 774 |
+
"lstrip": false,
|
| 775 |
+
"normalized": false,
|
| 776 |
+
"rstrip": false,
|
| 777 |
+
"single_word": false,
|
| 778 |
+
"special": false
|
| 779 |
+
},
|
| 780 |
+
"97": {
|
| 781 |
+
"content": "<unused90>",
|
| 782 |
+
"lstrip": false,
|
| 783 |
+
"normalized": false,
|
| 784 |
+
"rstrip": false,
|
| 785 |
+
"single_word": false,
|
| 786 |
+
"special": false
|
| 787 |
+
},
|
| 788 |
+
"98": {
|
| 789 |
+
"content": "<unused91>",
|
| 790 |
+
"lstrip": false,
|
| 791 |
+
"normalized": false,
|
| 792 |
+
"rstrip": false,
|
| 793 |
+
"single_word": false,
|
| 794 |
+
"special": false
|
| 795 |
+
},
|
| 796 |
+
"99": {
|
| 797 |
+
"content": "<unused92>",
|
| 798 |
+
"lstrip": false,
|
| 799 |
+
"normalized": false,
|
| 800 |
+
"rstrip": false,
|
| 801 |
+
"single_word": false,
|
| 802 |
+
"special": false
|
| 803 |
+
},
|
| 804 |
+
"100": {
|
| 805 |
+
"content": "<unused93>",
|
| 806 |
+
"lstrip": false,
|
| 807 |
+
"normalized": false,
|
| 808 |
+
"rstrip": false,
|
| 809 |
+
"single_word": false,
|
| 810 |
+
"special": false
|
| 811 |
+
},
|
| 812 |
+
"101": {
|
| 813 |
+
"content": "<unused94>",
|
| 814 |
+
"lstrip": false,
|
| 815 |
+
"normalized": false,
|
| 816 |
+
"rstrip": false,
|
| 817 |
+
"single_word": false,
|
| 818 |
+
"special": false
|
| 819 |
+
},
|
| 820 |
+
"102": {
|
| 821 |
+
"content": "<unused95>",
|
| 822 |
+
"lstrip": false,
|
| 823 |
+
"normalized": false,
|
| 824 |
+
"rstrip": false,
|
| 825 |
+
"single_word": false,
|
| 826 |
+
"special": false
|
| 827 |
+
},
|
| 828 |
+
"103": {
|
| 829 |
+
"content": "<unused96>",
|
| 830 |
+
"lstrip": false,
|
| 831 |
+
"normalized": false,
|
| 832 |
+
"rstrip": false,
|
| 833 |
+
"single_word": false,
|
| 834 |
+
"special": false
|
| 835 |
+
},
|
| 836 |
+
"104": {
|
| 837 |
+
"content": "<unused97>",
|
| 838 |
+
"lstrip": false,
|
| 839 |
+
"normalized": false,
|
| 840 |
+
"rstrip": false,
|
| 841 |
+
"single_word": false,
|
| 842 |
+
"special": false
|
| 843 |
+
},
|
| 844 |
+
"105": {
|
| 845 |
+
"content": "<unused98>",
|
| 846 |
+
"lstrip": false,
|
| 847 |
+
"normalized": false,
|
| 848 |
+
"rstrip": false,
|
| 849 |
+
"single_word": false,
|
| 850 |
+
"special": false
|
| 851 |
+
},
|
| 852 |
+
"106": {
|
| 853 |
+
"content": "<start_of_turn>",
|
| 854 |
+
"lstrip": false,
|
| 855 |
+
"normalized": false,
|
| 856 |
+
"rstrip": false,
|
| 857 |
+
"single_word": false,
|
| 858 |
+
"special": true
|
| 859 |
+
},
|
| 860 |
+
"107": {
|
| 861 |
+
"content": "<end_of_turn>",
|
| 862 |
+
"lstrip": false,
|
| 863 |
+
"normalized": false,
|
| 864 |
+
"rstrip": false,
|
| 865 |
+
"single_word": false,
|
| 866 |
+
"special": true
|
| 867 |
+
},
|
| 868 |
+
"108": {
|
| 869 |
+
"content": "\n",
|
| 870 |
+
"lstrip": false,
|
| 871 |
+
"normalized": false,
|
| 872 |
+
"rstrip": false,
|
| 873 |
+
"single_word": false,
|
| 874 |
+
"special": false
|
| 875 |
+
},
|
| 876 |
+
"109": {
|
| 877 |
+
"content": "\n\n",
|
| 878 |
+
"lstrip": false,
|
| 879 |
+
"normalized": false,
|
| 880 |
+
"rstrip": false,
|
| 881 |
+
"single_word": false,
|
| 882 |
+
"special": false
|
| 883 |
+
},
|
| 884 |
+
"110": {
|
| 885 |
+
"content": "\n\n\n",
|
| 886 |
+
"lstrip": false,
|
| 887 |
+
"normalized": false,
|
| 888 |
+
"rstrip": false,
|
| 889 |
+
"single_word": false,
|
| 890 |
+
"special": false
|
| 891 |
+
},
|
| 892 |
+
"111": {
|
| 893 |
+
"content": "\n\n\n\n",
|
| 894 |
+
"lstrip": false,
|
| 895 |
+
"normalized": false,
|
| 896 |
+
"rstrip": false,
|
| 897 |
+
"single_word": false,
|
| 898 |
+
"special": false
|
| 899 |
+
},
|
| 900 |
+
"112": {
|
| 901 |
+
"content": "\n\n\n\n\n",
|
| 902 |
+
"lstrip": false,
|
| 903 |
+
"normalized": false,
|
| 904 |
+
"rstrip": false,
|
| 905 |
+
"single_word": false,
|
| 906 |
+
"special": false
|
| 907 |
+
},
|
| 908 |
+
"113": {
|
| 909 |
+
"content": "\n\n\n\n\n\n",
|
| 910 |
+
"lstrip": false,
|
| 911 |
+
"normalized": false,
|
| 912 |
+
"rstrip": false,
|
| 913 |
+
"single_word": false,
|
| 914 |
+
"special": false
|
| 915 |
+
},
|
| 916 |
+
"114": {
|
| 917 |
+
"content": "\n\n\n\n\n\n\n",
|
| 918 |
+
"lstrip": false,
|
| 919 |
+
"normalized": false,
|
| 920 |
+
"rstrip": false,
|
| 921 |
+
"single_word": false,
|
| 922 |
+
"special": false
|
| 923 |
+
},
|
| 924 |
+
"115": {
|
| 925 |
+
"content": "\n\n\n\n\n\n\n\n",
|
| 926 |
+
"lstrip": false,
|
| 927 |
+
"normalized": false,
|
| 928 |
+
"rstrip": false,
|
| 929 |
+
"single_word": false,
|
| 930 |
+
"special": false
|
| 931 |
+
},
|
| 932 |
+
"116": {
|
| 933 |
+
"content": "\n\n\n\n\n\n\n\n\n",
|
| 934 |
+
"lstrip": false,
|
| 935 |
+
"normalized": false,
|
| 936 |
+
"rstrip": false,
|
| 937 |
+
"single_word": false,
|
| 938 |
+
"special": false
|
| 939 |
+
},
|
| 940 |
+
"117": {
|
| 941 |
+
"content": "\n\n\n\n\n\n\n\n\n\n",
|
| 942 |
+
"lstrip": false,
|
| 943 |
+
"normalized": false,
|
| 944 |
+
"rstrip": false,
|
| 945 |
+
"single_word": false,
|
| 946 |
+
"special": false
|
| 947 |
+
},
|
| 948 |
+
"118": {
|
| 949 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n",
|
| 950 |
+
"lstrip": false,
|
| 951 |
+
"normalized": false,
|
| 952 |
+
"rstrip": false,
|
| 953 |
+
"single_word": false,
|
| 954 |
+
"special": false
|
| 955 |
+
},
|
| 956 |
+
"119": {
|
| 957 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 958 |
+
"lstrip": false,
|
| 959 |
+
"normalized": false,
|
| 960 |
+
"rstrip": false,
|
| 961 |
+
"single_word": false,
|
| 962 |
+
"special": false
|
| 963 |
+
},
|
| 964 |
+
"120": {
|
| 965 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 966 |
+
"lstrip": false,
|
| 967 |
+
"normalized": false,
|
| 968 |
+
"rstrip": false,
|
| 969 |
+
"single_word": false,
|
| 970 |
+
"special": false
|
| 971 |
+
},
|
| 972 |
+
"121": {
|
| 973 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 974 |
+
"lstrip": false,
|
| 975 |
+
"normalized": false,
|
| 976 |
+
"rstrip": false,
|
| 977 |
+
"single_word": false,
|
| 978 |
+
"special": false
|
| 979 |
+
},
|
| 980 |
+
"122": {
|
| 981 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 982 |
+
"lstrip": false,
|
| 983 |
+
"normalized": false,
|
| 984 |
+
"rstrip": false,
|
| 985 |
+
"single_word": false,
|
| 986 |
+
"special": false
|
| 987 |
+
},
|
| 988 |
+
"123": {
|
| 989 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 990 |
+
"lstrip": false,
|
| 991 |
+
"normalized": false,
|
| 992 |
+
"rstrip": false,
|
| 993 |
+
"single_word": false,
|
| 994 |
+
"special": false
|
| 995 |
+
},
|
| 996 |
+
"124": {
|
| 997 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 998 |
+
"lstrip": false,
|
| 999 |
+
"normalized": false,
|
| 1000 |
+
"rstrip": false,
|
| 1001 |
+
"single_word": false,
|
| 1002 |
+
"special": false
|
| 1003 |
+
},
|
| 1004 |
+
"125": {
|
| 1005 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1006 |
+
"lstrip": false,
|
| 1007 |
+
"normalized": false,
|
| 1008 |
+
"rstrip": false,
|
| 1009 |
+
"single_word": false,
|
| 1010 |
+
"special": false
|
| 1011 |
+
},
|
| 1012 |
+
"126": {
|
| 1013 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1014 |
+
"lstrip": false,
|
| 1015 |
+
"normalized": false,
|
| 1016 |
+
"rstrip": false,
|
| 1017 |
+
"single_word": false,
|
| 1018 |
+
"special": false
|
| 1019 |
+
},
|
| 1020 |
+
"127": {
|
| 1021 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1022 |
+
"lstrip": false,
|
| 1023 |
+
"normalized": false,
|
| 1024 |
+
"rstrip": false,
|
| 1025 |
+
"single_word": false,
|
| 1026 |
+
"special": false
|
| 1027 |
+
},
|
| 1028 |
+
"128": {
|
| 1029 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1030 |
+
"lstrip": false,
|
| 1031 |
+
"normalized": false,
|
| 1032 |
+
"rstrip": false,
|
| 1033 |
+
"single_word": false,
|
| 1034 |
+
"special": false
|
| 1035 |
+
},
|
| 1036 |
+
"129": {
|
| 1037 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1038 |
+
"lstrip": false,
|
| 1039 |
+
"normalized": false,
|
| 1040 |
+
"rstrip": false,
|
| 1041 |
+
"single_word": false,
|
| 1042 |
+
"special": false
|
| 1043 |
+
},
|
| 1044 |
+
"130": {
|
| 1045 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1046 |
+
"lstrip": false,
|
| 1047 |
+
"normalized": false,
|
| 1048 |
+
"rstrip": false,
|
| 1049 |
+
"single_word": false,
|
| 1050 |
+
"special": false
|
| 1051 |
+
},
|
| 1052 |
+
"131": {
|
| 1053 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1054 |
+
"lstrip": false,
|
| 1055 |
+
"normalized": false,
|
| 1056 |
+
"rstrip": false,
|
| 1057 |
+
"single_word": false,
|
| 1058 |
+
"special": false
|
| 1059 |
+
},
|
| 1060 |
+
"132": {
|
| 1061 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1062 |
+
"lstrip": false,
|
| 1063 |
+
"normalized": false,
|
| 1064 |
+
"rstrip": false,
|
| 1065 |
+
"single_word": false,
|
| 1066 |
+
"special": false
|
| 1067 |
+
},
|
| 1068 |
+
"133": {
|
| 1069 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1070 |
+
"lstrip": false,
|
| 1071 |
+
"normalized": false,
|
| 1072 |
+
"rstrip": false,
|
| 1073 |
+
"single_word": false,
|
| 1074 |
+
"special": false
|
| 1075 |
+
},
|
| 1076 |
+
"134": {
|
| 1077 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1078 |
+
"lstrip": false,
|
| 1079 |
+
"normalized": false,
|
| 1080 |
+
"rstrip": false,
|
| 1081 |
+
"single_word": false,
|
| 1082 |
+
"special": false
|
| 1083 |
+
},
|
| 1084 |
+
"135": {
|
| 1085 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1086 |
+
"lstrip": false,
|
| 1087 |
+
"normalized": false,
|
| 1088 |
+
"rstrip": false,
|
| 1089 |
+
"single_word": false,
|
| 1090 |
+
"special": false
|
| 1091 |
+
},
|
| 1092 |
+
"136": {
|
| 1093 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1094 |
+
"lstrip": false,
|
| 1095 |
+
"normalized": false,
|
| 1096 |
+
"rstrip": false,
|
| 1097 |
+
"single_word": false,
|
| 1098 |
+
"special": false
|
| 1099 |
+
},
|
| 1100 |
+
"137": {
|
| 1101 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1102 |
+
"lstrip": false,
|
| 1103 |
+
"normalized": false,
|
| 1104 |
+
"rstrip": false,
|
| 1105 |
+
"single_word": false,
|
| 1106 |
+
"special": false
|
| 1107 |
+
},
|
| 1108 |
+
"138": {
|
| 1109 |
+
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
|
| 1110 |
+
"lstrip": false,
|
| 1111 |
+
"normalized": false,
|
| 1112 |
+
"rstrip": false,
|
| 1113 |
+
"single_word": false,
|
| 1114 |
+
"special": false
|
| 1115 |
+
},
|
| 1116 |
+
"139": {
|
| 1117 |
+
"content": "▁▁",
|
| 1118 |
+
"lstrip": false,
|
| 1119 |
+
"normalized": false,
|
| 1120 |
+
"rstrip": false,
|
| 1121 |
+
"single_word": false,
|
| 1122 |
+
"special": false
|
| 1123 |
+
},
|
| 1124 |
+
"140": {
|
| 1125 |
+
"content": "▁▁▁",
|
| 1126 |
+
"lstrip": false,
|
| 1127 |
+
"normalized": false,
|
| 1128 |
+
"rstrip": false,
|
| 1129 |
+
"single_word": false,
|
| 1130 |
+
"special": false
|
| 1131 |
+
},
|
| 1132 |
+
"141": {
|
| 1133 |
+
"content": "▁▁▁▁",
|
| 1134 |
+
"lstrip": false,
|
| 1135 |
+
"normalized": false,
|
| 1136 |
+
"rstrip": false,
|
| 1137 |
+
"single_word": false,
|
| 1138 |
+
"special": false
|
| 1139 |
+
},
|
| 1140 |
+
"142": {
|
| 1141 |
+
"content": "▁▁▁▁▁",
|
| 1142 |
+
"lstrip": false,
|
| 1143 |
+
"normalized": false,
|
| 1144 |
+
"rstrip": false,
|
| 1145 |
+
"single_word": false,
|
| 1146 |
+
"special": false
|
| 1147 |
+
},
|
| 1148 |
+
"143": {
|
| 1149 |
+
"content": "▁▁▁▁▁▁",
|
| 1150 |
+
"lstrip": false,
|
| 1151 |
+
"normalized": false,
|
| 1152 |
+
"rstrip": false,
|
| 1153 |
+
"single_word": false,
|
| 1154 |
+
"special": false
|
| 1155 |
+
},
|
| 1156 |
+
"144": {
|
| 1157 |
+
"content": "▁▁▁▁▁▁▁",
|
| 1158 |
+
"lstrip": false,
|
| 1159 |
+
"normalized": false,
|
| 1160 |
+
"rstrip": false,
|
| 1161 |
+
"single_word": false,
|
| 1162 |
+
"special": false
|
| 1163 |
+
},
|
| 1164 |
+
"145": {
|
| 1165 |
+
"content": "▁▁▁▁▁▁▁▁",
|
| 1166 |
+
"lstrip": false,
|
| 1167 |
+
"normalized": false,
|
| 1168 |
+
"rstrip": false,
|
| 1169 |
+
"single_word": false,
|
| 1170 |
+
"special": false
|
| 1171 |
+
},
|
| 1172 |
+
"146": {
|
| 1173 |
+
"content": "▁▁▁▁▁▁▁▁▁",
|
| 1174 |
+
"lstrip": false,
|
| 1175 |
+
"normalized": false,
|
| 1176 |
+
"rstrip": false,
|
| 1177 |
+
"single_word": false,
|
| 1178 |
+
"special": false
|
| 1179 |
+
},
|
| 1180 |
+
"147": {
|
| 1181 |
+
"content": "▁▁▁▁▁▁▁▁▁▁",
|
| 1182 |
+
"lstrip": false,
|
| 1183 |
+
"normalized": false,
|
| 1184 |
+
"rstrip": false,
|
| 1185 |
+
"single_word": false,
|
| 1186 |
+
"special": false
|
| 1187 |
+
},
|
| 1188 |
+
"148": {
|
| 1189 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁",
|
| 1190 |
+
"lstrip": false,
|
| 1191 |
+
"normalized": false,
|
| 1192 |
+
"rstrip": false,
|
| 1193 |
+
"single_word": false,
|
| 1194 |
+
"special": false
|
| 1195 |
+
},
|
| 1196 |
+
"149": {
|
| 1197 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1198 |
+
"lstrip": false,
|
| 1199 |
+
"normalized": false,
|
| 1200 |
+
"rstrip": false,
|
| 1201 |
+
"single_word": false,
|
| 1202 |
+
"special": false
|
| 1203 |
+
},
|
| 1204 |
+
"150": {
|
| 1205 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1206 |
+
"lstrip": false,
|
| 1207 |
+
"normalized": false,
|
| 1208 |
+
"rstrip": false,
|
| 1209 |
+
"single_word": false,
|
| 1210 |
+
"special": false
|
| 1211 |
+
},
|
| 1212 |
+
"151": {
|
| 1213 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1214 |
+
"lstrip": false,
|
| 1215 |
+
"normalized": false,
|
| 1216 |
+
"rstrip": false,
|
| 1217 |
+
"single_word": false,
|
| 1218 |
+
"special": false
|
| 1219 |
+
},
|
| 1220 |
+
"152": {
|
| 1221 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1222 |
+
"lstrip": false,
|
| 1223 |
+
"normalized": false,
|
| 1224 |
+
"rstrip": false,
|
| 1225 |
+
"single_word": false,
|
| 1226 |
+
"special": false
|
| 1227 |
+
},
|
| 1228 |
+
"153": {
|
| 1229 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1230 |
+
"lstrip": false,
|
| 1231 |
+
"normalized": false,
|
| 1232 |
+
"rstrip": false,
|
| 1233 |
+
"single_word": false,
|
| 1234 |
+
"special": false
|
| 1235 |
+
},
|
| 1236 |
+
"154": {
|
| 1237 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1238 |
+
"lstrip": false,
|
| 1239 |
+
"normalized": false,
|
| 1240 |
+
"rstrip": false,
|
| 1241 |
+
"single_word": false,
|
| 1242 |
+
"special": false
|
| 1243 |
+
},
|
| 1244 |
+
"155": {
|
| 1245 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1246 |
+
"lstrip": false,
|
| 1247 |
+
"normalized": false,
|
| 1248 |
+
"rstrip": false,
|
| 1249 |
+
"single_word": false,
|
| 1250 |
+
"special": false
|
| 1251 |
+
},
|
| 1252 |
+
"156": {
|
| 1253 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1254 |
+
"lstrip": false,
|
| 1255 |
+
"normalized": false,
|
| 1256 |
+
"rstrip": false,
|
| 1257 |
+
"single_word": false,
|
| 1258 |
+
"special": false
|
| 1259 |
+
},
|
| 1260 |
+
"157": {
|
| 1261 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1262 |
+
"lstrip": false,
|
| 1263 |
+
"normalized": false,
|
| 1264 |
+
"rstrip": false,
|
| 1265 |
+
"single_word": false,
|
| 1266 |
+
"special": false
|
| 1267 |
+
},
|
| 1268 |
+
"158": {
|
| 1269 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1270 |
+
"lstrip": false,
|
| 1271 |
+
"normalized": false,
|
| 1272 |
+
"rstrip": false,
|
| 1273 |
+
"single_word": false,
|
| 1274 |
+
"special": false
|
| 1275 |
+
},
|
| 1276 |
+
"159": {
|
| 1277 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1278 |
+
"lstrip": false,
|
| 1279 |
+
"normalized": false,
|
| 1280 |
+
"rstrip": false,
|
| 1281 |
+
"single_word": false,
|
| 1282 |
+
"special": false
|
| 1283 |
+
},
|
| 1284 |
+
"160": {
|
| 1285 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1286 |
+
"lstrip": false,
|
| 1287 |
+
"normalized": false,
|
| 1288 |
+
"rstrip": false,
|
| 1289 |
+
"single_word": false,
|
| 1290 |
+
"special": false
|
| 1291 |
+
},
|
| 1292 |
+
"161": {
|
| 1293 |
+
"content": "▁▁▁���▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1294 |
+
"lstrip": false,
|
| 1295 |
+
"normalized": false,
|
| 1296 |
+
"rstrip": false,
|
| 1297 |
+
"single_word": false,
|
| 1298 |
+
"special": false
|
| 1299 |
+
},
|
| 1300 |
+
"162": {
|
| 1301 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1302 |
+
"lstrip": false,
|
| 1303 |
+
"normalized": false,
|
| 1304 |
+
"rstrip": false,
|
| 1305 |
+
"single_word": false,
|
| 1306 |
+
"special": false
|
| 1307 |
+
},
|
| 1308 |
+
"163": {
|
| 1309 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1310 |
+
"lstrip": false,
|
| 1311 |
+
"normalized": false,
|
| 1312 |
+
"rstrip": false,
|
| 1313 |
+
"single_word": false,
|
| 1314 |
+
"special": false
|
| 1315 |
+
},
|
| 1316 |
+
"164": {
|
| 1317 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1318 |
+
"lstrip": false,
|
| 1319 |
+
"normalized": false,
|
| 1320 |
+
"rstrip": false,
|
| 1321 |
+
"single_word": false,
|
| 1322 |
+
"special": false
|
| 1323 |
+
},
|
| 1324 |
+
"165": {
|
| 1325 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1326 |
+
"lstrip": false,
|
| 1327 |
+
"normalized": false,
|
| 1328 |
+
"rstrip": false,
|
| 1329 |
+
"single_word": false,
|
| 1330 |
+
"special": false
|
| 1331 |
+
},
|
| 1332 |
+
"166": {
|
| 1333 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1334 |
+
"lstrip": false,
|
| 1335 |
+
"normalized": false,
|
| 1336 |
+
"rstrip": false,
|
| 1337 |
+
"single_word": false,
|
| 1338 |
+
"special": false
|
| 1339 |
+
},
|
| 1340 |
+
"167": {
|
| 1341 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1342 |
+
"lstrip": false,
|
| 1343 |
+
"normalized": false,
|
| 1344 |
+
"rstrip": false,
|
| 1345 |
+
"single_word": false,
|
| 1346 |
+
"special": false
|
| 1347 |
+
},
|
| 1348 |
+
"168": {
|
| 1349 |
+
"content": "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
|
| 1350 |
+
"lstrip": false,
|
| 1351 |
+
"normalized": false,
|
| 1352 |
+
"rstrip": false,
|
| 1353 |
+
"single_word": false,
|
| 1354 |
+
"special": false
|
| 1355 |
+
},
|
| 1356 |
+
"169": {
|
| 1357 |
+
"content": "<table>",
|
| 1358 |
+
"lstrip": false,
|
| 1359 |
+
"normalized": false,
|
| 1360 |
+
"rstrip": false,
|
| 1361 |
+
"single_word": false,
|
| 1362 |
+
"special": false
|
| 1363 |
+
},
|
| 1364 |
+
"170": {
|
| 1365 |
+
"content": "<caption>",
|
| 1366 |
+
"lstrip": false,
|
| 1367 |
+
"normalized": false,
|
| 1368 |
+
"rstrip": false,
|
| 1369 |
+
"single_word": false,
|
| 1370 |
+
"special": false
|
| 1371 |
+
},
|
| 1372 |
+
"171": {
|
| 1373 |
+
"content": "<thead>",
|
| 1374 |
+
"lstrip": false,
|
| 1375 |
+
"normalized": false,
|
| 1376 |
+
"rstrip": false,
|
| 1377 |
+
"single_word": false,
|
| 1378 |
+
"special": false
|
| 1379 |
+
},
|
| 1380 |
+
"172": {
|
| 1381 |
+
"content": "<tbody>",
|
| 1382 |
+
"lstrip": false,
|
| 1383 |
+
"normalized": false,
|
| 1384 |
+
"rstrip": false,
|
| 1385 |
+
"single_word": false,
|
| 1386 |
+
"special": false
|
| 1387 |
+
},
|
| 1388 |
+
"173": {
|
| 1389 |
+
"content": "<tfoot>",
|
| 1390 |
+
"lstrip": false,
|
| 1391 |
+
"normalized": false,
|
| 1392 |
+
"rstrip": false,
|
| 1393 |
+
"single_word": false,
|
| 1394 |
+
"special": false
|
| 1395 |
+
},
|
| 1396 |
+
"174": {
|
| 1397 |
+
"content": "<tr>",
|
| 1398 |
+
"lstrip": false,
|
| 1399 |
+
"normalized": false,
|
| 1400 |
+
"rstrip": false,
|
| 1401 |
+
"single_word": false,
|
| 1402 |
+
"special": false
|
| 1403 |
+
},
|
| 1404 |
+
"175": {
|
| 1405 |
+
"content": "<th>",
|
| 1406 |
+
"lstrip": false,
|
| 1407 |
+
"normalized": false,
|
| 1408 |
+
"rstrip": false,
|
| 1409 |
+
"single_word": false,
|
| 1410 |
+
"special": false
|
| 1411 |
+
},
|
| 1412 |
+
"176": {
|
| 1413 |
+
"content": "<td>",
|
| 1414 |
+
"lstrip": false,
|
| 1415 |
+
"normalized": false,
|
| 1416 |
+
"rstrip": false,
|
| 1417 |
+
"single_word": false,
|
| 1418 |
+
"special": false
|
| 1419 |
+
},
|
| 1420 |
+
"177": {
|
| 1421 |
+
"content": "</table>",
|
| 1422 |
+
"lstrip": false,
|
| 1423 |
+
"normalized": false,
|
| 1424 |
+
"rstrip": false,
|
| 1425 |
+
"single_word": false,
|
| 1426 |
+
"special": false
|
| 1427 |
+
},
|
| 1428 |
+
"178": {
|
| 1429 |
+
"content": "</caption>",
|
| 1430 |
+
"lstrip": false,
|
| 1431 |
+
"normalized": false,
|
| 1432 |
+
"rstrip": false,
|
| 1433 |
+
"single_word": false,
|
| 1434 |
+
"special": false
|
| 1435 |
+
},
|
| 1436 |
+
"179": {
|
| 1437 |
+
"content": "</thead>",
|
| 1438 |
+
"lstrip": false,
|
| 1439 |
+
"normalized": false,
|
| 1440 |
+
"rstrip": false,
|
| 1441 |
+
"single_word": false,
|
| 1442 |
+
"special": false
|
| 1443 |
+
},
|
| 1444 |
+
"180": {
|
| 1445 |
+
"content": "</tbody>",
|
| 1446 |
+
"lstrip": false,
|
| 1447 |
+
"normalized": false,
|
| 1448 |
+
"rstrip": false,
|
| 1449 |
+
"single_word": false,
|
| 1450 |
+
"special": false
|
| 1451 |
+
},
|
| 1452 |
+
"181": {
|
| 1453 |
+
"content": "</tfoot>",
|
| 1454 |
+
"lstrip": false,
|
| 1455 |
+
"normalized": false,
|
| 1456 |
+
"rstrip": false,
|
| 1457 |
+
"single_word": false,
|
| 1458 |
+
"special": false
|
| 1459 |
+
},
|
| 1460 |
+
"182": {
|
| 1461 |
+
"content": "</tr>",
|
| 1462 |
+
"lstrip": false,
|
| 1463 |
+
"normalized": false,
|
| 1464 |
+
"rstrip": false,
|
| 1465 |
+
"single_word": false,
|
| 1466 |
+
"special": false
|
| 1467 |
+
},
|
| 1468 |
+
"183": {
|
| 1469 |
+
"content": "</th>",
|
| 1470 |
+
"lstrip": false,
|
| 1471 |
+
"normalized": false,
|
| 1472 |
+
"rstrip": false,
|
| 1473 |
+
"single_word": false,
|
| 1474 |
+
"special": false
|
| 1475 |
+
},
|
| 1476 |
+
"184": {
|
| 1477 |
+
"content": "</td>",
|
| 1478 |
+
"lstrip": false,
|
| 1479 |
+
"normalized": false,
|
| 1480 |
+
"rstrip": false,
|
| 1481 |
+
"single_word": false,
|
| 1482 |
+
"special": false
|
| 1483 |
+
},
|
| 1484 |
+
"185": {
|
| 1485 |
+
"content": "<h1>",
|
| 1486 |
+
"lstrip": false,
|
| 1487 |
+
"normalized": false,
|
| 1488 |
+
"rstrip": false,
|
| 1489 |
+
"single_word": false,
|
| 1490 |
+
"special": false
|
| 1491 |
+
},
|
| 1492 |
+
"186": {
|
| 1493 |
+
"content": "<h2>",
|
| 1494 |
+
"lstrip": false,
|
| 1495 |
+
"normalized": false,
|
| 1496 |
+
"rstrip": false,
|
| 1497 |
+
"single_word": false,
|
| 1498 |
+
"special": false
|
| 1499 |
+
},
|
| 1500 |
+
"187": {
|
| 1501 |
+
"content": "<h3>",
|
| 1502 |
+
"lstrip": false,
|
| 1503 |
+
"normalized": false,
|
| 1504 |
+
"rstrip": false,
|
| 1505 |
+
"single_word": false,
|
| 1506 |
+
"special": false
|
| 1507 |
+
},
|
| 1508 |
+
"188": {
|
| 1509 |
+
"content": "<h4>",
|
| 1510 |
+
"lstrip": false,
|
| 1511 |
+
"normalized": false,
|
| 1512 |
+
"rstrip": false,
|
| 1513 |
+
"single_word": false,
|
| 1514 |
+
"special": false
|
| 1515 |
+
},
|
| 1516 |
+
"189": {
|
| 1517 |
+
"content": "<h5>",
|
| 1518 |
+
"lstrip": false,
|
| 1519 |
+
"normalized": false,
|
| 1520 |
+
"rstrip": false,
|
| 1521 |
+
"single_word": false,
|
| 1522 |
+
"special": false
|
| 1523 |
+
},
|
| 1524 |
+
"190": {
|
| 1525 |
+
"content": "<h6>",
|
| 1526 |
+
"lstrip": false,
|
| 1527 |
+
"normalized": false,
|
| 1528 |
+
"rstrip": false,
|
| 1529 |
+
"single_word": false,
|
| 1530 |
+
"special": false
|
| 1531 |
+
},
|
| 1532 |
+
"191": {
|
| 1533 |
+
"content": "<blockquote>",
|
| 1534 |
+
"lstrip": false,
|
| 1535 |
+
"normalized": false,
|
| 1536 |
+
"rstrip": false,
|
| 1537 |
+
"single_word": false,
|
| 1538 |
+
"special": false
|
| 1539 |
+
},
|
| 1540 |
+
"192": {
|
| 1541 |
+
"content": "</h1>",
|
| 1542 |
+
"lstrip": false,
|
| 1543 |
+
"normalized": false,
|
| 1544 |
+
"rstrip": false,
|
| 1545 |
+
"single_word": false,
|
| 1546 |
+
"special": false
|
| 1547 |
+
},
|
| 1548 |
+
"193": {
|
| 1549 |
+
"content": "</h2>",
|
| 1550 |
+
"lstrip": false,
|
| 1551 |
+
"normalized": false,
|
| 1552 |
+
"rstrip": false,
|
| 1553 |
+
"single_word": false,
|
| 1554 |
+
"special": false
|
| 1555 |
+
},
|
| 1556 |
+
"194": {
|
| 1557 |
+
"content": "</h3>",
|
| 1558 |
+
"lstrip": false,
|
| 1559 |
+
"normalized": false,
|
| 1560 |
+
"rstrip": false,
|
| 1561 |
+
"single_word": false,
|
| 1562 |
+
"special": false
|
| 1563 |
+
},
|
| 1564 |
+
"195": {
|
| 1565 |
+
"content": "</h4>",
|
| 1566 |
+
"lstrip": false,
|
| 1567 |
+
"normalized": false,
|
| 1568 |
+
"rstrip": false,
|
| 1569 |
+
"single_word": false,
|
| 1570 |
+
"special": false
|
| 1571 |
+
},
|
| 1572 |
+
"196": {
|
| 1573 |
+
"content": "</h5>",
|
| 1574 |
+
"lstrip": false,
|
| 1575 |
+
"normalized": false,
|
| 1576 |
+
"rstrip": false,
|
| 1577 |
+
"single_word": false,
|
| 1578 |
+
"special": false
|
| 1579 |
+
},
|
| 1580 |
+
"197": {
|
| 1581 |
+
"content": "</h6>",
|
| 1582 |
+
"lstrip": false,
|
| 1583 |
+
"normalized": false,
|
| 1584 |
+
"rstrip": false,
|
| 1585 |
+
"single_word": false,
|
| 1586 |
+
"special": false
|
| 1587 |
+
},
|
| 1588 |
+
"198": {
|
| 1589 |
+
"content": "</blockquote>",
|
| 1590 |
+
"lstrip": false,
|
| 1591 |
+
"normalized": false,
|
| 1592 |
+
"rstrip": false,
|
| 1593 |
+
"single_word": false,
|
| 1594 |
+
"special": false
|
| 1595 |
+
},
|
| 1596 |
+
"199": {
|
| 1597 |
+
"content": "<strong>",
|
| 1598 |
+
"lstrip": false,
|
| 1599 |
+
"normalized": false,
|
| 1600 |
+
"rstrip": false,
|
| 1601 |
+
"single_word": false,
|
| 1602 |
+
"special": false
|
| 1603 |
+
},
|
| 1604 |
+
"200": {
|
| 1605 |
+
"content": "<em>",
|
| 1606 |
+
"lstrip": false,
|
| 1607 |
+
"normalized": false,
|
| 1608 |
+
"rstrip": false,
|
| 1609 |
+
"single_word": false,
|
| 1610 |
+
"special": false
|
| 1611 |
+
},
|
| 1612 |
+
"201": {
|
| 1613 |
+
"content": "<b>",
|
| 1614 |
+
"lstrip": false,
|
| 1615 |
+
"normalized": false,
|
| 1616 |
+
"rstrip": false,
|
| 1617 |
+
"single_word": false,
|
| 1618 |
+
"special": false
|
| 1619 |
+
},
|
| 1620 |
+
"202": {
|
| 1621 |
+
"content": "<i>",
|
| 1622 |
+
"lstrip": false,
|
| 1623 |
+
"normalized": false,
|
| 1624 |
+
"rstrip": false,
|
| 1625 |
+
"single_word": false,
|
| 1626 |
+
"special": false
|
| 1627 |
+
},
|
| 1628 |
+
"203": {
|
| 1629 |
+
"content": "<u>",
|
| 1630 |
+
"lstrip": false,
|
| 1631 |
+
"normalized": false,
|
| 1632 |
+
"rstrip": false,
|
| 1633 |
+
"single_word": false,
|
| 1634 |
+
"special": false
|
| 1635 |
+
},
|
| 1636 |
+
"204": {
|
| 1637 |
+
"content": "<s>",
|
| 1638 |
+
"lstrip": false,
|
| 1639 |
+
"normalized": false,
|
| 1640 |
+
"rstrip": false,
|
| 1641 |
+
"single_word": false,
|
| 1642 |
+
"special": false
|
| 1643 |
+
},
|
| 1644 |
+
"205": {
|
| 1645 |
+
"content": "<sub>",
|
| 1646 |
+
"lstrip": false,
|
| 1647 |
+
"normalized": false,
|
| 1648 |
+
"rstrip": false,
|
| 1649 |
+
"single_word": false,
|
| 1650 |
+
"special": false
|
| 1651 |
+
},
|
| 1652 |
+
"206": {
|
| 1653 |
+
"content": "<sup>",
|
| 1654 |
+
"lstrip": false,
|
| 1655 |
+
"normalized": false,
|
| 1656 |
+
"rstrip": false,
|
| 1657 |
+
"single_word": false,
|
| 1658 |
+
"special": false
|
| 1659 |
+
},
|
| 1660 |
+
"207": {
|
| 1661 |
+
"content": "<code>",
|
| 1662 |
+
"lstrip": false,
|
| 1663 |
+
"normalized": false,
|
| 1664 |
+
"rstrip": false,
|
| 1665 |
+
"single_word": false,
|
| 1666 |
+
"special": false
|
| 1667 |
+
},
|
| 1668 |
+
"208": {
|
| 1669 |
+
"content": "</strong>",
|
| 1670 |
+
"lstrip": false,
|
| 1671 |
+
"normalized": false,
|
| 1672 |
+
"rstrip": false,
|
| 1673 |
+
"single_word": false,
|
| 1674 |
+
"special": false
|
| 1675 |
+
},
|
| 1676 |
+
"209": {
|
| 1677 |
+
"content": "</em>",
|
| 1678 |
+
"lstrip": false,
|
| 1679 |
+
"normalized": false,
|
| 1680 |
+
"rstrip": false,
|
| 1681 |
+
"single_word": false,
|
| 1682 |
+
"special": false
|
| 1683 |
+
},
|
| 1684 |
+
"210": {
|
| 1685 |
+
"content": "</b>",
|
| 1686 |
+
"lstrip": false,
|
| 1687 |
+
"normalized": false,
|
| 1688 |
+
"rstrip": false,
|
| 1689 |
+
"single_word": false,
|
| 1690 |
+
"special": false
|
| 1691 |
+
},
|
| 1692 |
+
"211": {
|
| 1693 |
+
"content": "</i>",
|
| 1694 |
+
"lstrip": false,
|
| 1695 |
+
"normalized": false,
|
| 1696 |
+
"rstrip": false,
|
| 1697 |
+
"single_word": false,
|
| 1698 |
+
"special": false
|
| 1699 |
+
},
|
| 1700 |
+
"212": {
|
| 1701 |
+
"content": "</u>",
|
| 1702 |
+
"lstrip": false,
|
| 1703 |
+
"normalized": false,
|
| 1704 |
+
"rstrip": false,
|
| 1705 |
+
"single_word": false,
|
| 1706 |
+
"special": false
|
| 1707 |
+
},
|
| 1708 |
+
"213": {
|
| 1709 |
+
"content": "</s>",
|
| 1710 |
+
"lstrip": false,
|
| 1711 |
+
"normalized": false,
|
| 1712 |
+
"rstrip": false,
|
| 1713 |
+
"single_word": false,
|
| 1714 |
+
"special": false
|
| 1715 |
+
},
|
| 1716 |
+
"214": {
|
| 1717 |
+
"content": "</sub>",
|
| 1718 |
+
"lstrip": false,
|
| 1719 |
+
"normalized": false,
|
| 1720 |
+
"rstrip": false,
|
| 1721 |
+
"single_word": false,
|
| 1722 |
+
"special": false
|
| 1723 |
+
},
|
| 1724 |
+
"215": {
|
| 1725 |
+
"content": "</sup>",
|
| 1726 |
+
"lstrip": false,
|
| 1727 |
+
"normalized": false,
|
| 1728 |
+
"rstrip": false,
|
| 1729 |
+
"single_word": false,
|
| 1730 |
+
"special": false
|
| 1731 |
+
},
|
| 1732 |
+
"216": {
|
| 1733 |
+
"content": "</code>",
|
| 1734 |
+
"lstrip": false,
|
| 1735 |
+
"normalized": false,
|
| 1736 |
+
"rstrip": false,
|
| 1737 |
+
"single_word": false,
|
| 1738 |
+
"special": false
|
| 1739 |
+
},
|
| 1740 |
+
"255968": {
|
| 1741 |
+
"content": "[toxicity=0]",
|
| 1742 |
+
"lstrip": false,
|
| 1743 |
+
"normalized": false,
|
| 1744 |
+
"rstrip": false,
|
| 1745 |
+
"single_word": false,
|
| 1746 |
+
"special": false
|
| 1747 |
+
},
|
| 1748 |
+
"255969": {
|
| 1749 |
+
"content": "\t\t",
|
| 1750 |
+
"lstrip": false,
|
| 1751 |
+
"normalized": false,
|
| 1752 |
+
"rstrip": false,
|
| 1753 |
+
"single_word": false,
|
| 1754 |
+
"special": false
|
| 1755 |
+
},
|
| 1756 |
+
"255970": {
|
| 1757 |
+
"content": "\t\t\t",
|
| 1758 |
+
"lstrip": false,
|
| 1759 |
+
"normalized": false,
|
| 1760 |
+
"rstrip": false,
|
| 1761 |
+
"single_word": false,
|
| 1762 |
+
"special": false
|
| 1763 |
+
},
|
| 1764 |
+
"255971": {
|
| 1765 |
+
"content": "\t\t\t\t",
|
| 1766 |
+
"lstrip": false,
|
| 1767 |
+
"normalized": false,
|
| 1768 |
+
"rstrip": false,
|
| 1769 |
+
"single_word": false,
|
| 1770 |
+
"special": false
|
| 1771 |
+
},
|
| 1772 |
+
"255972": {
|
| 1773 |
+
"content": "\t\t\t\t\t",
|
| 1774 |
+
"lstrip": false,
|
| 1775 |
+
"normalized": false,
|
| 1776 |
+
"rstrip": false,
|
| 1777 |
+
"single_word": false,
|
| 1778 |
+
"special": false
|
| 1779 |
+
},
|
| 1780 |
+
"255973": {
|
| 1781 |
+
"content": "\t\t\t\t\t\t",
|
| 1782 |
+
"lstrip": false,
|
| 1783 |
+
"normalized": false,
|
| 1784 |
+
"rstrip": false,
|
| 1785 |
+
"single_word": false,
|
| 1786 |
+
"special": false
|
| 1787 |
+
},
|
| 1788 |
+
"255974": {
|
| 1789 |
+
"content": "\t\t\t\t\t\t\t",
|
| 1790 |
+
"lstrip": false,
|
| 1791 |
+
"normalized": false,
|
| 1792 |
+
"rstrip": false,
|
| 1793 |
+
"single_word": false,
|
| 1794 |
+
"special": false
|
| 1795 |
+
},
|
| 1796 |
+
"255975": {
|
| 1797 |
+
"content": "\t\t\t\t\t\t\t\t",
|
| 1798 |
+
"lstrip": false,
|
| 1799 |
+
"normalized": false,
|
| 1800 |
+
"rstrip": false,
|
| 1801 |
+
"single_word": false,
|
| 1802 |
+
"special": false
|
| 1803 |
+
},
|
| 1804 |
+
"255976": {
|
| 1805 |
+
"content": "\t\t\t\t\t\t\t\t\t",
|
| 1806 |
+
"lstrip": false,
|
| 1807 |
+
"normalized": false,
|
| 1808 |
+
"rstrip": false,
|
| 1809 |
+
"single_word": false,
|
| 1810 |
+
"special": false
|
| 1811 |
+
},
|
| 1812 |
+
"255977": {
|
| 1813 |
+
"content": "\t\t\t\t\t\t\t\t\t\t",
|
| 1814 |
+
"lstrip": false,
|
| 1815 |
+
"normalized": false,
|
| 1816 |
+
"rstrip": false,
|
| 1817 |
+
"single_word": false,
|
| 1818 |
+
"special": false
|
| 1819 |
+
},
|
| 1820 |
+
"255978": {
|
| 1821 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t",
|
| 1822 |
+
"lstrip": false,
|
| 1823 |
+
"normalized": false,
|
| 1824 |
+
"rstrip": false,
|
| 1825 |
+
"single_word": false,
|
| 1826 |
+
"special": false
|
| 1827 |
+
},
|
| 1828 |
+
"255979": {
|
| 1829 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1830 |
+
"lstrip": false,
|
| 1831 |
+
"normalized": false,
|
| 1832 |
+
"rstrip": false,
|
| 1833 |
+
"single_word": false,
|
| 1834 |
+
"special": false
|
| 1835 |
+
},
|
| 1836 |
+
"255980": {
|
| 1837 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1838 |
+
"lstrip": false,
|
| 1839 |
+
"normalized": false,
|
| 1840 |
+
"rstrip": false,
|
| 1841 |
+
"single_word": false,
|
| 1842 |
+
"special": false
|
| 1843 |
+
},
|
| 1844 |
+
"255981": {
|
| 1845 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1846 |
+
"lstrip": false,
|
| 1847 |
+
"normalized": false,
|
| 1848 |
+
"rstrip": false,
|
| 1849 |
+
"single_word": false,
|
| 1850 |
+
"special": false
|
| 1851 |
+
},
|
| 1852 |
+
"255982": {
|
| 1853 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1854 |
+
"lstrip": false,
|
| 1855 |
+
"normalized": false,
|
| 1856 |
+
"rstrip": false,
|
| 1857 |
+
"single_word": false,
|
| 1858 |
+
"special": false
|
| 1859 |
+
},
|
| 1860 |
+
"255983": {
|
| 1861 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1862 |
+
"lstrip": false,
|
| 1863 |
+
"normalized": false,
|
| 1864 |
+
"rstrip": false,
|
| 1865 |
+
"single_word": false,
|
| 1866 |
+
"special": false
|
| 1867 |
+
},
|
| 1868 |
+
"255984": {
|
| 1869 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1870 |
+
"lstrip": false,
|
| 1871 |
+
"normalized": false,
|
| 1872 |
+
"rstrip": false,
|
| 1873 |
+
"single_word": false,
|
| 1874 |
+
"special": false
|
| 1875 |
+
},
|
| 1876 |
+
"255985": {
|
| 1877 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1878 |
+
"lstrip": false,
|
| 1879 |
+
"normalized": false,
|
| 1880 |
+
"rstrip": false,
|
| 1881 |
+
"single_word": false,
|
| 1882 |
+
"special": false
|
| 1883 |
+
},
|
| 1884 |
+
"255986": {
|
| 1885 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1886 |
+
"lstrip": false,
|
| 1887 |
+
"normalized": false,
|
| 1888 |
+
"rstrip": false,
|
| 1889 |
+
"single_word": false,
|
| 1890 |
+
"special": false
|
| 1891 |
+
},
|
| 1892 |
+
"255987": {
|
| 1893 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1894 |
+
"lstrip": false,
|
| 1895 |
+
"normalized": false,
|
| 1896 |
+
"rstrip": false,
|
| 1897 |
+
"single_word": false,
|
| 1898 |
+
"special": false
|
| 1899 |
+
},
|
| 1900 |
+
"255988": {
|
| 1901 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1902 |
+
"lstrip": false,
|
| 1903 |
+
"normalized": false,
|
| 1904 |
+
"rstrip": false,
|
| 1905 |
+
"single_word": false,
|
| 1906 |
+
"special": false
|
| 1907 |
+
},
|
| 1908 |
+
"255989": {
|
| 1909 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1910 |
+
"lstrip": false,
|
| 1911 |
+
"normalized": false,
|
| 1912 |
+
"rstrip": false,
|
| 1913 |
+
"single_word": false,
|
| 1914 |
+
"special": false
|
| 1915 |
+
},
|
| 1916 |
+
"255990": {
|
| 1917 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1918 |
+
"lstrip": false,
|
| 1919 |
+
"normalized": false,
|
| 1920 |
+
"rstrip": false,
|
| 1921 |
+
"single_word": false,
|
| 1922 |
+
"special": false
|
| 1923 |
+
},
|
| 1924 |
+
"255991": {
|
| 1925 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1926 |
+
"lstrip": false,
|
| 1927 |
+
"normalized": false,
|
| 1928 |
+
"rstrip": false,
|
| 1929 |
+
"single_word": false,
|
| 1930 |
+
"special": false
|
| 1931 |
+
},
|
| 1932 |
+
"255992": {
|
| 1933 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1934 |
+
"lstrip": false,
|
| 1935 |
+
"normalized": false,
|
| 1936 |
+
"rstrip": false,
|
| 1937 |
+
"single_word": false,
|
| 1938 |
+
"special": false
|
| 1939 |
+
},
|
| 1940 |
+
"255993": {
|
| 1941 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1942 |
+
"lstrip": false,
|
| 1943 |
+
"normalized": false,
|
| 1944 |
+
"rstrip": false,
|
| 1945 |
+
"single_word": false,
|
| 1946 |
+
"special": false
|
| 1947 |
+
},
|
| 1948 |
+
"255994": {
|
| 1949 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1950 |
+
"lstrip": false,
|
| 1951 |
+
"normalized": false,
|
| 1952 |
+
"rstrip": false,
|
| 1953 |
+
"single_word": false,
|
| 1954 |
+
"special": false
|
| 1955 |
+
},
|
| 1956 |
+
"255995": {
|
| 1957 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1958 |
+
"lstrip": false,
|
| 1959 |
+
"normalized": false,
|
| 1960 |
+
"rstrip": false,
|
| 1961 |
+
"single_word": false,
|
| 1962 |
+
"special": false
|
| 1963 |
+
},
|
| 1964 |
+
"255996": {
|
| 1965 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1966 |
+
"lstrip": false,
|
| 1967 |
+
"normalized": false,
|
| 1968 |
+
"rstrip": false,
|
| 1969 |
+
"single_word": false,
|
| 1970 |
+
"special": false
|
| 1971 |
+
},
|
| 1972 |
+
"255997": {
|
| 1973 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1974 |
+
"lstrip": false,
|
| 1975 |
+
"normalized": false,
|
| 1976 |
+
"rstrip": false,
|
| 1977 |
+
"single_word": false,
|
| 1978 |
+
"special": false
|
| 1979 |
+
},
|
| 1980 |
+
"255998": {
|
| 1981 |
+
"content": "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
|
| 1982 |
+
"lstrip": false,
|
| 1983 |
+
"normalized": false,
|
| 1984 |
+
"rstrip": false,
|
| 1985 |
+
"single_word": false,
|
| 1986 |
+
"special": false
|
| 1987 |
+
},
|
| 1988 |
+
"255999": {
|
| 1989 |
+
"content": "<unused99>",
|
| 1990 |
+
"lstrip": false,
|
| 1991 |
+
"normalized": false,
|
| 1992 |
+
"rstrip": false,
|
| 1993 |
+
"single_word": false,
|
| 1994 |
+
"special": false
|
| 1995 |
+
}
|
| 1996 |
+
},
|
| 1997 |
+
"additional_special_tokens": [
|
| 1998 |
+
"<start_of_turn>",
|
| 1999 |
+
"<end_of_turn>"
|
| 2000 |
+
],
|
| 2001 |
+
"bos_token": "<bos>",
|
| 2002 |
+
"clean_up_tokenization_spaces": false,
|
| 2003 |
+
"cls_token": "<bos>",
|
| 2004 |
+
"eos_token": "<eos>",
|
| 2005 |
+
"extra_special_tokens": {},
|
| 2006 |
+
"mask_token": "<mask>",
|
| 2007 |
+
"model_input_names": [
|
| 2008 |
+
"input_ids",
|
| 2009 |
+
"attention_mask"
|
| 2010 |
+
],
|
| 2011 |
+
"model_max_length": 32768,
|
| 2012 |
+
"pad_token": "<pad>",
|
| 2013 |
+
"padding_side": "right",
|
| 2014 |
+
"sep_token": "<eos>",
|
| 2015 |
+
"spaces_between_special_tokens": false,
|
| 2016 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
| 2017 |
+
"unk_token": "<unk>"
|
| 2018 |
+
}
|
training-origin.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"method": "full",
|
| 3 |
+
"base_model": "vllm-sr/Vela-1.0-Encoder-307M",
|
| 4 |
+
"base_revision": "720ab37904ce15054068d429381bfae7549f00f6"
|
| 5 |
+
}
|