Ericu950 commited on
Commit
5952424
·
verified ·
1 Parent(s): f319761

Stoicheia: training and evaluation code

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +11 -0
  2. LICENSE +201 -0
  3. MODEL_CARDS_INDEX.md +44 -0
  4. NOTICE +21 -0
  5. README.md +98 -0
  6. REPRODUCING.md +214 -0
  7. Stoicheia_demo.ipynb +279 -0
  8. analysis/merge_dsh.py +71 -0
  9. analysis/merge_ptp.py +60 -0
  10. analysis/paper_tables.py +189 -0
  11. analysis/pick_ckpt.py +29 -0
  12. analysis/sig_all.py +164 -0
  13. configs/insc/finetune_whole_v3_randinit_t0v1.json +49 -0
  14. configs/insc/finetune_whole_v3_randinit_t1v2.json +49 -0
  15. configs/insc/finetune_whole_v3_randinit_t2v3.json +49 -0
  16. configs/insc/finetune_whole_v3_randinit_t3v4.json +49 -0
  17. configs/insc/finetune_whole_v3_randinit_t4v5.json +49 -0
  18. configs/insc/finetune_whole_v3_randinit_t5v6.json +49 -0
  19. configs/insc/finetune_whole_v3_randinit_t6v7.json +49 -0
  20. configs/insc/finetune_whole_v3_randinit_t7v8.json +49 -0
  21. configs/insc/finetune_whole_v3_randinit_t8v9.json +49 -0
  22. configs/insc/finetune_whole_v3_randinit_t9v0.json +49 -0
  23. configs/insc/finetune_whole_v3_t0v1.json +49 -0
  24. configs/insc/finetune_whole_v3_t1v2.json +49 -0
  25. configs/insc/finetune_whole_v3_t2v3.json +49 -0
  26. configs/insc/finetune_whole_v3_t3v4.json +49 -0
  27. configs/insc/finetune_whole_v3_t4v5.json +49 -0
  28. configs/insc/finetune_whole_v3_t5v6.json +49 -0
  29. configs/insc/finetune_whole_v3_t6v7.json +49 -0
  30. configs/insc/finetune_whole_v3_t7v8.json +49 -0
  31. configs/insc/finetune_whole_v3_t8v9.json +49 -0
  32. configs/insc/finetune_whole_v3_t9v0.json +49 -0
  33. configs/insc/finetune_whole_v4_t0v1.json +55 -0
  34. configs/insc/finetune_whole_v4_t1v2.json +55 -0
  35. configs/insc/finetune_whole_v4_t2v3.json +55 -0
  36. configs/insc/finetune_whole_v4_t3v4.json +54 -0
  37. configs/insc/finetune_whole_v4_t3v4_seed1.json +54 -0
  38. configs/insc/finetune_whole_v4_t3v4_seed2.json +54 -0
  39. configs/insc/finetune_whole_v4_t4v5.json +55 -0
  40. configs/insc/finetune_whole_v4_t5v6.json +55 -0
  41. configs/insc/finetune_whole_v4_t6v7.json +54 -0
  42. configs/insc/finetune_whole_v4_t7v8.json +54 -0
  43. configs/insc/finetune_whole_v4_t8v9.json +54 -0
  44. configs/insc/finetune_whole_v4_t9v0.json +54 -0
  45. configs/meter/_smoke.json +31 -0
  46. configs/meter/joint_docclean.json +30 -0
  47. configs/meter/joint_docclean_s1.json +30 -0
  48. configs/meter/joint_docclean_s2.json +30 -0
  49. configs/meter/joint_docclean_s3.json +30 -0
  50. configs/meter/joint_docclean_s4.json +30 -0
.gitignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ logs/
5
+ out/
6
+ .venv-cpu/
7
+ .venv-x86/
8
+ *.egg-info/
9
+ build/
10
+ dist/
11
+ hf_release_output/
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
141
+ the 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.
MODEL_CARDS_INDEX.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stoicheia — Released Models and Datasets
2
+
3
+ All models are character-level masked-diffusion Transformers for Ancient Greek (405M
4
+ params, `d_model=1024`, depth 32), loadable via
5
+ `AutoModel.from_pretrained(repo_id, trust_remote_code=True)`. See each model card for
6
+ usage examples specific to that checkpoint's task.
7
+
8
+ ## Pretrained backbones (11)
9
+
10
+ Ten rotated, work-level-decontaminated literary folds plus one documentary-clean model.
11
+ For any passage in the open training corpus, at least one of these eleven has provably
12
+ never seen it during pretraining.
13
+
14
+ | model | decontamination |
15
+ |---|---|
16
+ | [`Ericu950/Stoicheia-doc_clean`](https://huggingface.co/Ericu950/Stoicheia-doc_clean) | zero documentary (inscription/papyrus) exposure of any kind |
17
+ | [`Ericu950/Stoicheia-fold-0`](https://huggingface.co/Ericu950/Stoicheia-fold-0) … [`fold-9`](https://huggingface.co/Ericu950/Stoicheia-fold-9) | rotated 80/10/10 literary split, fold *k*'s test set unseen by fold *k*'s model |
18
+
19
+ ## Fine-tuned downstream models (4)
20
+
21
+ All built on `Stoicheia-doc_clean`.
22
+
23
+ | model | task |
24
+ |---|---|
25
+ | [`Ericu950/Stoicheia-restoration-test0`](https://huggingface.co/Ericu950/Stoicheia-restoration-test0) … [`-test9`](https://huggingface.co/Ericu950/Stoicheia-restoration-test9) | documentary restoration, ten checkpoints — checkpoint *k* holds out every PHI/TM identifier ending in digit *k*, so every document in the corpus has a model that provably never saw it |
26
+ | [`Ericu950/Stoicheia-tagger-parser`](https://huggingface.co/Ericu950/Stoicheia-tagger-parser) | morphosyntactic tagging (XPOS/UPOS/lemma) + dependency parsing |
27
+ | [`Ericu950/Stoicheia-meter`](https://huggingface.co/Ericu950/Stoicheia-meter) | macronization (vowel length) + metrical scansion, trained jointly |
28
+ | [`Ericu950/Stoicheia-macronizer`](https://huggingface.co/Ericu950/Stoicheia-macronizer) | macronization only — the arm the paper's macronization ablation is measured on |
29
+
30
+ Not released as a model: the authorship-attribution / hermeneutic probes, which are
31
+ designed to be fine-tuned per-task rather than distributed as a general-purpose model
32
+ (see the paper's Discussion section).
33
+
34
+ ## Datasets
35
+
36
+ | dataset | what it is |
37
+ |---|---|
38
+ | [`Ericu950/AncientGreek`](https://huggingface.co/datasets/Ericu950/AncientGreek) | main pretraining corpus (gold + silver tiers) |
39
+ | [`Ericu950/SyntheticAncientGreek-CorpusCorporum`](https://huggingface.co/datasets/Ericu950/SyntheticAncientGreek-CorpusCorporum) | bronze synthetic augmentation tier |
40
+ | [`Ericu950/Inscriptions_2`](https://huggingface.co/datasets/Ericu950/Inscriptions_2) | PHI inscriptions used for the 10-fold split and restoration fine-tuning |
41
+
42
+ Not re-released (already public elsewhere, cited not duplicated): the *Norma*
43
+ macronization/scansion benchmark (GitHub), the OGA/AGDT treebank
44
+ (Celano's own repository).
NOTICE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Stoicheia
2
+ Copyright 2026 Anonymous (under review)
3
+
4
+ This product is licensed under the Apache License, Version 2.0 (see LICENSE).
5
+
6
+ Evaluation of the Ithaca and Aeneas baselines uses DeepMind's released code, obtained
7
+ separately from their repositories (not vendored here): the Ithaca codebase
8
+ from DeepMind:
9
+
10
+ Ithaca
11
+ Copyright DeepMind Technologies Limited
12
+ https://github.com/google-deepmind/ithaca
13
+ Licensed under the Apache License, Version 2.0
14
+
15
+ Ithaca (Assael, Sommerschield, Shillingford, Bordbar, Pavlopoulos, Chatzipanagiotou,
16
+ Androutsopoulos, Prag & de Freitas, "Restoring and attributing ancient texts using deep
17
+ neural networks", Nature 2022) is used purely as a reference baseline that this project's
18
+ own inscription-restoration evaluation code (`insc/eval/`) compares against. No code from
19
+ Ithaca has been copied into this repository's source tree; the baseline harness expects a
20
+ separately downloaded checkout (see `scripts/slurm/insc_ithaca_gpu.sbatch`), which retains
21
+ its own LICENSE.
README.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stoicheia
2
+
3
+ A character-level masked-diffusion Transformer for Ancient Greek, pretrained on an
4
+ open, revision-pinned corpus and released as eleven decontaminated checkpoints (ten
5
+ rotated literary folds + one documentary-clean model), fine-tuned for restoration of
6
+ damaged inscriptions/papyri, morphosyntactic tagging and dependency parsing, and
7
+ macronization/metrical scansion.
8
+
9
+ This repository is the training/evaluation code. The pretrained and fine-tuned model
10
+ weights are on the HuggingFace Hub — see [`MODEL_CARDS_INDEX.md`](MODEL_CARDS_INDEX.md)
11
+ for the full list, or jump straight to
12
+ [`Ericu950/Stoicheia-doc_clean`](https://huggingface.co/Ericu950/Stoicheia-doc_clean)
13
+ (the flagship backbone) or
14
+ [`Ericu950/Stoicheia-restoration-test3`](https://huggingface.co/Ericu950/Stoicheia-restoration-test3) (or any of the ten digit-rotation checkpoints) /
15
+ [`-tagger-parser`](https://huggingface.co/Ericu950/Stoicheia-tagger-parser) for a
16
+ ready-to-use downstream model (or [`-meter`](https://huggingface.co/Ericu950/Stoicheia-meter) for
17
+ macronization and scansion). All model repos are public: weights ship as `model.safetensors` with a `config.json`,
18
+ loadable directly through `AutoModel.from_pretrained(..., trust_remote_code=True)`.
19
+
20
+
21
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Ericu950/stoicheia/blob/main/Stoicheia_demo.ipynb)
22
+
23
+ Run everything in the browser: [`Stoicheia_demo.ipynb`](Stoicheia_demo.ipynb) restores a lacuna of
24
+ unknown width, picks the checkpoint that has provably never read your document, tags and parses a
25
+ verse of Homer, macronizes and scans a line, and scores the macronizer on the benchmark.
26
+
27
+ ## Quickstart (no training required)
28
+
29
+ ```python
30
+ import torch
31
+ from transformers import AutoModel
32
+ from huggingface_hub import hf_hub_download
33
+
34
+ REPO = "Ericu950/Stoicheia-doc_clean"
35
+ model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()
36
+
37
+ # `trust_remote_code` loads the model classes; the processor is a separate helper, so
38
+ # fetch it into the working directory before importing it.
39
+ hf_hub_download(repo_id=REPO, filename="processing_char_bert.py", local_dir=".")
40
+ from processing_char_bert import CharBertProcessor
41
+
42
+ processor = CharBertProcessor()
43
+
44
+ # a lacuna of UNCERTAIN width, in text that's ALSO fully bare scriptio continua (no
45
+ # spaces, no accents) -- the realistic case for damaged, unaccented primary sources.
46
+ # Write "[N±M]" for a best-guess width N and a plausible range N-M..N+M; every
47
+ # candidate width is scored by the model's own confidence, recovering both the
48
+ # width and the text while jointly restoring accents/word-boundaries throughout.
49
+ text = "εναρχηηνο[5±3]καιολογοςηνπροστονθεον"
50
+ best_text, best_width, candidates = processor.restore_elastic(model, text, mask_dia_boundary=True)
51
+ print(best_text) # -> ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν.
52
+ ```
53
+
54
+ A damaged inscription, unaccented and unspaced where the break falls:
55
+
56
+ ```python
57
+ print(processor.restore_respaced(model, "ἔδοξεν τηβου-- καὶ τῷ δήμῳ"))
58
+ # -> ἔδοξεν τῇ βουλῇ καὶ τῷ δήμῳ
59
+ ```
60
+
61
+ Accents and word division are predictions, not requirements: a bare majuscule transcript is as
62
+ readable to this model as a modern critical text, and the gap is filled in the same pass that
63
+ decides where the words end.
64
+
65
+
66
+ ## What's here
67
+
68
+ - `model/`, `data/`, `train/`, `eval/` — the pretraining architecture (`CharBertEncoder`,
69
+ a five-plane character-level masked-diffusion Transformer) and training loop.
70
+ - `insc/` — restoration fine-tuning (inscriptions + papyri) and strict-protocol
71
+ evaluation (same-harness comparison against DeepMind's Ithaca).
72
+ - `tagger/`, `parser/` — morphosyntactic tagging (factored XPOS, edit-script lemma,
73
+ UPOS) and biaffine dependency parsing, plus a joint multi-task model and a
74
+ pluggable HuggingFace-encoder bridge for cross-encoder ablations.
75
+ - `meter/` — macronization (vowel length) and metrical scansion, including the
76
+ *Norma* benchmark protocol and rule-based silver-data mining pipeline.
77
+ - `tests/` — CPU-only pytest suite.
78
+
79
+ See [`REPRODUCING.md`](REPRODUCING.md) for the full environment setup and end-to-end
80
+ reproduction walkthrough.
81
+
82
+ ## Citation
83
+
84
+ ```bibtex
85
+ @misc{stoicheia2026,
86
+ title = {Stoicheia: Character-Level Masked Diffusion for Ancient Greek Textual
87
+ Restoration, Parsing, and Metrical Scansion},
88
+ author = {Anonymous},
89
+ year = {2026},
90
+ note = {Under review; citation to be finalized on publication}
91
+ }
92
+ ```
93
+
94
+ ## License
95
+
96
+ Apache 2.0 (see `LICENSE`). External baselines (DeepMind's Ithaca and predictingthepast releases) are
97
+ downloaded separately from their own repositories and retain their own licenses — see
98
+ `NOTICE` and `REPRODUCING.md`.
REPRODUCING.md ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Reproducing Stoicheia
2
+
3
+ ## 1. Environment
4
+
5
+ ```bash
6
+ git clone https://github.com/Ericu950/stoicheia
7
+ cd stoicheia
8
+ export STOICHEIA_DATA=/path/to/a/writable/data+checkpoints/directory
9
+ source env.sh
10
+ pip install -e .
11
+ ```
12
+
13
+ For GPU training at scale, the project used an Apptainer container on aarch64 GH200
14
+ nodes via a SLURM cluster; the container image itself is not included in this repo (see
15
+ `scripts/slurm/README.md` for what's expected inside it, and how to point `STOICHEIA_SIF`
16
+ at your own equivalent, or run without a container at all). See the same file for the
17
+ cluster-specific sbatch templates (edit the account/partition placeholders before
18
+ submitting). For CPU-only work (tests, small-scale inference, data preparation),
19
+ `pip install -r requirements-cpu.txt` is sufficient — no container needed,
20
+ `attn_impl="sdpa"` runs on CPU.
21
+
22
+ ## 2. Data
23
+
24
+ Three core datasets are already public and used as-is (no re-release needed):
25
+
26
+ ```python
27
+ from datasets import load_dataset
28
+ gold_silver = load_dataset("Ericu950/AncientGreek") # pretraining corpus
29
+ bronze = load_dataset("Ericu950/SyntheticAncientGreek-CorpusCorporum") # synthetic augmentation
30
+ inscriptions = load_dataset("Ericu950/Inscriptions_2") # PHI inscriptions
31
+ ```
32
+
33
+ Two further data dependencies are external, citable resources — clone/download them
34
+ directly rather than expecting a copy in this repo:
35
+ - **OGA/AGDT treebank** (tagging/parsing fine-tuning, morphosyntax evaluation): clone
36
+ Celano's own repository, `git.informatik.uni-leipzig.de/celano/morphosyntactic_parser_for_oga`.
37
+ - **Norma** (macronization/scansion benchmark): released with the vowel-length paper
38
+ cited in the paper's macronization section; the harnesses read it through
39
+ `MACRONIZER_SRC` (see the last section of this file).
40
+
41
+ The 10-fold decontamination split is built by the pipeline in `data/split_pipeline/`
42
+ (MinHash-LSH near-duplicate clustering, a last-digit rule for papyri/inscriptions,
43
+ and n-gram decontamination against the eval sets — see the last section of this file
44
+ and `data/fold_manifests/SPLIT_DESIGN.md`). Its downstream consumer,
45
+ `data/build_fold_shards.py`, takes a fold's `train.jsonl.zst` and builds the memmap
46
+ shards the pretraining loader reads. In practice you don't need to rebuild the fold
47
+ assignments from scratch: use the pretrained checkpoints directly
48
+ (`MODEL_CARDS_INDEX.md`), and `data/fold_manifests/` records every fold's test-work
49
+ assignments for verification.
50
+
51
+ ## 3. Pretraining (the 11 backbones)
52
+
53
+ ```bash
54
+ sbatch scripts/slurm/pretrain_fold.sbatch 0 # one of ten literary folds (0-9)
55
+ sbatch scripts/slurm/pretrain_doc_clean.sbatch # the documentary-clean model
56
+ ```
57
+
58
+ Each is a long-running, checkpointed, resumable job chain (dev-driven schedule, not
59
+ step-capped — see the paper's Model section for the staged-anneal training regime).
60
+ Pretrained checkpoints are also available directly on the Hub (see
61
+ `MODEL_CARDS_INDEX.md`) — you do not need to re-pretrain to use or fine-tune the models.
62
+
63
+ ## 4. Fine-tuning the three downstream tasks
64
+
65
+ All three fine-tune from `$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt` (or the equivalent
66
+ Hub checkpoint, downloaded locally first if you want to fine-tune outside this
67
+ pipeline's own checkpoint format).
68
+
69
+ ```bash
70
+ # restoration, v2 recipe, held-out digit 3 (the paper's headline model)
71
+ sbatch scripts/slurm/insc_finetune_whole_4node.sbatch configs/insc/finetune_whole_v4_t3v4.json
72
+
73
+ # joint tagger + dependency parser
74
+ sbatch scripts/slurm/syntax_joint_ddp.sbatch configs/syntax/joint_docclean_f3_s0.json
75
+
76
+ # macronization + metrical scansion (joint), and the macron-only arm of the ablation
77
+ sbatch scripts/slurm/meter_meter.sbatch configs/meter/joint_docclean.json
78
+ sbatch scripts/slurm/meter_meter.sbatch configs/meter/mac_v2.json
79
+ ```
80
+
81
+ For the leak-proof 10-fold restoration rotation used to interrogate individual
82
+ inscriptions/papyri (every document gets a fine-tuned model that provably never saw it,
83
+ regardless of which digit its ID ends in — restoration fine-tunes in about an hour, so
84
+ the full rotation is cheap):
85
+
86
+ ```bash
87
+ # test_digit/val_digit rotate together: (1,2), (2,3), ..., (9,0), (0,1)
88
+ sbatch scripts/slurm/insc_finetune_whole_4node.sbatch configs/insc/finetune_whole_v4_t1v2.json
89
+ ```
90
+
91
+ Each `configs/insc/finetune_whole_v*_t*v*.json` pins its own `test_digit`/
92
+ `val_digit` fields; `insc/train/finetune_whole.py` reads them and exports
93
+ `INSC_TEST_DIGIT`/`INSC_VAL_DIGIT` itself before any data loads, so the intended split
94
+ holds however the script is launched. The eval scripts
95
+ (`insc/eval/restore_strict{,_papyri}.py`) are not config-driven — when evaluating one of
96
+ these fold models, export the matching `INSC_TEST_DIGIT`/`INSC_VAL_DIGIT` yourself
97
+ before `--make-samples`/`--ckpt` (defaults to the flagship 3/4 split otherwise).
98
+
99
+ ## 5. Evaluation (reproducing the paper's tables)
100
+
101
+ Every reconstruction number uses one protocol: whole documents, real lacunae left in
102
+ context as unknowns, spaces counted toward the gap length, word division predicted, beam
103
+ 20, Levenshtein CER. `--make-samples` writes a frozen sample file; evaluation then reads
104
+ it, so every system sees identical gaps.
105
+
106
+ **Ten-fold rotation (Table 1).** For each held-out digit `t` (val digit `v = (t+1) % 10`),
107
+ with the arm's checkpoint from `MODEL_CARDS_INDEX.md`:
108
+
109
+ ```bash
110
+ export INSC_TEST_DIGIT=3 INSC_VAL_DIGIT=4 # must match the model's fold
111
+ python -m insc.eval.restore_strict --make-samples --n 100 --samples f3_inscr.json
112
+ python -m insc.eval.restore_strict_papyri --make-samples --n 100 --samples f3_pap.json
113
+ python -m insc.eval.restore_strict --ckpt <run>/best.pt --samples f3_inscr.json --out v2_d3_inscr.json
114
+ python -m insc.eval.restore_strict_papyri --ckpt <run>/best.pt --samples f3_pap.json --out v2_d3_pap.json
115
+ ```
116
+
117
+ Repeat over the ten `v4_*` runs (paper revision v2), the ten `v3_*` runs (v1), and the ten
118
+ `v3_randinit_*` runs (the matched control), then aggregate and run the fold-paired
119
+ permutation tests with `python -m analysis.sig_all`.
120
+
121
+ **Starting from a released checkpoint.** The Hub ships `model.safetensors` for
122
+ `AutoModel.from_pretrained`, while the evaluation scripts read the trainer's `.pt`. Convert once:
123
+
124
+ ```bash
125
+ python scripts/hf_to_eval_checkpoint.py \
126
+ --repo Ericu950/Stoicheia-restoration-test3 --out runs/t3v4/best.pt
127
+ ```
128
+
129
+ The result is bit-identical to the checkpoint the paper evaluated (268 tensors, max absolute
130
+ difference 0.0). Export `INSC_TEST_DIGIT`/`INSC_VAL_DIGIT` to match the checkpoint's held-out
131
+ digit before running any evaluation below.
132
+
133
+ **Head-to-head against Ithaca and Aeneas (Table 2).** All three systems read the frozen
134
+ 3,000-sample digit-3 file shipped in `insc/eval/frozen/`:
135
+
136
+ ```bash
137
+ python -m insc.eval.restore_strict --ckpt <digit-3 run>/best.pt \
138
+ --samples insc/eval/frozen/strict_test_fold3_samples.json --out ours_strict.json
139
+ python -m insc.eval.ithaca_baseline --samples insc/eval/frozen/strict_test_fold3_samples.json --out ithaca.json
140
+ python -m insc.eval.ptp_baseline --ckpt <aeneas>.pkl \
141
+ --samples insc/eval/frozen/strict_test_fold3_samples.json --out aeneas.json
142
+ ```
143
+
144
+ **Recently edited documents (Tables 3-4).** Scored on the comparison release's own
145
+ documents and normalization, with every system rescored under the same Levenshtein CER:
146
+
147
+ ```bash
148
+ python -m insc.eval.restore_dsh --ckpt <run>/best.pt --data <recent-inscriptions>.jsonl --out ours_recent.json
149
+ python -m insc.eval.ptp_baseline --ckpt <aeneas>.pkl --dsh <recent-inscriptions>.jsonl --out aeneas_recent.json
150
+ python -m analysis.merge_dsh # aggregate shards, macro over gap lengths
151
+ ```
152
+
153
+ **Tagging and parsing (Table 5).** The full 5-fold x 2-seed matrix per encoder:
154
+
155
+ ```bash
156
+ for f in 0 1 2 3 4; do for s in 0 1; do
157
+ sbatch scripts/slurm/syntax_joint_ddp.sbatch configs/syntax/joint_docclean_f${f}_s${s}.json
158
+ done; done
159
+ python -m parser.joint_evaluate --run $STOICHEIA_DATA/parser_data/runs/joint_docclean_f0_s0 --split test
160
+ ```
161
+
162
+ **Macronization and scansion (Tables 6-7).** The macronization ablation uses the
163
+ macron-only runs (`mac_v2*`, six seeds per arm), the scansion ablation the joint runs
164
+ (`joint_docclean*` / `joint_randinit*`); the external macronizer comparison scores the
165
+ joint model on Norma's 1,916 test positions:
166
+
167
+ ```bash
168
+ python -m meter.predict --model $STOICHEIA_DATA/runs/meter_joint_docclean/best.pt --norma
169
+ python -m meter.predict --model $STOICHEIA_DATA/runs/meter_mac_v2/best.pt --norma --norma-source git
170
+ ```
171
+
172
+ `python -m analysis.paper_tables` collects finished evaluation logs into the table
173
+ layouts used in the paper.
174
+
175
+ ## 6. Tests
176
+
177
+ ```bash
178
+ pytest tests/ -q
179
+ ```
180
+ CPU-only, seconds-scale. Covers normalization/packing/noising (pretraining), edit-script
181
+ lemma encoding + dataset construction (tagger), macron/scansion mark parsing (meter),
182
+ plus lightweight forward-pass smoke tests for the restoration and joint tagger/parser
183
+ pipelines (tiny randomly-initialized configs — these check the tensor plumbing survives
184
+ refactors, not model quality).
185
+
186
+ ## Reproducing the 10-fold split itself
187
+
188
+ The split is not an input -- it is constructed by the 13-stage pipeline in
189
+ `data/split_pipeline/` (sentence segmentation, pristine-edition clustering via
190
+ exact/MinHash-LSH/shared-sentence evidence, zone assignment, per-fold exclusion
191
+ masks, documentary decontamination incl. blocklist, bronze back-translation
192
+ filters, verification, manifests). `data/fold_manifests/SPLIT_DESIGN.md`
193
+ documents the design; `fold_k_test_works.tsv.gz` lists every work in fold k's
194
+ test bucket (group id, kind, source, record/char counts, author+title), so the
195
+ "provably never seen" guarantee is checkable work-by-work without rebuilding
196
+ anything.
197
+
198
+ ## Revision naming
199
+
200
+ The paper's reconstruction revisions v1 and v2 correspond, for historical
201
+ reasons, to configuration files named `finetune_whole_v3_*` and
202
+ `finetune_whole_v4_*` respectively (earlier internal iterations v1/v2 were
203
+ superseded before evaluation and are not part of the release).
204
+
205
+ ## External pieces the harnesses expect
206
+
207
+ * Meter training data: `MACRONIZER_SRC` must point at a checkout of the
208
+ `Ericu950/Stoicheia-meter-silver` dataset (silver verse lines + scanner corpus);
209
+ the Norma benchmark itself comes from `Ericu950/norma`.
210
+ * The Ithaca baseline harness (`insc/eval/ithaca_baseline.py`) expects DeepMind's
211
+ Ithaca repository cloned at `ithaca_upstream/` and its released checkpoint;
212
+ the Aeneas harness (`insc/eval/ptp_baseline.py`) expects DeepMind's
213
+ `predictingthepast` repository and its Greek checkpoint. Both are public
214
+ third-party releases and are not vendored here.
Stoicheia_demo.ipynb ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Stoicheia — a character-level model for Ancient Greek\n",
8
+ "\n",
9
+ "Stoicheia is a 405M-parameter character-level masked-diffusion encoder for Ancient Greek.\n",
10
+ "Its input is factored into five aligned planes — letters, word/sentence boundaries,\n",
11
+ "diacritics, capitalization, punctuation — and **any of them can be set to *unknown* at\n",
12
+ "inference**. One model therefore reads an edited text, bare *scriptio continua*, and a\n",
13
+ "lacuna of unknown length, changing nothing but its input.\n",
14
+ "\n",
15
+ "This notebook runs the whole release end to end on a free Colab GPU (CPU works too, slower):\n",
16
+ "\n",
17
+ "1. restore a lacuna whose width is *not known* in advance\n",
18
+ "2. pick the restoration model that has provably **never read** your document\n",
19
+ "3. tag and parse a verse of Homer\n",
20
+ "4. macronize and scan a line of verse\n",
21
+ "5. score the macronizer against a hand-annotated benchmark\n",
22
+ "\n",
23
+ "Every model and dataset used below is public. Anonymous release accompanying a paper under review.\n"
24
+ ]
25
+ },
26
+ {
27
+ "cell_type": "code",
28
+ "metadata": {},
29
+ "execution_count": null,
30
+ "outputs": [],
31
+ "source": [
32
+ "%pip install -q --upgrade transformers huggingface_hub safetensors torch datasets\n"
33
+ ]
34
+ },
35
+ {
36
+ "cell_type": "markdown",
37
+ "metadata": {},
38
+ "source": [
39
+ "## 1. Restoring a lacuna of unknown width\n",
40
+ "\n",
41
+ "The hard case in epigraphy and papyrology is a break whose extent is uncertain, in text that\n",
42
+ "carries no accents and no word division. Write `[N±M]` and the model scores every width in\n",
43
+ "`N-M … N+M` by its own confidence, restoring the letters, the accents and the word boundaries\n",
44
+ "together.\n"
45
+ ]
46
+ },
47
+ {
48
+ "cell_type": "code",
49
+ "metadata": {},
50
+ "execution_count": null,
51
+ "outputs": [],
52
+ "source": [
53
+ "import sys, torch\n",
54
+ "from transformers import AutoModel\n",
55
+ "from huggingface_hub import hf_hub_download, snapshot_download\n",
56
+ "\n",
57
+ "REPO = \"Ericu950/Stoicheia-doc_clean\" # zero exposure to inscriptions or papyri\n",
58
+ "model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()\n",
59
+ "\n",
60
+ "# the processor is a plain helper module, not part of the model classes: fetch it first\n",
61
+ "hf_hub_download(repo_id=REPO, filename=\"processing_char_bert.py\", local_dir=\".\")\n",
62
+ "from processing_char_bert import CharBertProcessor\n",
63
+ "proc = CharBertProcessor()\n",
64
+ "\n",
65
+ "# John 1:1 as it would reach us on a damaged, unaccented, unspaced witness\n",
66
+ "damaged = \"εναρχηηνο[5±3]καιολογοςηνπροστονθεον\"\n",
67
+ "best, width, candidates = proc.restore_elastic(model, damaged, mask_dia_boundary=True)\n",
68
+ "print(\"restored :\", best)\n",
69
+ "print(\"width :\", width, \"characters\")\n",
70
+ "for c in candidates[:5]:\n",
71
+ " print(\" \", c)\n"
72
+ ]
73
+ },
74
+ {
75
+ "cell_type": "markdown",
76
+ "metadata": {},
77
+ "source": [
78
+ "## 2. The model that has never read your document\n",
79
+ "\n",
80
+ "A single fixed train/test split makes a model useless for exactly the documents an editor\n",
81
+ "cares about. Ten restoration checkpoints are released instead, one per held-out final digit\n",
82
+ "of the PHI/TM identifier: whatever inscription or papyrus you are working on, one of the ten\n",
83
+ "has provably never seen it during fine-tuning, and its backbone never saw a documentary text\n",
84
+ "at all. A reading proposed by *that* model cannot be a memory of the edition you are checking.\n"
85
+ ]
86
+ },
87
+ {
88
+ "cell_type": "code",
89
+ "metadata": {},
90
+ "execution_count": null,
91
+ "outputs": [],
92
+ "source": [
93
+ "def model_that_never_read(document_id: str) -> str:\n",
94
+ " \"\"\"Pick the released checkpoint whose held-out digit matches this document.\"\"\"\n",
95
+ " digit = str(document_id).strip()[-1]\n",
96
+ " return f\"Ericu950/Stoicheia-restoration-test{digit}\"\n",
97
+ "\n",
98
+ "for phi in [\"PHI 12345\", \"PHI 293\", \"TM 8100\"]:\n",
99
+ " print(f\"{phi:12s} -> {model_that_never_read(phi)}\")\n",
100
+ "\n",
101
+ "# use it exactly like the backbone above\n",
102
+ "REPO = model_that_never_read(\"PHI 293\")\n",
103
+ "local = snapshot_download(REPO, allow_patterns=[\"*.py\", \"*.json\"])\n",
104
+ "sys.path.insert(0, local)\n",
105
+ "restorer = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()\n",
106
+ "\n",
107
+ "# note the inputs: τηβου and στεφα...ετης carry no accents and no word division.\n",
108
+ "# accents and spacing are predictions here, not requirements, so the model fills\n",
109
+ "# the gap and decides where the words end in the same pass.\n",
110
+ "print(\"\\n\", proc.restore_respaced(restorer, \"ἔδοξεν τηβου-- καὶ τῷ δήμῳ\"))\n",
111
+ "# -> ἔδοξεν τῇ βουλῇ καὶ τῷ δήμῳ\n",
112
+ "print(proc.restore_respaced(restorer, \"στεφανῶσαι αὐτὸν χρυσῷ στεφα[3±1]ετης ἕνεκα\"))\n",
113
+ "# -> στεφανῶσαι αὐτὸν χρυσῷ στεφάνῳ ἀρετῆς ἕνεκα\n"
114
+ ]
115
+ },
116
+ {
117
+ "cell_type": "markdown",
118
+ "metadata": {},
119
+ "source": [
120
+ "## 3. Tagging and parsing\n",
121
+ "\n",
122
+ "Four heads on one shared backbone — factored XPOS, an edit-script lemmatizer, a UPOS\n",
123
+ "auxiliary and a biaffine dependency parser — all from a single forward pass.\n"
124
+ ]
125
+ },
126
+ {
127
+ "cell_type": "code",
128
+ "metadata": {},
129
+ "execution_count": null,
130
+ "outputs": [],
131
+ "source": [
132
+ "from huggingface_hub import snapshot_download\n",
133
+ "REPO = \"Ericu950/Stoicheia-tagger-parser\"\n",
134
+ "local = snapshot_download(REPO, allow_patterns=[\"*.json\", \"*.txt\", \"*.py\", \"*.model\"])\n",
135
+ "sys.path.insert(0, local)\n",
136
+ "from processing_char_bert_joint import CharBertJointProcessor\n",
137
+ "\n",
138
+ "parser_model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()\n",
139
+ "jproc = CharBertJointProcessor.from_pretrained(local)\n",
140
+ "\n",
141
+ "words = \"μῆνιν ἄειδε θεὰ Πηληϊάδεω Ἀχιλῆος\".split()\n",
142
+ "batch = jproc([words])\n",
143
+ "with torch.no_grad():\n",
144
+ " out = parser_model(**batch)\n",
145
+ "rows = jproc.decode(out, batch, ud=True)\n",
146
+ "\n",
147
+ "sent = rows[0] if rows and not isinstance(rows[0], dict) else rows\n",
148
+ "hdr = ('id', 'form', 'lemma', 'upos', 'head', 'deprel')\n",
149
+ "print('%3s %-12s%-12s%-8s%4s %s' % hdr)\n",
150
+ "for i, w in enumerate(sent, 1):\n",
151
+ " print('%3d %-12s%-12s%-8s%4s %s' % (i, w['form'], w['lemma'], w['upos'], w['head'], w['deprel']))\n"
152
+ ]
153
+ },
154
+ {
155
+ "cell_type": "markdown",
156
+ "metadata": {},
157
+ "source": [
158
+ "## 4. Vowel length and metre\n",
159
+ "\n",
160
+ "Greek orthography never marks vowel length: α, ι and υ — the *dichrona* — are ambiguous.\n",
161
+ "Recovering it (*macronization*) is lexical knowledge, and it is the prerequisite for scanning\n",
162
+ "verse. `Stoicheia-meter` does both at once; `Stoicheia-macronizer` does vowel length alone,\n",
163
+ "slightly better.\n"
164
+ ]
165
+ },
166
+ {
167
+ "cell_type": "code",
168
+ "metadata": {},
169
+ "execution_count": null,
170
+ "outputs": [],
171
+ "source": [
172
+ "REPO = \"Ericu950/Stoicheia-meter\"\n",
173
+ "local = snapshot_download(REPO, allow_patterns=[\"*.json\", \"*.txt\", \"*.py\", \"*.model\"])\n",
174
+ "sys.path.insert(0, local)\n",
175
+ "from processing_char_bert_meter import CharBertMeterProcessor\n",
176
+ "\n",
177
+ "meter_model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()\n",
178
+ "mproc = CharBertMeterProcessor()\n",
179
+ "\n",
180
+ "line = \"ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ\"\n",
181
+ "batch = mproc(line)\n",
182
+ "with torch.no_grad():\n",
183
+ " out = meter_model(**{k: v for k, v in batch.items() if not k.startswith(\"_\")})\n",
184
+ "print(\"macronized:\", mproc.decode_macronization(out, batch)) # _ long, ^ short\n",
185
+ "print(\"scanned :\", mproc.decode_scansion(out, batch)) # [heavy] {light}\n"
186
+ ]
187
+ },
188
+ {
189
+ "cell_type": "markdown",
190
+ "metadata": {},
191
+ "source": [
192
+ "## 5. Scoring against the benchmark\n",
193
+ "\n",
194
+ "*Norma Syllabarum Graecarum* is a hand-annotated benchmark of macronization and\n",
195
+ "syllabification. Here we score the dedicated macronizer on its test split — every ambiguous\n",
196
+ "α/ι/υ position, compared against the gold mark.\n"
197
+ ]
198
+ },
199
+ {
200
+ "cell_type": "code",
201
+ "metadata": {},
202
+ "execution_count": null,
203
+ "outputs": [],
204
+ "source": [
205
+ "import json, re\n",
206
+ "from huggingface_hub import hf_hub_download\n",
207
+ "\n",
208
+ "REPO = \"Ericu950/Stoicheia-macronizer\"\n",
209
+ "local = snapshot_download(REPO, allow_patterns=[\"*.json\", \"*.txt\", \"*.py\", \"*.model\"])\n",
210
+ "sys.path.insert(0, local)\n",
211
+ "mac_model = AutoModel.from_pretrained(REPO, trust_remote_code=True).eval()\n",
212
+ "\n",
213
+ "path = hf_hub_download(\"Ericu950/norma\", \"data/test.jsonl\", repo_type=\"dataset\")\n",
214
+ "rows = [json.loads(l) for l in open(path, encoding=\"utf-8\")]\n",
215
+ "rows = [r for r in rows if r[\"task\"] == \"macronize\"][:120] # raise for the full set\n",
216
+ "\n",
217
+ "MARKS = re.compile(r\"[_^]\")\n",
218
+ "n = correct = 0\n",
219
+ "for r in rows:\n",
220
+ " gold = r[\"text\"]\n",
221
+ " raw = MARKS.sub(\"\", gold)\n",
222
+ " batch = mproc(raw)\n",
223
+ " with torch.no_grad():\n",
224
+ " out = mac_model(**{k: v for k, v in batch.items() if not k.startswith(\"_\")})\n",
225
+ " pred = mproc.decode_macronization(out, batch)\n",
226
+ " for g, p in zip(gold, pred):\n",
227
+ " pass\n",
228
+ " # compare mark-by-mark at the positions the gold marks\n",
229
+ " gi = pi = 0\n",
230
+ " while gi < len(gold) and pi < len(pred):\n",
231
+ " if gold[gi] in \"_^\" and pred[pi] in \"_^\":\n",
232
+ " n += 1; correct += (gold[gi] == pred[pi]); gi += 1; pi += 1\n",
233
+ " elif gold[gi] in \"_^\":\n",
234
+ " n += 1; gi += 1\n",
235
+ " elif pred[pi] in \"_^\":\n",
236
+ " pi += 1\n",
237
+ " else:\n",
238
+ " gi += 1; pi += 1\n",
239
+ "print(f\"macronization accuracy on {len(rows)} lines: {100*correct/max(n,1):.2f}% ({n} scored positions)\")\n"
240
+ ]
241
+ },
242
+ {
243
+ "cell_type": "markdown",
244
+ "metadata": {},
245
+ "source": [
246
+ "---\n",
247
+ "\n",
248
+ "**Everything in the release**\n",
249
+ "\n",
250
+ "| | |\n",
251
+ "|---|---|\n",
252
+ "| 11 pretrained backbones | ten rotated literary folds + one documentary-clean |\n",
253
+ "| 10 restoration checkpoints | one per held-out PHI/TM digit |\n",
254
+ "| tagger-parser, meter, macronizer | fine-tuned from the documentary-clean backbone |\n",
255
+ "| 5 datasets | pretraining corpus, synthetic augmentation, inscriptions, meter silver, benchmark |\n",
256
+ "\n",
257
+ "Training and evaluation code, including the split pipeline that produces the decontamination\n",
258
+ "guarantee, is in the accompanying code repository.\n"
259
+ ]
260
+ }
261
+ ],
262
+ "metadata": {
263
+ "kernelspec": {
264
+ "display_name": "Python 3",
265
+ "language": "python",
266
+ "name": "python3"
267
+ },
268
+ "language_info": {
269
+ "name": "python"
270
+ },
271
+ "colab": {
272
+ "provenance": [],
273
+ "toc_visible": true
274
+ },
275
+ "accelerator": "GPU"
276
+ },
277
+ "nbformat": 4,
278
+ "nbformat_minor": 0
279
+ }
analysis/merge_dsh.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Merge sharded restore_dsh.py outputs and print the three-way comparison.
2
+
3
+ Shards are stride slices, so each covers all gap lengths; merging re-weights each
4
+ length by its own sample count rather than averaging shard means (which would be
5
+ wrong whenever shards see different numbers of samples at a length).
6
+
7
+ The headline "Overall Average CER" in the DSH 41(1) comparison paper (2026) is the mean of the ten
8
+ per-length means, so that is what we report as CER_macro for comparability; the
9
+ sample-weighted CER_micro is printed alongside rather than chosen selectively.
10
+
11
+ python3 analysis/merge_dsh.py
12
+ """
13
+ import glob, json, os
14
+
15
+ BASE = os.path.join(os.path.dirname(__file__), "dsh")
16
+
17
+ # Published reference numbers, the DSH 41(1) comparison paper (2026) DSH 41(1) 69-76, recent/unedited sets.
18
+ # Inscriptions verified reproducible from their released per-record predictions
19
+ # (top-1 51.28%, top-20 68.62% reproduced exactly; CER 0.2859 published).
20
+ # Ithaca and papyri rows were scored by us from the released per-record predictions
21
+ # using the verified metric port (our calculate_cer reproduces their stored CER with
22
+ # zero difference, and their published inscription top-1/top-20 to the decimal).
23
+ REF = {
24
+ "inscr": {
25
+ "Llama 3.1 8B (DSH 2026)": dict(CER=0.2859, top1=0.5128, top20=0.6862),
26
+ "Ithaca (Assael et al. 2022)": dict(CER=0.3118, top1=0.4841, top20=0.6067),
27
+ },
28
+ "pap": {
29
+ "Llama 3.1 8B (DSH 2026)": dict(CER=0.3010, top1=0.5037, top20=0.7051),
30
+ # Ithaca is inscriptions-only: no papyri row exists, by design not omission.
31
+ },
32
+ }
33
+
34
+
35
+ def merge(pattern):
36
+ per_len, tot, t1, t20 = {}, 0, 0.0, 0.0
37
+ files = sorted(glob.glob(pattern))
38
+ for f in files:
39
+ d = json.load(open(f))
40
+ for L, v in d.get("by_length", {}).items():
41
+ a = per_len.setdefault(int(L), dict(n=0, cer=0.0, t1=0.0, t20=0.0))
42
+ a["n"] += v["n"]
43
+ a["cer"] += v["CER"] * v["n"] # back out the sum from the mean
44
+ a["t1"] += v["top1"] * v["n"]
45
+ a["t20"] += v["top20"] * v["n"]
46
+ tot += d["n"]; t1 += d["top1"] * d["n"]; t20 += d["top20"] * d["n"]
47
+ if not per_len:
48
+ return None
49
+ by = {L: dict(n=a["n"], CER=a["cer"] / a["n"], top1=a["t1"] / a["n"],
50
+ top20=a["t20"] / a["n"]) for L, a in sorted(per_len.items())}
51
+ return dict(shards=len(files), n=tot,
52
+ CER_macro=sum(v["CER"] for v in by.values()) / len(by),
53
+ CER_micro=sum(v["CER"] * v["n"] for v in by.values()) / tot,
54
+ top1=t1 / tot, top20=t20 / tot, by_length=by)
55
+
56
+
57
+ for tag, name in (("inscr", "RECENT INSCRIPTIONS"), ("pap", "RECENT PAPYRI")):
58
+ m = merge(f"{BASE}/v4_recent_{tag}_s*.json")
59
+ print("=" * 72); print(name); print("=" * 72)
60
+ if not m:
61
+ print(" (no shard output yet)\n"); continue
62
+ print(f" shards={m['shards']} n={m['n']}")
63
+ print(f" {'system':<32}{'CER':>8}{'top-1':>9}{'top-20':>9}")
64
+ print(f" {'Stoicheia (ours, 405M)':<32}{m['CER_macro']:>8.4f}{m['top1']:>9.4f}{m['top20']:>9.4f}")
65
+ for k, v in REF[tag].items():
66
+ print(f" {k:<32}{v['CER']:>8.4f}{v['top1']:>9.4f}{v['top20']:>9.4f}")
67
+ print(f" (ours sample-weighted CER {m['CER_micro']:.4f}; macro is the comparable one)")
68
+ print(" per length:")
69
+ for L, v in m["by_length"].items():
70
+ print(f" L={L:<3} n={v['n']:<5} CER={v['CER']:.4f} top1={v['top1']:.4f} top20={v['top20']:.4f}")
71
+ print()
analysis/merge_ptp.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Merge sharded ptp_baseline.py outputs for the Aeneas-Greek (Nature 2025) rows.
2
+
3
+ Strict shards are per-length files (strict_L{L}_s{i}.json); recent shards are
4
+ stride slices (recent_s{i}.json). Both are merged per length with sample-count
5
+ weighting, then summarized the same two ways as the existing tables:
6
+ * strict: AVG over L=1..10 of per-length means (the convention of the
7
+ strict table) -- comparable to the Ithaca/Stoicheia rows there.
8
+ * recent: macro over lengths + sample-weighted micro, comparable to the
9
+ uncontaminated table rows.
10
+
11
+ python3 analysis/merge_ptp.py
12
+ """
13
+ import glob, json, os
14
+
15
+ D = os.path.expandvars("$STOICHEIA_ROOT/ptp_out")
16
+
17
+
18
+ def merge(pattern):
19
+ per = {}
20
+ err = 0
21
+ for f in sorted(glob.glob(f"{D}/{pattern}")):
22
+ d = json.load(open(f))
23
+ err += d.get("errors", 0)
24
+ for L, v in d.get("per_L", {}).items():
25
+ a = per.setdefault(int(L), dict(n=0, cer=0.0, t1=0.0, t20=0.0))
26
+ a["n"] += v["n"]
27
+ a["cer"] += v["CER"] * v["n"]
28
+ a["t1"] += v["top1"] * v["n"]
29
+ a["t20"] += v["top20"] * v["n"]
30
+ if not per:
31
+ return None
32
+ by = {L: dict(n=a["n"], CER=a["cer"] / a["n"], top1=a["t1"] / a["n"],
33
+ top20=a["t20"] / a["n"]) for L, a in sorted(per.items())}
34
+ n = sum(v["n"] for v in by.values())
35
+ return dict(errors=err, n=n,
36
+ CER_macro=sum(v["CER"] for v in by.values()) / len(by),
37
+ top1=sum(v["top1"] * v["n"] for v in by.values()) / n,
38
+ top20=sum(v["top20"] * v["n"] for v in by.values()) / n,
39
+ by_length=by)
40
+
41
+
42
+ for name, pat, ref in (
43
+ ("STRICT (vs Table 1: Ithaca 24.55/63.0/74.9, Stoicheia v4 15.46/74.5/81.7)",
44
+ "strict_L*_s*.json", 3000),
45
+ ("RECENT INSCRIPTIONS (vs Table: Ithaca 31.18/48.41/60.67, "
46
+ "Llama 28.59/51.28/68.62, Stoicheia 20.20/64.41/73.34)",
47
+ "recent_s*.json", 4111),
48
+ ):
49
+ m = merge(pat)
50
+ print("=" * 74)
51
+ print("AENEAS-GREEK 2025 --", name)
52
+ if not m:
53
+ print(" (no output yet)")
54
+ continue
55
+ done = m["n"]
56
+ print(f" n={done}/{ref} errors={m['errors']}")
57
+ print(f" CER={m['CER_macro']:.4f} top1={m['top1']:.4f} top20={m['top20']:.4f}")
58
+ for L, v in m["by_length"].items():
59
+ print(f" L={L:<3} n={v['n']:<4} CER={v['CER']:.4f} "
60
+ f"top1={v['top1']:.4f} top20={v['top20']:.4f}")
analysis/paper_tables.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Regenerate every paper table from results already on disk. Reads only; safe to run
2
+ at any time and shows partial state (n=) while jobs are still finishing.
3
+
4
+ python3 analysis/paper_tables.py # all three experiments
5
+ python3 analysis/paper_tables.py parsing # documentary | parsing | meter
6
+ """
7
+ from __future__ import annotations
8
+ import collections, glob, json, os, re, sys
9
+ import numpy as np
10
+
11
+ GCB=os.path.expandvars("$STOICHEIA_DATA")
12
+ INSC=os.path.expandvars("$STOICHEIA_DATA")
13
+ REPO=os.path.expandvars("$STOICHEIA_ROOT")
14
+
15
+ def _agg(v): return (np.mean(v), np.std(v), len(v)) if v else (float("nan"), 0.0, 0)
16
+
17
+ def parsing():
18
+ print("\n"+"="*78); print("EXPERIMENT 2 -- PARSING (joint tagger+parser, OGA 5 folds x 2 seeds)"); print("="*78)
19
+ g=collections.defaultdict(list)
20
+ for d in sorted(glob.glob(f"{GCB}/parser_data/runs/joint_*_f*_s*")):
21
+ p=os.path.join(d,"test_scores_greedy.json")
22
+ if not os.path.exists(p): continue
23
+ j=json.load(open(p))
24
+ if j.get("las") is None: continue
25
+ tag=re.sub(r"_f\d+_s\d+$","",os.path.basename(d))
26
+ # joint_tune_* are single-fold LR-sweep diagnostics -- reported by lr_control(),
27
+ # not systems for the main table (an n=1 row next to n=10 rows invites misreading)
28
+ if tag.startswith("joint_tune_"): continue
29
+ g[tag].append((j["las"], j["uas"], j["xpos_exact"], j["upos"]))
30
+ if not g: print(" (no results yet)"); return
31
+ print(f"{'system':<24}{'n':>3} {'LAS':>15} {'UAS':>8} {'XPOS':>8} {'UPOS':>8}")
32
+ for tag,v in sorted(g.items(), key=lambda kv:-np.mean([x[0] for x in kv[1]])):
33
+ m,s,n=_agg([x[0] for x in v])
34
+ star=" <- ours" if tag=="joint_docclean" else (" <- pretraining ablation" if tag=="joint_randinit" else "")
35
+ print(f"{tag.replace('joint_',''):<24}{n:>3} {m:.4f}+-{s:.4f} "
36
+ f"{np.mean([x[1] for x in v]):.4f} {np.mean([x[2] for x in v]):.4f} "
37
+ f"{np.mean([x[3] for x in v]):.4f}{star}")
38
+ if g.get("joint_docclean") and g.get("joint_randinit"):
39
+ a=np.mean([x[0] for x in g["joint_docclean"]]); b=np.mean([x[0] for x in g["joint_randinit"]])
40
+ print(f"\n PRETRAINING EFFECT: {100*(a-b):+.1f} LAS points")
41
+ # Headline margin must be against the STRONGEST baseline at ITS OWN tuned LR, not
42
+ # against a baseline handicapped by our shared recipe (see lr_control below).
43
+ if g.get("joint_docclean"):
44
+ a=np.mean([x[0] for x in g["joint_docclean"]])
45
+ cands={k:np.mean([x[0] for x in v]) for k,v in g.items()
46
+ if k not in ("joint_docclean","joint_docclean_long","joint_randinit",
47
+ "joint_randinit_long") and len(v)>=8}
48
+ if cands:
49
+ bk=max(cands,key=cands.get)
50
+ print(f" vs strongest baseline ({bk.replace('joint_','')}, n>=8): "
51
+ f"{100*(a-cands[bk]):+.1f} LAS points")
52
+ if g.get("joint_docclean") and g.get("joint_randinit_long"):
53
+ a=np.mean([x[0] for x in g["joint_docclean"]])
54
+ b=np.mean([x[0] for x in g["joint_randinit_long"]])
55
+ print(f" PRETRAINING EFFECT (converged random-init): {100*(a-b):+.1f} LAS points")
56
+
57
+ def lr_control():
58
+ print("\n" + "-"*78)
59
+ print("BASELINE-TUNING CONTROL (fold 0 / seed 0): is the shared recipe unfair to the")
60
+ print("subword baselines? lr_enc swept for them AND for us.")
61
+ print("-"*78)
62
+ S=f"{GCB}/parser_data/runs"
63
+ for enc,label in (("docclean","ours"),("philberta","PhilBerta"),("greberta","GreBerta")):
64
+ row=[]
65
+ b=os.path.join(S,f"joint_{enc}_f0_s0","test_scores_greedy.json")
66
+ if os.path.exists(b): row.append(("1e-04*", json.load(open(b))["las"]))
67
+ for d in sorted(glob.glob(f"{S}/joint_tune_{enc}_lr*_f0_s0")):
68
+ q=os.path.join(d,"test_scores_greedy.json")
69
+ if not os.path.exists(q): continue
70
+ v=re.search(r"_lr([0-9.e-]+)_f0",os.path.basename(d)).group(1)
71
+ row.append((f"{float(v):.0e}", json.load(open(q))["las"]))
72
+ if not row: continue
73
+ row.sort(key=lambda r: float(r[0].rstrip("*")))
74
+ best=max(row,key=lambda r:r[1])
75
+ print(f" {label:<10} " + " ".join(f"{k}:{v:.4f}" for k,v in row)
76
+ + f" -> best {best[0]} ({best[1]:.4f})")
77
+ print(" (* = shared recipe used for the main table)")
78
+
79
+
80
+ def meter():
81
+ print("\n"+"="*78); print("EXPERIMENT 3 -- METER (macronization, Norma test, git source, n=2660)"); print("="*78)
82
+ rows=collections.defaultdict(dict)
83
+ for f in sorted(glob.glob(f"{REPO}/logs/eval-*.out")):
84
+ txt=open(f, errors="ignore").read()
85
+ if "--norma" not in txt: continue
86
+ mm=re.search(r"model=(\S+)", txt); mt=re.search(r"macron test: (\{.*?\})", txt)
87
+ if not (mm and mt): continue
88
+ run=mm.group(1).split("/runs/")[-1].split("/")[0]
89
+ if not run.startswith("meter_mac_v2"): continue
90
+ d=json.loads(mt.group(1))
91
+ rows["random-init" if "randinit" in run else "pretrained"][run]=(
92
+ d["bal_acc"], d["acc"], d["macro_bal_acc"])
93
+ if not rows: print(" (no results yet)"); return
94
+ print(f"{'arm':<14}{'n':>3} {'balanced acc':>16} {'acc':>8} {'macro-bal':>10}")
95
+ means={}
96
+ for arm in ("pretrained","random-init"):
97
+ v=list(rows.get(arm,{}).values())
98
+ if not v: continue
99
+ m,s,n=_agg([x[0] for x in v]); means[arm]=m
100
+ print(f"{arm:<14}{n:>3} {m:.4f}+-{s:.4f} {np.mean([x[1] for x in v]):.4f} "
101
+ f"{np.mean([x[2] for x in v]):.4f}")
102
+ if len(means)==2:
103
+ print(f"\n PRETRAINING EFFECT: {100*(means['pretrained']-means['random-init']):+.1f} points balanced accuracy")
104
+
105
+ def documentary():
106
+ print("\n"+"="*78); print("EXPERIMENT 1 -- DOCUMENTARY RECONSTRUCTION (inscriptions + papyri)"); print("="*78)
107
+ prot={"iphi_whole_unk":"inscriptions, whole-doc (no meta)",
108
+ "iphi_clean_unk":"inscriptions, clean ctx (no meta)",
109
+ "iphi_whole_meta":"inscriptions, whole-doc (+meta)",
110
+ "pap_whole_unk":"papyri, whole-doc (no meta)"}
111
+ for ver,label in (("v4","v4 (6-tier mix, pilot)"),
112
+ ("v3","v3 (pretrained)"),
113
+ ("v3_randinit","v3 RANDOM-INIT (pretraining ablation)"),
114
+ ("v2","v2 (undertrained, superseded)")):
115
+ agg=collections.defaultdict(list)
116
+ for f in glob.glob(f"{REPO}/.scratch/evals/{ver}_t*.json"):
117
+ p=os.path.basename(f)[len(ver)+1:-5][5:]
118
+ if p not in prot: continue
119
+ d=json.load(open(f)); agg[p].append((d["avg"]["CER"], d["avg"]["top1"], d["avg"]["top20"]))
120
+ if not agg: continue
121
+ print(f"\n -- {label} --")
122
+ for k,lab in prot.items():
123
+ if k not in agg: continue
124
+ m,s,n=_agg([x[0] for x in agg[k]])
125
+ print(f" {lab:<36} n={n:>2} CER={m:.4f}+-{s:.4f} "
126
+ f"top1={np.mean([x[1] for x in agg[k]]):.4f} top20={np.mean([x[2] for x in agg[k]]):.4f}")
127
+ print("\n -- STRICT Ithaca-comparable (PHI digit-3 test, whole inscriptions,")
128
+ print(" real lacunae in context, SPACES COUNTED, beam 20, no metadata) --")
129
+ def merge(files):
130
+ a=collections.defaultdict(lambda: dict(n=0,cer=0.0,cl=0.0,t1=0.0,t20=0.0))
131
+ for f in files:
132
+ try: d=json.load(open(f))
133
+ except Exception: continue
134
+ for r in d.get("per_L",[]):
135
+ x=a[r["L"]]; n=r["n"]; x["n"]+=n; x["cer"]+=r["CER"]*n
136
+ x["cl"]+=(r.get("CER_letters") or 0)*n; x["t1"]+=r["top1"]*n; x["t20"]+=r["top20"]*n
137
+ return a
138
+ for tag,pat in (("Ithaca (DeepMind release)", f"{INSC}/strict_f3/ithaca_shard*.json"),
139
+ ("ours old (both_ft_docclean)", f"{INSC}/strict_f3/ours_old.json"),
140
+ ("ours v2 (undertrained)", f"{INSC}/strict_f3/ours_v2_shard*.json"),
141
+ ("ours v3", f"{INSC}/strict_f3/ours_v3_shard*.json"),
142
+ ("ours v4 (pilot)", f"{INSC}/strict_f3/ours_v4_shard*.json")):
143
+ fs=sorted(glob.glob(pat))
144
+ if not fs: continue
145
+ a=merge(fs)
146
+ if not a: continue
147
+ Ls=sorted(a)
148
+ cer=np.mean([a[L]["cer"]/max(a[L]["n"],1) for L in Ls])
149
+ cl=np.mean([a[L]["cl"]/max(a[L]["n"],1) for L in Ls])
150
+ t1=np.mean([a[L]["t1"]/max(a[L]["n"],1) for L in Ls])
151
+ t20=np.mean([a[L]["t20"]/max(a[L]["n"],1) for L in Ls])
152
+ ntot=sum(a[L]["n"] for L in Ls)
153
+ extra=f" CER_let={cl:.4f}" if cl>0 else ""
154
+ print(f" {tag:<30} CER={cer:.4f}{extra} top1={t1:.4f} top20={t20:.4f} (n={ntot})")
155
+
156
+ def scanner():
157
+ print("\n" + "="*78)
158
+ print("EXPERIMENT 3b -- SCANNER (Norma syllabify test, joint model, git source)")
159
+ print("="*78)
160
+ rows=collections.defaultdict(dict)
161
+ for f in sorted(glob.glob(f"{REPO}/logs/eval-*.out")):
162
+ t=open(f,errors="ignore").read()
163
+ mm=re.search(r"model=(\S+)",t); ms=re.search(r"norma syllabify \(test\) ===\n (\{.*?\})",t)
164
+ if not(mm and ms): continue
165
+ run=mm.group(1).split("/runs/")[-1].split("/")[0]
166
+ # joint_pilot is an older, different config -- not part of the seed-matched ablation
167
+ if not run.startswith("meter_joint") or run=="meter_joint_pilot": continue
168
+ d=json.loads(ms.group(1))
169
+ arm="random-init" if "randinit" in run else "pretrained"
170
+ rows[arm][run]=(d["bal_acc"], d["acc"], d["boundary_f1"])
171
+ if not rows: print(" (no results yet)"); return
172
+ print(f"{'arm':<14}{'n':>3} {'balanced acc':>16} {'acc':>8} {'boundary F1':>12}")
173
+ means={}
174
+ for arm in ("pretrained","random-init"):
175
+ v=list(rows.get(arm,{}).values())
176
+ if not v: continue
177
+ m,sd,n=_agg([x[0] for x in v]); means[arm]=m
178
+ print(f"{arm:<14}{n:>3} {m:.4f}+-{sd:.4f} {np.mean([x[1] for x in v]):.4f} "
179
+ f"{np.mean([x[2] for x in v]):.4f}")
180
+ if len(means)==2:
181
+ print(f"\n PRETRAINING EFFECT: {100*(means['pretrained']-means['random-init']):+.1f} pts balanced accuracy")
182
+
183
+
184
+ if __name__=="__main__":
185
+ w=sys.argv[1] if len(sys.argv)>1 else "all"
186
+ if w in ("all","documentary"): documentary()
187
+ if w in ("all","parsing"): parsing(); lr_control()
188
+ if w in ("all","meter"): meter(); scanner()
189
+ print()
analysis/pick_ckpt.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Per-fold checkpoint selection on dev CER, using numbers already in the training log.
2
+
3
+ The v3 runs selected best.pt on bits_per_char, but bpc and dev CER decorrelate late in
4
+ training (r~0.82) -- bpc bottoms out and rises while CER keeps improving. So best.pt can
5
+ be ~0.02 dev CER worse than the run's end state. Both best.pt and last.pt are legitimate
6
+ checkpoints; choosing between them on DEV CER is standard model selection (dev is exactly
7
+ what selection is for) and costs no GPU, because every eval's dev CER is in the log.
8
+
9
+ python3 analysis/pick_ckpt.py # report
10
+ python3 analysis/pick_ckpt.py --write # write chosen_ckpt.txt into each run dir
11
+ """
12
+ import glob, json, os, re, sys
13
+ I=os.path.expandvars("$STOICHEIA_DATA/insc_data/runs")
14
+ write="--write" in sys.argv
15
+ print(f"{'run':<28}{'best.pt cer':>12}{'last.pt cer':>12} choice")
16
+ for d in sorted(glob.glob(f"{I}/whole_v*")):
17
+ ev=os.path.join(d,"eval.jsonl")
18
+ if not os.path.exists(ev): continue
19
+ rows=[json.loads(l) for l in open(ev)]
20
+ if not rows: continue
21
+ # best.pt = argmin bpc (how these runs were selected); last.pt = final eval
22
+ bb=min(rows,key=lambda r:r["bits_per_char"])
23
+ last=rows[-1]
24
+ pick="best.pt" if bb["dev_cer"]<=last["dev_cer"] else "last.pt"
25
+ gain=abs(bb["dev_cer"]-last["dev_cer"])
26
+ flag="" if pick=="best.pt" else f" (+{gain:.4f} CER recovered)"
27
+ print(f"{os.path.basename(d):<28}{bb['dev_cer']:>12.4f}{last['dev_cer']:>12.4f} {pick}{flag}")
28
+ if write:
29
+ open(os.path.join(d,"chosen_ckpt.txt"),"w").write(pick+"\n")
analysis/sig_all.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Paired significance tests for ALL three experiments.
2
+
3
+ Everything is paired on the unit that was actually replicated -- (fold, seed) for parsing,
4
+ fold for documentary, seed for meter -- so each comparison controls for split difficulty
5
+ and only the system varies. The headline p-value is an EXACT sign-flip permutation test
6
+ (no distributional assumption); note its floor is 2/2^n, so p=0.002 at n=10 is the
7
+ smallest attainable value, not a coincidence. d_z is paired Cohen's d.
8
+ """
9
+ from __future__ import annotations
10
+ import collections, glob, json, math, os, re, sys
11
+ import numpy as np
12
+
13
+ GCB=os.path.expandvars("$STOICHEIA_DATA")
14
+ REPO=os.path.expandvars("$STOICHEIA_ROOT")
15
+
16
+ def _ttest_rel_p(d):
17
+ """Two-sided paired t-test p-value without scipy (survival fn of |t| via a
18
+ continued-fraction incomplete beta -- keeps this script dependency-free so the
19
+ released code needs only numpy)."""
20
+ n=len(d); sd=d.std(ddof=1)
21
+ if sd==0 or n<2: return float("nan")
22
+ t=abs(d.mean())/(sd/np.sqrt(n)); v=n-1
23
+ x=v/(v+t*t)
24
+ # regularised incomplete beta I_x(v/2, 1/2) via Lentz continued fraction
25
+ a,b=v/2.0,0.5
26
+ lbeta=(math.lgamma(a)+math.lgamma(b)-math.lgamma(a+b))
27
+ def betacf(a,b,x,itmax=300,eps=3e-16):
28
+ qab,qap,qam=a+b,a+1.0,a-1.0
29
+ c=1.0; d_=1.0-qab*x/qap
30
+ if abs(d_)<1e-30: d_=1e-30
31
+ d_=1.0/d_; h=d_
32
+ for m in range(1,itmax+1):
33
+ m2=2*m
34
+ aa=m*(b-m)*x/((qam+m2)*(a+m2))
35
+ d_=1.0+aa*d_; c=1.0+aa/c
36
+ if abs(d_)<1e-30: d_=1e-30
37
+ if abs(c)<1e-30: c=1e-30
38
+ d_=1.0/d_; h*=d_*c
39
+ aa=-(a+m)*(qab+m)*x/((a+m2)*(qap+m2))
40
+ d_=1.0+aa*d_; c=1.0+aa/c
41
+ if abs(d_)<1e-30: d_=1e-30
42
+ if abs(c)<1e-30: c=1e-30
43
+ d_=1.0/d_; delta=d_*c; h*=delta
44
+ if abs(delta-1.0)<eps: break
45
+ return h
46
+ if x < (a+1.0)/(a+b+2.0):
47
+ ib=np.exp(a*np.log(x)+b*np.log(1-x)-lbeta)*betacf(a,b,x)/a
48
+ else:
49
+ ib=1.0-np.exp(b*np.log(1-x)+a*np.log(x)-lbeta)*betacf(b,a,1-x)/b
50
+ return float(min(1.0, max(0.0, ib)))
51
+
52
+
53
+ def perm_p(diff):
54
+ n=len(diff); obs=abs(diff.mean())
55
+ if n<=20:
56
+ c=t=0
57
+ for m in range(1<<n):
58
+ s=np.array([1 if m>>i&1 else -1 for i in range(n)])
59
+ c+= abs((diff*s).mean())>=obs-1e-12; t+=1
60
+ return c/t
61
+ rng=np.random.default_rng(0)
62
+ s=rng.choice([-1,1],size=(100000,n))
63
+ return float((np.abs((diff*s).mean(1))>=obs-1e-12).mean())
64
+
65
+ def report(title, unit, a_name, a, b_name, b, higher_better=True):
66
+ keys=sorted(set(a)&set(b))
67
+ if len(keys)<3:
68
+ print(f" {a_name} vs {b_name}: only {len(keys)} paired {unit}s -- not testable yet"); return
69
+ x=np.array([a[k] for k in keys]); y=np.array([b[k] for k in keys])
70
+ d=(x-y) if higher_better else (y-x)
71
+ p=perm_p(d); dz=d.mean()/(d.std(ddof=1)+1e-12)
72
+ t=_ttest_rel_p(d)
73
+ print(f" {a_name} vs {b_name}: n={len(keys)} {unit}s mean diff={d.mean():+.4f} "
74
+ f"perm p={p:.2e} t p={t:.1e} d_z={dz:.1f}")
75
+
76
+ def parsing():
77
+ print("\nPARSING (LAS, paired by fold+seed; higher better)")
78
+ S=f"{GCB}/parser_data/runs"; g=collections.defaultdict(dict)
79
+ for d in sorted(glob.glob(f"{S}/joint_*_f*_s*")):
80
+ f=os.path.join(d,"test_scores_greedy.json")
81
+ if not os.path.exists(f): continue
82
+ j=json.load(open(f))
83
+ if j.get("las") is None: continue
84
+ b=os.path.basename(d); m=re.search(r"_(f\d+_s\d+)$",b)
85
+ g[re.sub(r"_f\d+_s\d+$","",b)][m.group(1)]=j["las"]
86
+ ref=g.get("joint_docclean",{})
87
+ for k in sorted(g):
88
+ if k=="joint_docclean": continue
89
+ # joint_tune_* are single-fold LR-sweep diagnostics (reported separately as the
90
+ # baseline-tuning control), not systems to significance-test.
91
+ if k.startswith("joint_tune_"): continue
92
+ report("", "run", "ours", ref, k.replace("joint_",""), g[k])
93
+
94
+ def documentary():
95
+ print("\nDOCUMENTARY (CER, paired by fold; LOWER better)")
96
+ def load(ver):
97
+ out={}
98
+ for f in glob.glob(f"{REPO}/.scratch/evals/{ver}_t*_iphi_whole_unk.json"):
99
+ tv=re.search(r"_(t\dv\d)_",os.path.basename(f)).group(1)
100
+ out[tv]=json.load(open(f))["avg"]["CER"]
101
+ return out
102
+ v3=load("v3"); ri=load("v3_randinit"); v2=load("v2")
103
+ if v3 and ri: report("", "fold", "v3", v3, "random-init", ri, higher_better=False)
104
+ if v3 and v2: report("", "fold", "v3", v3, "v2 (superseded)", v2, higher_better=False)
105
+ if not v3: print(" (v3 evals not written yet)")
106
+
107
+ def strict_ithaca():
108
+ print("\nSTRICT vs ITHACA (top-1/top-20 exact-match, two-proportion z-test, n=3000 each side)")
109
+ print(" (samples are IDENTICAL on both sides -- same frozen file -- so this unpaired")
110
+ print(" test is conservative; a paired McNemar test would only be stronger)")
111
+ INSC=os.path.expandvars("$STOICHEIA_DATA")
112
+ import collections
113
+ def merge(pat):
114
+ a=collections.defaultdict(lambda: dict(n=0,t1=0.0,t20=0.0))
115
+ for f in glob.glob(pat):
116
+ try: d=json.load(open(f))
117
+ except Exception: continue
118
+ for r in d.get("per_L",[]):
119
+ x=a[r["L"]]; x["n"]+=r["n"]; x["t1"]+=r["top1"]*r["n"]; x["t20"]+=r["top20"]*r["n"]
120
+ n=sum(v["n"] for v in a.values())
121
+ return (n, sum(v["t1"] for v in a.values()), sum(v["t20"] for v in a.values())) if n else None
122
+ def ztest(k1,n1,k2,n2):
123
+ p1,p2=k1/n1,k2/n2; p=(k1+k2)/(n1+n2)
124
+ se=math.sqrt(p*(1-p)*(1/n1+1/n2))
125
+ z=(p1-p2)/se
126
+ # two-sided normal sf via erfc
127
+ pv=math.erfc(abs(z)/math.sqrt(2))
128
+ return z,pv
129
+ ith=merge(f"{INSC}/strict_f3/ithaca_shard*.json")
130
+ if not ith: print(" (ithaca results missing)"); return
131
+ for tag,pat in (("ours old",f"{INSC}/strict_f3/ours_old.json"),
132
+ ("ours v3",f"{INSC}/strict_f3/ours_v3_shard*.json"),
133
+ ("ours v4",f"{INSC}/strict_f3/ours_v4_shard*.json")):
134
+ m=merge(pat)
135
+ if not m: continue
136
+ for name,ki,ko in (("top-1",1,1),("top-20",2,2)):
137
+ z,pv=ztest(m[ki],m[0],ith[ko],ith[0])
138
+ print(f" {tag:<9} vs Ithaca {name:<7}: {m[ki]/m[0]:.4f} vs {ith[ko]/ith[0]:.4f}"
139
+ f" z={z:+.2f} p={pv:.2e}")
140
+
141
+
142
+ def meter():
143
+ print("\nMETER (macron balanced acc, paired by seed; higher better)")
144
+ rows=collections.defaultdict(dict)
145
+ for f in sorted(glob.glob(f"{REPO}/logs/eval-*.out")):
146
+ txt=open(f,errors="ignore").read()
147
+ if "--norma" not in txt: continue
148
+ mm=re.search(r"model=(\S+)",txt); mt=re.search(r"macron test: (\{.*?\})",txt)
149
+ if not(mm and mt): continue
150
+ run=mm.group(1).split("/runs/")[-1].split("/")[0]
151
+ if not run.startswith("meter_mac_v2"): continue
152
+ seed=re.search(r"_s(\d)$",run); seed=seed.group(1) if seed else "0"
153
+ arm="randinit" if "randinit" in run else "pretrained"
154
+ rows[arm][seed]=json.loads(mt.group(1))["bal_acc"]
155
+ if rows.get("pretrained") and rows.get("randinit"):
156
+ report("", "seed", "pretrained", rows["pretrained"], "random-init", rows["randinit"])
157
+ else: print(" (not enough scored runs yet)")
158
+
159
+ if __name__=="__main__":
160
+ w=sys.argv[1] if len(sys.argv)>1 else "all"
161
+ if w in ("all","parsing"): parsing()
162
+ if w in ("all","documentary"): documentary(); strict_ithaca()
163
+ if w in ("all","meter"): meter()
164
+ print()
configs/insc/finetune_whole_v3_randinit_t0v1.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t0v1",
3
+ "test_digit": "0",
4
+ "val_digit": "1",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t0v1"
49
+ }
configs/insc/finetune_whole_v3_randinit_t1v2.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t1v2",
3
+ "test_digit": "1",
4
+ "val_digit": "2",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t1v2"
49
+ }
configs/insc/finetune_whole_v3_randinit_t2v3.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t2v3",
3
+ "test_digit": "2",
4
+ "val_digit": "3",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t2v3"
49
+ }
configs/insc/finetune_whole_v3_randinit_t3v4.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t3v4",
3
+ "test_digit": "3",
4
+ "val_digit": "4",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t3v4"
49
+ }
configs/insc/finetune_whole_v3_randinit_t4v5.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t4v5",
3
+ "test_digit": "4",
4
+ "val_digit": "5",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t4v5"
49
+ }
configs/insc/finetune_whole_v3_randinit_t5v6.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t5v6",
3
+ "test_digit": "5",
4
+ "val_digit": "6",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t5v6"
49
+ }
configs/insc/finetune_whole_v3_randinit_t6v7.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t6v7",
3
+ "test_digit": "6",
4
+ "val_digit": "7",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t6v7"
49
+ }
configs/insc/finetune_whole_v3_randinit_t7v8.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t7v8",
3
+ "test_digit": "7",
4
+ "val_digit": "8",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t7v8"
49
+ }
configs/insc/finetune_whole_v3_randinit_t8v9.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t8v9",
3
+ "test_digit": "8",
4
+ "val_digit": "9",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t8v9"
49
+ }
configs/insc/finetune_whole_v3_randinit_t9v0.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_randinit_t9v0",
3
+ "test_digit": "9",
4
+ "val_digit": "0",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "random",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_randinit_t9v0"
49
+ }
configs/insc/finetune_whole_v3_t0v1.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t0v1",
3
+ "test_digit": "0",
4
+ "val_digit": "1",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t0v1"
49
+ }
configs/insc/finetune_whole_v3_t1v2.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t1v2",
3
+ "test_digit": "1",
4
+ "val_digit": "2",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t1v2"
49
+ }
configs/insc/finetune_whole_v3_t2v3.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t2v3",
3
+ "test_digit": "2",
4
+ "val_digit": "3",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t2v3"
49
+ }
configs/insc/finetune_whole_v3_t3v4.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t3v4",
3
+ "test_digit": "3",
4
+ "val_digit": "4",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t3v4"
49
+ }
configs/insc/finetune_whole_v3_t4v5.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t4v5",
3
+ "test_digit": "4",
4
+ "val_digit": "5",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t4v5"
49
+ }
configs/insc/finetune_whole_v3_t5v6.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t5v6",
3
+ "test_digit": "5",
4
+ "val_digit": "6",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t5v6"
49
+ }
configs/insc/finetune_whole_v3_t6v7.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t6v7",
3
+ "test_digit": "6",
4
+ "val_digit": "7",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t6v7"
49
+ }
configs/insc/finetune_whole_v3_t7v8.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t7v8",
3
+ "test_digit": "7",
4
+ "val_digit": "8",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t7v8"
49
+ }
configs/insc/finetune_whole_v3_t8v9.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t8v9",
3
+ "test_digit": "8",
4
+ "val_digit": "9",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t8v9"
49
+ }
configs/insc/finetune_whole_v3_t9v0.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v3_t9v0",
3
+ "test_digit": "9",
4
+ "val_digit": "0",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 4096,
12
+ "micro_batch": 8,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "papyri": 1.0
34
+ },
35
+ "noise": {
36
+ "w_span": 0.45,
37
+ "w_word": 0.15,
38
+ "w_elastic": 0.05,
39
+ "w_iid": 0.15,
40
+ "w_halfword": 0.15,
41
+ "w_substitute": 0.05,
42
+ "span_mean": 4.0,
43
+ "span_max": 12,
44
+ "p_region_none": 0.3,
45
+ "p_century_none": 0.3
46
+ },
47
+ "dev_exclude": "",
48
+ "out_dir": "$INS_DATA/runs/whole_v3_t9v0"
49
+ }
configs/insc/finetune_whole_v4_t0v1.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t0v1",
3
+ "test_digit": "0",
4
+ "val_digit": "1",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 6000,
18
+ "decay_len": 1500,
19
+ "eval_every": 1000000000,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t0v1",
54
+ "save_every": 500
55
+ }
configs/insc/finetune_whole_v4_t1v2.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t1v2",
3
+ "test_digit": "1",
4
+ "val_digit": "2",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 6000,
18
+ "decay_len": 1500,
19
+ "eval_every": 1000000000,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t1v2",
54
+ "save_every": 0
55
+ }
configs/insc/finetune_whole_v4_t2v3.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t2v3",
3
+ "test_digit": "2",
4
+ "val_digit": "3",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 6000,
18
+ "decay_len": 1500,
19
+ "eval_every": 1000000000,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t2v3",
54
+ "save_every": 500
55
+ }
configs/insc/finetune_whole_v4_t3v4.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t3v4",
3
+ "test_digit": "3",
4
+ "val_digit": "4",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t3v4"
54
+ }
configs/insc/finetune_whole_v4_t3v4_seed1.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t3v4_seed1",
3
+ "test_digit": "3",
4
+ "val_digit": "4",
5
+ "seed": 1,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t3v4_seed1"
54
+ }
configs/insc/finetune_whole_v4_t3v4_seed2.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t3v4_seed2",
3
+ "test_digit": "3",
4
+ "val_digit": "4",
5
+ "seed": 2,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t3v4_seed2"
54
+ }
configs/insc/finetune_whole_v4_t4v5.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t4v5",
3
+ "test_digit": "4",
4
+ "val_digit": "5",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 6000,
18
+ "decay_len": 1500,
19
+ "eval_every": 1000000000,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t4v5",
54
+ "save_every": 0
55
+ }
configs/insc/finetune_whole_v4_t5v6.json ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t5v6",
3
+ "test_digit": "5",
4
+ "val_digit": "6",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 6000,
18
+ "decay_len": 1500,
19
+ "eval_every": 1000000000,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t5v6",
54
+ "save_every": 500
55
+ }
configs/insc/finetune_whole_v4_t6v7.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t6v7",
3
+ "test_digit": "6",
4
+ "val_digit": "7",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t6v7"
54
+ }
configs/insc/finetune_whole_v4_t7v8.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t7v8",
3
+ "test_digit": "7",
4
+ "val_digit": "8",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t7v8"
54
+ }
configs/insc/finetune_whole_v4_t8v9.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t8v9",
3
+ "test_digit": "8",
4
+ "val_digit": "9",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 8600,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t8v9"
54
+ }
configs/insc/finetune_whole_v4_t9v0.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "whole_v4_t9v0",
3
+ "test_digit": "9",
4
+ "val_digit": "0",
5
+ "seed": 0,
6
+ "d_model": 1024,
7
+ "depth": 32,
8
+ "char_window": 256,
9
+ "attn": "flex",
10
+ "compile": true,
11
+ "seq_len": 8192,
12
+ "micro_batch": 4,
13
+ "grad_accum": 2,
14
+ "lr": 0.0001,
15
+ "wd": 0.1,
16
+ "warmup": 200,
17
+ "total_steps": 14000,
18
+ "decay_len": 1500,
19
+ "eval_every": 250,
20
+ "eval_n": 256,
21
+ "dev_cer_n_per_L": 60,
22
+ "dev_cer_L_max": 20,
23
+ "stall_window": 8,
24
+ "stall_eps": 0.002,
25
+ "anneal_patience": 3,
26
+ "log_every": 20,
27
+ "lam": 0.1,
28
+ "meta_condition": true,
29
+ "min_len": 20,
30
+ "torso": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
31
+ "mix": {
32
+ "iphi": 1.0,
33
+ "iphi_syn": 0.5,
34
+ "papyri": 1.0,
35
+ "iphi_seg": 0.5,
36
+ "pap_seg": 0.3,
37
+ "literary": 0.3,
38
+ "literary_n": 60000
39
+ },
40
+ "noise": {
41
+ "w_span": 0.45,
42
+ "w_word": 0.15,
43
+ "w_elastic": 0.05,
44
+ "w_iid": 0.15,
45
+ "w_halfword": 0.15,
46
+ "w_substitute": 0.05,
47
+ "span_mean": 4.0,
48
+ "span_max": 12,
49
+ "p_region_none": 0.3,
50
+ "p_century_none": 0.3
51
+ },
52
+ "dev_exclude": "",
53
+ "out_dir": "$INS_DATA/runs/whole_v4_t9v0"
54
+ }
configs/meter/_smoke.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_smoke",
3
+ "seed": 0,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_pretrain_staged/best.pt",
5
+ "out_dir": "$METER_DATA/runs/meter_smoke",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 512,
9
+ "micro_batch": 2,
10
+ "eval_micro": 2,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 2,
17
+ "patience": 2,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 64,
25
+ "scan_passes": 1,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 1,
30
+ "max_records": 64
31
+ }
configs/meter/joint_docclean.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_joint_docclean",
3
+ "seed": 0,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
5
+ "out_dir": "$STOICHEIA_DATA/runs/meter_joint_docclean",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 2048,
9
+ "micro_batch": 16,
10
+ "eval_micro": 16,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 25,
17
+ "patience": 6,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 150000,
25
+ "scan_passes": 2,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 50
30
+ }
configs/meter/joint_docclean_s1.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_joint_docclean_s1",
3
+ "seed": 1,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
5
+ "out_dir": "$STOICHEIA_DATA/runs/meter_joint_docclean_s1",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 2048,
9
+ "micro_batch": 16,
10
+ "eval_micro": 16,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 25,
17
+ "patience": 6,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 150000,
25
+ "scan_passes": 2,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 50
30
+ }
configs/meter/joint_docclean_s2.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_joint_docclean_s2",
3
+ "seed": 2,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
5
+ "out_dir": "$STOICHEIA_DATA/runs/meter_joint_docclean_s2",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 2048,
9
+ "micro_batch": 16,
10
+ "eval_micro": 16,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 25,
17
+ "patience": 6,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 150000,
25
+ "scan_passes": 2,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 50
30
+ }
configs/meter/joint_docclean_s3.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_joint_docclean_s3",
3
+ "seed": 3,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
5
+ "out_dir": "$STOICHEIA_DATA/runs/meter_joint_docclean_s3",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 2048,
9
+ "micro_batch": 16,
10
+ "eval_micro": 16,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 25,
17
+ "patience": 6,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 150000,
25
+ "scan_passes": 2,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 50
30
+ }
configs/meter/joint_docclean_s4.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "meter_joint_docclean_s4",
3
+ "seed": 4,
4
+ "ckpt": "$STOICHEIA_DATA/runs/stoicheia_doc_clean/best.pt",
5
+ "out_dir": "$STOICHEIA_DATA/runs/meter_joint_docclean_s4",
6
+ "encoded": "$METER_DATA/encoded",
7
+ "attn": "sdpa",
8
+ "T": 2048,
9
+ "micro_batch": 16,
10
+ "eval_micro": 16,
11
+ "lr_enc": 0.0001,
12
+ "lr_head": 0.0008,
13
+ "wd": 0.01,
14
+ "clip": 1.0,
15
+ "warmup_frac": 0.1,
16
+ "epochs": 25,
17
+ "patience": 6,
18
+ "head_dropout": 0.33,
19
+ "use_cap": true,
20
+ "scalar_mix": true,
21
+ "w_mac": 1.0,
22
+ "w_scan": 1.0,
23
+ "select": "mean",
24
+ "prose_per_epoch": 150000,
25
+ "scan_passes": 2,
26
+ "scan_max_verses": 8,
27
+ "mac_class_w": "auto",
28
+ "scan_class_w": "auto",
29
+ "log_every": 50
30
+ }