InviolusOCR: tiny Turkish line OCR for microcontrollers
A compact convolutional CTC recognizer for one cropped line of printed Turkish text: 560,954 parameters and a 598 KB full-int8 TensorFlow Lite file that keeps almost all of the float model's accuracy.
Türkçe özet: Mikrodenetleyiciler için tek satır Türkçe metin okuyan, 561 bin parametreli, int8 TFLite dosyası 598 KB olan küçük bir OCR modeli. int8 hâli, ayrılmış test satırlarının %78,4'ünü ve gerçek sahne metni (TS-TR) test kırpıntılarının %58,2'sini harfi harfine doğru okuyor. Ticari olmayan kullanım içindir (CC BY-NC-SA 4.0).
This replaces inviolus/erdem-ocr-tr-tinyml (2026-10-09), whose int8 file lost most of its accuracy.
Newer version on GitHub (2026-11-01): a continuation of this model, D, trained with 47,613 extra printed-document lines (donut 200k, CC BY-SA 4.0), reads 46.5% of the donut test rows exactly as int8 (this model: 9.3%), with the same size and 1 to 2 points less on the sets below. The files here are still the 2026-10-31 model. Scores: InviolusOCR results.
Files
| File | What it is |
|---|---|
inviolusocr.keras |
Float model, input (batch, 32, 160, 1), output (batch, 40, 90) softmax |
inviolusocr_int8.tflite |
Full-int8 export, input [1, 32, 160, 1] int8 (scale 0.007843, zero point -1), output [1, 40, 90] int8 (scale 0.00390625, zero point -128) |
alphabet.json |
Character set used to decode the output |
benchmark.json |
All scores below, for this model and the earlier versions |
Model
- Input: one horizontal text line, grayscale, resized to 160×32, scaled
to
[-1, 1](pixel / 127.5 - 1). - Architecture: 4 conv + batch-norm + pool blocks, a dense projection, then four residual dilated 1-D convolutions (dilation 1, 2, 4, 1) instead of an LSTM, and a dense softmax. Only ops that quantize cleanly to int8.
- Output: 40 timesteps × 90 classes. Class
0is padding,1..88are the characters ofalphabet.jsonin order,89is the CTC blank. - Character set: digits, ASCII letters,
ç ğ ı İ ö ş ü Ç Ğ Ö Ş Ü, space and.,:;!?-_/()'%. Up to 24 characters per line. - Not included: text detection. The line must already be cropped.
Usage
import json
import numpy as np
import tensorflow as tf
alphabet = json.load(open("alphabet.json", encoding="utf-8"))["alphabet"]
BLANK = len(alphabet) + 1
def preprocess(path):
image = tf.io.decode_image(tf.io.read_file(path), channels=1, expand_animations=False)
image = tf.image.resize(image, [32, 160])
return (tf.cast(image, tf.float32) / 127.5 - 1.0).numpy()
def decode(ids):
text, previous = [], None
for i in ids:
if i != previous and 0 < i < BLANK:
text.append(alphabet[i - 1])
previous = i
return "".join(text)
# int8 TFLite (the file meant for devices)
interpreter = tf.lite.Interpreter(model_path="inviolusocr_int8.tflite")
interpreter.allocate_tensors()
inp, out = interpreter.get_input_details()[0], interpreter.get_output_details()[0]
scale, zero = inp["quantization"]
x = np.clip(np.round(preprocess("line.png") / scale + zero), -128, 127).astype(np.int8)
interpreter.set_tensor(inp["index"], x[np.newaxis])
interpreter.invoke()
print(decode(interpreter.get_tensor(out["index"])[0].argmax(-1)))
Results
Exact-line accuracy (the whole line correct), all models scored on the same rows: 12,093 held-out lines (synthetic, Zenodo, TS-TR, esengul3, STS-TR) and the 2,078-crop official TS-TR test split (real scene text, never trained on).
| Model | Params | int8 size | Held-out float | Held-out int8 | TS-TR float | TS-TR int8 |
|---|---|---|---|---|---|---|
| erdem-ocr 2026-10-09 (LSTM) | 631,226 | 665 KB | 58.8% | 32.9% | 45.3% | 33.5% |
| unpublished 2026-10-25 (LSTM) | 631,226 | 665 KB | 80.0% | 32.1% | 65.1% | 48.7% |
| InviolusOCR 2026-10-31 | 560,954 | 598 KB | 79.4% | 78.4% | 60.0% | 58.2% |
Character error rate of the int8 file: 9.1% held-out, 18.1% TS-TR.
The 2026-10-25 model is not published because it was trained with a dataset that states no license.
Limitations
- Printed text only; no handwriting, curved text or full pages.
- Real scene text is still the weak spot (58% exact).
- Licence plates are not read (0% exact on 250 plate crops in a first, unchecked test).
- Text detection and line cropping must be done before this model runs.
Training data
Trained for 200 minutes on CPU, starting from the 2026-10-09 weights, on about 66,000 crops:
- Synthetic Turkish lines rendered from a 50k-word Turkish word list.
- Turkish OCR Text Image Dataset, Zenodo, CC BY 4.0.
- Turkish Scene Text Recognition (TS-TR), Serdar Yıldız, CC BY-NC 4.0.
- Synthetic Turkish Scene Text (STS-TR), Serdar Yıldız, CC BY-NC 4.0.
- Turkish Word OCR, esengul3, CC BY-SA 4.0.
License
Because of the non-commercial (TS-TR, STS-TR) and share-alike (esengul3) terms of the training data, this model is released under CC BY-NC-SA 4.0: non-commercial use only, credit this model and the datasets above, and share adaptations under the same license.
Training code (MIT): ErdemWilkinson/InviolusOCR.