#4618·tesseract

lstmtraining --convert_to_int leaves the ADAM training_flags_ bit set, unlike official int-optimized traineddata

Author: mk-startialabCreated Aug 28, 2026Updated Sep 3, 2026
Labelsbug

Current Behavior

When fine-tuning an LSTM model starting from a float base model (e.g. tessdata_best/eng.traineddata) via lstmtraining --continue_from <checkpoint> (default ADAM optimizer), then producing an int-optimized traineddata with:

lstmtraining --stop_training --convert_to_int --continue_from <checkpoint> --traineddata <base> --model_output <out>

the resulting <out>.traineddata differs from the officially distributed int-optimized models in one network-header byte.

Extracting the .lstm component with combine_tessdata -u <out>.traineddata <prefix>. and inspecting the byte immediately following the "Series" type-name string (network header training_flags_) shows it retains 0x02 (NF_ADAM) — i.e. the flag from the original float/ADAM training is still set — even though the model has been converted to int.

By contrast, extracting the same byte from the officially distributed int eng.traineddata (tesseract-ocr/tessdata) shows 0x00.

I reproduced this as follows:

  1. lstmtraining --continue_from <float checkpoint from tessdata_best> ... (fine-tune with default ADAM optimizer).
  2. lstmtraining --stop_training --convert_to_int --continue_from <checkpoint> --traineddata <base traineddata> --model_output out
  3. combine_tessdata -u out.traineddata extracted.
  4. Inspect extracted.lstm: the byte right after the "Series" string is 0x02, not 0x00.
  5. Compare with the official int eng.traineddata from tessdata — same byte is 0x00 there.

Expected Behavior

lstmtraining --stop_training --convert_to_int should clear the ADAM-related training_flags_ bit when producing an int-optimized model, so its network header matches the format of the officially distributed int models (as if trained with a non-ADAM / int-native pipeline from the start).

Suggested Fix

In the --convert_to_int code path (network serialization in lstmtraining/Network), clear the ADAM optimizer flag bit in training_flags_ before writing the int-converted network, mirroring the header produced by a native int/non-ADAM training run.

tesseract -v

tesseract 5.5.3
 leptonica-1.87.0
  libgif 5.2.2 : libjpeg 8d (libjpeg-turbo 3.1.3) : libpng 1.6.58 : libtiff 4.7.2 : zlib 1.2.12 : libwebp 1.6.0 : libopenjp2 2.5.4
 Found NEON
 Found libarchive 3.8.9 zlib/1.2.12 liblzma/5.8.3 bz2lib/1.0.8 liblz4/1.10.0 libzstd/1.5.7 expat/expat_2.7.4 CommonCrypto/system libb2/system
 Found libcurl/8.7.1 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.68.1

(Installed via Homebrew.)

Operating System

macOS 26 Tahoe

Other Operating System

Actual installed version reports as macOS 26.5.2 (build 25F84); closest dropdown option selected above.

uname -a

Darwin MAC0040 25.5.0 Darwin Kernel Version 25.5.0: Tue Jun  9 22:26:15 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T6031 arm64

Compiler

N/A — used prebuilt Homebrew binary, did not compile from source.

CPU

Apple M3 Max (Apple Silicon, arm64)

Virtualization / Containers

N/A

Other Information

This was found while fine-tuning a font-specific digit-recognition model for use with Tesseract.js (a WASM build of Tesseract used in a browser). With the training_flags_ byte left at 0x02, the resulting model crashes when loaded in the WASM build with RuntimeError: missing function: _ZN9tesseract13DotProductSSEEPKfS1_i (a float-path SIMD function not compiled into that particular WASM build). Manually zeroing the byte after --convert_to_int (via combine_tessdata -u / re-pack) produces a traineddata that is byte-identical in this respect to the official int models and works correctly in both native tesseract and the WASM build. I'm not asking for anything WASM-specific to be fixed here — just noting it as the real-world symptom that led to discovering the discrepancy versus the official int traineddata format. Happy to share the full before/after .lstm header bytes or a minimal reproduction script (pure lstmtraining/combine_tessdata CLI calls) if useful.