Ekrem-the-second commited on
Commit
a3f4427
·
verified ·
1 Parent(s): 2eb7978

Ethosoft-Math-Translator v1: symbol-preserving EN->TR math translation (fine-tuned NedoTranslator)

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ source.spm filter=lfs diff=lfs merge=lfs -text
37
+ target.spm filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ - tr
5
+ license: cc-by-nc-4.0
6
+ library_name: transformers
7
+ pipeline_tag: translation
8
+ base_model: nmsofficial/NedoTranslator
9
+ tags:
10
+ - translation
11
+ - marian
12
+ - english
13
+ - turkish
14
+ - math
15
+ - latex
16
+ - symbol-preserving
17
+ - mathematics
18
+ - ethosoft
19
+ ---
20
+
21
+ <div align="center">
22
+
23
+ # 🧮 Ethosoft-Math-Translator
24
+
25
+ ### English → Turkish translation for **mathematics** — formulas, symbols and numbers survive intact.
26
+
27
+ [![Base](https://img.shields.io/badge/base-NedoTranslator-blue)](https://huggingface.co/nmsofficial/NedoTranslator)
28
+ [![Params](https://img.shields.io/badge/params-236.9M-informational)]()
29
+ [![Pairs](https://img.shields.io/badge/fine--tune%20pairs-161K-success)]()
30
+ [![Placeholder%20integrity](https://img.shields.io/badge/formula%20integrity-99.3%25-brightgreen)]()
31
+ [![Library](https://img.shields.io/badge/pip-Ethosoft--Math-orange)](https://github.com/ethosoftai/ethosoft-math)
32
+
33
+ </div>
34
+
35
+ General-purpose MT models are good at prose and terrible at math: they translate `\frac{a}{b}` into
36
+ nonsense, "fix" decimal points, drop `±`, `√`, `∑`, CJK characters, and silently change numbers.
37
+ **Ethosoft-Math-Translator** is [NedoTranslator](https://huggingface.co/nmsofficial/NedoTranslator)
38
+ fine-tuned so that mathematical content is treated as *untouchable*: it translates the words around
39
+ the math and hands every formula back byte-for-byte.
40
+
41
+ ```text
42
+ EN Since $x^2-4=(x-2)(x+2)$, the solutions are x = ±2, so the sum is 0.
43
+ TR $x^2-4=(x-2)(x+2)$ olduğundan, çözümler x = ±2'dir, bu yüzden toplam 0'dır.
44
+
45
+ EN Compute $\sqrt{16} + 3^2$. First, $\sqrt{16}=4$ and $3^2=9$, hence the total is $13$.
46
+ TR $\sqrt{16} + 3^2$ değerini hesaplayın. Önce $\sqrt{16}=4$ ve $3^2=9$, dolayısıyla toplam $13$'tür.
47
+
48
+ EN Evaluate ∑_{k=1}^{10} k × 2 ≤ 110. 你好
49
+ TR ∑_{k=1}^{10} k × 2 ≤ 110 değerini hesaplayın. 你好
50
+ ```
51
+
52
+ *(real, unedited outputs of the released checkpoint)*
53
+
54
+ ## How it works
55
+
56
+ ```
57
+ text ──► mask ──► translate line by line ──► check ──► restore ──► Turkish text
58
+ │ │
59
+ │ LaTeX ($..$, $$..$$, \[..\], \begin..\end),
60
+ │ code, URLs, tool-call blocks, math Unicode (±×÷√∑∫≤≥≠…),
61
+ │ CJK, and characters missing from the vocabulary
62
+ └─► become [[1]] [[2]] … (renumbered per line)
63
+ ```
64
+
65
+ The model was fine-tuned to **copy `[[n]]` placeholders exactly** while translating everything else.
66
+ After translation every placeholder is verified and substituted back; a line whose placeholders were
67
+ damaged is rejected instead of being silently corrupted. This is why formulas can never be
68
+ "translated" or altered.
69
+
70
+ ## Quick start
71
+
72
+ The easiest way is the [`Ethosoft-Math`](https://github.com/ethosoftai/ethosoft-math) library, which
73
+ ships the masking / restoring pipeline:
74
+
75
+ ```bash
76
+ pip install "Ethosoft-Math[translate]"
77
+ ```
78
+
79
+ ```python
80
+ from ethosoft_math.translate import MathTranslator
81
+
82
+ t = MathTranslator() # downloads Ethosoft/Ethosoft-Math-Translator
83
+ print(t.translate("If $x^2 = 9$, then x = ±3.\nThe answer is $\\boxed{3}$ or $-3$."))
84
+ # Eğer $x^2 = 9$ ise, x = ±3.
85
+ # Cevap $\boxed{3}$ veya $-3$'tür.
86
+
87
+ # whole records (e.g. dataset rows); returns None if any formula could not be preserved
88
+ row = t.translate_record({"problem": "What is $\\frac{1}{2}+\\frac{1}{3}$?", "solution": "It is $\\frac{5}{6}$."})
89
+ ```
90
+
91
+ Or from the command line:
92
+
93
+ ```bash
94
+ ethosoft-math translate "Compute $\\sqrt{16} + 3^2$."
95
+ ethosoft-math translate --input data.jsonl --output data_tr.jsonl # adds problem_tr / solution_tr
96
+ ```
97
+
98
+ ### Plain 🤗 Transformers
99
+
100
+ The raw model works on **already masked** text. If you call it directly, mask math yourself
101
+ (see `ethosoft_math.translate.protect_all`) – feeding raw LaTeX to the model is not what it was trained for.
102
+
103
+ ```python
104
+ from transformers import MarianMTModel, MarianTokenizer
105
+ tok = MarianTokenizer.from_pretrained("Ethosoft/Ethosoft-Math-Translator")
106
+ model = MarianMTModel.from_pretrained("Ethosoft/Ethosoft-Math-Translator")
107
+
108
+ batch = tok(["Therefore the value of [[1]] is [[2]]."], return_tensors="pt")
109
+ out = model.generate(**batch, num_beams=4, max_new_tokens=256)
110
+ print(tok.batch_decode(out, skip_special_tokens=True)) # Turkish sentence with [[1]] and [[2]] kept verbatim
111
+ ```
112
+
113
+ ## Results
114
+
115
+ Held-out evaluation (rows never seen in fine-tuning; hash-based split):
116
+
117
+ | Metric | NedoTranslator (base) | **Ethosoft-Math-Translator** |
118
+ |---|---:|---:|
119
+ | Validation loss (masked lines) | 0.701 | **0.373** |
120
+ | Placeholder integrity, line level (all `[[n]]` reproduced) | 68.5 % | **99.3 %** |
121
+ | End-to-end rows passing *all* quality gates¹ (276 unseen rows) | – | **94.9 %** |
122
+
123
+ ¹ numbers unchanged, formulas unchanged, answer preserved, no foreign scripts, Turkish output, same structure.
124
+ Of the 5.1 % rejected rows, 11 were placeholder failures and 3 changed a number – they are *dropped*, not emitted.
125
+
126
+ On sampled rows the output is close to the teacher's translations (see below); we did not run a
127
+ human evaluation, so treat fluency claims accordingly.
128
+
129
+ ## In production: 755,035 rows translated
130
+
131
+ The released checkpoint was run over the full pool of math corpora (on top of the 27,768 teacher-translated
132
+ rows used for training). Every row went through the same quality gate; rows that failed were **deleted, not repaired**.
133
+
134
+ | Dataset | Translated | Rejected | Pass rate |
135
+ |---|---:|---:|---:|
136
+ | MetaMathQA | 382,532 | 8,180 | 97.9 % |
137
+ | MathInstruct | 111,186 | 6,061 | 94.8 % |
138
+ | OpenR1-Math | 78,894 | 10,767 | 88.0 % |
139
+ | NuminaMath-TIR | 64,772 | 4,944 | 92.9 % |
140
+ | Orca-Math | 59,239 | 2,584 | 95.8 % |
141
+ | AQuA-RAT | 40,103 | 1,295 | 96.9 % |
142
+ | MATH | 7,886 | 858 | 90.2 % |
143
+ | GSM8K | 6,228 | 171 | 97.3 % |
144
+ | DeepScaleR | 4,195 | 1,537 | 73.2 % |
145
+ | **Total** | **755,035** | **36,397** | **95.4 %** |
146
+
147
+ Main rejection reasons: a placeholder was damaged (17.7 k), a number changed (17.2 k), answer lost (0.6 k),
148
+ formula changed (0.5 k), output not Turkish (0.4 k). Throughput on a single H100: ~10–19 rows/s (beam 4).
149
+ Hard competition sets such as DeepScaleR lose the most rows because their solutions are dense with formulas.
150
+
151
+ ## Training
152
+
153
+ * **Base**: [`nmsofficial/NedoTranslator`](https://huggingface.co/nmsofficial/NedoTranslator) (MarianMT, 236.9 M parameters),
154
+ itself fine-tuned from [`Helsinki-NLP/opus-mt-tc-big-en-tr`](https://huggingface.co/Helsinki-NLP/opus-mt-tc-big-en-tr).
155
+ * **Teacher data**: 27,768 math problems + solutions translated into Turkish by a strong LLM
156
+ (DeepSeek-V4 Flash, reasoning off, via the Evren LLM gateway) under a strict quality gate, then
157
+ masked and split into **161,085 aligned line pairs** (1,412 held out).
158
+ Source corpora: GSM8K, MATH, MetaMathQA, Orca-Math, MathInstruct, OpenR1-Math, NuminaMath-TIR,
159
+ DeepScaleR, AQuA-RAT.
160
+ * **Quality gate** for teacher output (rows failing any check were deleted, ~4–10 % per dataset):
161
+ number multiset preserved · every formula block preserved · gold answer still present ·
162
+ every CJK/math symbol of the source present · no foreign script added · Turkish-ness · line structure.
163
+ * **Recipe**: 3 epochs, AdamW, lr 5e-5 (linear warm-up/decay), label smoothing 0.1, bf16, ~12 k tokens/batch,
164
+ 1 × H100 (≈ 4 minutes), TRUBA HPC.
165
+
166
+ ## Intended use & limitations
167
+
168
+ * ✅ Translating math word problems, solutions, proofs and textbook-style exposition EN → TR, especially to build Turkish math datasets.
169
+ * ✅ Pipelines that must keep formulas/numbers exactly (the library rejects rows it cannot guarantee).
170
+ * ⚠️ Text *inside* masked blocks (e.g. `\text{if } n …` inside a LaTeX block, or code comments) is **not translated**.
171
+ * ⚠️ Translations inherit the teacher model's style and mistakes; terminology is not hand-verified.
172
+ * ⚠️ Long lines are truncated at 256 tokens – the library splits input by line, so keep one idea per line.
173
+ * ⚠️ English → Turkish only.
174
+
175
+ ## License
176
+
177
+ Released under **CC BY-NC 4.0**. The upstream NedoTranslator card lists `cc-by-nc-2.0` in its metadata and
178
+ "CC BY 4.0" in its text; we adopt the more restrictive non-commercial terms until that is clarified.
179
+ Please also retain attribution to the upstream models below.
180
+
181
+ ## Attribution & citation
182
+
183
+ This work stands on **NedoTranslator** by *nmsofficial* — please credit it:
184
+ <https://huggingface.co/nmsofficial/NedoTranslator> — which in turn builds on Helsinki-NLP's OPUS-MT:
185
+
186
+ ```bibtex
187
+ @inproceedings{tiedemann-thottingal-2020-opus,
188
+ title = {{OPUS-MT} -- Building open translation services for the World},
189
+ author = {Tiedemann, J{\"o}rg and Thottingal, Santhosh},
190
+ booktitle = {Proceedings of the 22nd Annual Conference of the European Association for Machine Translation},
191
+ year = {2020}
192
+ }
193
+ ```
194
+
195
+ If you use Ethosoft-Math-Translator:
196
+
197
+ ```bibtex
198
+ @misc{ethosoft_math_translator_2026,
199
+ title = {Ethosoft-Math-Translator: Symbol-Preserving English-to-Turkish Mathematical Translation},
200
+ author = {Ethosoft},
201
+ year = {2026},
202
+ howpublished = {\url{https://huggingface.co/Ethosoft/Ethosoft-Math-Translator}},
203
+ note = {Fine-tuned from NedoTranslator (nmsofficial)}
204
+ }
205
+ ```
206
+
207
+ <div align="center"><sub>Made by <a href="https://github.com/ethosoftai">Ethosoft</a> · Ethosoft-Math library: <a href="https://github.com/ethosoftai/ethosoft-math">github.com/ethosoftai/ethosoft-math</a></sub></div>
config.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "mathtr/ft_model",
3
+ "activation_dropout": 0.0,
4
+ "activation_function": "relu",
5
+ "architectures": [
6
+ "MarianMTModel"
7
+ ],
8
+ "attention_dropout": 0.0,
9
+ "bos_token_id": 0,
10
+ "classifier_dropout": 0.0,
11
+ "d_model": 1024,
12
+ "decoder_attention_heads": 16,
13
+ "decoder_ffn_dim": 4096,
14
+ "decoder_layerdrop": 0.0,
15
+ "decoder_layers": 6,
16
+ "decoder_start_token_id": 57059,
17
+ "decoder_vocab_size": 57060,
18
+ "dropout": 0.1,
19
+ "encoder_attention_heads": 16,
20
+ "encoder_ffn_dim": 4096,
21
+ "encoder_layerdrop": 0.0,
22
+ "encoder_layers": 6,
23
+ "eos_token_id": 43741,
24
+ "forced_eos_token_id": null,
25
+ "init_std": 0.02,
26
+ "is_encoder_decoder": true,
27
+ "max_length": null,
28
+ "max_position_embeddings": 1024,
29
+ "model_type": "marian",
30
+ "normalize_embedding": false,
31
+ "num_beams": null,
32
+ "num_hidden_layers": 6,
33
+ "pad_token_id": 57059,
34
+ "scale_embedding": true,
35
+ "share_encoder_decoder_embeddings": true,
36
+ "static_position_embeddings": true,
37
+ "torch_dtype": "float32",
38
+ "transformers_version": "4.33.0",
39
+ "use_cache": false,
40
+ "vocab_size": 57060
41
+ }
generation_config.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bad_words_ids": [
3
+ [
4
+ 57059
5
+ ]
6
+ ],
7
+ "bos_token_id": 0,
8
+ "decoder_start_token_id": 57059,
9
+ "eos_token_id": 43741,
10
+ "forced_eos_token_id": 43741,
11
+ "max_length": 512,
12
+ "num_beams": 4,
13
+ "pad_token_id": 57059,
14
+ "renormalize_logits": true,
15
+ "transformers_version": "4.33.0"
16
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6ebdf54a83ff0a4a1ea5b2ed20feaae81e5380c7c1633ebcdf33ebdfb38c9712
3
+ size 939405120
source.spm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:180d3f94ddfee5585d78b702290ded0f4f9bd40f299349c8383b32a579fefad4
3
+ size 796953
special_tokens_map.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "eos_token": "</s>",
3
+ "pad_token": "<pad>",
4
+ "unk_token": "<unk>"
5
+ }
target.spm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd0c475692178b6c626aadaef01bd8f98d8053946938e4e67005fc1e4811d797
3
+ size 833391
tokenizer_config.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "43741": {
4
+ "content": "</s>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "52508": {
12
+ "content": "<unk>",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "57059": {
20
+ "content": "<pad>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ }
27
+ },
28
+ "clean_up_tokenization_spaces": false,
29
+ "eos_token": "</s>",
30
+ "model_max_length": 512,
31
+ "pad_token": "<pad>",
32
+ "separate_vocabs": false,
33
+ "source_lang": "en",
34
+ "sp_model_kwargs": {},
35
+ "target_lang": "tr",
36
+ "tokenizer_class": "MarianTokenizer",
37
+ "unk_token": "<unk>"
38
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff