TypLens / INFERENCE.md
dbcccc's picture
V1.1
f982163
|
Raw History Blame Contribute Delete
5.58 kB

TypLens V1.1 inference contract

TypLens V1.1 recognizes a single printed formula crop and directly generates the content of a Typst math expression. The consuming application may add $ delimiters. No LaTeX conversion is involved in inference. This is a weights-only release: preprocessing, generation and runtime libraries are supplied by the application.

Required single-channel preprocessing

V1.1 expects float32 pixel_values shaped [1, 1, 384, 384] (NCHW). Do not reuse V1's three-channel input or duplicate luminance into RGB. The contract is native-content-box-gray-v2, also recorded in preprocessor_config.json. Apply these operations in order:

  1. Decode the image to 8-bit RGBA. Composite each color channel C onto white: floor((C*A + 255*(255-A) + 127) / 255).
  2. Convert the resulting RGB bytes to one luminance byte: Y = floor((77*R + 150*G + 29*B + 128) / 256). Retain intermediate gray levels; do not threshold the image to black and white.
  3. Collect the perimeter pixels, counting each corner once. Let b be the lower median (sorted index floor((N-1)/2)). If b is below 128, replace every Y with 255-Y and replace b with 255-b.
  4. Find the inclusive bounding box of all pixels satisfying Y <= b-12. Retain isolated dots and accents. If no pixel qualifies, use the whole image.
  5. For a nonempty box with ink height h, add max(1, floor(0.02*h + 0.5)) pixels on each side. Copy the image pixels within this rectangle, filling only portions outside the source image with b.
  6. Resize the resulting rectangle directly to 384 by 384 with Pillow-compatible uint8 bicubic interpolation (pillow-bicubic-u8-v1). This is the trained resize behavior; do not substitute an aspect-ratio letterbox or center crop.
  7. Convert to float32 and calculate (Y/255 - 0.5)/0.5, using float32 arithmetic. Add batch and channel axes to obtain [1, 1, 384, 384].

The standard Transformers DeiT image processor does not implement the custom grayscale, background polarity and content-box steps above. Its presence in the configuration does not make a generic image-to-text pipeline sufficient. Supply the fully preprocessed tensor to the model; do not apply normalization twice. Browser canvas interpolation is not guaranteed to match Pillow bicubic.

Cached ONNX graphs

The full variant is onnx/fp32/; the compact variant is onnx/int8/. Each GitHub asset ZIP instead places its encoder and decoder in the ZIP root. Keep the encoder and decoder from the same version and precision together. These are custom cached exports, not a generic Optimum export layout.

Graph Name Type and shape
Encoder input pixel_values float32 [1, 1, 384, 384]
Encoder outputs cross_keys, cross_values float32 [6, 1, 8, 578, 32] each
Decoder input token_ids int64 [1, 1]
Decoder inputs self_keys, self_values float32 [6, 1, 8, past, 32] each
Decoder inputs cross_keys, cross_values Encoder outputs, unchanged
Decoder output logits float32 [1, 1199]
Decoder outputs self_keys_out, self_values_out float32 [6, 1, 8, past+1, 32] each

Initialize both self caches with past=0. Start with BOS=1. At each step select the first maximum of the 1,199 logits, feed that token into the next step, and reuse the returned self caches. EOS=2 ends generation. Allow at most 1,023 new tokens after BOS, including EOS. Do not force EOS when reaching the limit.

For each content token, append its byte array from token-bytes.json. Decode the complete byte sequence as strict UTF-8. The first five entries are reserved; generated IDs 0, 1, 3 and 4, or invalid UTF-8, indicate a decoding error. Preserve the decoded Typst literally, without syntax repair or LaTeX conversion.

Applications should expose any available decoded text for editing and copying even when generation is incomplete or formula checks fail. Display the warning separately and keep completion/validation flags false. A syntax or compilation check passing does not establish mathematical correctness. Empty or undecodable output should produce a clear error rather than a fabricated formula.

The compact graphs use ONNX Runtime dynamic per-channel signed INT8 quantization of constant MatMul/Gemm weights. Inputs and caches remain float32; convolution and other unquantized operations also remain FP32. It is not an all-INT8 model.

Both variants were exercised with ONNX Runtime 1.22.0 and the WASM provider in desktop Edge. Four WASM threads require cross-origin isolation. Runtime binaries are not bundled. WebGPU and mobile inference have not been evaluated for V1.1.

Native safetensors

The Hugging Face pack contains optimizer-free FP32 model.safetensors, the one-channel architecture configuration, and the 1,199-entry tokenizer. The recorded architecture is a DeiT encoder without its unused pooling layer and a TrOCR causal decoder, combined as a VisionEncoderDecoderModel. Construct DeiT with add_pooling_layer=False and use eager attention to match the recorded setup. The encoder has 12 layers, hidden size 384 and 6 heads; the decoder has 6 layers, hidden size 256 and 8 heads. Transformers 4.52.3 was used.

The native configuration retains use_cache: false; the custom ONNX graphs above provide their own explicit caches. The packaged generation configuration sets greedy decoding, no forced EOS, and a 1,023-token generation budget. These are inference metadata changes only. Checkpoint and ONNX weight bytes are unchanged from the completed training/export run.