Model card for the public release

#3
Files changed (3) hide show
  1. .gitattributes +1 -0
  2. README.md +199 -136
  3. assets/millid-architecture.png +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ assets/millid-architecture.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -4,8 +4,12 @@ library_name: pytorch
4
  pipeline_tag: text-classification
5
  tags:
6
  - language-identification
7
- - onnx
 
8
  - byte-level
 
 
 
9
  datasets:
10
  - baobabtech/millid-dataset
11
  metrics:
@@ -45,13 +49,78 @@ model-index:
45
  value: 0.8524
46
  ---
47
 
48
- # MillID medium v1: MultiLingual Language IDentifier
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- A byte-level, encoder-only transformer that names the language of a passage, from a table cell to a paragraph: **1,641 language-script labels** (ISO 639-3 + script, e.g. `eng_Latn`, `amh_Ethi`). 115.0M parameters, trained from scratch. Apache-2.0.
 
 
51
 
52
- ## The MillID models
53
 
54
- Three sizes, this one in bold. Macro F1 on `test` and `udhr`, the sets below:
55
 
56
  | Model | Parameters | ONNX | Test F1 | UDHR F1 | Runs on |
57
  |---|---|---|---|---|---|
@@ -59,61 +128,21 @@ Three sizes, this one in bold. Macro F1 on `test` and `udhr`, the sets below:
59
  | **MillID medium v1** | 115M | 455 MB | 0.9576 | 0.8780 | GPU |
60
  | [MillID large v1.5](https://huggingface.co/baobabtech/millid-large-v1.5) | 193M | 764 MB | 0.9646 | 0.8812 | GPU |
61
 
62
- All three, language by language, against GlotLID and Meta's fastText: the [leaderboard](https://huggingface.co/baobabtech/millid). GlotLID, restricted to MillID's labels, scores 0.9755 and 0.8873.
63
-
64
- ## Use it
65
-
66
- No server and no PyTorch: the model runs in your process from `onnx/model.onnx`, in Python or JavaScript, and the two give the same answers (one encoder, ported line for line and tested against the same fixtures in [baobab-tech/millid](https://github.com/baobab-tech/millid)).
67
-
68
- ```bash
69
- pip install "millid[cpu] @ git+https://github.com/baobab-tech/millid.git" # [gpu] for CUDA
70
- ```
71
-
72
- ```python
73
- from millid import MillID
74
-
75
- model = MillID.from_pretrained("baobabtech/millid-medium-v1")
76
- model.predict("Lave men ou ak savon anvan ou manje.", k=3)
77
- # [Prediction(label='hat_Latn', language='Haitian Creole', probability=...), ...]
78
- model.predict(["one text", "another"], k=3) # one list of answers per text
79
- model.identify_document(long_text) # any length: its languages and segments
80
- ```
81
-
82
- ```bash
83
- millid predict "Lave men ou ak savon anvan ou manje." --model baobabtech/millid-medium-v1 -k 3
84
- ```
85
-
86
- JavaScript, in Node or a browser (`js/` in the same repository; not on npm yet):
87
-
88
- ```js
89
- import { MillID } from "@baobabtech/millid"; // "@baobabtech/millid/web" in a browser, with { ort }
90
- const model = await MillID.fromPretrained("baobabtech/millid-medium-v1");
91
- await model.predict("Lave men ou ak savon anvan ou manje.", 3);
92
- ```
93
-
94
- `millid.py` in this repository is the PyTorch training code, which reads `model.safetensors` to fine-tune or export.
95
-
96
- The ONNX graph takes, for each UTF-8 byte of a passage cut to 255 bytes after a CLS token, `ids`, `script` and `charpos` (int64, `[batch, bytes]`), `ngrams` (int64, `[batch, bytes, 3]`) and `mask` (bool, `[batch, bytes]`), and returns `logits` (float32, `[batch, labels]`). `millid.encode_batch` and the JavaScript `encodeBatch` build them; script ids come from a frozen table (Unicode 15.0), so every runtime gives the same ones.
97
-
98
- ## Architecture
99
-
100
- UTF-8 bytes (after Unicode NFKC), each embedded as byte + Unicode script + byte-in-character + hashed character 2-, 3- and 4-grams (32,768 buckets) -> depthwise convolution stem (kernel 5) -> strided convolution, 2 bytes per token -> 12 pre-norm blocks (RMSNorm, attention with RoPE, 12 heads, SwiGLU; d=768) -> masked mean pooling -> language head, each language's vector the sum of its own, its language's and its script's. Up to 256 bytes per passage. See `ARCHITECTURE.md`.
101
 
102
- ## Evaluation against GlotLID and fastText
103
 
104
- `validation` chose the checkpoint; `test` is split by document from training; `udhr` is the Universal Declaration of Human Rights, labelled by its translators, over the languages MillID knows, and `udhr-all` over all of them. [GlotLID](https://huggingface.co/cis-lmu/glotlid) and Meta's [fastText language identifier](https://huggingface.co/facebook/fasttext-language-identification) (NLLB, 218 labels) are each restricted to MillID's labels, their best answer among them: the like-for-like comparison. fastText's answers are mapped onto MillID's spelling (Simplified and Traditional Han as `Hani`, `pes`/`prs` as `fas`, `est` as `ekk`). GlotLID's own labels came from training on data that includes UDHR and labelled FinePDFs and FineWeb-2, so its scores on `udhr` and on those sources are optimistic. fastText cannot answer most of the 1,600 languages here, so `test-common` and `udhr-common` score every system on the passages whose language all of them know: the head-to-head on equal terms.
105
-
106
- Macro F1 on each set, every system on the same passages; GlotLID and fastText restricted to MillID's labels:
107
-
108
- | Set | Languages | MillID | GlotLID | fastText |
109
  |---|---|---|---|---|
110
- | `test` | 1,621 | 0.9576 | 0.9755 | 0.0659 |
111
- | `test-common` | 213 | 0.9527 | 0.9846 | 0.9173 |
112
- | `udhr` | 358 | 0.8780 | 0.8873 | 0.3499 |
113
- | `udhr-common` | 170 | 0.9480 | 0.9659 | 0.9329 |
114
- | `udhr-all` | 429 | 0.7184 | 0.7245 | 0.2797 |
 
 
115
 
116
- MillID on each set:
117
 
118
  | Set | Top-1 | Top-3 | Top-5 | Macro P | Macro R | Macro F1 | Median F1 |
119
  |---|---|---|---|---|---|---|---|
@@ -124,19 +153,7 @@ MillID on each set:
124
  | `udhr-common` | 0.9121 | 0.9633 | 0.9688 | 0.9770 | 0.9382 | 0.9480 | 0.9955 |
125
  | `udhr-all` | 0.7301 | 0.7875 | 0.8000 | 0.7415 | 0.7318 | 0.7184 | 0.9672 |
126
 
127
- Top-1 accuracy by passage length:
128
-
129
- | Set | System | Short | Sentence | Paragraph |
130
- |---|---|---|---|---|
131
- | `validation` | MillID | 0.9363 | 0.9818 | 0.9858 |
132
- | `test` | MillID | 0.9382 | 0.9809 | 0.9846 |
133
- | `test` | GlotLID | 0.9674 | 0.9858 | 0.9912 |
134
- | `test` | fastText | 0.2764 | 0.2506 | 0.1959 |
135
- | `test-common` | MillID | 0.9169 | 0.9696 | 0.9737 |
136
- | `test-common` | GlotLID | 0.9609 | 0.9885 | 0.9949 |
137
- | `test-common` | fastText | 0.9125 | 0.9581 | 0.9655 |
138
-
139
- ### Per language: test
140
 
141
  F1 language by language, GlotLID and fastText restricted to MillID's labels: against GlotLID, MillID is better on **110** languages, worse on **776** and within 0.01 on 735; against fastText, MillID is better on **1616** languages, worse on **0** and within 0.01 on 5. Every language, with precision, recall and the unrestricted scores, is in `reports/test/leaderboard.csv`.
142
 
@@ -205,7 +222,7 @@ Where MillID loses most to GlotLID:
205
  | `mbd_Latn` | Dibabawon Manobo | 14 | 0.757 | 1.000 | 0.000 |
206
  | `lnd_Latn` | Lundayeh | 5 | 0.769 | 1.000 | 0.000 |
207
 
208
- ### Per language: udhr
209
 
210
  F1 language by language, GlotLID and fastText restricted to MillID's labels: against GlotLID, MillID is better on **63** languages, worse on **95** and within 0.01 on 200; against fastText, MillID is better on **304** languages, worse on **13** and within 0.01 on 41. Every language, with precision, recall and the unrestricted scores, is in `reports/udhr/leaderboard.csv`.
211
 
@@ -274,83 +291,129 @@ Where MillID loses most to GlotLID:
274
  | `maz_Latn` | Central Mazahua | 59 | 0.742 | 0.939 | 0.000 |
275
  | `rmn_Latn` | Balkan Romani | 116 | 0.667 | 0.857 | 0.000 |
276
 
277
- ### Per language: test-common
278
 
279
- F1 language by language, GlotLID and fastText restricted to MillID's labels: against GlotLID, MillID is better on **6** languages, worse on **142** and within 0.01 on 65; against fastText, MillID is better on **93** languages, worse on **47** and within 0.01 on 73. Every language, with precision, recall and the unrestricted scores, is in `reports/test-common/leaderboard.csv`.
280
 
281
- The 20 languages with the most passages:
282
 
283
- | Label | Language | Passages | MillID | GlotLID | fastText |
284
- |---|---|---|---|---|---|
285
- | `fra_Latn` | French | 1652 | 0.974 | 0.955 | 0.963 |
286
- | `eng_Latn` | English | 1444 | 0.941 | 0.877 | 0.857 |
287
- | `spa_Latn` | Spanish | 1136 | 0.953 | 0.958 | 0.941 |
288
- | `tam_Taml` | Tamil | 754 | 0.998 | 1.000 | 0.997 |
289
- | `arb_Arab` | Arabic (Modern Standard) | 745 | 0.905 | 0.886 | 0.954 |
290
- | `por_Latn` | Portuguese | 657 | 0.963 | 0.956 | 0.949 |
291
- | `kan_Knda` | Kannada | 601 | 0.987 | 0.994 | 0.999 |
292
- | `zul_Latn` | Zulu | 594 | 0.871 | 0.904 | 0.970 |
293
- | `swh_Latn` | Swahili | 592 | 0.897 | 0.953 | 0.945 |
294
- | `mar_Deva` | Marathi | 589 | 0.981 | 0.990 | 0.987 |
295
- | `tso_Latn` | Tsonga | 581 | 0.984 | 0.956 | 0.986 |
296
- | `hun_Latn` | Hungarian | 576 | 0.991 | 1.000 | 0.980 |
297
- | `afr_Latn` | Afrikaans | 569 | 0.976 | 0.985 | 0.986 |
298
- | `tel_Telu` | Telugu | 555 | 1.000 | 0.998 | 0.999 |
299
- | `rus_Cyrl` | Russian | 528 | 0.929 | 0.985 | 0.927 |
300
- | `ory_Orya` | Odia (individual language) | 511 | 0.996 | 1.000 | 0.996 |
301
- | `sot_Latn` | Southern Sotho | 491 | 0.967 | 0.978 | 0.856 |
302
- | `nso_Latn` | Northern Sotho | 479 | 0.961 | 0.970 | 0.967 |
303
- | `asm_Beng` | Assamese | 467 | 0.995 | 0.999 | 0.997 |
304
- | `ben_Beng` | Bangla | 466 | 0.987 | 0.997 | 0.989 |
305
 
306
- Where MillID gains most over GlotLID:
307
 
308
- | Label | Language | Passages | MillID | GlotLID | fastText |
309
- |---|---|---|---|---|---|
310
- | `ewo_Latn` | Ewondo | 134 | 0.965 | 0.883 | 0.860 |
311
- | `eng_Latn` | English | 1444 | 0.941 | 0.877 | 0.857 |
312
- | `arb_Latn` | Standard Arabic | 163 | 0.944 | 0.913 | 0.852 |
313
- | `tso_Latn` | Tsonga | 581 | 0.984 | 0.956 | 0.986 |
314
- | `fra_Latn` | French | 1652 | 0.974 | 0.955 | 0.963 |
315
- | `arb_Arab` | Arabic (Modern Standard) | 745 | 0.905 | 0.886 | 0.954 |
316
- | `knc_Latn` | Central Kanuri | 293 | 0.959 | 0.952 | 0.981 |
317
- | `por_Latn` | Portuguese | 657 | 0.963 | 0.956 | 0.949 |
318
- | `san_Deva` | Sanskrit | 239 | 0.996 | 0.990 | 0.971 |
319
- | `bug_Latn` | Buginese | 78 | 0.987 | 0.981 | 0.938 |
320
- | `kam_Latn` | Kamba | 272 | 0.980 | 0.974 | 0.863 |
321
- | `mlt_Latn` | Maltese | 291 | 0.997 | 0.993 | 0.961 |
322
- | `tel_Telu` | Telugu | 555 | 1.000 | 0.998 | 0.999 |
323
- | `sin_Sinh` | Sinhala | 232 | 1.000 | 1.000 | 0.998 |
324
- | `pan_Guru` | Punjabi | 460 | 1.000 | 1.000 | 0.990 |
325
 
326
- Where MillID loses most to GlotLID:
 
 
 
 
 
327
 
328
- | Label | Language | Passages | MillID | GlotLID | fastText |
329
- |---|---|---|---|---|---|
330
- | `knc_Arab` | Central Kanuri | 68 | 0.562 | 0.860 | 0.029 |
331
- | `tzm_Tfng` | Central Atlas Tamazight | 157 | 0.645 | 0.934 | 0.751 |
332
- | `hrv_Latn` | Croatian | 168 | 0.717 | 0.994 | 0.856 |
333
- | `bos_Latn` | Bosnian | 198 | 0.727 | 1.000 | 0.897 |
334
- | `zsm_Latn` | Standard Malay | 244 | 0.773 | 0.998 | 0.908 |
335
- | `taq_Tfng` | Tamasheq | 104 | 0.613 | 0.805 | 0.000 |
336
- | `ind_Latn` | Indonesian | 335 | 0.807 | 0.991 | 0.887 |
337
- | `kin_Latn` | Kinyarwanda | 210 | 0.818 | 0.981 | 0.854 |
338
- | `run_Latn` | Rundi | 291 | 0.843 | 0.985 | 0.855 |
339
- | `nob_Latn` | Norwegian Bokmål | 265 | 0.820 | 0.959 | 0.894 |
340
- | `fuv_Latn` | Nigerian Fulfulde | 164 | 0.797 | 0.892 | 0.859 |
341
- | `mag_Deva` | Magahi | 97 | 0.905 | 1.000 | 0.772 |
342
- | `vec_Latn` | Venetian | 49 | 0.766 | 0.861 | 0.620 |
343
- | `cjk_Latn` | Chokwe | 24 | 0.909 | 1.000 | 0.807 |
344
- | `taq_Latn` | Tamasheq | 106 | 0.909 | 1.000 | 0.838 |
345
-
346
- Per-language precision, recall (sensitivity), F1 and specificity for every system, restricted and as it is, are in `reports/<set>/`, and the totals in `reports/summary.json`.
347
-
348
- ## Training
349
 
350
- 1,944,095 passages; the best validation macro F1 at step 56,000, after 3.4 hours on 1 GPU. Languages sampled in proportion to n^0.3; 25% of passages cut to a 20 to 80 character snippet; batch 512, AdamW at 0.0003, cosine schedule, label smoothing 0.1.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
 
352
  The training data is the full MillID build. The public [baobabtech/millid-dataset](https://huggingface.co/datasets/baobabtech/millid-dataset) is that build without Save the Children's and Nal'ibali's text (1.6% of its passages), which is not ours to redistribute. Its splits are the same, so its `test` split is the one scored above, without those passages.
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  ## Licence
355
 
356
  The weights and the code are Apache-2.0. The training data carries its own licence row by row (see the [dataset card](https://huggingface.co/datasets/baobabtech/millid-dataset#licensing)), including text licensed for non-commercial use only (CC BY-NC, CC BY-NC-SA).
 
4
  pipeline_tag: text-classification
5
  tags:
6
  - language-identification
7
+ - text-classification
8
+ - multilingual
9
  - byte-level
10
+ - onnx
11
+ language:
12
+ - multilingual
13
  datasets:
14
  - baobabtech/millid-dataset
15
  metrics:
 
49
  value: 0.8524
50
  ---
51
 
52
+ <p align="center">
53
+ <a href="https://github.com/baobab-tech/millid" target="_blank">GitHub</a> |
54
+ <a href="https://huggingface.co/baobabtech/millid" target="_blank">Leaderboard</a> |
55
+ <a href="https://huggingface.co/datasets/baobabtech/millid-dataset" target="_blank">Dataset</a> |
56
+ <a href="https://github.com/baobab-tech/millid/blob/main/training/ARCHITECTURE.md" target="_blank">Architecture</a>
57
+ <br>
58
+ <b>License</b>: <a href="https://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache 2.0</a> | <b>Authors</b>: <a href="https://huggingface.co/baobabtech" target="_blank">Baobab Tech</a>
59
+ </p>
60
+
61
+ # MillID medium v1
62
+
63
+ **MillID** (MultiLingual Language IDentifier) is an open language identification model built by Baobab Tech. It names the language of a passage of text, from a table cell to a paragraph, among 1,641 language-script labels: 1,550 languages written in 56 scripts, and 37 labels for text in a script whose language it cannot name (`und_<Script>`). MillID medium v1 has 115.0M parameters and an ONNX file of 455 MB.
64
+
65
+ The middle size, more accurate than tiny v1.5 on both test sets and best run on a GPU; on a laptop CPU it reads about 2 passages a second per thread.
66
+
67
+ MillID offers:
68
+
69
+ * **Language and script:** labels are ISO 639-3 plus ISO 15924 script, so Serbian in Cyrillic (`srp_Cyrl`) and in Latin (`srp_Latn`) are told apart. Many of the languages are low-resource, with a few hundred passages each to learn from.
70
+ * **No tokenizer:** it reads UTF-8 bytes, each with its Unicode script and the character n-grams ending there, so any script is input it can read and nothing is an unknown token.
71
+ * **Short text:** a quarter of its training passages were cut to 20 to 80 characters, the length of a heading or a table cell, where language identification is hardest.
72
+ * **Whole documents:** `identify_document` reads text of any length in windows and returns the document's languages and the segments of each.
73
+ * **No server, no PyTorch:** one ONNX file and a small encoder, in Python (NumPy) or JavaScript (Node and browsers); the two are tested to give the same answers.
74
+ * **Three sizes, one label set:** tiny v1.5, medium v1 and large v1.5 share their labels, so changing size changes no code.
75
+
76
+ ### Model overview
77
+
78
+ | **Parameters** | Total | 115.0M |
79
+ |---|---|---|
80
+ | | Embeddings | 25.8M |
81
+ | | Convolution stem | 1.8M |
82
+ | | Transformer blocks | 85.0M |
83
+ | | Language head | 2.5M |
84
+ | **Architecture** | Blocks | 12 |
85
+ | | Model dimension | 768 |
86
+ | | Attention heads | 12 |
87
+ | | Bytes per token | 2 |
88
+ | | N-gram buckets | 32,768 |
89
+ | | Normalisation | RMSNorm, pre-norm |
90
+ | | Positions | RoPE |
91
+ | | Feed-forward | SwiGLU |
92
+ | | Pooling | Masked mean |
93
+ | **Input and output** | Input | UTF-8 bytes, NFKC |
94
+ | | Passage length | Up to 255 bytes |
95
+ | | Labels | 1,641 |
96
+ | | Runtime | ONNX (455 MB) |
97
+
98
+ ## Benchmark results
99
+
100
+ MillID was evaluated on two test sets: `test`, passages from documents never seen in training, split from the training data by document; and UDHR-LID (`udhr`), the Universal Declaration of Human Rights labelled by its translators. It is compared with [GlotLID](https://huggingface.co/cis-lmu/glotlid) and Meta's [fastText language identifier](https://huggingface.co/facebook/fasttext-language-identification) (NLLB, 218 labels), each restricted to MillID's labels, its best answer among them: the like-for-like comparison.
101
+
102
+ ### Overall results
103
+
104
+ | Set | Languages | Metric | MillID | GlotLID | fastText |
105
+ |---|---|---|---|---|---|
106
+ | `test` | 1,621 | Macro F1 | 0.9576 | 0.9755 | 0.0659 |
107
+ | | | Top-1 | 0.9616 | 0.9783 | 0.2515 |
108
+ | `test-common` | 213 | Macro F1 | 0.9527 | 0.9846 | 0.9173 |
109
+ | | | Top-1 | 0.9425 | 0.9749 | 0.9352 |
110
+ | `udhr` | 358 | Macro F1 | 0.8780 | 0.8873 | 0.3499 |
111
+ | | | Top-1 | 0.8524 | 0.8614 | 0.4629 |
112
+ | `udhr-common` | 170 | Macro F1 | 0.9480 | 0.9659 | 0.9329 |
113
+ | | | Top-1 | 0.9121 | 0.9338 | 0.9195 |
114
+ | `udhr-all` | 429 | Macro F1 | 0.7184 | 0.7245 | 0.2797 |
115
+ | | | Top-1 | 0.7301 | 0.7378 | 0.3964 |
116
 
117
+ * `test`: every language, 1,621 of them. `test-common`: the languages all three systems know, the head-to-head on equal terms, since fastText cannot answer most of MillID's.
118
+ * `udhr`: the Declaration in the languages MillID knows. `udhr-common`: in the languages all three know. `udhr-all`: in every language it has, MillID's unknown ones counted wrong.
119
+ * GlotLID's labels came from training on data that includes UDHR, and it labelled the FinePDFs and FineWeb-2 passages in `test`, so its scores are optimistic on both.
120
 
121
+ ### The three MillID models
122
 
123
+ Macro F1 on `test` and `udhr`; this model in bold. All three, language by language, are on the [leaderboard](https://huggingface.co/baobabtech/millid).
124
 
125
  | Model | Parameters | ONNX | Test F1 | UDHR F1 | Runs on |
126
  |---|---|---|---|---|---|
 
128
  | **MillID medium v1** | 115M | 455 MB | 0.9576 | 0.8780 | GPU |
129
  | [MillID large v1.5](https://huggingface.co/baobabtech/millid-large-v1.5) | 193M | 764 MB | 0.9646 | 0.8812 | GPU |
130
 
131
+ ### By passage length
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
+ Top-1 accuracy on passages of 20 to 80 characters (short), up to 300 (sentence) and up to 1,000 (paragraph):
134
 
135
+ | Set | System | Short | Sentence | Paragraph |
 
 
 
 
136
  |---|---|---|---|---|
137
+ | `validation` | MillID | 0.9363 | 0.9818 | 0.9858 |
138
+ | `test` | MillID | 0.9382 | 0.9809 | 0.9846 |
139
+ | `test` | GlotLID | 0.9674 | 0.9858 | 0.9912 |
140
+ | `test` | fastText | 0.2764 | 0.2506 | 0.1959 |
141
+ | `test-common` | MillID | 0.9169 | 0.9696 | 0.9737 |
142
+ | `test-common` | GlotLID | 0.9609 | 0.9885 | 0.9949 |
143
+ | `test-common` | fastText | 0.9125 | 0.9581 | 0.9655 |
144
 
145
+ ### MillID on each set
146
 
147
  | Set | Top-1 | Top-3 | Top-5 | Macro P | Macro R | Macro F1 | Median F1 |
148
  |---|---|---|---|---|---|---|---|
 
153
  | `udhr-common` | 0.9121 | 0.9633 | 0.9688 | 0.9770 | 0.9382 | 0.9480 | 0.9955 |
154
  | `udhr-all` | 0.7301 | 0.7875 | 0.8000 | 0.7415 | 0.7318 | 0.7184 | 0.9672 |
155
 
156
+ #### Per language: test
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  F1 language by language, GlotLID and fastText restricted to MillID's labels: against GlotLID, MillID is better on **110** languages, worse on **776** and within 0.01 on 735; against fastText, MillID is better on **1616** languages, worse on **0** and within 0.01 on 5. Every language, with precision, recall and the unrestricted scores, is in `reports/test/leaderboard.csv`.
159
 
 
222
  | `mbd_Latn` | Dibabawon Manobo | 14 | 0.757 | 1.000 | 0.000 |
223
  | `lnd_Latn` | Lundayeh | 5 | 0.769 | 1.000 | 0.000 |
224
 
225
+ #### Per language: udhr
226
 
227
  F1 language by language, GlotLID and fastText restricted to MillID's labels: against GlotLID, MillID is better on **63** languages, worse on **95** and within 0.01 on 200; against fastText, MillID is better on **304** languages, worse on **13** and within 0.01 on 41. Every language, with precision, recall and the unrestricted scores, is in `reports/udhr/leaderboard.csv`.
228
 
 
291
  | `maz_Latn` | Central Mazahua | 59 | 0.742 | 0.939 | 0.000 |
292
  | `rmn_Latn` | Balkan Romani | 116 | 0.667 | 0.857 | 0.000 |
293
 
294
+ Precision, recall (sensitivity), F1 and specificity for every language and system, restricted and as it is, are in `reports/<set>/`, and the totals in `reports/summary.json`.
295
 
296
+ ## Quick start
297
 
298
+ Install the `millid` package, with ONNX Runtime for the CPU (`[gpu]` for CUDA):
299
 
300
+ ```bash
301
+ pip install "millid[cpu] @ git+https://github.com/baobab-tech/millid.git"
302
+ ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
+ Identify a passage, several, or a whole document:
305
 
306
+ ```python
307
+ from millid import MillID
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
 
309
+ model = MillID.from_pretrained("baobabtech/millid-medium-v1")
310
+ model.predict("Lave men ou ak savon anvan ou manje.", k=3)
311
+ # [Prediction(label='hat_Latn', language='Haitian Creole', probability=...), ...]
312
+ model.predict(["one text", "another"], k=3) # one list of answers per text
313
+ model.identify_document(long_text) # any length: its languages and segments
314
+ ```
315
 
316
+ From the command line:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
+ ```bash
319
+ millid predict "Lave men ou ak savon anvan ou manje." --model baobabtech/millid-medium-v1 -k 3
320
+ ```
321
+
322
+ In JavaScript, in Node or a browser (`js/` in [baobab-tech/millid](https://github.com/baobab-tech/millid); not on npm yet):
323
+
324
+ ```js
325
+ import { MillID } from "@baobabtech/millid"; // "@baobabtech/millid/web" in a browser, with { ort }
326
+ const model = await MillID.fromPretrained("baobabtech/millid-medium-v1");
327
+ await model.predict("Lave men ou ak savon anvan ou manje.", 3);
328
+ ```
329
+
330
+ `millid.py` in this repository is the PyTorch training code, which reads `model.safetensors` to fine-tune or export.
331
+
332
+ ## Best practices
333
+
334
+ ### 1. Pass the text as it is
335
+
336
+ The encoder applies Unicode NFKC and collapses whitespace itself. Accents, diacritics and the script are much of what it reads, so do not strip, transliterate or romanise text before passing it.
337
+
338
+ ### 2. Read long text as a document
339
+
340
+ `predict` reads the first 255 bytes of a passage. For anything longer, `identify_document` reads consecutive windows (at most 256, spread evenly over a longer text), weighs their probabilities by length, and reports the document's languages and the runs of each.
341
+
342
+ ### 3. Treat a low top probability as unsure
343
+
344
+ In our tests on real PDFs, a text layer whose characters were mapped to the wrong Unicode code points got a top probability below 0.5 from every MillID model, and reading the same pages from their images gave the right language. A top answer below 0.5 is worth a second look; but see the legacy fonts under Limitations, where that check does not hold.
345
+
346
+ ### 4. Expect less from very short text
347
+
348
+ On `test`, top-1 accuracy is 0.9382 for passages of 20 to 80 characters against 0.9846 for paragraphs. For a heading or a table cell, look at the top three answers rather than the first alone.
349
+
350
+ ### 5. One text alone and the same text in a batch can score differently
351
+
352
+ A batch is lower-cased as one string, so a dotted capital `İ` anywhere in it changes how every text in it is lower-cased (one Greek passage scored 0.976 alone and 0.985 beside Turkish text). The Python and JavaScript runtimes do this identically; send one text at a time where scores must not depend on their neighbours.
353
+
354
+ ### 6. Choose the size for where it runs
355
+
356
+ tiny v1.5 on a CPU or in a web page; medium v1 or large v1.5 on a GPU, large v1.5 when accuracy matters most. The three share their labels, so the choice changes no code.
357
+
358
+ ## Model data
359
+
360
+ MillID was trained on passages cut from pages the way a page is read: short lines, sentences and paragraphs.
361
+
362
+ * **PDFs:** [FinePDFs](https://huggingface.co/datasets/HuggingFaceFW/finepdfs), PDF text from Common Crawl, labelled by GlotLID.
363
+ * **Web pages:** [FineWeb-2](https://huggingface.co/datasets/HuggingFaceFW/fineweb-2), web text from Common Crawl, labelled by GlotLID.
364
+ * **Storybooks:** [GlotStoryBook](https://huggingface.co/datasets/cis-lmu/GlotStoryBook) (African Storybook, Pratham Books, LIDA, Little Cree Books) and Nal'ibali's stories in South African languages, labelled by their publishers.
365
+ * **News in sparse languages:** [GlotSparse](https://huggingface.co/datasets/cis-lmu/GlotSparse), labelled by the sites.
366
+ * **Publishers' documents:** [CAWST](https://washresources.cawst.org)'s training material and the [Save the Children Resource Centre](https://resourcecentre.savethechildren.net)'s reports and guidance, each document labelled with the language its publisher catalogued.
367
+ * **Not trained on:** the Universal Declaration of Human Rights, kept for testing; passages quoting it were removed from training.
368
 
369
  The training data is the full MillID build. The public [baobabtech/millid-dataset](https://huggingface.co/datasets/baobabtech/millid-dataset) is that build without Save the Children's and Nal'ibali's text (1.6% of its passages), which is not ours to redistribute. Its splits are the same, so its `test` split is the one scored above, without those passages.
370
 
371
+ ### Data processing
372
+
373
+ * **Passages:** Unicode NFKC, which folds the ligatures and presentation forms PDF text layers are full of; URLs, emails and dot leaders removed; a passage must be mostly letters. Exact duplicates were removed across every source, and no PDF gives more than 40 passages, article 20 or web page 10.
374
+ * **Labels checked:** a publisher's label is kept unless GlotLID is confident (≥ 0.8) the passage is in another major language, typically a copyright line; a passage from FinePDFs or FineWeb-2 is kept only when GlotLID's reading of the passage agrees with its document's.
375
+ * **Text that is no language removed:** passages GlotLID is confident are `zxx` (no linguistic content), mostly PDFs whose fonts map letters to the wrong code points, and documents catalogued in the wrong language.
376
+ * **Splits by document:** no test passage shares a document with a training one.
377
+
378
+ ### Training
379
+
380
+ 1,944,095 passages; the best validation macro F1 at step 56,000, after 3.4 hours on 1 GPU. Languages sampled in proportion to n^0.3; 25% of passages cut to a 20 to 80 character snippet; batch 512, AdamW at 0.0003, cosine schedule, label smoothing 0.1.
381
+
382
+ ## Architecture
383
+
384
+ ![MillID's architecture: a passage is normalised, encoded per UTF-8 byte into byte, script, byte-in-character and hashed character n-gram ids, embedded and summed, passed through a convolutional stem, downsampling and pre-norm transformer blocks, mean-pooled, and scored against label, language and script embeddings](assets/millid-architecture.png)
385
+
386
+ *Drawn at the medium preset's sizes (12 blocks, d = 768); this model's are in the table above.*
387
+
388
+ UTF-8 bytes (after Unicode NFKC), each embedded as byte + Unicode script + byte-in-character + hashed character 2-, 3- and 4-grams (32,768 buckets) -> depthwise convolution stem (kernel 5) -> strided convolution, 2 bytes per token -> 12 pre-norm blocks (RMSNorm, attention with RoPE, 12 heads, SwiGLU; d=768) -> masked mean pooling -> language head, each language's vector the sum of its own, its language's and its script's. See `ARCHITECTURE.md`.
389
+
390
+ ## Usage and limitations
391
+
392
+ ### Intended usage
393
+
394
+ * **Routing documents:** choosing the OCR, translation or language model for a document by its language.
395
+ * **Building and filtering corpora:** sorting web or PDF text by language, low-resource languages included.
396
+ * **Describing collections:** which languages a set of documents holds, and how much of each.
397
+ * **On-device detection:** in a browser or on a phone with tiny v1.5, where text should not leave the device.
398
+
399
+ ### Limitations
400
+
401
+ * **Close languages:** languages that differ by a few words are its weakest (F1 on `test`: Croatian 0.69, Bosnian 0.67, Malay 0.75, Indonesian 0.78, Norwegian Bokmål 0.81). Their short passages are often genuinely ambiguous.
402
+ * **Text that is no language:** there is no "no language" class. Nepali typed in the legacy Preeti font, whose text layer is Latin letters standing for Devanagari, was labelled as another language by MillID models, some with a top probability up to 0.74.
403
+ * **One label per passage:** a passage that mixes languages gets one; `identify_document` gives the segments of a longer text.
404
+ * **Labels learned from GlotLID:** the FinePDFs and FineWeb-2 passages were labelled by GlotLID, so MillID learned its labels, mistakes included; `udhr`, labelled by translators, is the independent test.
405
+ * **Genre:** for many low-resource languages the training text is mostly religious web text or children's stories, and a model can learn the genre along with the language.
406
+
407
+ ### Ethical considerations and risks
408
+
409
+ * **Errors fall on the smallest languages:** filtering or routing text by language can drop or mishandle the text of speakers of low-resource and closely related languages, where MillID is least accurate. Check the per-language scores of the languages that matter before filtering with it.
410
+ * **A language is not an identity:** do not use a language label to infer a person's nationality, ethnicity or origin.
411
+ * **Labels can be contested:** whether two varieties are one language or two is political as well as linguistic. MillID's labels follow ISO 639-3 and its training data, not a judgement on that question.
412
+
413
+ ### Benefits
414
+
415
+ MillID medium v1 is within 0.018 macro F1 of GlotLID, a 1.7 GB fastText model, on the 1,621 languages of `test`, and within 0.009 on `udhr`. All three sizes are open under Apache-2.0, with the code that trained and evaluated them and the dataset, less the text that is not ours to share.
416
+
417
  ## Licence
418
 
419
  The weights and the code are Apache-2.0. The training data carries its own licence row by row (see the [dataset card](https://huggingface.co/datasets/baobabtech/millid-dataset#licensing)), including text licensed for non-commercial use only (CC BY-NC, CC BY-NC-SA).
assets/millid-architecture.png ADDED

Git LFS Details

  • SHA256: e3e3149611e7153369df26b94b01603f158658d1f0a93ca924d4af915b0c54d2
  • Pointer size: 132 Bytes
  • Size of remote file: 1.47 MB