Skip to content

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

Description

@mk-startialab

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions