Skip to main content
Developer guide

Train Tesseract on custom fonts
and data (tesstrain, v5).

A tested, decision-driven guide to fine-tuning and training Tesseract 5 models with tesstrain: building from source, preparing ground truth, running make training, tuning the important variables, measuring CER with lstmeval, and deploying your traineddata.

TL;DR — fine-tune an existing model

If your script is already supported, fine-tuning is the fastest path to a better model.

bash
git clone https://github.com/tesseract-ocr/tesstrain.git
cd tesstrain && make tesseract-langdata
# put line images + .gt.txt in data/myfont-ground-truth/
make training MODEL_NAME=myfont START_MODEL=eng

Training is not available through the binary installers. You need Linux or WSL2. See installation for building from source.

Decision tree: fine-tune vs cut top layer vs from scratch

Choosing the right approach saves days of wasted training.

ApproachUse whenData neededTime
Fine-tune (FINETUNE_TYPE=1)Same script, new font or domain vocabulary1,000–5,000 linesHours
Cut top layer (FINETUNE_TYPE=2)Same script, meaningfully different glyph shapes5,000–20,000 linesHours–days
Train from scratchNew script or very different alphabet50,000+ linesDays

Start with the lightest option that could work, evaluate, and only escalate if CER is unacceptable. Most custom-font problems are solved by fine-tuning.

Prerequisites

Training requires the source build, not the packaged binary.

bash
sudo apt update
sudo apt install -y git make automake pkg-config g++ \
  libleptonica-dev libtesseract-dev tesseract-ocr

git clone https://github.com/tesseract-ocr/tesstrain.git
cd tesstrain
make tesseract-langdata   # fetches langdata_lstm + tessdata_best

Prepare ground truth

Ground truth is line images paired with their exact text.

tesstrain expects one image per text line in data/<MODEL_NAME>-ground-truth/, each with a matching .gt.txt file containing the exact transcription. Generate images from a text file and a font with text2image, then split long text into lines with split_training_text.py from langdata_lstm.

bash
# Generate line images from a text corpus + a font
text2image --text=corpus.txt \
  --outputbase=data/myfont-ground-truth/myfont \
  --font='My Custom Font' --fonts_dir=/usr/share/fonts \
  --ptsize=14

# text2image also emits .box files; convert them to .gt.txt
# (tesstrain/training/ has helper scripts, or rename after verification)

How much data: 100–500 lines to validate the pipeline, 1,000–5,000 for production. Accuracy comes from variety — different fonts, sizes, spacing and noise — more than raw volume.

Fonts and unicharset selection

The character set must cover everything the model will see.

Run training

One command drives the whole Makefile pipeline.

bash
make training \
  MODEL_NAME=myfont \
  START_MODEL=eng \
  TESSDATA_PREFIX=../tessdata_best \
  MAX_ITERATIONS=10000
VariableMeaningTypical value
START_MODELModel to continue from (fine-tuning)eng, jpn…
TESSDATA_PREFIXDirectory holding the starting model../tessdata_best
MAX_ITERATIONSUpper bound on training steps10000–100000
LEARNING_RATEStep size; lower is safer for fine-tuning0.0001–0.001
FINETUNE_TYPE0 scratch, 1 fine-tune, 2 cut top layer1
NET_SPECNetwork architecture specleave default
RATIO_TRAINTrain/validation split0.9
TARGET_ERROR_RATEEarly-stop CER target0.01

Checkpoints, stop_training and best vs fast

Evaluation: character error rate with lstmeval

Judge the model on data it never trained on.

bash
lstmeval --model data/myfont_checkpoint \
  --traineddata ../tessdata_best/eng.traineddata \
  --eval_listfile data/myfont-ground-truth/eval_files.txt

Track CER on a held-out set. When it stops falling — or starts climbing while training loss still drops — you are overfitting; stop and use the earlier checkpoint.

Deploy the trained model

Copy the traineddata, point the engine at it, and test.

bash
# Copy into a tessdata directory
cp data/myfont.traineddata /usr/share/tesseract-ocr/5/tessdata/
# or set a custom prefix
export TESSDATA_PREFIX=/path/to/tessdata
tesseract sample.png stdout -l myfont

You can combine your model with a base language, e.g. -l myfont+eng. In Python, pass the same value to pytesseract — see the Python guide.

Troubleshooting

SymptomCauseFix
Bad boxes / misaligned ground truthIncorrect font metrics or oversized line imagesRegenerate with the right --font and --ptsize; verify a few images by eye.
Missing characters in outputCharacter absent from the unicharsetAdd the glyphs to your ground truth and rebuild the unicharset.
Loss diverges / NaNLearning rate too highLower LEARNING_RATE and resume from an earlier checkpoint.
Out of memoryBatch too large for RAM/GPUReduce BATCH_SIZE/network size, or use a machine with more memory.
Validation CER rises while training loss fallsOverfittingStop earlier, add more varied ground truth, or use a lower learning rate.

Training FAQ

Can I train Tesseract without building it from source?

No. The training tools are not in the binary installers; use Linux or WSL2 with libtesseract-dev and the tesstrain repository.

How many samples do I need?

About 100–500 lines to validate the pipeline, and 1,000–5,000 for production. Fine-tuning needs less than training from scratch.

Fine-tune or train from scratch?

Fine-tune for a new font or vocabulary in an existing script; train from scratch only for a genuinely new script.

When should I stop training?

When held-out CER stops improving — not when training loss flattens. That gap is overfitting.

Where does the model go?

Copy <MODEL_NAME>.traineddata into a tessdata directory (or set TESSDATA_PREFIX) and run tesseract image.png stdout -l myfont.