Upload folder using huggingface_hub
Browse files- README.md +290 -0
- __init__.py +6 -0
- config.json +197 -0
- configuration_feraoun_pro.py +63 -0
- export.stats.json +100 -0
- model.safetensors +3 -0
- modeling_feraoun_pro.py +207 -0
- tokenizer.json +291 -0
- tokenizer_config.json +9 -0
README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- kab
|
| 4 |
+
license: apache-2.0
|
| 5 |
+
tags:
|
| 6 |
+
- kabyle
|
| 7 |
+
- taqbaylit
|
| 8 |
+
- berber
|
| 9 |
+
- amazigh
|
| 10 |
+
- ocr
|
| 11 |
+
- image-to-text
|
| 12 |
+
- tifinagh
|
| 13 |
+
- document-understanding
|
| 14 |
+
- low-resource
|
| 15 |
+
- ctc
|
| 16 |
+
pipeline_tag: image-to-text
|
| 17 |
+
metrics:
|
| 18 |
+
- cer
|
| 19 |
+
- wer
|
| 20 |
+
- exact_match
|
| 21 |
+
model-index:
|
| 22 |
+
- name: Feraoun-Pro
|
| 23 |
+
results:
|
| 24 |
+
- task:
|
| 25 |
+
type: image-to-text
|
| 26 |
+
name: Line-level document OCR, Kabyle Latin
|
| 27 |
+
dataset:
|
| 28 |
+
type: agbalu/KabTifinagh
|
| 29 |
+
name: 25,484 held-out rendered lines, Latin
|
| 30 |
+
metrics:
|
| 31 |
+
- type: cer
|
| 32 |
+
value: 0.0734
|
| 33 |
+
name: Character error rate
|
| 34 |
+
- task:
|
| 35 |
+
type: image-to-text
|
| 36 |
+
name: Line-level document OCR, Kabyle Neo-Tifinagh
|
| 37 |
+
dataset:
|
| 38 |
+
type: agbalu/KabTifinagh
|
| 39 |
+
name: 4,516 held-out rendered lines, Neo-Tifinagh
|
| 40 |
+
metrics:
|
| 41 |
+
- type: cer
|
| 42 |
+
value: 0.0091
|
| 43 |
+
name: Character error rate
|
| 44 |
+
---
|
| 45 |
+
|
| 46 |
+
# Feraoun-Pro
|
| 47 |
+
|
| 48 |
+
A 51M-parameter CTC recogniser that reads a **line of printed Kabyle** (Taqbaylit, `kab`)
|
| 49 |
+
from a pixel strip and writes it out as text — in the Berber Latin orthography and in
|
| 50 |
+
Neo-Tifinagh, from one checkpoint, without being told which script it is looking at, in a
|
| 51 |
+
single forward pass.
|
| 52 |
+
|
| 53 |
+
It exists because the Kabyle written record is on paper. Novels, grammars, periodicals and
|
| 54 |
+
the archive scans that carry a century of prose are images, and general-purpose OCR was
|
| 55 |
+
never trained on the language: the emphatic consonants `ḍ ḥ ṛ ṣ ṭ ẓ` are a base letter plus
|
| 56 |
+
a sub-dot that other engines drop or normalise away, and dropping the dot changes the word.
|
| 57 |
+
`ţ` — Boulifa's original transcription convention — has a slot in this vocabulary. It has
|
| 58 |
+
never had one before.
|
| 59 |
+
|
| 60 |
+
**What it adds over [`agbalu/Feraoun-36M`](https://huggingface.co/agbalu/Feraoun-36M),
|
| 61 |
+
which also reads both scripts.** A 173-symbol table against 171 — `ţ` and `Ţ`, Boulifa's
|
| 62 |
+
convention, and 33 Neo-Tifinagh codepoints against 31. A single CTC forward pass in place of
|
| 63 |
+
one autoregressive decoder step per character. A variable-width canvas up to 1,024 px, so a
|
| 64 |
+
long line is no longer squeezed to fit. 600,000 training lines against 80,000. The two
|
| 65 |
+
models are separate artifacts on the same task and both stay published; Results says how to
|
| 66 |
+
choose.
|
| 67 |
+
|
| 68 |
+
## Results
|
| 69 |
+
|
| 70 |
+
**30,000 held-out lines, rendered**, drawn at a fixed seed over the full 600,000-line pool —
|
| 71 |
+
85% Latin, 15% Neo-Tifinagh, matching the training mix. The model saw none of these
|
| 72 |
+
sentences during training.
|
| 73 |
+
|
| 74 |
+
| | Latin (`n` = 25,484) | Neo-Tifinagh (`n` = 4,516) |
|
| 75 |
+
|---|---|---|
|
| 76 |
+
| Character error rate | **7.34%** | **0.91%** |
|
| 77 |
+
|
| 78 |
+
**Line exact match over all 30,000 lines: 81.77%.**
|
| 79 |
+
|
| 80 |
+
Three things the table does not say on its own.
|
| 81 |
+
|
| 82 |
+
**`Feraoun-36M` publishes 2.85% Latin CER, 1.64% Neo-Tifinagh CER and 70.20% exact match,
|
| 83 |
+
and none of those is comparable with the figures above.** The two models were scored on
|
| 84 |
+
different held-out draws from different line sets, and neither has been run on the other's —
|
| 85 |
+
so the pair is two measurements, not a ranking, and this card does not turn it into one.
|
| 86 |
+
Choose by page: this model takes a line up to 1,024 px without squeezing it, has `ţ` in its
|
| 87 |
+
alphabet, and decodes in one pass; the 36M model is smaller and is the one whose font
|
| 88 |
+
generalisation has been tested.
|
| 89 |
+
|
| 90 |
+
**The Tifinagh number is a retention result, not a difficulty result.** Neo-Tifinagh writes
|
| 91 |
+
no sub-dots and no capitals and its lines are shorter, so sub-1% there is not a better score
|
| 92 |
+
on the same task — it is an easier task, and the figure's value is that it proves the script
|
| 93 |
+
survived training alongside Latin rather than fading.
|
| 94 |
+
|
| 95 |
+
**Checkpoint selection was gated on both scripts at once.** The combined error
|
| 96 |
+
`0.5 · Latin CER + 0.5 · Tifinagh CER` had to improve while neither script regressed past
|
| 97 |
+
its baseline. A checkpoint that reads Tifinagh better by forgetting Latin is not selected,
|
| 98 |
+
which is the failure this model's whole training design is built around.
|
| 99 |
+
|
| 100 |
+
## What the numbers cover, and what they do not
|
| 101 |
+
|
| 102 |
+
Every figure above is measured on rendered lines. What that leaves open, stated so you can
|
| 103 |
+
plan around it rather than discover it:
|
| 104 |
+
|
| 105 |
+
- **Real scanned pages are not in the evaluation.** Training and validation are both
|
| 106 |
+
synthetic renders, as is `Feraoun-36M`'s 2.85%. Performance on Adlis book scans — genuine
|
| 107 |
+
century-old print — is open for both models.
|
| 108 |
+
- **The head-to-head against `Feraoun-36M` has not been run**, for the reason above.
|
| 109 |
+
- **`ţ`/`Ţ` have vocabulary slots and no per-glyph score.** The validation pool holds too
|
| 110 |
+
few `ţ` lines to report one. The slots are what make the glyph representable at all; no
|
| 111 |
+
other Kabyle OCR system has them.
|
| 112 |
+
- **Font generalisation is not quantified.** Training and evaluation draw from the same set
|
| 113 |
+
of container faces, so a typeface the model has never seen is outside what these numbers
|
| 114 |
+
describe. Expect it to be the axis that moves most.
|
| 115 |
+
|
| 116 |
+
## Architecture
|
| 117 |
+
|
| 118 |
+
| | |
|
| 119 |
+
|---|---|
|
| 120 |
+
| Parameters | **51,440,589**, plus 132,036 elements of buffer — the sinusoidal position table and the stem's batch-norm statistics — for 51,572,625 tensor elements in the weights file. The training checkpoint holds 60,158,014: the difference is an 8,585,389-parameter auxiliary decoder that supplies gradients and is not exported |
|
| 121 |
+
| Stem | 5-layer convolutional front end, 64 px fixed height, variable width to 1,024 px |
|
| 122 |
+
| Encoder | 16-layer pre-norm Transformer, 512 hidden, 8 heads |
|
| 123 |
+
| Head | CTC over 173 classes, greedy decode |
|
| 124 |
+
| Input | `(1, 3, 64, W)`, pixel range `[−1, 1]`, aspect ratio preserved |
|
| 125 |
+
| Vocabulary | 173 classes — 4 special, Latin, Kabyle extended and sub-dot (`ḍ ḥ ṛ ṣ ṭ ẓ`), accented Latin, `ţ`/`Ţ`, digits, punctuation, 33 Neo-Tifinagh |
|
| 126 |
+
|
| 127 |
+
**No decoder steps, no beam search, no key-value cache.** A line is one forward pass:
|
| 128 |
+
convolutional stem, Transformer encoder, linear projection, CTC argmax. The auxiliary
|
| 129 |
+
autoregressive decoder existed only to keep gradients reaching the early convolutional
|
| 130 |
+
layers, and it is not in the published weights.
|
| 131 |
+
|
| 132 |
+
**173 classes, not subwords.** A subword tokeniser completes vocabulary words where the ink
|
| 133 |
+
is broken, which is precisely the failure an OCR system must not have: it produces fluent
|
| 134 |
+
Kabyle that is not what the page says.
|
| 135 |
+
|
| 136 |
+
## Intended use
|
| 137 |
+
|
| 138 |
+
Turning printed Kabyle into text: scanned novels, grammars, periodicals and archive
|
| 139 |
+
material, in the Latin orthography or in Neo-Tifinagh, from the same model.
|
| 140 |
+
|
| 141 |
+
**Not suitable for**: handwriting, absent from the training data; multi-column layout, which
|
| 142 |
+
`transcribe_page` reads straight across; any decision about a person; or any language other
|
| 143 |
+
than Kabyle. Tarifit, Tashelhit and Central Atlas Tamazight share part of this orthography
|
| 144 |
+
and are not evaluated here.
|
| 145 |
+
|
| 146 |
+
## Usage
|
| 147 |
+
|
| 148 |
+
`transformers`, `torch`, `pillow` and `numpy`, nothing else. The architecture is not one of
|
| 149 |
+
the library's own, so the modelling code travels in this repository and
|
| 150 |
+
`trust_remote_code=True` is what loads it.
|
| 151 |
+
|
| 152 |
+
```python
|
| 153 |
+
from PIL import Image
|
| 154 |
+
from transformers import AutoModel
|
| 155 |
+
|
| 156 |
+
model = AutoModel.from_pretrained("agbalu/Feraoun-Pro", trust_remote_code=True).eval()
|
| 157 |
+
|
| 158 |
+
print(model.transcribe(Image.open("line_crop.png")))
|
| 159 |
+
# 'Taqbaylit d tutlayt tayemmat nneɣ.'
|
| 160 |
+
|
| 161 |
+
print(model.transcribe(Image.open("tifinagh_line.png")))
|
| 162 |
+
# 'ⵜⴰⵇⴱⴰⵢⵍⵉⵜ ⴷ ⵜⵓⵜⵍⴰⵢⵜ ⵜⴰⵢⴻⵎⵎⴰⵜ ⵏⵏⴻⵖ.'
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
`transcribe` does the preprocessing as well as the decoding, and that matters: the model was
|
| 166 |
+
fitted on lines scaled to 64 px of height with aspect ratio preserved, so a caller who builds
|
| 167 |
+
the tensor themselves at another scale is measuring a different model.
|
| 168 |
+
|
| 169 |
+
For a full page, `transcribe_page` segments on the horizontal ink profile first. That
|
| 170 |
+
segmentation assumes a single column of roughly horizontal lines; it has not been evaluated
|
| 171 |
+
on multi-column layouts, marginalia or skewed scans.
|
| 172 |
+
|
| 173 |
+
## Training data
|
| 174 |
+
|
| 175 |
+
Lines are **rendered, not scanned.** There is no page of real Kabyle print with
|
| 176 |
+
character-level ground truth to train against.
|
| 177 |
+
|
| 178 |
+
| | |
|
| 179 |
+
|---|---|
|
| 180 |
+
| Latin text | AƔBALU-Text v1, not publicly released |
|
| 181 |
+
| Neo-Tifinagh text | [`agbalu/KabTifinagh`](https://huggingface.co/datasets/agbalu/KabTifinagh) `script_conversion` train split, CC-BY-2.0 |
|
| 182 |
+
| Objective | CTC, plus an auxiliary autoregressive decoder whose gradients reach the encoder and which is **not** exported |
|
| 183 |
+
|
| 184 |
+
The renderer composites text set at 24–38 pt in the faces available in the training container
|
| 185 |
+
onto generated paper grain, then degrades by blur, exposure, JPEG artefacting and a slight
|
| 186 |
+
skew. Height is fixed at 64 px; width follows the line up to 1,024 px, so glyphs are never
|
| 187 |
+
squashed to a square canvas.
|
| 188 |
+
|
| 189 |
+
**The degradation is deliberately modest**, and the model has not been shown genuinely hard
|
| 190 |
+
inputs: no bleed-through from the reverse of the page, no ink starvation, no page-edge
|
| 191 |
+
shadow, no show-through from facing pages. Expect real archival scans to be harder than
|
| 192 |
+
anything in training.
|
| 193 |
+
|
| 194 |
+
**The corpus composition is uneven.** AƔBALU-Text v1 is a 42-source mixture and the sources
|
| 195 |
+
are not weighted equally. The line set is a seeded draw over the full pool rather than a
|
| 196 |
+
prefix, which is what keeps it from being one source, but it does not flatten the source
|
| 197 |
+
distribution: a novel's long sentences and a newspaper's headlines are both in the pool and
|
| 198 |
+
both outside what a 30,000-line validation draw can fully represent.
|
| 199 |
+
|
| 200 |
+
## Training recipe
|
| 201 |
+
|
| 202 |
+
One A10G throughout, 600,000 rendered lines per stage, 570,000 train / 30,000 validation on
|
| 203 |
+
a fixed seed, batch 64, one epoch per stage, cosine schedule with 5% warmup.
|
| 204 |
+
|
| 205 |
+
| stage | mix | peak lr | what it does |
|
| 206 |
+
|---|---|---|---|
|
| 207 |
+
| 1 | Latin only | `2e-5` | builds the Latin recogniser and the sub-dot distinctions |
|
| 208 |
+
| 2 | 60% Latin / 40% Tifinagh | `2e-5` | introduces the 33 Neo-Tifinagh codepoints |
|
| 209 |
+
| 3 | 85% Latin / 15% Tifinagh | `5e-6` → `2.5e-7` | settles both scripts; 8,907 steps |
|
| 210 |
+
|
| 211 |
+
**The staging is the design, not a schedule that happened to be split up.** Introducing
|
| 212 |
+
Neo-Tifinagh at 40% costs Latin accuracy — that is where this model's 7.34% Latin CER comes
|
| 213 |
+
from, and it is why stage 3 drops the Tifinagh share to a rehearsal fraction and the learning
|
| 214 |
+
rate by 4×. The 15% rehearsal is enough to keep the Tifinagh codepoints from fading while the
|
| 215 |
+
Latin weights settle. Every stage's checkpoint is gated on the combined two-script error with
|
| 216 |
+
a per-script regression ceiling, so no stage can trade one script for the other.
|
| 217 |
+
|
| 218 |
+
## Limitations
|
| 219 |
+
|
| 220 |
+
**7.34% Latin CER on synthetic renders is not 7.34% on your documents.** The validation set
|
| 221 |
+
is drawn from the same rendered distribution as training. Real scanned pages have ink bleed,
|
| 222 |
+
page curvature, show-through and aging that the renderer approximates at modest levels.
|
| 223 |
+
Whether the gap is one point or ten is not known.
|
| 224 |
+
|
| 225 |
+
**Latin character accuracy is the weak axis.** It is the price of dual-script capacity in a
|
| 226 |
+
model this size, and it is stated in Results rather than buried here.
|
| 227 |
+
|
| 228 |
+
**Punctuation after dense glyph clusters is a consistent weakness.** In Neo-Tifinagh,
|
| 229 |
+
`ⴰⵣⵓⵍ ⴼⵍⵍ-ⴰⵡⴻⵏ, ⴰⵎⴻⴽ ⵜⴻⵍⵍⴰⵎ?` came back as `ⴰⵣⵓⵍ ⴼⵍⵍ,ⴰⵡⴻⵏ, ⴰⵎⴻⴽ ⵜⴻⵍⵍⴰⵎ!` — the hyphen read
|
| 230 |
+
as a comma and the closing `?` as `!`, both at marks that follow glyphs without a full
|
| 231 |
+
inter-word space.
|
| 232 |
+
|
| 233 |
+
**Whitespace boundaries are not reliable.** The validation ground truth is stripped, so
|
| 234 |
+
trailing-space errors introduced by the renderer's post-processing do not appear in the CER.
|
| 235 |
+
They will appear in your output if the downstream consumer is whitespace-sensitive.
|
| 236 |
+
|
| 237 |
+
**Page layout is a projection profile, nothing more.** `transcribe_page` finds horizontal ink
|
| 238 |
+
bands and crops them. There is no column detection, no reading-order model and no table or
|
| 239 |
+
figure handling, so a two-column periodical is read straight across.
|
| 240 |
+
|
| 241 |
+
## Files
|
| 242 |
+
|
| 243 |
+
| file | contents |
|
| 244 |
+
|---|---|
|
| 245 |
+
| `model.safetensors` | the convolutional stem, the 16-layer encoder and the CTC head — 51,440,589 parameters and 132,036 elements of buffer, 206 MB fp32. `from_pretrained` reports no missing and no unexpected keys |
|
| 246 |
+
| `config.json` | architecture and the `auto_map` that points at the code below |
|
| 247 |
+
| `configuration_feraoun_pro.py`, `modeling_feraoun_pro.py` | the architecture and the preprocessing, importing only `torch`, `transformers`, `pillow` and `numpy` |
|
| 248 |
+
| `tokenizer.json`, `tokenizer_config.json` | the 173-symbol table, id for id with the one the model was trained on |
|
| 249 |
+
|
| 250 |
+
Training cannot be resumed from the published files: the optimizer, scheduler, step and epoch
|
| 251 |
+
stay in the source checkpoint on the training volume and are not exported.
|
| 252 |
+
|
| 253 |
+
## Reproduction
|
| 254 |
+
|
| 255 |
+
```bash
|
| 256 |
+
make modal-ocr-pro RUN=latin EPOCHS=1 LR=2e-5 RATIO=0.0 LINES=600000
|
| 257 |
+
make modal-ocr-pro RUN=dual EPOCHS=1 LR=2e-5 RATIO=0.40 RESUME=latin
|
| 258 |
+
make modal-ocr-pro RUN=feraoun-pro EPOCHS=1 LR=5e-6 RATIO=0.15 RESUME=dual
|
| 259 |
+
make modal-ocr-pro-pull RUN=feraoun-pro
|
| 260 |
+
make push REPO=feraoun-pro
|
| 261 |
+
```
|
| 262 |
+
|
| 263 |
+
## The name
|
| 264 |
+
|
| 265 |
+
**Mouloud Feraoun** (1913–1962), the schoolteacher from Tizi Hibel who wrote *Le Fils du
|
| 266 |
+
pauvre* and put Si Mohand's oral poetry onto the printed page — the direction this model
|
| 267 |
+
reverses. He was assassinated by the OAS on 15 March 1962, three days before the Évian
|
| 268 |
+
Accords were signed. The naming is homage and carries no endorsement.
|
| 269 |
+
|
| 270 |
+
## Citation
|
| 271 |
+
|
| 272 |
+
```bibtex
|
| 273 |
+
@software{agbalu_feraoun_pro_2026,
|
| 274 |
+
title = {Feraoun-Pro: dual-script CTC document OCR for Kabyle},
|
| 275 |
+
author = {AƔBALU},
|
| 276 |
+
year = {2026},
|
| 277 |
+
url = {https://huggingface.co/agbalu/Feraoun-Pro},
|
| 278 |
+
note = {51,572,625 parameters; Latin CER 7.34\%, Neo-Tifinagh CER 0.91\%,
|
| 279 |
+
line exact match 81.77\%, over 30,000 held-out rendered lines}
|
| 280 |
+
}
|
| 281 |
+
```
|
| 282 |
+
|
| 283 |
+
## Licence
|
| 284 |
+
|
| 285 |
+
**Apache-2.0** on the weights and the code. The training text is CC-BY-2.0 on the Tifinagh
|
| 286 |
+
side and a mixed corpus of uneven provenance on the Latin side. A permissive grant on the
|
| 287 |
+
weights makes no claim about the text behind them, so the corpus composition is stated above
|
| 288 |
+
rather than assumed.
|
| 289 |
+
|
| 290 |
+
Part of [AƔBALU](https://huggingface.co/agbalu), a Kabyle NLP collection.
|
__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Feraoun-Pro standalone hub package."""
|
| 2 |
+
|
| 3 |
+
from .configuration_feraoun_pro import FeraounProConfig
|
| 4 |
+
from .modeling_feraoun_pro import FeraounProForCTC, prepare_line_image, segment_page_into_lines
|
| 5 |
+
|
| 6 |
+
__all__ = ["FeraounProConfig", "FeraounProForCTC", "prepare_line_image", "segment_page_into_lines"]
|
config.json
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"FeraounProForCTC"
|
| 4 |
+
],
|
| 5 |
+
"auto_map": {
|
| 6 |
+
"AutoConfig": "configuration_feraoun_pro.FeraounProConfig",
|
| 7 |
+
"AutoModel": "modeling_feraoun_pro.FeraounProForCTC"
|
| 8 |
+
},
|
| 9 |
+
"bos_token_id": 1,
|
| 10 |
+
"d_model": 512,
|
| 11 |
+
"dim_feedforward": 2048,
|
| 12 |
+
"dropout": 0.1,
|
| 13 |
+
"eos_token_id": 2,
|
| 14 |
+
"max_width_frames": 256,
|
| 15 |
+
"model_type": "feraoun_pro",
|
| 16 |
+
"num_encoder_layers": 16,
|
| 17 |
+
"num_heads": 8,
|
| 18 |
+
"pad_token_id": 0,
|
| 19 |
+
"transformers_version": "5.12.1",
|
| 20 |
+
"unk_token_id": 3,
|
| 21 |
+
"vocab_size": 173,
|
| 22 |
+
"vocabulary": [
|
| 23 |
+
"<pad>",
|
| 24 |
+
"<s>",
|
| 25 |
+
"</s>",
|
| 26 |
+
"<unk>",
|
| 27 |
+
"a",
|
| 28 |
+
"b",
|
| 29 |
+
"c",
|
| 30 |
+
"d",
|
| 31 |
+
"e",
|
| 32 |
+
"f",
|
| 33 |
+
"g",
|
| 34 |
+
"h",
|
| 35 |
+
"i",
|
| 36 |
+
"j",
|
| 37 |
+
"k",
|
| 38 |
+
"l",
|
| 39 |
+
"m",
|
| 40 |
+
"n",
|
| 41 |
+
"o",
|
| 42 |
+
"p",
|
| 43 |
+
"q",
|
| 44 |
+
"r",
|
| 45 |
+
"s",
|
| 46 |
+
"t",
|
| 47 |
+
"u",
|
| 48 |
+
"v",
|
| 49 |
+
"w",
|
| 50 |
+
"x",
|
| 51 |
+
"y",
|
| 52 |
+
"z",
|
| 53 |
+
"A",
|
| 54 |
+
"B",
|
| 55 |
+
"C",
|
| 56 |
+
"D",
|
| 57 |
+
"E",
|
| 58 |
+
"F",
|
| 59 |
+
"G",
|
| 60 |
+
"H",
|
| 61 |
+
"I",
|
| 62 |
+
"J",
|
| 63 |
+
"K",
|
| 64 |
+
"L",
|
| 65 |
+
"M",
|
| 66 |
+
"N",
|
| 67 |
+
"O",
|
| 68 |
+
"P",
|
| 69 |
+
"Q",
|
| 70 |
+
"R",
|
| 71 |
+
"S",
|
| 72 |
+
"T",
|
| 73 |
+
"U",
|
| 74 |
+
"V",
|
| 75 |
+
"W",
|
| 76 |
+
"X",
|
| 77 |
+
"Y",
|
| 78 |
+
"Z",
|
| 79 |
+
"\u0263",
|
| 80 |
+
"\u0194",
|
| 81 |
+
"\u025b",
|
| 82 |
+
"\u0190",
|
| 83 |
+
"\u010d",
|
| 84 |
+
"\u010c",
|
| 85 |
+
"\u01e7",
|
| 86 |
+
"\u01e6",
|
| 87 |
+
"\u0163",
|
| 88 |
+
"\u0162",
|
| 89 |
+
"\u1e0d",
|
| 90 |
+
"\u1e0c",
|
| 91 |
+
"\u1e25",
|
| 92 |
+
"\u1e24",
|
| 93 |
+
"\u1e5b",
|
| 94 |
+
"\u1e5a",
|
| 95 |
+
"\u1e63",
|
| 96 |
+
"\u1e62",
|
| 97 |
+
"\u1e6d",
|
| 98 |
+
"\u1e6c",
|
| 99 |
+
"\u1e93",
|
| 100 |
+
"\u1e92",
|
| 101 |
+
"\u00e9",
|
| 102 |
+
"\u00e8",
|
| 103 |
+
"\u00ea",
|
| 104 |
+
"\u00eb",
|
| 105 |
+
"\u00e0",
|
| 106 |
+
"\u00e2",
|
| 107 |
+
"\u00ee",
|
| 108 |
+
"\u00ef",
|
| 109 |
+
"\u00f4",
|
| 110 |
+
"\u00f9",
|
| 111 |
+
"\u00fb",
|
| 112 |
+
"\u00e7",
|
| 113 |
+
"\u00c9",
|
| 114 |
+
"\u00c8",
|
| 115 |
+
"\u00ca",
|
| 116 |
+
"\u00cb",
|
| 117 |
+
"\u00c0",
|
| 118 |
+
"\u00c2",
|
| 119 |
+
"\u00ce",
|
| 120 |
+
"\u00cf",
|
| 121 |
+
"\u00d4",
|
| 122 |
+
"\u00d9",
|
| 123 |
+
"\u00db",
|
| 124 |
+
"\u00c7",
|
| 125 |
+
"0",
|
| 126 |
+
"1",
|
| 127 |
+
"2",
|
| 128 |
+
"3",
|
| 129 |
+
"4",
|
| 130 |
+
"5",
|
| 131 |
+
"6",
|
| 132 |
+
"7",
|
| 133 |
+
"8",
|
| 134 |
+
"9",
|
| 135 |
+
" ",
|
| 136 |
+
".",
|
| 137 |
+
",",
|
| 138 |
+
"?",
|
| 139 |
+
"!",
|
| 140 |
+
"\u00ab",
|
| 141 |
+
"\u00bb",
|
| 142 |
+
"-",
|
| 143 |
+
"\u2014",
|
| 144 |
+
":",
|
| 145 |
+
";",
|
| 146 |
+
"'",
|
| 147 |
+
"\"",
|
| 148 |
+
"/",
|
| 149 |
+
"(",
|
| 150 |
+
")",
|
| 151 |
+
"[",
|
| 152 |
+
"]",
|
| 153 |
+
"{",
|
| 154 |
+
"}",
|
| 155 |
+
"%",
|
| 156 |
+
"*",
|
| 157 |
+
"+",
|
| 158 |
+
"=",
|
| 159 |
+
"_",
|
| 160 |
+
"~",
|
| 161 |
+
"\u2013",
|
| 162 |
+
"\u2026",
|
| 163 |
+
"\n",
|
| 164 |
+
"\t",
|
| 165 |
+
"\u2d30",
|
| 166 |
+
"\u2d31",
|
| 167 |
+
"\u2d33",
|
| 168 |
+
"\u2d37",
|
| 169 |
+
"\u2d39",
|
| 170 |
+
"\u2d3b",
|
| 171 |
+
"\u2d3c",
|
| 172 |
+
"\u2d3d",
|
| 173 |
+
"\u2d40",
|
| 174 |
+
"\u2d43",
|
| 175 |
+
"\u2d44",
|
| 176 |
+
"\u2d45",
|
| 177 |
+
"\u2d47",
|
| 178 |
+
"\u2d49",
|
| 179 |
+
"\u2d4a",
|
| 180 |
+
"\u2d4d",
|
| 181 |
+
"\u2d4e",
|
| 182 |
+
"\u2d4f",
|
| 183 |
+
"\u2d53",
|
| 184 |
+
"\u2d54",
|
| 185 |
+
"\u2d55",
|
| 186 |
+
"\u2d59",
|
| 187 |
+
"\u2d5a",
|
| 188 |
+
"\u2d5b",
|
| 189 |
+
"\u2d5c",
|
| 190 |
+
"\u2d5f",
|
| 191 |
+
"\u2d61",
|
| 192 |
+
"\u2d62",
|
| 193 |
+
"\u2d63",
|
| 194 |
+
"\u2d65",
|
| 195 |
+
"\u2d56"
|
| 196 |
+
]
|
| 197 |
+
}
|
configuration_feraoun_pro.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Configuration for the Feraoun-Pro document OCR model."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from typing import Any, Final
|
| 6 |
+
|
| 7 |
+
from transformers import PreTrainedConfig
|
| 8 |
+
|
| 9 |
+
SYMBOLS: Final[str] = (
|
| 10 |
+
"abcdefghijklmnopqrstuvwxyz"
|
| 11 |
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
| 12 |
+
"ɣƔɛƐčČǧǦţŢ"
|
| 13 |
+
"ḍḌḥḤṛṚṣṢṭṬẓẒ"
|
| 14 |
+
"éèêëàâîïôùûçÉÈÊËÀÂÎÏÔÙÛÇ"
|
| 15 |
+
"0123456789"
|
| 16 |
+
" .,?!«»-—:;'\"/()[]{}%*+=_~–…\n\t"
|
| 17 |
+
"ⴰⴱⴳⴷⴹⴻⴼⴽⵀⵃⵄⵅⵇⵉⵊⵍⵎⵏⵓⵔⵕⵙⵚⵛⵜⵟⵡⵢⵣⵥⵖ"
|
| 18 |
+
)
|
| 19 |
+
"""The 169 printable classes after the four special tokens, spelled out rather than
|
| 20 |
+
imported: nothing under `hub/` may import `agbalu`, because these modules are loaded from
|
| 21 |
+
the published repository where this package does not exist.
|
| 22 |
+
`tests/unit/test_ocr_pro.py` pins them against `agbalu.ocr.vocabulary_pro`, so the two
|
| 23 |
+
copies cannot drift apart silently."""
|
| 24 |
+
|
| 25 |
+
DEFAULT_VOCABULARY: Final[tuple[str, ...]] = ("<pad>", "<s>", "</s>", "<unk>", *SYMBOLS)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class FeraounProConfig(PreTrainedConfig):
|
| 29 |
+
model_type = "feraoun_pro"
|
| 30 |
+
|
| 31 |
+
def __init__(
|
| 32 |
+
self,
|
| 33 |
+
vocabulary: list[str] | tuple[str, ...] | None = None,
|
| 34 |
+
vocab_size: int = 173,
|
| 35 |
+
d_model: int = 512,
|
| 36 |
+
num_encoder_layers: int = 16,
|
| 37 |
+
num_heads: int = 8,
|
| 38 |
+
dim_feedforward: int = 2048,
|
| 39 |
+
max_width_frames: int = 256,
|
| 40 |
+
dropout: float = 0.1,
|
| 41 |
+
**kwargs: Any,
|
| 42 |
+
) -> None:
|
| 43 |
+
# The symbol table ships in `config.json`: a CTC id means nothing without it, and a
|
| 44 |
+
# downloader who has to reconstruct it from this repository does not have a usable
|
| 45 |
+
# artifact. `vocab_size` stays a separate field because it is the width of
|
| 46 |
+
# `ctc_head` and a saved config carries it.
|
| 47 |
+
self.vocabulary = list(vocabulary) if vocabulary is not None else list(DEFAULT_VOCABULARY)
|
| 48 |
+
self.vocab_size = vocab_size
|
| 49 |
+
self.d_model = d_model
|
| 50 |
+
self.num_encoder_layers = num_encoder_layers
|
| 51 |
+
self.num_heads = num_heads
|
| 52 |
+
self.dim_feedforward = dim_feedforward
|
| 53 |
+
self.max_width_frames = max_width_frames
|
| 54 |
+
self.dropout = dropout
|
| 55 |
+
|
| 56 |
+
kwargs.setdefault("pad_token_id", 0)
|
| 57 |
+
kwargs.setdefault("bos_token_id", 1)
|
| 58 |
+
kwargs.setdefault("eos_token_id", 2)
|
| 59 |
+
kwargs.setdefault("unk_token_id", 3)
|
| 60 |
+
super().__init__(**kwargs)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
__all__ = ["DEFAULT_VOCABULARY", "SYMBOLS", "FeraounProConfig"]
|
export.stats.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"source": "artifacts/runs/feraoun-pro/best.pt",
|
| 3 |
+
"source_contents": [
|
| 4 |
+
"model",
|
| 5 |
+
"optimizer",
|
| 6 |
+
"rng",
|
| 7 |
+
"state"
|
| 8 |
+
],
|
| 9 |
+
"dropped_state": [
|
| 10 |
+
"optimizer",
|
| 11 |
+
"rng"
|
| 12 |
+
],
|
| 13 |
+
"dropped_tied": [],
|
| 14 |
+
"dropped_derived": [],
|
| 15 |
+
"dropped_training_only": [
|
| 16 |
+
"aux_decoder.decoder.layers.0.linear1.bias",
|
| 17 |
+
"aux_decoder.decoder.layers.0.linear1.weight",
|
| 18 |
+
"aux_decoder.decoder.layers.0.linear2.bias",
|
| 19 |
+
"aux_decoder.decoder.layers.0.linear2.weight",
|
| 20 |
+
"aux_decoder.decoder.layers.0.multihead_attn.in_proj_bias",
|
| 21 |
+
"aux_decoder.decoder.layers.0.multihead_attn.in_proj_weight",
|
| 22 |
+
"aux_decoder.decoder.layers.0.multihead_attn.out_proj.bias",
|
| 23 |
+
"aux_decoder.decoder.layers.0.multihead_attn.out_proj.weight",
|
| 24 |
+
"aux_decoder.decoder.layers.0.norm1.bias",
|
| 25 |
+
"aux_decoder.decoder.layers.0.norm1.weight",
|
| 26 |
+
"aux_decoder.decoder.layers.0.norm2.bias",
|
| 27 |
+
"aux_decoder.decoder.layers.0.norm2.weight",
|
| 28 |
+
"aux_decoder.decoder.layers.0.norm3.bias",
|
| 29 |
+
"aux_decoder.decoder.layers.0.norm3.weight",
|
| 30 |
+
"aux_decoder.decoder.layers.0.self_attn.in_proj_bias",
|
| 31 |
+
"aux_decoder.decoder.layers.0.self_attn.in_proj_weight",
|
| 32 |
+
"aux_decoder.decoder.layers.0.self_attn.out_proj.bias",
|
| 33 |
+
"aux_decoder.decoder.layers.0.self_attn.out_proj.weight",
|
| 34 |
+
"aux_decoder.decoder.layers.1.linear1.bias",
|
| 35 |
+
"aux_decoder.decoder.layers.1.linear1.weight",
|
| 36 |
+
"aux_decoder.decoder.layers.1.linear2.bias",
|
| 37 |
+
"aux_decoder.decoder.layers.1.linear2.weight",
|
| 38 |
+
"aux_decoder.decoder.layers.1.multihead_attn.in_proj_bias",
|
| 39 |
+
"aux_decoder.decoder.layers.1.multihead_attn.in_proj_weight",
|
| 40 |
+
"aux_decoder.decoder.layers.1.multihead_attn.out_proj.bias",
|
| 41 |
+
"aux_decoder.decoder.layers.1.multihead_attn.out_proj.weight",
|
| 42 |
+
"aux_decoder.decoder.layers.1.norm1.bias",
|
| 43 |
+
"aux_decoder.decoder.layers.1.norm1.weight",
|
| 44 |
+
"aux_decoder.decoder.layers.1.norm2.bias",
|
| 45 |
+
"aux_decoder.decoder.layers.1.norm2.weight",
|
| 46 |
+
"aux_decoder.decoder.layers.1.norm3.bias",
|
| 47 |
+
"aux_decoder.decoder.layers.1.norm3.weight",
|
| 48 |
+
"aux_decoder.decoder.layers.1.self_attn.in_proj_bias",
|
| 49 |
+
"aux_decoder.decoder.layers.1.self_attn.in_proj_weight",
|
| 50 |
+
"aux_decoder.decoder.layers.1.self_attn.out_proj.bias",
|
| 51 |
+
"aux_decoder.decoder.layers.1.self_attn.out_proj.weight",
|
| 52 |
+
"aux_decoder.embedding.weight",
|
| 53 |
+
"aux_decoder.lm_head.bias",
|
| 54 |
+
"aux_decoder.lm_head.weight"
|
| 55 |
+
],
|
| 56 |
+
"tensors": 221,
|
| 57 |
+
"parameters": 51572625,
|
| 58 |
+
"files": [
|
| 59 |
+
{
|
| 60 |
+
"name": "README.md",
|
| 61 |
+
"bytes": 13969,
|
| 62 |
+
"sha256": "39d5914cdb53dcfd14aefcb7838e870cbd981600ac21ac3734934a0534b2007f"
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"name": "__init__.py",
|
| 66 |
+
"bytes": 296,
|
| 67 |
+
"sha256": "9ac3b94df93a57b0dac01996acc6e5ef217e016f117fbc97fd05c473d7dbfc84"
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"name": "config.json",
|
| 71 |
+
"bytes": 2507,
|
| 72 |
+
"sha256": "746ce438be8325339c8e5a0b0caddcbd20d1cab56386f13e0157d147ce3f65ab"
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"name": "configuration_feraoun_pro.py",
|
| 76 |
+
"bytes": 2423,
|
| 77 |
+
"sha256": "32020487761b9375e0a6931cfdfd39551bccd8c50939a39108bdc845036b8b8f"
|
| 78 |
+
},
|
| 79 |
+
{
|
| 80 |
+
"name": "model.safetensors",
|
| 81 |
+
"bytes": 206313076,
|
| 82 |
+
"sha256": "dfc55395ed15b9d727eae16594ec7f87c8ef28fdc2e6d5f7bd6e88d7bbafe165"
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"name": "modeling_feraoun_pro.py",
|
| 86 |
+
"bytes": 7590,
|
| 87 |
+
"sha256": "7c8018a171eb4647453140103bf919f98d2860339a74d819ef1869865a239563"
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"name": "tokenizer.json",
|
| 91 |
+
"bytes": 4764,
|
| 92 |
+
"sha256": "350100049e4f193563065147c35fce2dbcc344cf98420e0fa209c4b668864c37"
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"name": "tokenizer_config.json",
|
| 96 |
+
"bytes": 193,
|
| 97 |
+
"sha256": "444cfded3d0102faf5c8bb4706f540becd8103ce7344ddbbad8df2da0928fa52"
|
| 98 |
+
}
|
| 99 |
+
]
|
| 100 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:dfc55395ed15b9d727eae16594ec7f87c8ef28fdc2e6d5f7bd6e88d7bbafe165
|
| 3 |
+
size 206313076
|
modeling_feraoun_pro.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Feraoun-Pro: Hybrid CNN-Transformer CTC Document OCR Model for Kabyle."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
import math
|
| 6 |
+
from typing import TYPE_CHECKING, Final
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
from torch import Tensor, nn
|
| 10 |
+
from transformers import PreTrainedModel
|
| 11 |
+
|
| 12 |
+
from .configuration_feraoun_pro import FeraounProConfig
|
| 13 |
+
|
| 14 |
+
if TYPE_CHECKING:
|
| 15 |
+
from PIL import Image
|
| 16 |
+
|
| 17 |
+
TARGET_HEIGHT: Final[int] = 64
|
| 18 |
+
MAX_WIDTH: Final[int] = 1024
|
| 19 |
+
CROP_INK_THRESHOLD: Final[int] = 225
|
| 20 |
+
LINE_INK_THRESHOLD: Final[int] = 200
|
| 21 |
+
LINE_MARGIN: Final[int] = 4
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def crop_text_bbox(image: Image.Image, padding: int = LINE_MARGIN) -> Image.Image:
|
| 25 |
+
"""Crop to the bounding box of the ink."""
|
| 26 |
+
import numpy as np
|
| 27 |
+
|
| 28 |
+
array = np.array(image.convert("L"), dtype=np.uint8)
|
| 29 |
+
ink = array < CROP_INK_THRESHOLD
|
| 30 |
+
if not ink.any():
|
| 31 |
+
return image
|
| 32 |
+
|
| 33 |
+
rows, columns = np.where(ink)
|
| 34 |
+
left = max(0, int(columns.min()) - padding)
|
| 35 |
+
right = min(image.width, int(columns.max()) + padding)
|
| 36 |
+
top = max(0, int(rows.min()) - padding)
|
| 37 |
+
bottom = min(image.height, int(rows.max()) + padding)
|
| 38 |
+
if right <= left or bottom <= top:
|
| 39 |
+
return image
|
| 40 |
+
return image.crop((left, top, right, bottom))
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def prepare_line_image(image: Image.Image) -> Tensor:
|
| 44 |
+
"""Crop to the ink, scale the height to 64 px, normalise, and clamp the width."""
|
| 45 |
+
import numpy as np
|
| 46 |
+
from PIL import Image as PILImage
|
| 47 |
+
|
| 48 |
+
cropped = crop_text_bbox(image).convert("RGB")
|
| 49 |
+
width, height = cropped.size
|
| 50 |
+
|
| 51 |
+
scale = float(TARGET_HEIGHT) / max(height, 1)
|
| 52 |
+
new_width = max(16, min(MAX_WIDTH, int(width * scale)))
|
| 53 |
+
# Ensure divisible by 4 for CNN stem
|
| 54 |
+
new_width = int(math.ceil(new_width / 4.0) * 4)
|
| 55 |
+
|
| 56 |
+
resized = cropped.resize((new_width, TARGET_HEIGHT), resample=PILImage.Resampling.LANCZOS)
|
| 57 |
+
arr = np.array(resized, dtype=np.float32) / 255.0
|
| 58 |
+
arr = (arr - 0.5) / 0.5
|
| 59 |
+
return torch.from_numpy(arr).permute(2, 0, 1).unsqueeze(0) # (1, 3, 64, W)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def segment_page_into_lines(page: Image.Image, min_line_height: int = 15) -> list[Image.Image]:
|
| 63 |
+
"""Segment page into line strips on horizontal ink profile."""
|
| 64 |
+
import numpy as np
|
| 65 |
+
|
| 66 |
+
array = np.array(page.convert("L"), dtype=np.uint8)
|
| 67 |
+
ink = (array < LINE_INK_THRESHOLD).astype(np.float32).sum(axis=1)
|
| 68 |
+
active = ink > 0.015 * array.shape[1]
|
| 69 |
+
|
| 70 |
+
lines: list[Image.Image] = []
|
| 71 |
+
start = 0
|
| 72 |
+
inside = False
|
| 73 |
+
|
| 74 |
+
for idx, is_ink in enumerate(active):
|
| 75 |
+
if is_ink and not inside:
|
| 76 |
+
start = idx
|
| 77 |
+
inside = True
|
| 78 |
+
elif not is_ink and inside:
|
| 79 |
+
inside = False
|
| 80 |
+
if idx - start >= min_line_height:
|
| 81 |
+
lines.append(
|
| 82 |
+
page.crop(
|
| 83 |
+
(0, max(0, start - 2), page.width, min(page.height, idx + 2))
|
| 84 |
+
).convert("RGB")
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
if inside and len(active) - start >= min_line_height:
|
| 88 |
+
lines.append(page.crop((0, start, page.width, len(active))).convert("RGB"))
|
| 89 |
+
|
| 90 |
+
return lines
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class CNNStem(nn.Module):
|
| 94 |
+
def __init__(self, d_model: int) -> None:
|
| 95 |
+
super().__init__()
|
| 96 |
+
self.block1 = nn.Sequential(
|
| 97 |
+
nn.Conv2d(3, 32, kernel_size=3, stride=(2, 1), padding=1, bias=False),
|
| 98 |
+
nn.BatchNorm2d(32),
|
| 99 |
+
nn.GELU(),
|
| 100 |
+
)
|
| 101 |
+
self.block2 = nn.Sequential(
|
| 102 |
+
nn.Conv2d(32, 64, kernel_size=3, stride=(2, 1), padding=1, bias=False),
|
| 103 |
+
nn.BatchNorm2d(64),
|
| 104 |
+
nn.GELU(),
|
| 105 |
+
)
|
| 106 |
+
self.block3 = nn.Sequential(
|
| 107 |
+
nn.Conv2d(64, 128, kernel_size=3, stride=(2, 2), padding=1, bias=False),
|
| 108 |
+
nn.BatchNorm2d(128),
|
| 109 |
+
nn.GELU(),
|
| 110 |
+
)
|
| 111 |
+
self.block4 = nn.Sequential(
|
| 112 |
+
nn.Conv2d(128, 256, kernel_size=3, stride=(2, 2), padding=1, bias=False),
|
| 113 |
+
nn.BatchNorm2d(256),
|
| 114 |
+
nn.GELU(),
|
| 115 |
+
)
|
| 116 |
+
self.proj = nn.Linear(256 * 4, d_model)
|
| 117 |
+
|
| 118 |
+
def forward(self, x: Tensor) -> Tensor:
|
| 119 |
+
x = self.block1(x)
|
| 120 |
+
x = self.block2(x)
|
| 121 |
+
x = self.block3(x)
|
| 122 |
+
x = self.block4(x)
|
| 123 |
+
b, c, h, w = x.shape
|
| 124 |
+
x = x.permute(0, 3, 1, 2).contiguous().view(b, w, c * h)
|
| 125 |
+
out: Tensor = self.proj(x)
|
| 126 |
+
return out
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
class FeraounProForCTC(PreTrainedModel):
|
| 130 |
+
config_class = FeraounProConfig
|
| 131 |
+
base_model_prefix = "feraoun_pro"
|
| 132 |
+
|
| 133 |
+
def __init__(self, config: FeraounProConfig) -> None:
|
| 134 |
+
super().__init__(config)
|
| 135 |
+
self.config = config
|
| 136 |
+
self.stem = CNNStem(d_model=config.d_model)
|
| 137 |
+
|
| 138 |
+
# Build sinusoidal positional encodings
|
| 139 |
+
pe = torch.zeros(config.max_width_frames, config.d_model)
|
| 140 |
+
position = torch.arange(config.max_width_frames).unsqueeze(1)
|
| 141 |
+
div_term = torch.exp(
|
| 142 |
+
torch.arange(0, config.d_model, 2) * (-math.log(10000.0) / config.d_model)
|
| 143 |
+
)
|
| 144 |
+
pe[:, 0::2] = torch.sin(position * div_term)
|
| 145 |
+
pe[:, 1::2] = torch.cos(position * div_term)
|
| 146 |
+
self.register_buffer("pos_encoding", pe)
|
| 147 |
+
|
| 148 |
+
encoder_layer = nn.TransformerEncoderLayer(
|
| 149 |
+
d_model=config.d_model,
|
| 150 |
+
nhead=config.num_heads,
|
| 151 |
+
dim_feedforward=config.dim_feedforward,
|
| 152 |
+
dropout=config.dropout,
|
| 153 |
+
activation="gelu",
|
| 154 |
+
batch_first=True,
|
| 155 |
+
norm_first=True,
|
| 156 |
+
)
|
| 157 |
+
# The nested-tensor fast path does not apply to a pre-norm layer; torch infers that
|
| 158 |
+
# and warns. Declaring it keeps a downloader's console clean.
|
| 159 |
+
self.encoder = nn.TransformerEncoder(
|
| 160 |
+
encoder_layer, num_layers=config.num_encoder_layers, enable_nested_tensor=False
|
| 161 |
+
)
|
| 162 |
+
self.ctc_head = nn.Linear(config.d_model, config.vocab_size)
|
| 163 |
+
self.post_init()
|
| 164 |
+
|
| 165 |
+
def forward(self, pixel_values: Tensor) -> Tensor:
|
| 166 |
+
features = self.stem(pixel_values)
|
| 167 |
+
seq_len = features.size(1)
|
| 168 |
+
# `get_buffer` rather than the attribute: `nn.Module.__getattr__` is typed as
|
| 169 |
+
# `Tensor | Module`, and a registered buffer is always the former.
|
| 170 |
+
pe = self.get_buffer("pos_encoding")[:seq_len, :].unsqueeze(0).to(features.device)
|
| 171 |
+
encoded = self.encoder(features + pe)
|
| 172 |
+
logits: Tensor = self.ctc_head(encoded)
|
| 173 |
+
return logits
|
| 174 |
+
|
| 175 |
+
def decode_ctc(self, token_ids: list[int]) -> str:
|
| 176 |
+
"""Collapse repeats, then drop blanks — the CTC rule, in that order.
|
| 177 |
+
|
| 178 |
+
Dropping blanks first merges the two characters a blank was separating, so a
|
| 179 |
+
geminate consonant comes back single.
|
| 180 |
+
"""
|
| 181 |
+
vocabulary = self.config.vocabulary
|
| 182 |
+
blank = self.config.pad_token_id
|
| 183 |
+
special = {blank, self.config.bos_token_id, self.config.eos_token_id}
|
| 184 |
+
collapsed: list[int] = []
|
| 185 |
+
previous = -1
|
| 186 |
+
for token_id in token_ids:
|
| 187 |
+
if token_id != previous:
|
| 188 |
+
if token_id not in special:
|
| 189 |
+
collapsed.append(token_id)
|
| 190 |
+
previous = token_id
|
| 191 |
+
return "".join(vocabulary[token_id] for token_id in collapsed if token_id < len(vocabulary))
|
| 192 |
+
|
| 193 |
+
@torch.no_grad()
|
| 194 |
+
def transcribe(self, image: Image.Image) -> str:
|
| 195 |
+
"""Read one line crop. Preprocessing included, because it is half of this model."""
|
| 196 |
+
self.eval()
|
| 197 |
+
pixel_values = prepare_line_image(image).to(self.device)
|
| 198 |
+
logits = self(pixel_values=pixel_values)
|
| 199 |
+
return self.decode_ctc(torch.argmax(logits, dim=-1)[0].tolist())
|
| 200 |
+
|
| 201 |
+
@torch.no_grad()
|
| 202 |
+
def transcribe_page(self, page: Image.Image) -> list[str]:
|
| 203 |
+
"""Segment a page into lines and read each one."""
|
| 204 |
+
return [self.transcribe(line) for line in segment_page_into_lines(page)]
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
__all__ = ["FeraounProForCTC", "prepare_line_image", "segment_page_into_lines"]
|
tokenizer.json
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"version": "1.0",
|
| 3 |
+
"truncation": null,
|
| 4 |
+
"padding": null,
|
| 5 |
+
"added_tokens": [
|
| 6 |
+
{
|
| 7 |
+
"id": 0,
|
| 8 |
+
"content": "<pad>",
|
| 9 |
+
"single_word": false,
|
| 10 |
+
"lstrip": false,
|
| 11 |
+
"rstrip": false,
|
| 12 |
+
"normalized": false,
|
| 13 |
+
"special": true
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"id": 1,
|
| 17 |
+
"content": "<s>",
|
| 18 |
+
"single_word": false,
|
| 19 |
+
"lstrip": false,
|
| 20 |
+
"rstrip": false,
|
| 21 |
+
"normalized": false,
|
| 22 |
+
"special": true
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"id": 2,
|
| 26 |
+
"content": "</s>",
|
| 27 |
+
"single_word": false,
|
| 28 |
+
"lstrip": false,
|
| 29 |
+
"rstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"special": true
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"id": 3,
|
| 35 |
+
"content": "<unk>",
|
| 36 |
+
"single_word": false,
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"rstrip": false,
|
| 39 |
+
"normalized": false,
|
| 40 |
+
"special": true
|
| 41 |
+
}
|
| 42 |
+
],
|
| 43 |
+
"normalizer": null,
|
| 44 |
+
"pre_tokenizer": {
|
| 45 |
+
"type": "Split",
|
| 46 |
+
"pattern": {
|
| 47 |
+
"Regex": "[\\s\\S]"
|
| 48 |
+
},
|
| 49 |
+
"behavior": "Isolated",
|
| 50 |
+
"invert": false
|
| 51 |
+
},
|
| 52 |
+
"post_processor": {
|
| 53 |
+
"type": "TemplateProcessing",
|
| 54 |
+
"single": [
|
| 55 |
+
{
|
| 56 |
+
"SpecialToken": {
|
| 57 |
+
"id": "<s>",
|
| 58 |
+
"type_id": 0
|
| 59 |
+
}
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"Sequence": {
|
| 63 |
+
"id": "A",
|
| 64 |
+
"type_id": 0
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
{
|
| 68 |
+
"SpecialToken": {
|
| 69 |
+
"id": "</s>",
|
| 70 |
+
"type_id": 0
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
],
|
| 74 |
+
"pair": [
|
| 75 |
+
{
|
| 76 |
+
"Sequence": {
|
| 77 |
+
"id": "A",
|
| 78 |
+
"type_id": 0
|
| 79 |
+
}
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"Sequence": {
|
| 83 |
+
"id": "B",
|
| 84 |
+
"type_id": 1
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
],
|
| 88 |
+
"special_tokens": {
|
| 89 |
+
"</s>": {
|
| 90 |
+
"id": "</s>",
|
| 91 |
+
"ids": [
|
| 92 |
+
2
|
| 93 |
+
],
|
| 94 |
+
"tokens": [
|
| 95 |
+
"</s>"
|
| 96 |
+
]
|
| 97 |
+
},
|
| 98 |
+
"<s>": {
|
| 99 |
+
"id": "<s>",
|
| 100 |
+
"ids": [
|
| 101 |
+
1
|
| 102 |
+
],
|
| 103 |
+
"tokens": [
|
| 104 |
+
"<s>"
|
| 105 |
+
]
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
},
|
| 109 |
+
"decoder": {
|
| 110 |
+
"type": "Fuse"
|
| 111 |
+
},
|
| 112 |
+
"model": {
|
| 113 |
+
"type": "WordLevel",
|
| 114 |
+
"vocab": {
|
| 115 |
+
"<pad>": 0,
|
| 116 |
+
"<s>": 1,
|
| 117 |
+
"</s>": 2,
|
| 118 |
+
"<unk>": 3,
|
| 119 |
+
"a": 4,
|
| 120 |
+
"b": 5,
|
| 121 |
+
"c": 6,
|
| 122 |
+
"d": 7,
|
| 123 |
+
"e": 8,
|
| 124 |
+
"f": 9,
|
| 125 |
+
"g": 10,
|
| 126 |
+
"h": 11,
|
| 127 |
+
"i": 12,
|
| 128 |
+
"j": 13,
|
| 129 |
+
"k": 14,
|
| 130 |
+
"l": 15,
|
| 131 |
+
"m": 16,
|
| 132 |
+
"n": 17,
|
| 133 |
+
"o": 18,
|
| 134 |
+
"p": 19,
|
| 135 |
+
"q": 20,
|
| 136 |
+
"r": 21,
|
| 137 |
+
"s": 22,
|
| 138 |
+
"t": 23,
|
| 139 |
+
"u": 24,
|
| 140 |
+
"v": 25,
|
| 141 |
+
"w": 26,
|
| 142 |
+
"x": 27,
|
| 143 |
+
"y": 28,
|
| 144 |
+
"z": 29,
|
| 145 |
+
"A": 30,
|
| 146 |
+
"B": 31,
|
| 147 |
+
"C": 32,
|
| 148 |
+
"D": 33,
|
| 149 |
+
"E": 34,
|
| 150 |
+
"F": 35,
|
| 151 |
+
"G": 36,
|
| 152 |
+
"H": 37,
|
| 153 |
+
"I": 38,
|
| 154 |
+
"J": 39,
|
| 155 |
+
"K": 40,
|
| 156 |
+
"L": 41,
|
| 157 |
+
"M": 42,
|
| 158 |
+
"N": 43,
|
| 159 |
+
"O": 44,
|
| 160 |
+
"P": 45,
|
| 161 |
+
"Q": 46,
|
| 162 |
+
"R": 47,
|
| 163 |
+
"S": 48,
|
| 164 |
+
"T": 49,
|
| 165 |
+
"U": 50,
|
| 166 |
+
"V": 51,
|
| 167 |
+
"W": 52,
|
| 168 |
+
"X": 53,
|
| 169 |
+
"Y": 54,
|
| 170 |
+
"Z": 55,
|
| 171 |
+
"ɣ": 56,
|
| 172 |
+
"Ɣ": 57,
|
| 173 |
+
"ɛ": 58,
|
| 174 |
+
"Ɛ": 59,
|
| 175 |
+
"č": 60,
|
| 176 |
+
"Č": 61,
|
| 177 |
+
"ǧ": 62,
|
| 178 |
+
"Ǧ": 63,
|
| 179 |
+
"ţ": 64,
|
| 180 |
+
"Ţ": 65,
|
| 181 |
+
"ḍ": 66,
|
| 182 |
+
"Ḍ": 67,
|
| 183 |
+
"ḥ": 68,
|
| 184 |
+
"Ḥ": 69,
|
| 185 |
+
"ṛ": 70,
|
| 186 |
+
"Ṛ": 71,
|
| 187 |
+
"ṣ": 72,
|
| 188 |
+
"Ṣ": 73,
|
| 189 |
+
"ṭ": 74,
|
| 190 |
+
"Ṭ": 75,
|
| 191 |
+
"ẓ": 76,
|
| 192 |
+
"Ẓ": 77,
|
| 193 |
+
"é": 78,
|
| 194 |
+
"è": 79,
|
| 195 |
+
"ê": 80,
|
| 196 |
+
"ë": 81,
|
| 197 |
+
"à": 82,
|
| 198 |
+
"â": 83,
|
| 199 |
+
"î": 84,
|
| 200 |
+
"ï": 85,
|
| 201 |
+
"ô": 86,
|
| 202 |
+
"ù": 87,
|
| 203 |
+
"û": 88,
|
| 204 |
+
"ç": 89,
|
| 205 |
+
"É": 90,
|
| 206 |
+
"È": 91,
|
| 207 |
+
"Ê": 92,
|
| 208 |
+
"Ë": 93,
|
| 209 |
+
"À": 94,
|
| 210 |
+
"Â": 95,
|
| 211 |
+
"Î": 96,
|
| 212 |
+
"Ï": 97,
|
| 213 |
+
"Ô": 98,
|
| 214 |
+
"Ù": 99,
|
| 215 |
+
"Û": 100,
|
| 216 |
+
"Ç": 101,
|
| 217 |
+
"0": 102,
|
| 218 |
+
"1": 103,
|
| 219 |
+
"2": 104,
|
| 220 |
+
"3": 105,
|
| 221 |
+
"4": 106,
|
| 222 |
+
"5": 107,
|
| 223 |
+
"6": 108,
|
| 224 |
+
"7": 109,
|
| 225 |
+
"8": 110,
|
| 226 |
+
"9": 111,
|
| 227 |
+
" ": 112,
|
| 228 |
+
".": 113,
|
| 229 |
+
",": 114,
|
| 230 |
+
"?": 115,
|
| 231 |
+
"!": 116,
|
| 232 |
+
"«": 117,
|
| 233 |
+
"»": 118,
|
| 234 |
+
"-": 119,
|
| 235 |
+
"—": 120,
|
| 236 |
+
":": 121,
|
| 237 |
+
";": 122,
|
| 238 |
+
"'": 123,
|
| 239 |
+
"\"": 124,
|
| 240 |
+
"/": 125,
|
| 241 |
+
"(": 126,
|
| 242 |
+
")": 127,
|
| 243 |
+
"[": 128,
|
| 244 |
+
"]": 129,
|
| 245 |
+
"{": 130,
|
| 246 |
+
"}": 131,
|
| 247 |
+
"%": 132,
|
| 248 |
+
"*": 133,
|
| 249 |
+
"+": 134,
|
| 250 |
+
"=": 135,
|
| 251 |
+
"_": 136,
|
| 252 |
+
"~": 137,
|
| 253 |
+
"–": 138,
|
| 254 |
+
"…": 139,
|
| 255 |
+
"\n": 140,
|
| 256 |
+
"\t": 141,
|
| 257 |
+
"ⴰ": 142,
|
| 258 |
+
"ⴱ": 143,
|
| 259 |
+
"ⴳ": 144,
|
| 260 |
+
"ⴷ": 145,
|
| 261 |
+
"ⴹ": 146,
|
| 262 |
+
"ⴻ": 147,
|
| 263 |
+
"ⴼ": 148,
|
| 264 |
+
"ⴽ": 149,
|
| 265 |
+
"ⵀ": 150,
|
| 266 |
+
"ⵃ": 151,
|
| 267 |
+
"ⵄ": 152,
|
| 268 |
+
"ⵅ": 153,
|
| 269 |
+
"ⵇ": 154,
|
| 270 |
+
"ⵉ": 155,
|
| 271 |
+
"ⵊ": 156,
|
| 272 |
+
"ⵍ": 157,
|
| 273 |
+
"ⵎ": 158,
|
| 274 |
+
"ⵏ": 159,
|
| 275 |
+
"ⵓ": 160,
|
| 276 |
+
"ⵔ": 161,
|
| 277 |
+
"ⵕ": 162,
|
| 278 |
+
"ⵙ": 163,
|
| 279 |
+
"ⵚ": 164,
|
| 280 |
+
"ⵛ": 165,
|
| 281 |
+
"ⵜ": 166,
|
| 282 |
+
"ⵟ": 167,
|
| 283 |
+
"ⵡ": 168,
|
| 284 |
+
"ⵢ": 169,
|
| 285 |
+
"ⵣ": 170,
|
| 286 |
+
"ⵥ": 171,
|
| 287 |
+
"ⵖ": 172
|
| 288 |
+
},
|
| 289 |
+
"unk_token": "<unk>"
|
| 290 |
+
}
|
| 291 |
+
}
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"bos_token": "<s>",
|
| 4 |
+
"eos_token": "</s>",
|
| 5 |
+
"model_max_length": 1024,
|
| 6 |
+
"pad_token": "<pad>",
|
| 7 |
+
"tokenizer_class": "TokenizersBackend",
|
| 8 |
+
"unk_token": "<unk>"
|
| 9 |
+
}
|