diff --git a/BENCHMARK.md b/BENCHMARK.md new file mode 100644 index 0000000000000000000000000000000000000000..0c67b2a27686e3e26dab5965d1fa24055463d236 --- /dev/null +++ b/BENCHMARK.md @@ -0,0 +1,26 @@ +# Reader throughput measurements + +Crops/second on the same 300 frozen development crops per reader. Exact-result caches were disabled. This measures preprocessed input to compact CTC outputs, excluding loading, page segmentation, cropping, text assembly and table extraction. The source and ONNX/LiteRT measurements are batch one; tract reports warmed native model execution. Implementation timing boundaries differ slightly; these are indicative measurements, not a controlled cross-runtime ranking. + +**Mac conversions and browser validation ran concurrently, so Mac timing numbers are contended.** WASM body/short-label tests used two threads and the other three used one. Browser background scheduling may affect these numbers. Linux CPU and GPU measurements must not be treated as the same device. Native Windows, iOS and Android hardware remain untested. + +| Runtime/device | Body | Short labels | Printed | Numeric/math | Degraded | +|---|---:|---:|---:|---:|---:| +| Source FP32 / PyTorch2.10 CUDA / RTX5080 Laptop | 210.08 | 210.76 | 211.76 | 211.45 | 210.52 | +| Linux / RTX5080 Laptop / ORT CUDA1.23.2 | 347.08 | 342.76 | 315.42 | 330.48 | 323.72 | +| Linux / RTX5080 Laptop / tract CUDA | 230.45 | 242.53 | 225.46 | 222.40 | 216.53 | +| Linux / CPU / ORT1.31,2 threads | 14.42 | 14.50 | 10.16 | 13.45 | 13.47 | +| Linux / CPU / LiteRT2.3,2 threads | 43.50 | 45.07 | 42.84 | 42.01 | 43.30 | +| M2 Mac / Core ML CPU_AND_GPU | 51.39 | 37.93 | 37.90 | 47.45 | 78.94 | +| M2 Mac / tract CPU | 21.78 | 21.85 | 17.85 | 17.48 | 27.58 | +| M2 Mac / tract Metal | 27.30 | 27.76 | 14.09 | 20.46 | 43.57 | +| M2 Mac / ORT1.31 CPU | 8.34 | 8.34 | 5.11 | 5.23 | 7.32 | +| M2 Mac / ORT1.31 CPU HQQ | 7.69 | 7.67 | 5.34 | 5.27 | 9.59 | +| M2 Mac / Chrome WebGPU | 8.43 | 8.82 | 8.62 | 7.43 | 5.81 | +| M2 Mac / Chrome WASM | 0.91 | 0.99 | 0.55 | 0.45 | 0.47 | + +All 55 reader/runtime pairs passed the >=98% character-parity gate in every development bucket. The lowest bucket across all pairs was 98.2586%. This is character agreement with the uncompressed model, not exact-line agreement or OCR accuracy. + +The pure-W4 full-page handwritten-table diagnostic failed (~86.51% parity on the CPU block16 route). An optional image-only route retained FP32 readers for color-separated handwriting and reached 100% on that example. The three public page diagnostics with that mixed-precision policy reached 100%,99.8895%,100%. No table-grid extraction was exercised (table_grids=0); full document qualification remains open. + +See VALIDATION.json for the complete per-reader bucket metrics and diagnostic scope. diff --git a/MANIFEST.json b/MANIFEST.json new file mode 100644 index 0000000000000000000000000000000000000000..cf29f1b4a570cc5ea853163cf8e3ddaa5d746f7f --- /dev/null +++ b/MANIFEST.json @@ -0,0 +1,221 @@ +{ + "base_revision": "51b8c314b0552b1884c1f0e28016cb12a143f637", + "files": { + "requirements.txt": { + "bytes": 69, + "sha256": "9cd44c4193ee2ecb75fa477e10dd43690492120201bf43820151f38030e45df3" + }, + "polarity.py": { + "bytes": 1442, + "sha256": "f006a8a94626496af91f604489efba22d29cca75621c3766a912e271a5139e9c" + }, + "RECIPE.md": { + "bytes": 4075, + "sha256": "34dee9f78a3e9639def9c64926b088eb31f5cb6dca22ee54c92b811f10feb80f" + }, + "BENCHMARK.md": { + "bytes": 2584, + "sha256": "adaab95a33f2e857a2f295a52e1c6fc61c7926c60b28e1e011dcc7865b0c618f" + }, + "README.md": { + "bytes": 5015, + "sha256": "5f1b76bc9a908613348ea5a004374c659b5d27bf96037a8c2b49a61267929c42" + }, + "quantization_config.json": { + "bytes": 2590, + "sha256": "da732a8e71b618ca018705b6e0aec17590fc067f7a8f5a801377d07944c5f18a" + }, + "geometry.py": { + "bytes": 1922, + "sha256": "e8b6e0d5cabeeb5a6eeff6aa2ef9b317f8f34c83e88f0a5f82e17a99f7d0a6cc" + }, + "VALIDATION.json": { + "bytes": 140369, + "sha256": "245ed6184048bfecefa67b188c0eeb04ea45943713cc2fbb5ddda0832f01c749" + }, + "inference.py": { + "bytes": 4595, + "sha256": "2fab88114deb001eba8e0cb4cd4f9af7d190867fea5c84245d9ae78981ff712b" + }, + "components.json": { + "bytes": 2016, + "sha256": "5d49aa0d30d5a7e0eebde35cdf4f149b07e6903d3e1461cf30b22e565ee15be5" + }, + "vocab.json": { + "bytes": 20007, + "sha256": "d4330d46b65dca6f328fa6191bf02240c819ad83d9216bd9c78c13de895048dc" + }, + "rtl.py": { + "bytes": 6097, + "sha256": "d5e90e33913d66d1204a2966cc54f42b7b8fd3f37ab476c493c564fe4d020b8b" + }, + "experimental/portable_pipeline.py": { + "bytes": 11120, + "sha256": "c2d0b4a620b7e04b0ad46766950ead312a59f602a41293e99f7bc85bb174ed97" + }, + "checks/package-smoke.json": { + "bytes": 311, + "sha256": "f4acb4534946a3ac7f8e6bff6cc25e92c62beb6dce3de7337734c3e82729138d" + }, + "checks/browser-loader-check.json": { + "bytes": 338, + "sha256": "6681534f6712a591fb71c09e6a32fe49d4ab61d669036400106475ef94696d5e" + }, + "checks/package-litert-smoke.json": { + "bytes": 140, + "sha256": "f1be9492777c493cf1beeacf99efa53815e0f96718830ebf872787c4f40eeae7" + }, + "checks/browser-decoder-check.json": { + "bytes": 84, + "sha256": "7aa2b6c50334737c5f22721a7d689f7c45fc032e7dc9d94cbc52baabae4105a0" + }, + "recipe/requirements-macos.txt": { + "bytes": 93, + "sha256": "8eb76eb39c4a004abd208f8ebe994a72a2669d07ff04fc3214b68ebf57b0d9cd" + }, + "recipe/portable_model.py": { + "bytes": 2129, + "sha256": "f68eae9b098cd23e38560797f33e986ea922e56c886282b08631fe0d422ee283" + }, + "recipe/export_litert.py": { + "bytes": 2807, + "sha256": "be7054e54d4d491074b49b294e31a9eab8a854756a96334e5eed8c1b30f4fe13" + }, + "recipe/build_recognizer.py": { + "bytes": 5638, + "sha256": "1f0229995217d7265bc9cfba67948c2c9fce84922e86b4ceccc41d53e3da2431" + }, + "recipe/requirements-litert.txt": { + "bytes": 97, + "sha256": "3def04424ae7d7f8023bf6164a16361744a36a6cae79b6ad385a5b0ddfbb017e" + }, + "recipe/source/recognizer.py": { + "bytes": 3455, + "sha256": "03ffcc439ba4ada082c71b1e08e9bdcc8589332ae1e882557d44f004e3515dd2" + }, + "__pycache__/inference.cpython-311.pyc": { + "bytes": 11159, + "sha256": "4daf2b018aa95dc40d25ce5db54ce592d1e96de8d95714fd358af32b2053c0e2" + }, + "components/degraded/models/recognizer-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "675633649969487f825f5e61559d8fdeec20b22639b384f46f8713d55a3c5fa3" + }, + "components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 136655, + "sha256": "fbb59f5a96148ffd4cbcda007e715e76bc7b9beed799b9700a4b6dd6f087280a" + }, + "components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 26263424, + "sha256": "b300ceb473e7c9e3d97220cb34be29f7b49b030fa8693e58ae1b45710da8f55d" + }, + "components/body/models/recognizer-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "2c7c591fa00b408a154d4623215337654358c5b2191ef35934c614f3889ffc4a" + }, + "components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 136655, + "sha256": "068b9dd28a4464a544732ae3972b7da23629eb2fdd0434d855cdcec17be71fa9" + }, + "components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 26263424, + "sha256": "45e4f1c7d1d8e0689dbe458d99014bef4ecf1e3f3e308a1399a94dfda1056e17" + }, + "components/short_labels/models/recognizer-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "ce7c7bbce2d2f841baf7af009dd827cf0be193bbac12fab75ebbc62eb146f670" + }, + "components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 136655, + "sha256": "236f3f7de9ce5e2b2356333e653d996ff335d0bb6acde2c612c7f3190f57631a" + }, + "components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 26263424, + "sha256": "3d5c895f49c743122580765a36e37ab4a5ed6ae88526e940296e949cdd27cdd8" + }, + "components/numeric_math/models/recognizer-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "6befae03e35e7c8b0214292bb2c9cfd56946157d4950795c637461cefefaf867" + }, + "components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 136655, + "sha256": "c29f36bd45b9469a594b67e420efde84dfd8d663c138e0f1bee325c7d059debe" + }, + "components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 26263424, + "sha256": "d15e99ea723d66fedbe3ab66319266a156273f84a352081b69f9650af4802ba1" + }, + "components/printed/models/recognizer-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "81016c05409bafc0b082d3b4d3b4a60827adec441c383b41761648f2834b429b" + }, + "components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 136655, + "sha256": "5bfd191c319ff8ede42f41f35ac4ed609d1373c02f97f14b012649d705d08374" + }, + "components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 26263424, + "sha256": "b7c7da642b5bb0f429cdde70b0ea8815cce86175a1eb8b2a98a1d04c88c40f79" + }, + "experimental-detectors/line_guard/config.json": { + "bytes": 858, + "sha256": "0f99d8176e3fc194966659cf6f1c52ab9ca1d573f47ba57aca55036ff5267d69" + }, + "experimental-detectors/line_guard/preprocessor_config.json": { + "bytes": 373, + "sha256": "594344843fcd54db03240194c7677b5c459e78d349e68d4a89d7d91e4fa90587" + }, + "experimental-detectors/line_guard/detector-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "893c116ab8685122991388c4ecf30ee0f9c7b05eb290c94f9e29da429585d26f" + }, + "experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 183292, + "sha256": "3bbc26f64bd5168c8df476ce207d70977a29391ac85fc8745d967f2b573f6064" + }, + "experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 30454400, + "sha256": "e9614d48774aae3a1e28ff645664d9b8f654f71c80bad4585432be258875b58c" + }, + "experimental-detectors/printed_detector/config.json": { + "bytes": 858, + "sha256": "0f99d8176e3fc194966659cf6f1c52ab9ca1d573f47ba57aca55036ff5267d69" + }, + "experimental-detectors/printed_detector/preprocessor_config.json": { + "bytes": 373, + "sha256": "594344843fcd54db03240194c7677b5c459e78d349e68d4a89d7d91e4fa90587" + }, + "experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "55e73dae6485700c908feedaaafd055315a5b2fa40e2e2bf1ea741984518f173" + }, + "experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 183292, + "sha256": "b65e5fc8008ef59de2d91e4c7ec3e44a3d7e037367678564bfd5fb5810b69021" + }, + "experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 30454400, + "sha256": "02ba967fc37e29fe11eca73bdc77334272af1d2533cb9c7004f5eb0eb6d7591d" + }, + "experimental-detectors/main_detector/config.json": { + "bytes": 858, + "sha256": "0f99d8176e3fc194966659cf6f1c52ab9ca1d573f47ba57aca55036ff5267d69" + }, + "experimental-detectors/main_detector/preprocessor_config.json": { + "bytes": 373, + "sha256": "594344843fcd54db03240194c7677b5c459e78d349e68d4a89d7d91e4fa90587" + }, + "experimental-detectors/main_detector/detector-w4-block16.mlpackage/Manifest.json": { + "bytes": 617, + "sha256": "ba24569c2754a72a8d28dd3eeccd666812aca11b6e98bce29b4afcefa820241e" + }, + "experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel": { + "bytes": 183292, + "sha256": "a7df9637d121d036e2bb2e251b9004240f441d83433cde53226e56a36f6c27a8" + }, + "experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin": { + "bytes": 30454400, + "sha256": "0640641e7f2df4053feb5f831e4974739f7839deee0b7c146229db7f10000267" + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..38cd9b4b9dfd446264e398022613ff3cacd2beaf --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +--- +language: +- fa +license: other +license_name: bina-0.4-rizeh +license_link: https://huggingface.co/Reza2kn/Bina-0.4-Rizeh/blob/51b8c314b0552b1884c1f0e28016cb12a143f637/README.md +base_model: Reza2kn/Bina-0.4-Rizeh +base_model_relation: quantized +pipeline_tag: image-to-text +tags: +- bina +- ocr +- int4 +- coreml +--- + +# Bina0.4 Rizeh — CoreML-INT4 + +Quantized CTC reader components and experimental line-detector conversions of [the final release](https://huggingface.co/Reza2kn/Bina-0.4-Rizeh/tree/51b8c314b0552b1884c1f0e28016cb12a143f637), pinned at `51b8c314b0552b1884c1f0e28016cb12a143f637`. All five readers are included: body95k, short labels, printed, numeric/math and degraded scans. Original pipeline code and nonconverted dependencies remain in the source repository. + +These are mixed-weight4-bit artifacts. They are not an all-INT4 document pipeline. The reference Python pipeline also uses Surya layout/order, native detector paths, table machinery and small admission/ordering models. No Sherpa-ONNX OCR support is claimed. + +## Measured reader parity + +Fresh uncompressed PyTorch2.10 CUDA baselines were generated for each published checkpoint. Each target uses the same300 frozen internal development crops (50 each: English, handwriting, mixed, newspaper, printed, synthetic). No text normalization is applied to parity. At least98% character parity is required in every bucket; exact-line agreement is reported separately in VALIDATION.json. These are development canaries, not held-out accuracy or full-page certification. + +| Runtime | Reader components | Lowest bucket character parity | +|---|---:|---:| +| coreml-w4-block16 | 5/5 | 98.466% | + +Mac timings were collected during concurrent conversion/browser work and are not controlled speed rankings. Linux CPU/CUDA results are host-specific; native Windows is untested. LiteRT was tested on Linux CPU, without an Android test device. Apple validation used an M2 Mac; iOS hardware was not tested. + +## Page-pipeline limitation + +The public release demo matched the original text in a small ONNX page test, and exact reader-cache reuse avoided recognition calls on its repeat. A broader public handwritten-table sample exposed a failure: the pure-W4 pipeline changed the output substantially even though line canaries passed. Therefore this bundle does **not** pass the full-page98% transcription gate and is not a drop-in fully qualified4-bit replacement for the production pipeline. Detector mask IoU is not transcription parity. + +The experimental Python adapter preserves upstream crop geometry, routing and decoding. It also partitions an upstream geometry-reread cache by actual backend/weight hash, preventing cross-model cache reuse. Its optional image-only safety route uses original FP32 readers on color-separated handwritten pages, before OCR, avoiding a trial quantized pass. That route is mixed-precision and requires separate full-pipeline qualification. It does not make the pure-W4 model pass. + +## Line-level use + +Install requirements.txt, then run `python inference.py line.png --role body`. This expects one text line or an explicit line box through `Recognizer.read_line`; it does not detect or assemble a whole document. Persistent sessions and bounded exact-input caching are included. Widths are never squashed or truncated. + +Inputs are64px-high float32 ink maps with aspect preserved, black=1/paper=0,20% vertical and30% horizontal margins measured in original line height. True widths retain masking semantics. CTC blank is0 and nonblank indices map to vocab.json. Persian visual-to-logical conversion follows the original rtl.py. + +Core ML ML Program packages require iOS18/macOS15 or later. Inputs: pixels float32 `[B,1,64,W]`, widths int32 `[B]`; batch1..8 and width8..8192. Use CPU_AND_GPU. W4/block16 applies to compatible large weights, retaining floating operations where required. GPU-only/ANE placement is not claimed. + +## Experimental detectors + +Three detector roles are included under experimental-detectors/: combined main detector1000, rule-C line guard500 and the printed detector/head. Their procedural-dev heatmaps were compared against their original FP32 models. Their full geometry/table/transcription impact is unqualified. Do not replace the production detectors based on mask IoU alone. + +## Provenance and licensing + +Quantization did not alter the source repository. The aggregate model.safetensors was verified tensor-for-tensor against the published native core checkpoints. Each component records its exact source checkpoint SHA256 in quantization_config.json. MANIFEST.json hashes the shipped artifacts. No private calibration images, benchmark fixtures, or private prediction texts are shipped. + +Original recognizer weights/code remain under the source release CC BY-NC4.0 terms; Surya-derived detector/layout components retain their upstream Surya model terms. These conversions grant no additional rights. Retain the original Bina/Indra/Surya attribution. See the source release model card for details. diff --git a/RECIPE.md b/RECIPE.md new file mode 100644 index 0000000000000000000000000000000000000000..597f1795b5c05685ee1545b041fdfa4873224d73 --- /dev/null +++ b/RECIPE.md @@ -0,0 +1,31 @@ +# Conversion recipe + +Source: Reza2kn/Bina-0.4-Rizeh, revision51b8c314b0552b1884c1f0e28016cb12a143f637. components.json records the five exact native checkpoint paths and SHA256 values. Verify the checkpoint hash before converting. All five readers have the same architecture and unchanged vocabulary IDs. Body weights matched the previously exported body graph and were reused only after identity verification; every runtime was retested with fresh source baselines. + +The recipe/source/recognizer.py file comes from that release. portable_model.py algebraically replaces pointwise Conv1d with Linear, preserving masked squeeze-excitation, true widths and CTC lengths. build_recognizer.py checks FP32 logit/argmax equivalence on varied synthetic shapes before exporting. Compact outputs contain tokens, frame confidence and lengths; callers do not need to transfer full logits. + +Use separate environments for Mac and Linux LiteRT. The requirements files list the measured key converter versions, not complete dependency locks. Python3.11 was used on Mac; LiteRT was built in its existing Linux Python3.12 environment. No upstream training environment was changed. + +```sh +# Mac: repeat for each source checkpoint listed in components.json. +python -m pip install -r recipe/requirements-macos.txt +python recipe/build_recognizer.py --checkpoint /absolute/path/to/checkpoint.pt --onnx --hqq --coreml --blocks 16 + +# Separate Linux environment; same source checkpoint. +python -m pip install -r recipe/requirements-litert.txt +python recipe/export_litert.py --checkpoint /absolute/path/to/checkpoint.pt +``` + +The LiteRT script's reader branch is portable; its legacy --detector branch requires additional detector helpers and the original Stallion checkout, and is not a standalone detector recipe. + +ONNX: opset18, dynamic batch/width, ORT1.31 MatMulNBits RTN symmetric4-bit group16, accuracy_level4; HQQ4 group32 is an additional CPU alternative. Eighty-one pointwise linear layers are packed. The stem, depthwise convolutions, biases and other unsupported values stay floating. Graph inputs are float32; accuracy_level4 permits lower internal precision in runtime kernels. HQQ does not require image calibration. The tract importer tested here supports RTN group16 but rejects HQQ floating zero points. + +Core ML: coremltools9 ML Program, FLOAT32 compute request, iOS18/macOS15 minimum, batch1..8, width8..8192. Apply linear_symmetric int4 per_block16 with weight_threshold512. Validate CPU_AND_GPU on Mac. Quantization storage does not guarantee a particular GPU/ANE placement. + +LiteRT: litert-torch0.10 converts five static batch-one signatures, widths512/1024/2048/4096/8192. True-width masks remain dynamic inputs. ai-edge-quantizer0.10 recipe.dynamic_wi4b32_afp32 is the accepted reader candidate. recipe.weight_only_wi4_afp32 is produced as an experiment, not the qualified reader artifact shipped here. Keep the dynamic4-block32 file and audit real INT4 buffers; about95.5% of stored constant elements are INT4. This denominator is not a trainable-parameter fraction. + +Qualification uses the same frozen300 development crops per reader,50 in each of six buckets. Compare every target to a freshly run uncompressed checkpoint without text normalization, requiring character parity>=0.98 in every bucket; report exact-line agreement separately. The frozen private manifest SHA256 is7e7049a3b56323588ae1f6bd38b1753afc2b1149d275c6f0f07c6993be991978. Private images and predictions are deliberately not included. Reproducing this exact canary requires authorized access to those frozen inputs; new public tests do not replace it. + +The successful recipes above do not use image calibration. A separate GPTQ experiment used144 frozen training-only calibration crops, did not recover the full-page target, and was not promoted or shipped. No public page was used to fit weights. Full-page pure-W4 qualification failed on a handwritten-table diagnostic; see the model card and VALIDATION.json. + +All original recognizer/code and Surya-derived model licensing and attribution still apply. diff --git a/VALIDATION.json b/VALIDATION.json new file mode 100644 index 0000000000000000000000000000000000000000..1d0bd2638e93ad3bd530864413c7be479cc65db0 --- /dev/null +++ b/VALIDATION.json @@ -0,0 +1,3748 @@ +{ + "base_model": "Reza2kn/Bina-0.4-Rizeh", + "base_revision": "51b8c314b0552b1884c1f0e28016cb12a143f637", + "scope": "Five CTC readers: frozen300 preprocessed crops each; detectors: procedural-dev heatmaps only", + "reader_targets": [ + { + "role": "short_labels", + "runtime": "browser-wasm", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 0.9867245422170867, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "onnx-linux-cpu-hqq4-block32", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "e0954ac2ffc4b574b9c6a2c5a1d09117b5238b9ec8a4e97b83b5f46f963fc817", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 14.501852935194389, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943560800410467, + "exact_line_parity": 0.88, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9940137683328345, + "exact_line_parity": 0.92, + "candidate_CER": 0.012481426448737, + "source_CER": 0.00861812778603269, + "CER_delta": 0.003863298662704309 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9981438515081207, + "exact_line_parity": 0.94, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.02736549165120594, + "CER_delta": 0.0 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992695398100804, + "exact_line_parity": 0.98, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.78, + "candidate_CER": 0.057543658746063556, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0028628685943315204 + } + } + }, + { + "role": "short_labels", + "runtime": "coreml-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": null, + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9846562407789908, + "crops_per_second": 37.9281905430233, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9938429964084146, + "exact_line_parity": 0.78, + "candidate_CER": 0.012276214833759591, + "source_CER": 0.010741687979539642, + "CER_delta": 0.001534526854219949 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.88, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.94, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.02736549165120594, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.92, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9846562407789908, + "exact_line_parity": 0.76, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "onnx-hqq4-block32", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "e0954ac2ffc4b574b9c6a2c5a1d09117b5238b9ec8a4e97b83b5f46f963fc817", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 7.6651239617737925, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943560800410467, + "exact_line_parity": 0.88, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9940137683328345, + "exact_line_parity": 0.92, + "candidate_CER": 0.012481426448737, + "source_CER": 0.00861812778603269, + "CER_delta": 0.003863298662704309 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9981438515081207, + "exact_line_parity": 0.94, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.02736549165120594, + "CER_delta": 0.0 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992695398100804, + "exact_line_parity": 0.98, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.78, + "candidate_CER": 0.057543658746063556, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0028628685943315204 + } + } + }, + { + "role": "short_labels", + "runtime": "tract-linux-cuda-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 242.5290926015559, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "browser-webgpu", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 8.822682174510609, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "onnx-linux-cuda-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 342.76497929340195, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "tract-cpu-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 21.854343609292783, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "short_labels", + "runtime": "onnx-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9861316022425495, + "crops_per_second": 8.339678565514452, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9861316022425495, + "exact_line_parity": 0.8, + "candidate_CER": 0.05353564271399943, + "source_CER": 0.05468079015173204, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "short_labels", + "runtime": "litert-dynamic4-block32", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "3e946ddfd8108019e56bee58462073b9f8daa038ad5cc6bda569bef95477639f", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9834759516081439, + "crops_per_second": 45.07273258563781, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9980506822612085, + "exact_line_parity": 0.9, + "candidate_CER": 0.0019498607242339832, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0008356545961002785 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9892252437147255, + "exact_line_parity": 0.72, + "candidate_CER": 0.01381074168797954, + "source_CER": 0.010741687979539642, + "CER_delta": 0.003069053708439898 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9964082609997007, + "exact_line_parity": 0.92, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.00861812778603269, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9967517401392111, + "exact_line_parity": 0.9, + "candidate_CER": 0.029684601113172542, + "source_CER": 0.02736549165120594, + "CER_delta": 0.002319109461966605 + }, + "printed": { + "cases": 50, + "character_parity": 0.9934258582907232, + "exact_line_parity": 0.84, + "candidate_CER": 0.008746355685131196, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0036443148688046646 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9834759516081439, + "exact_line_parity": 0.64, + "candidate_CER": 0.057543658746063556, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0028628685943315204 + } + } + }, + { + "role": "short_labels", + "runtime": "tract-metal-w4-block16", + "source_checkpoint_sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "model_sha256": "cdb2d08050b2a7cbaff7154d39b6bdfcf0fdcc601f9180641864cf1ab193c4cf", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873118914133963, + "crops_per_second": 27.759534227305558, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.995895330938943, + "exact_line_parity": 0.86, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.94, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.02736549165120594, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873118914133963, + "exact_line_parity": 0.8, + "candidate_CER": 0.05410821643286573, + "source_CER": 0.05468079015173204, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "body", + "runtime": "browser-wasm", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870473947600824, + "crops_per_second": 0.909649944111392, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870473947600824, + "exact_line_parity": 0.78, + "candidate_CER": 0.05382192957343258, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000286286859433152 + } + } + }, + { + "role": "body", + "runtime": "onnx-linux-cpu-hqq4-block32", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "c8b9677ce060c5e50edfcc7e78364b0219c78b4bbb84514a77ca71757fcd3f5f", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9885192817191639, + "crops_per_second": 14.416615669727436, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9917822290703646, + "exact_line_parity": 0.82, + "candidate_CER": 0.012276214833759591, + "source_CER": 0.010741687979539642, + "CER_delta": 0.001534526854219949 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9940119760479041, + "exact_line_parity": 0.92, + "candidate_CER": 0.01337295690936107, + "source_CER": 0.00861812778603269, + "CER_delta": 0.00475482912332838 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9985390796201608, + "exact_line_parity": 0.96, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9885192817191639, + "exact_line_parity": 0.8, + "candidate_CER": 0.05639851130833095, + "source_CER": 0.05410821643286573, + "CER_delta": 0.002290294875465216 + } + } + }, + { + "role": "body", + "runtime": "coreml-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": null, + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873417721518988, + "crops_per_second": 51.39025184516772, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.01432225063938619, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0035805626598465474 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9949101796407186, + "exact_line_parity": 0.86, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.92, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873417721518988, + "exact_line_parity": 0.78, + "candidate_CER": 0.0566847981677641, + "source_CER": 0.05410821643286573, + "CER_delta": 0.002576581734898368 + } + } + }, + { + "role": "body", + "runtime": "onnx-hqq4-block32", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "c8b9677ce060c5e50edfcc7e78364b0219c78b4bbb84514a77ca71757fcd3f5f", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9885192817191639, + "crops_per_second": 7.691890388291468, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9917822290703646, + "exact_line_parity": 0.82, + "candidate_CER": 0.012276214833759591, + "source_CER": 0.010741687979539642, + "CER_delta": 0.001534526854219949 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9940119760479041, + "exact_line_parity": 0.92, + "candidate_CER": 0.01337295690936107, + "source_CER": 0.00861812778603269, + "CER_delta": 0.00475482912332838 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9985390796201608, + "exact_line_parity": 0.96, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9885192817191639, + "exact_line_parity": 0.8, + "candidate_CER": 0.05639851130833095, + "source_CER": 0.05410821643286573, + "CER_delta": 0.002290294875465216 + } + } + }, + { + "role": "body", + "runtime": "tract-linux-cuda-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870473947600824, + "crops_per_second": 230.44644301836308, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870473947600824, + "exact_line_parity": 0.78, + "candidate_CER": 0.05382192957343258, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000286286859433152 + } + } + }, + { + "role": "body", + "runtime": "browser-webgpu", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870473947600824, + "crops_per_second": 8.434610749622383, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870473947600824, + "exact_line_parity": 0.78, + "candidate_CER": 0.05382192957343258, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000286286859433152 + } + } + }, + { + "role": "body", + "runtime": "onnx-linux-cuda-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867530173682661, + "crops_per_second": 347.07615365168624, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867530173682661, + "exact_line_parity": 0.78, + "candidate_CER": 0.05353564271399943, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000572573718866304 + } + } + }, + { + "role": "body", + "runtime": "tract-cpu-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870473947600824, + "crops_per_second": 21.779274798978328, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870473947600824, + "exact_line_parity": 0.78, + "candidate_CER": 0.05382192957343258, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000286286859433152 + } + } + }, + { + "role": "body", + "runtime": "onnx-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9841036208419194, + "crops_per_second": 8.33820322202337, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.998886104149262, + "exact_line_parity": 0.92, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9841036208419194, + "exact_line_parity": 0.78, + "candidate_CER": 0.05181792155740052, + "source_CER": 0.05410821643286573, + "CER_delta": -0.002290294875465216 + } + } + }, + { + "role": "body", + "runtime": "litert-dynamic4-block32", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "1228832b077ff44b4b79dbac09ef6ca40ae4caf53e0dde13e61d49be5ba19824", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9826317338828378, + "crops_per_second": 43.49684545370007, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9980506822612085, + "exact_line_parity": 0.9, + "candidate_CER": 0.0019498607242339832, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0008356545961002785 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9897277863379559, + "exact_line_parity": 0.68, + "candidate_CER": 0.014833759590792838, + "source_CER": 0.010741687979539642, + "CER_delta": 0.004092071611253197 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.86, + "candidate_CER": 0.008915304606240713, + "source_CER": 0.00861812778603269, + "CER_delta": 0.00029717682020802375 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9967532467532467, + "exact_line_parity": 0.92, + "candidate_CER": 0.029684601113172542, + "source_CER": 0.026437847866419294, + "CER_delta": 0.003246753246753247 + }, + "printed": { + "cases": 50, + "character_parity": 0.9934258582907232, + "exact_line_parity": 0.84, + "candidate_CER": 0.008746355685131196, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0036443148688046646 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9826317338828378, + "exact_line_parity": 0.7, + "candidate_CER": 0.06012024048096192, + "source_CER": 0.05410821643286573, + "CER_delta": 0.006012024048096192 + } + } + }, + { + "role": "body", + "runtime": "tract-metal-w4-block16", + "source_checkpoint_sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870473947600824, + "crops_per_second": 27.301717529508743, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952095808383233, + "exact_line_parity": 0.92, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.00861812778603269, + "CER_delta": 0.0014858841010401188 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.9, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870473947600824, + "exact_line_parity": 0.78, + "candidate_CER": 0.05382192957343258, + "source_CER": 0.05410821643286573, + "CER_delta": -0.000286286859433152 + } + } + }, + { + "role": "numeric_math", + "runtime": "browser-wasm", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870091526424565, + "crops_per_second": 0.45353221890262324, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870091526424565, + "exact_line_parity": 0.8, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0008588605782994561 + } + } + }, + { + "role": "numeric_math", + "runtime": "onnx-linux-cpu-hqq4-block32", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "b8e5b2aded4982446f5ac199de699e52ee04816fc69acfaa05b65cd7e0977d02", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9858281665190434, + "crops_per_second": 13.449897637871674, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9938524590163934, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.997000599880024, + "exact_line_parity": 0.96, + "candidate_CER": 0.011589895988112928, + "source_CER": 0.010401188707280832, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992690058479532, + "exact_line_parity": 0.98, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.0058309037900874635, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9858281665190434, + "exact_line_parity": 0.76, + "candidate_CER": 0.0572573718866304, + "source_CER": 0.05468079015173204, + "CER_delta": 0.002576581734898368 + } + } + }, + { + "role": "numeric_math", + "runtime": "coreml-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": null, + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9852376734573369, + "crops_per_second": 47.452310161828514, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.998886104149262, + "exact_line_parity": 0.94, + "candidate_CER": 0.001671309192200557, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0005571030640668524 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9923155737704918, + "exact_line_parity": 0.76, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0020460358056265983 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961007798440312, + "exact_line_parity": 0.9, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.010401188707280832, + "CER_delta": -0.00029717682020802375 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.99860853432282, + "exact_line_parity": 0.94, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0013914656771799629 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.96, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9852376734573369, + "exact_line_parity": 0.78, + "candidate_CER": 0.056112224448897796, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0014314342971657602 + } + } + }, + { + "role": "numeric_math", + "runtime": "onnx-hqq4-block32", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "b8e5b2aded4982446f5ac199de699e52ee04816fc69acfaa05b65cd7e0977d02", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9858281665190434, + "crops_per_second": 5.269215760371242, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9938524590163934, + "exact_line_parity": 0.84, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.997000599880024, + "exact_line_parity": 0.96, + "candidate_CER": 0.011589895988112928, + "source_CER": 0.010401188707280832, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995361781076066, + "exact_line_parity": 0.98, + "candidate_CER": 0.026901669758812616, + "source_CER": 0.026437847866419294, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992690058479532, + "exact_line_parity": 0.98, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.0058309037900874635, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9858281665190434, + "exact_line_parity": 0.76, + "candidate_CER": 0.0572573718866304, + "source_CER": 0.05468079015173204, + "CER_delta": 0.002576581734898368 + } + } + }, + { + "role": "numeric_math", + "runtime": "tract-linux-cuda-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870091526424565, + "crops_per_second": 222.39857308838302, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870091526424565, + "exact_line_parity": 0.8, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0008588605782994561 + } + } + }, + { + "role": "numeric_math", + "runtime": "browser-webgpu", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870091526424565, + "crops_per_second": 7.434653116622879, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870091526424565, + "exact_line_parity": 0.8, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0008588605782994561 + } + } + }, + { + "role": "numeric_math", + "runtime": "onnx-linux-cuda-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9873043991733097, + "crops_per_second": 330.48427191322395, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9873043991733097, + "exact_line_parity": 0.8, + "candidate_CER": 0.055253363870598336, + "source_CER": 0.05468079015173204, + "CER_delta": 0.000572573718866304 + } + } + }, + { + "role": "numeric_math", + "runtime": "tract-cpu-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870091526424565, + "crops_per_second": 17.48098874356552, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870091526424565, + "exact_line_parity": 0.8, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0008588605782994561 + } + } + }, + { + "role": "numeric_math", + "runtime": "onnx-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9861234130498967, + "crops_per_second": 5.231096362878766, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0005571030640668524, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0005571030640668524 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.84, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0010230179028132991 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.010104011887072809, + "source_CER": 0.010401188707280832, + "CER_delta": -0.00029717682020802375 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9861234130498967, + "exact_line_parity": 0.8, + "candidate_CER": 0.052963068995133124, + "source_CER": 0.05468079015173204, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "numeric_math", + "runtime": "litert-dynamic4-block32", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "e0908804c688599e5c42144cf83ba436e8a5fd33e2531b8f3946fc596b8fce17", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.984351933864777, + "crops_per_second": 42.00890459026271, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9974937343358397, + "exact_line_parity": 0.86, + "candidate_CER": 0.0025069637883008357, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.001392757660167131 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9902663934426229, + "exact_line_parity": 0.76, + "candidate_CER": 0.01381074168797954, + "source_CER": 0.009718670076726343, + "CER_delta": 0.004092071611253197 + }, + "mixed": { + "cases": 50, + "character_parity": 0.997000599880024, + "exact_line_parity": 0.9, + "candidate_CER": 0.011292719167904903, + "source_CER": 0.010401188707280832, + "CER_delta": 0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.99860853432282, + "exact_line_parity": 0.96, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0013914656771799629 + }, + "printed": { + "cases": 50, + "character_parity": 0.9956140350877193, + "exact_line_parity": 0.9, + "candidate_CER": 0.008746355685131196, + "source_CER": 0.0058309037900874635, + "CER_delta": 0.0029154518950437317 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.984351933864777, + "exact_line_parity": 0.66, + "candidate_CER": 0.059833953621528775, + "source_CER": 0.05468079015173204, + "CER_delta": 0.005153163469796736 + } + } + }, + { + "role": "numeric_math", + "runtime": "tract-metal-w4-block16", + "source_checkpoint_sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "model_sha256": "de7b841b7e1a3ca56da0e76c90f343d8fdad780d464e9b0a30818e71f8a75916", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870091526424565, + "crops_per_second": 20.460208750116568, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0011142061281337048, + "CER_delta": -0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948770491803278, + "exact_line_parity": 0.86, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.009718670076726343, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9973005398920216, + "exact_line_parity": 0.96, + "candidate_CER": 0.009806835066864784, + "source_CER": 0.010401188707280832, + "CER_delta": -0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990723562152134, + "exact_line_parity": 0.96, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.026437847866419294, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.0058309037900874635, + "CER_delta": -0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870091526424565, + "exact_line_parity": 0.8, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.05468079015173204, + "CER_delta": 0.0008588605782994561 + } + } + }, + { + "role": "printed", + "runtime": "browser-wasm", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867178276269185, + "crops_per_second": 0.5527785853213841, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867178276269185, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "printed", + "runtime": "onnx-linux-cpu-hqq4-block32", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "8c687c2e7bc56c1fc0878d9eddf86b83cac554764a227cc2f9a32bb9c82b73f2", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9878984651711924, + "crops_per_second": 10.156680017912882, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9958911145351823, + "exact_line_parity": 0.88, + "candidate_CER": 0.012276214833759591, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0010230179028132991 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9949117030829093, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990719257540603, + "exact_line_parity": 0.96, + "candidate_CER": 0.02922077922077922, + "source_CER": 0.02829313543599258, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9878984651711924, + "exact_line_parity": 0.78, + "candidate_CER": 0.0566847981677641, + "source_CER": 0.0566847981677641, + "CER_delta": 0.0 + } + } + }, + { + "role": "printed", + "runtime": "coreml-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": null, + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.98642266824085, + "crops_per_second": 37.901162275606005, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991645781119465, + "exact_line_parity": 0.94, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9933230611196713, + "exact_line_parity": 0.76, + "candidate_CER": 0.014833759590792838, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0035805626598465474 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9964082609997007, + "exact_line_parity": 0.9, + "candidate_CER": 0.009212481426448737, + "source_CER": 0.008023774145616641, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995359628770302, + "exact_line_parity": 0.98, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9948830409356725, + "exact_line_parity": 0.88, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.004373177842565598, + "CER_delta": 0.002186588921282799 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.98642266824085, + "exact_line_parity": 0.82, + "candidate_CER": 0.05553965073003149, + "source_CER": 0.0566847981677641, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "printed", + "runtime": "onnx-hqq4-block32", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "8c687c2e7bc56c1fc0878d9eddf86b83cac554764a227cc2f9a32bb9c82b73f2", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9878984651711924, + "crops_per_second": 5.344448209616115, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.999443052074631, + "exact_line_parity": 0.96, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9958911145351823, + "exact_line_parity": 0.88, + "candidate_CER": 0.012276214833759591, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0010230179028132991 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9949117030829093, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990719257540603, + "exact_line_parity": 0.96, + "candidate_CER": 0.02922077922077922, + "source_CER": 0.02829313543599258, + "CER_delta": 0.0009276437847866419 + }, + "printed": { + "cases": 50, + "character_parity": 0.9978070175438597, + "exact_line_parity": 0.94, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9878984651711924, + "exact_line_parity": 0.78, + "candidate_CER": 0.0566847981677641, + "source_CER": 0.0566847981677641, + "CER_delta": 0.0 + } + } + }, + { + "role": "printed", + "runtime": "tract-linux-cuda-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867178276269185, + "crops_per_second": 225.45710142207844, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867178276269185, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "printed", + "runtime": "browser-webgpu", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867178276269185, + "crops_per_second": 8.61619338907013, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867178276269185, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "printed", + "runtime": "onnx-linux-cuda-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.98642266824085, + "crops_per_second": 315.415471898614, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.98642266824085, + "exact_line_parity": 0.8, + "candidate_CER": 0.055253363870598336, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0014314342971657602 + } + } + }, + { + "role": "printed", + "runtime": "tract-cpu-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867178276269185, + "crops_per_second": 17.84714031262302, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867178276269185, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "printed", + "runtime": "onnx-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.987012987012987, + "crops_per_second": 5.109953854678509, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9958911145351823, + "exact_line_parity": 0.88, + "candidate_CER": 0.011253196930946292, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.987012987012987, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "printed", + "runtime": "litert-dynamic4-block32", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "89275286e73e2f2bd299caf0a9d4323c8ec00a4cb6817ad1ff132dc9219456f9", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9825855962219598, + "crops_per_second": 42.83810617735317, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9980506822612085, + "exact_line_parity": 0.88, + "candidate_CER": 0.0019498607242339832, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0008356545961002785 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9907550077041603, + "exact_line_parity": 0.72, + "candidate_CER": 0.01432225063938619, + "source_CER": 0.011253196930946292, + "CER_delta": 0.003069053708439898 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.9, + "candidate_CER": 0.00861812778603269, + "source_CER": 0.008023774145616641, + "CER_delta": 0.0005943536404160475 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.997215777262181, + "exact_line_parity": 0.92, + "candidate_CER": 0.030148423005565864, + "source_CER": 0.02829313543599258, + "CER_delta": 0.0018552875695732839 + }, + "printed": { + "cases": 50, + "character_parity": 0.9941520467836258, + "exact_line_parity": 0.86, + "candidate_CER": 0.008017492711370262, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0036443148688046646 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9825855962219598, + "exact_line_parity": 0.74, + "candidate_CER": 0.05954766676209562, + "source_CER": 0.0566847981677641, + "CER_delta": 0.0028628685943315204 + } + } + }, + { + "role": "printed", + "runtime": "tract-metal-w4-block16", + "source_checkpoint_sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "model_sha256": "7f4d08254381c298ce8b88966c4f5b905c7a57baa6f4f8aaf170986874dfc477", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9867178276269185, + "crops_per_second": 14.093633328198088, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9986076301865776, + "exact_line_parity": 0.9, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0011142061281337048, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.86, + "candidate_CER": 0.011764705882352941, + "source_CER": 0.011253196930946292, + "CER_delta": 0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.010698365527488856, + "source_CER": 0.008023774145616641, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986078886310905, + "exact_line_parity": 0.96, + "candidate_CER": 0.0287569573283859, + "source_CER": 0.02829313543599258, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9970760233918129, + "exact_line_parity": 0.92, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.004373177842565598, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9867178276269185, + "exact_line_parity": 0.8, + "candidate_CER": 0.05496707701116519, + "source_CER": 0.0566847981677641, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "degraded", + "runtime": "browser-wasm", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 0.4708207395006966, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "onnx-linux-cpu-hqq4-block32", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "5094b4720adf8436833e862eec1a90eadff60215563bce2dbb2f6a43cee17020", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870435806831567, + "crops_per_second": 13.465028526823433, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991648106904232, + "exact_line_parity": 0.94, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.88, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.01099554234769688, + "source_CER": 0.008320950965824666, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986098239110287, + "exact_line_parity": 0.94, + "candidate_CER": 0.02829313543599258, + "source_CER": 0.027829313543599257, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992695398100804, + "exact_line_parity": 0.98, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870435806831567, + "exact_line_parity": 0.8, + "candidate_CER": 0.05811623246492986, + "source_CER": 0.05697108502719725, + "CER_delta": 0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "coreml-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": null, + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9861601884570083, + "crops_per_second": 78.93670187737018, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0005571030640668524 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9953775038520801, + "exact_line_parity": 0.84, + "candidate_CER": 0.01329923273657289, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0025575447570332483 + }, + "mixed": { + "cases": 50, + "character_parity": 0.996707572583059, + "exact_line_parity": 0.9, + "candidate_CER": 0.007429420505200594, + "source_CER": 0.008320950965824666, + "CER_delta": -0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9990732159406858, + "exact_line_parity": 0.96, + "candidate_CER": 0.027829313543599257, + "source_CER": 0.027829313543599257, + "CER_delta": 0.0 + }, + "printed": { + "cases": 50, + "character_parity": 0.9963476990504018, + "exact_line_parity": 0.92, + "candidate_CER": 0.006559766763848397, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0014577259475218659 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9861601884570083, + "exact_line_parity": 0.74, + "candidate_CER": 0.0572573718866304, + "source_CER": 0.05697108502719725, + "CER_delta": 0.000286286859433152 + } + } + }, + { + "role": "degraded", + "runtime": "onnx-hqq4-block32", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "5094b4720adf8436833e862eec1a90eadff60215563bce2dbb2f6a43cee17020", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9870435806831567, + "crops_per_second": 9.594292903740188, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9991648106904232, + "exact_line_parity": 0.94, + "candidate_CER": 0.0011142061281337048, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0002785515320334262 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9948638931689779, + "exact_line_parity": 0.88, + "candidate_CER": 0.010230179028132993, + "source_CER": 0.010741687979539642, + "CER_delta": -0.0005115089514066496 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9958096378329842, + "exact_line_parity": 0.92, + "candidate_CER": 0.01099554234769688, + "source_CER": 0.008320950965824666, + "CER_delta": 0.002674591381872214 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9986098239110287, + "exact_line_parity": 0.94, + "candidate_CER": 0.02829313543599258, + "source_CER": 0.027829313543599257, + "CER_delta": 0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.9992695398100804, + "exact_line_parity": 0.98, + "candidate_CER": 0.0058309037900874635, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0007288629737609329 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9870435806831567, + "exact_line_parity": 0.8, + "candidate_CER": 0.05811623246492986, + "source_CER": 0.05697108502719725, + "CER_delta": 0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "tract-linux-cuda-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 216.53247316857357, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "browser-webgpu", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 5.805356834741982, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "onnx-linux-cuda-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 323.7218798515477, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "tract-cpu-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 27.57683044201156, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + }, + { + "role": "degraded", + "runtime": "onnx-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9885159010600707, + "crops_per_second": 7.316526044854179, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.009212481426448737, + "source_CER": 0.008320950965824666, + "CER_delta": 0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9885159010600707, + "exact_line_parity": 0.78, + "candidate_CER": 0.055253363870598336, + "source_CER": 0.05697108502719725, + "CER_delta": -0.0017177211565989122 + } + } + }, + { + "role": "degraded", + "runtime": "litert-dynamic4-block32", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "8201f9eb76f82ec573b7109bf19a3b02718b11d89891adb76c4dd09cff4fa0bb", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9826266195524146, + "crops_per_second": 43.29946678010443, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9988864142538976, + "exact_line_parity": 0.94, + "candidate_CER": 0.001392757660167131, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0005571030640668524 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9912686183872624, + "exact_line_parity": 0.72, + "candidate_CER": 0.014833759590792838, + "source_CER": 0.010741687979539642, + "CER_delta": 0.004092071611253197 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9961089494163424, + "exact_line_parity": 0.88, + "candidate_CER": 0.009212481426448737, + "source_CER": 0.008320950965824666, + "CER_delta": 0.0008915304606240713 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.995366079703429, + "exact_line_parity": 0.92, + "candidate_CER": 0.03153988868274583, + "source_CER": 0.027829313543599257, + "CER_delta": 0.0037105751391465678 + }, + "printed": { + "cases": 50, + "character_parity": 0.9948867786705624, + "exact_line_parity": 0.88, + "candidate_CER": 0.008746355685131196, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0036443148688046646 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9826266195524146, + "exact_line_parity": 0.64, + "candidate_CER": 0.06212424849699399, + "source_CER": 0.05697108502719725, + "CER_delta": 0.005153163469796736 + } + } + }, + { + "role": "degraded", + "runtime": "tract-metal-w4-block16", + "source_checkpoint_sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "model_sha256": "f9feca4a76053afea6640e46f66cb3b4709018ca3fe1a599a9e52524c6e24892", + "cases": 300, + "parity_gate": true, + "worst_bucket_character_parity": 0.9879269729093051, + "crops_per_second": 43.570941984219765, + "buckets": { + "english": { + "cases": 50, + "character_parity": 0.9994432071269488, + "exact_line_parity": 0.96, + "candidate_CER": 0.0008356545961002785, + "source_CER": 0.0008356545961002785, + "CER_delta": 0.0 + }, + "handwriting": { + "cases": 50, + "character_parity": 0.9943502824858758, + "exact_line_parity": 0.82, + "candidate_CER": 0.010741687979539642, + "source_CER": 0.010741687979539642, + "CER_delta": 0.0 + }, + "mixed": { + "cases": 50, + "character_parity": 0.9952110146662676, + "exact_line_parity": 0.92, + "candidate_CER": 0.00950965824665676, + "source_CER": 0.008320950965824666, + "CER_delta": 0.001188707280832095 + }, + "newspaper": { + "cases": 50, + "character_parity": 0.9995366079703429, + "exact_line_parity": 0.98, + "candidate_CER": 0.02736549165120594, + "source_CER": 0.027829313543599257, + "CER_delta": -0.00046382189239332097 + }, + "printed": { + "cases": 50, + "character_parity": 0.997808619430241, + "exact_line_parity": 0.94, + "candidate_CER": 0.00510204081632653, + "source_CER": 0.00510204081632653, + "CER_delta": 0.0 + }, + "synthetic": { + "cases": 50, + "character_parity": 0.9879269729093051, + "exact_line_parity": 0.78, + "candidate_CER": 0.05582593758946464, + "source_CER": 0.05697108502719725, + "CER_delta": -0.001145147437732608 + } + } + } + ], + "detector_candidates": [ + { + "role": "main_detector", + "runtime": "onnx-detector-w4-allconv", + "mean_text_mask_iou": 0.965475773488656, + "min_text_mask_iou": 0.9336849044166118, + "transcription_parity_qualified": false + }, + { + "role": "main_detector", + "runtime": "litert-detector-weight-only4", + "mean_text_mask_iou": 0.9595448080555493, + "min_text_mask_iou": 0.9307568438003221, + "transcription_parity_qualified": false + }, + { + "role": "main_detector", + "runtime": "onnx-detector-w4-pointwise", + "mean_text_mask_iou": 0.9773309403974731, + "min_text_mask_iou": 0.9627226287449951, + "transcription_parity_qualified": false + }, + { + "role": "main_detector", + "runtime": "coreml-detector-w4-block16", + "mean_text_mask_iou": 0.9810492286988853, + "min_text_mask_iou": 0.9689657529564564, + "transcription_parity_qualified": false + }, + { + "role": "line_guard", + "runtime": "onnx-detector-w4-allconv", + "mean_text_mask_iou": 0.9665194888564727, + "min_text_mask_iou": 0.9380598925006399, + "transcription_parity_qualified": false + }, + { + "role": "line_guard", + "runtime": "litert-detector-weight-only4", + "mean_text_mask_iou": 0.9555789912494387, + "min_text_mask_iou": 0.9315724097618003, + "transcription_parity_qualified": false + }, + { + "role": "line_guard", + "runtime": "onnx-detector-w4-pointwise", + "mean_text_mask_iou": 0.981330133565763, + "min_text_mask_iou": 0.9714587737843552, + "transcription_parity_qualified": false + }, + { + "role": "line_guard", + "runtime": "coreml-detector-w4-block16", + "mean_text_mask_iou": 0.9766960486901575, + "min_text_mask_iou": 0.9615810418599084, + "transcription_parity_qualified": false + }, + { + "role": "printed_detector", + "runtime": "onnx-detector-w4-allconv", + "mean_text_mask_iou": 0.9617834259340746, + "min_text_mask_iou": 0.9151712887438825, + "transcription_parity_qualified": false + }, + { + "role": "printed_detector", + "runtime": "litert-detector-weight-only4", + "mean_text_mask_iou": 0.9542730677661033, + "min_text_mask_iou": 0.9115772488906817, + "transcription_parity_qualified": false + }, + { + "role": "printed_detector", + "runtime": "onnx-detector-w4-pointwise", + "mean_text_mask_iou": 0.9855684873828712, + "min_text_mask_iou": 0.9750303684707787, + "transcription_parity_qualified": false + }, + { + "role": "printed_detector", + "runtime": "coreml-detector-w4-block16", + "mean_text_mask_iou": 0.9764452196609898, + "min_text_mask_iou": 0.9485420240137221, + "transcription_parity_qualified": false + } + ], + "public_page_diagnostics": { + "page-quant-cpu.json": { + "provider": "CPUExecutionProvider", + "load_seconds": 4.683880491997115, + "seconds": 19.141634956933558, + "character_parity": 1.0, + "parity_gate": true, + "source_characters": 140, + "candidate": { + "text": "نمونه آزمایشی بینا ۰٫۴ ریزه\n\nاین صفحه برای آزمودن نصب ساخته شده است.\n\nشماره: ۲۷۴\nتاریخ: ۱۴۰۵/۰۸/۱۶\n\nخواندن متن فارسی چاپی، عددها و نشانه‌ها.", + "lines": [ + { + "text": "نمونه آزمایشی بینا ۰٫۴ ریزه", + "layer": null, + "box": [ + 699.0, + 79.0, + 1164.0, + 130.0 + ], + "confidence": 0.9928557872772217 + }, + { + "text": "این صفحه برای آزمودن نصب ساخته شده است.", + "layer": null, + "box": [ + 536.5, + 187.5, + 1163.0, + 228.0 + ], + "confidence": 0.9855734705924988 + }, + { + "text": "شماره: ۲۷۴", + "layer": null, + "box": [ + 720.0, + 300.0, + 882.5, + 337.0 + ], + "confidence": 1.0 + }, + { + "text": "تاریخ: ۱۴۰۵/۰۸/۱۶", + "layer": null, + "box": [ + 917.0, + 298.5, + 1163.5, + 339.0 + ], + "confidence": 0.9910417199134827 + }, + { + "text": "خواندن متن فارسی چاپی، عددها و نشانه‌ها.", + "layer": null, + "box": [ + 592.0, + 407.5, + 1163.5, + 450.0 + ], + "confidence": 0.9801881909370422 + } + ] + }, + "repeat_text_identical": true, + "reader_calls_on_repeat": 0, + "readers": { + "body": { + "model_calls": 1, + "cache_hits": 5 + }, + "short_labels": { + "model_calls": 0, + "cache_hits": 0 + }, + "printed": { + "model_calls": 1, + "cache_hits": 5 + }, + "numeric_math": { + "model_calls": 0, + "cache_hits": 0 + }, + "degraded": { + "model_calls": 0, + "cache_hits": 0 + } + }, + "scope": "One public whole-page demo; not the full protected page/table gate" + }, + "public-pages-quant.json": { + "rows": [ + { + "image": "printed-modern.png", + "text": "بینا: خواندن متن فارسی بدون اینترنت\n\nبینا برنامه‌ای است که متن فارسی را از عکس و فایل PDF می‌خواند و به متن قابل\nویرایش تبدیل می‌کند. همۀ کار روی همین رایانه انجام می‌شود و هیچ تصویری به جای\nدیگری فرستاده نمی‌شود؛ برای همین می‌توان نامه‌های اداری، پرونده‌های شخصی و\nاسناد محرمانه را بی‌نگرانی به آن سپرد.\n\nمدل هوش مصنوعی بینا با هزاران صفحۀ چاپی و دست‌نویس آموزش دیده است. این\nمدل صفحه را به چند بخش تقسیم می‌کند، هر بخش را جداگانه می‌خواند و در پایان\nمتن کامل را به همان ترتیب خواندن کنار هم می‌گذارد.\n\nاگر رایانه کارت گرافیک انویدیا داشته باشد، بینا می‌تواند از آن کمک بگیرد و هر صفحه را\nچند برابر سریع‌تر بخواند. در غیر این صورت پردازندۀ مرکزی همین کار را با همان دقت\nانجام می‌دهد.", + "lines": 11, + "seconds": 19.679442223976366, + "table_grids": 0, + "table_errors": [], + "character_parity": 1.0, + "parity_gate": true + }, + { + "image": "hand-plain.jpg", + "text": "یک سال بعد از این کار دلیل این امر هم گستردگی\nمحصولات این شرکت بود این حافظه می‌تواند توسط نرم‌افزارهای\nارتباط مورد استفاده قرار بگیرند در این مجموعه دستوری از\nقواعد دستوری زیر استفاده می‌شود یک رشته می‌تواند شامل چندین\nدستور های س، باشد\nنرم‌افزار کاربردی نام عمومی برنامه‌های کامپیوتری برای\nانجام وظایف است نرم‌افزار منبع باز نرم‌افزاری، است\nکه کد منبع آن تحت یک مجوز خاص در اختیار\nدارندگان مجوز آن قرار می‌گیرد می‌اوان از آن برای\nهر هدفی استفاده و، منتشر کرد کد منبع باز\nاست و، می‌اوان آن را در صورت نیاز تغییر داد اگر\nهر دو نرم‌افزار از یک مجوز یکسان استفاده کنند معمولا\nقابل ادغام هستند مراقبت‌های بهداشتی و، کمک‌های\nاجتماعی برنامه‌های داخلی و، اختصاصی خط تجاری\nفعالیت این شرکت در راستای تولید نرم‌افزار و،\nبرنامه‌های کاربردی برای موبایل بود که در\nاین راه موفقیت بسیاری کسب کرده بود این سیستم عامل\nدر ابتدا ساختار بسیار ساده‌ای داشت و، از برنامه‌های\nمحدودی پشتیبانی می‌کرد اولین نسخه این سیستم عامل در", + "lines": 19, + "seconds": 19.4021920269588, + "table_grids": 0, + "table_errors": [], + "character_parity": 0.9977900552486187, + "parity_gate": true + }, + { + "image": "hand-table.jpg", + "text": "دبستان .....\nجمهوری اس لامی ایران\nاداره کل آموزش وپرورش استان ......\nمدیریت آموزش وپرورش .....\nفروردین\nوزارت اموزش وپرورش\nاولیا\nامضا آموزگار:\nجنگ جهانی یکم تا اواری دهه ۱۹۳۰ خدمات هوایی\nنیردی درمس و، خدهات هوایی نیروی دریایی یونان\nبا هم یکی شده و، نیروی دریایی یویان را تشکیل\nدارند جذگ جیانی ردوم و، جنگ داخلی نیروی\nهوایی یونان میز نظر وزارت دفاع ولی یونان و،\nمستقیما زر ظر ستاد کل دفاع ملی یونان قرار\nدااد\nقبل از جدک جهانی دوم استفاده بعد از\nجنگ ههانی دوم توکدات پ زاز سنگ\nجهانی ادوم استفاده گسترده توجه سروهای انتظامی و،\nنظمی کهی از جنگت نیریک ژمنی ور چلیس\nاستفاده توسط نیروی زمیمی تا رشه ۱۹۶۰\nاستفاده پس از جنگ جهانی دوم شرانفت شده\nاز ایالات متحده\nنام ونام خانوادگی دانش آموز:\nسال تحصیلی ۰۳-۰۴\nماه\nپایه پنجم\nقرآن\nاسفند\nبهمن\nورزش\nخوب\nخوب\nفصل\nمهر\nضعف\nضکیف\nمتوسط\nمهر وامضا مدیر مدرسه", + "lines": 38, + "seconds": 15.461470424081199, + "table_grids": 0, + "table_errors": [], + "character_parity": 0.7982989064398542, + "parity_gate": false + } + ], + "scope": "Three public Bina Desktop samples; no claim of full gate certification", + "readers": { + "body": { + "calls": 14, + "hits": 0 + }, + "short_labels": { + "calls": 3, + "hits": 0 + }, + "printed": { + "calls": 27, + "hits": 0 + }, + "numeric_math": { + "calls": 0, + "hits": 0 + }, + "degraded": { + "calls": 0, + "hits": 0 + } + } + }, + "public-pages-quant-cpu-block16.json": { + "rows": [ + { + "image": "hand-table.jpg", + "text": "دبستان .....\nمدیریت آموزش وپرورش .....\nاداره کل آموزش وپرورش استان .....\nجمهوری اس_ لامی ایران\nفروردین\nوزارت اموزش وپرورش\nفصیل\nژ:مسیتان\nاولیا\nامضا آموزگار:\nجنگ جهانی یکم تا اواشی دهه ۱۹۳۰ خدمات هوایع\nنیردی ترممی و، خدهات هوایی نیروی درپایی یونان\nبا قام یکی شده و، نیروی داریایی یویان را تشکیل\nدارند جنگ جهانی روم و، جنگ داخلی نیروی\nهوای یونان ران نظر وزارت دفاع ملی یونان و،\nمستقیما زر ظر ستاد کل دفاع ملی بونان قرار\nدا د\nقبل از جدن جهانی دوم استفماده بعد از\nجنگ ههانی لوم توهدات پ زان هنگ\nجهانی دوم استفاده گیسترده توسه سروهای انتظامی و،\nنظمی کی از جنگ نیروی ژرمیعی دو، چلیس\nاست‌فاده توسط نیروی زمینی تا رشه ۱۹۶۰\nاستفاده پس از جنگ جهانی دوم درافت شده\nاز ایالات متحده\nسال تحصیلی ۰۳-۰۴\nنام ونام خانوادگی دانش آموز:\n۵\nماه\nمهر\nپایه پنجم\nقرآن\nبهمن\nاسفند\nورزش\nخوب\nخالی\nخوب\nفصل\nمهر\nضعف\nموس\nضکیف\nمترسط\nکوبت دوم\nمهر وامضا مدیر مدرسه", + "lines": 45, + "seconds": 14.24943418300245, + "table_grids": 0, + "table_errors": [], + "character_parity": 0.8651275820170109, + "parity_gate": false + } + ], + "cache_identity": "5804c41c085f3903b79ce585", + "scope": "Public Bina Desktop samples; no claim of full gate certification", + "readers": { + "body": { + "calls": 9, + "hits": 0, + "variant": "block16" + }, + "short_labels": { + "calls": 3, + "hits": 0, + "variant": "block16" + }, + "printed": { + "calls": 19, + "hits": 0, + "variant": "block16" + }, + "numeric_math": { + "calls": 0, + "hits": 0, + "variant": "block16" + }, + "degraded": { + "calls": 0, + "hits": 0, + "variant": "block16" + } + } + }, + "public-pages-quant-cpu-block16-safe.json": { + "rows": [ + { + "image": "printed-modern.png", + "text": "بینا: خواندن متن فارسی بدون اینترنت\n\nبینا برنامه‌ای است که متن فارسی را از عکس و فایل PDF می‌خواند و به متن قابل\nویرایش تبدیل می‌کند. همۀ کار روی همین رایانه انجام می‌شود و هیچ تصویری به جای\nدیگری فرستاده نمی‌شود؛ برای همین می‌توان نامه‌های اداری، پرونده‌های شخصی و\nاسناد محرمانه را بی‌نگرانی به آن سپرد.\n\nمدل هوش مصنوعی بینا با هزاران صفحۀ چاپی و دست‌نویس آموزش دیده است. این\nمدل صفحه را به چند بخش تقسیم می‌کند، هر بخش را جداگانه می‌خواند و در پایان\nمتن کامل را به همان ترتیب خواندن کنار هم می‌گذارد.\n\nاگر رایانه کارت گرافیک انویدیا داشته باشد، بینا می‌تواند از آن کمک بگیرد و هر صفحه را\nچند برابر سریع‌تر بخواند. در غیر این صورت پردازندۀ مرکزی همین کار را با همان دقت\nانجام می‌دهد.", + "lines": 11, + "seconds": 18.71481087699067, + "table_grids": 0, + "table_errors": [], + "precision_route": { + "policy": "color-separated-handwriting-fp32-v1", + "original_precision": false, + "scope": { + "protected": false, + "reason": "No substantial coloured ink", + "image_only": true + } + }, + "character_parity": 1.0, + "parity_gate": true + }, + { + "image": "hand-plain.jpg", + "text": "یک سال بعد از این کار دلیل این امر هم گستردگی\nمحصولات این شرکت بود این حافظه می‌تواند توسط نرم‌افزارهای\nارتباط مورد استفاده قرار بگیرند در این مجموعه دستوری از\nقواعد دستوری زیر استفاده می‌شود یک رشته می‌تواند شامل چندین\nدستور های س، باشد\nنرم‌افزار کاربردی نام عمومی برنامه‌های کامپیوتری برای\nانجام وظایف است نرم‌افزار منبع باز نرم‌افزاری، است\nکه کد منبع آن تحت یک مجوز خاص در اختیار\nدارندگان مجوز آن قرار می‌گیرد می‌وان از آن برای\nهر هدفی استفاده و، منتشر کرد کد منبع باز\nاست و، می‌توان آن را در صورت نیاز تغییر داد اگر\nهر دو نرم‌افزار از یک مجوز یکسان استفاده کنند معمولا\nقابل ادغام هستند مراقبت‌های بهداشتی و، کمک‌های\nاجتماعی برنامه‌های داخلی و، اختصاصی خط تجاری\nفعالیت این شرکت در راستای تولید نرم‌افزار و،\nبرنامه‌های کاربردی برای موبایل بود که در\nاین راه موفقیت بسیاری کسب کرده بود این سیستم عامل\nدر ابتدا ساختار بسیار ساده‌ای داشت و، از برنامه‌های\nمحدودی پشتیبانی می‌کرد اولین نسخه این سیستم عامل در", + "lines": 19, + "seconds": 18.373127989005297, + "table_grids": 0, + "table_errors": [], + "precision_route": { + "policy": "color-separated-handwriting-fp32-v1", + "original_precision": false, + "scope": { + "protected": false, + "reason": "No substantial coloured ink", + "image_only": true + } + }, + "character_parity": 0.9988950276243094, + "parity_gate": true + }, + { + "image": "hand-table.jpg", + "text": "ردیف\nدبستان ......\nمدیریت آموزش وپرورش .....\nجمهوری اس لامی ایران\nاداره کل آموزش وپرورش استان .....\nفروردین\nوزارت آموزش وپرورش\nفصیل\nاولیا\nامضا آموزگار:\nجنگ جهانی یکم تا اواشی دهه ۱۹۳۰ خدمات هوایی\nنیروی رممن و، خدمات هوایی نیروی دریایی یونان\nبا قم یکی شده و، نیروی دریایی یویان را تشکیل\nدارند جنگ جهانی دوم و، جنگ داخلی نیروی\nهوایی یونان هران نظر وزارت دفاع ملی یونان و،\nمستقیما زن ظر ستاد کل دفاع ملی بونان قرار\nدا د\nقبل از جدو جهانی دوم استفاده بعد از\nجنگ جهانی بوم توکدات پر زاز هنگ\nجهانی ادوم استفاده گیسترده توسه سروهای انتظامی و،\nنظمی که از جنگ نیریک زمیمی دو، پلیس\nاستفاده توسط نیروی زمینی تا رشه ۱۹۶۰\nانستفاده پس از جنگ جهانی دوم درافت شده\nاز ایالات متحده\nسال تحصیلی ۰۳-۰۴\nنام ونام خانوادگی دانش آموز:\n۵\nماه\nمهر\nپایه پنجم\nقرآن\nبهمن\n۷\nاسفند\nورزش\nخوب\nخوب\nفصل\nمهر\nضعیف\nضکیف\nمتوسط\nکوبت دوم\n در سیس \nمهر وامضا مدیر مدرسه", + "lines": 45, + "seconds": 11.375215898966417, + "table_grids": 0, + "table_errors": [], + "precision_route": { + "policy": "color-separated-handwriting-fp32-v1", + "original_precision": true, + "scope": { + "protected": true, + "reason": "Confident separated colour layers", + "image_only": true, + "measurement_WH": [ + 535, + 768 + ], + "coloured_pixels": 39187, + "separator_trace": { + "reliable": true, + "estimated_line_height": 19.2, + "selected_class": 3, + "classes": [ + { + "class_id": 0, + "center": [ + 0.33404725790023804, + 0.3322349190711975, + 0.3337506651878357 + ], + "pixels": 30314, + "long_components": 152, + "vertical_bins": 17, + "score": 136.672 + }, + { + "class_id": 1, + "center": [ + 0.43719831109046936, + 0.4344765543937683, + 0.12832078337669373 + ], + "pixels": 106, + "long_components": 0, + "vertical_bins": 0, + "score": 0.0 + }, + { + "class_id": 2, + "center": [ + 0.06904967129230499, + 0.3027939200401306, + 0.6281484961509705 + ], + "pixels": 1803, + "long_components": 3, + "vertical_bins": 1, + "score": 13.005275715835074 + }, + { + "class_id": 3, + "center": [ + 0.38381364941596985, + 0.2830617427825928, + 0.3331200182437897 + ], + "pixels": 17362, + "long_components": 78, + "vertical_bins": 12, + "score": 649.6633543043666 + } + ], + "pen_components": 358, + "pen_pixels": 16746, + "color_span_y": 481, + "background_kernel": 23, + "no_gold_or_template_used": true + } + } + }, + "character_parity": 1.0, + "parity_gate": true + } + ], + "cache_identity": "52e96c5c9cb3c75e81371614", + "scope": "Public Bina Desktop samples; no claim of full gate certification", + "readers": { + "body": { + "calls": 5, + "hits": 0, + "variant": "block16" + }, + "short_labels": { + "calls": 0, + "hits": 0, + "variant": "block16" + }, + "printed": { + "calls": 8, + "hits": 0, + "variant": "block16" + }, + "numeric_math": { + "calls": 0, + "hits": 0, + "variant": "block16" + }, + "degraded": { + "calls": 0, + "hits": 0, + "variant": "block16" + } + } + } + }, + "full_gate_page_transcription_qualified": false, + "android_hardware_tested": false, + "ios_hardware_tested": false, + "native_windows_tested": false, + "pure_4bit_full_pipeline_qualified": false +} diff --git a/__pycache__/inference.cpython-311.pyc b/__pycache__/inference.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6a4796029a67d4e2826fda62de7446a1fca556c Binary files /dev/null and b/__pycache__/inference.cpython-311.pyc differ diff --git a/checks/browser-decoder-check.json b/checks/browser-decoder-check.json new file mode 100644 index 0000000000000000000000000000000000000000..01214bf3b1fd0a75c2bfbc08262416da09122d5f --- /dev/null +++ b/checks/browser-decoder-check.json @@ -0,0 +1,6 @@ +{ + "cases": 1500, + "failed": 0, + "passed": true, + "unicode_version": "13.0.0" +} diff --git a/checks/browser-loader-check.json b/checks/browser-loader-check.json new file mode 100644 index 0000000000000000000000000000000000000000..514dbfe373f6957c6a010cd93b5fa14b4034de99 --- /dev/null +++ b/checks/browser-loader-check.json @@ -0,0 +1,12 @@ +{ + "backend": "webgpu", + "text_matches_measured_candidate": true, + "concurrent_duplicate_identical": true, + "repeat_identical": true, + "repeat_cached": true, + "model_calls": 1, + "session_creates": 1, + "session_reused": true, + "model_sha256": "2cb6c60a23a2e9948b9df9679de0f8b2c849dd81bc54abbf4b23f64148edf574", + "passed": true +} diff --git a/checks/package-litert-smoke.json b/checks/package-litert-smoke.json new file mode 100644 index 0000000000000000000000000000000000000000..d17b5dc7fa4ab8e718a83c8c42eeb3ea6fa2a2a0 --- /dev/null +++ b/checks/package-litert-smoke.json @@ -0,0 +1,7 @@ +{ + "format": "LiteRT-INT4", + "text_matches_measured_candidate": true, + "repeat_identical": true, + "model_calls": 1, + "cache_hits": 1 +} diff --git a/checks/package-smoke.json b/checks/package-smoke.json new file mode 100644 index 0000000000000000000000000000000000000000..08e43048ff0adae889761da410053928b3973fed --- /dev/null +++ b/checks/package-smoke.json @@ -0,0 +1,16 @@ +[ + { + "format": "ONNX-INT4", + "text_matches_measured_candidate": true, + "repeat_identical": true, + "model_calls": 1, + "cache_hits": 1 + }, + { + "format": "CoreML-INT4", + "text_matches_measured_candidate": true, + "repeat_identical": true, + "model_calls": 1, + "cache_hits": 1 + } +] diff --git a/components.json b/components.json new file mode 100644 index 0000000000000000000000000000000000000000..4dc54417a08e501cd1e8f69d9a46366ed53c8be5 --- /dev/null +++ b/components.json @@ -0,0 +1,67 @@ +[ + { + "role": "short_labels", + "path": "stallion/bina04-order-form-batch-20261101/recognizer/weights-001000.pt", + "sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "tensor_sha256": "c6c4db8e963a4a7d0c2ee4108972acf6980b688a464b5a184f2f4fa838b0145b", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "body", + "path": "stallion/bina04-pagepath-v3-round3-clean-20261031/run/weights-095000.pt", + "sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "tensor_sha256": "f9d6e2479d18deee48d563e46121188bb5b7353ab9725948930ad12261fba51e", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "numeric_math", + "path": "stallion/bina04-numeric-math-recognizer-95k-20261102/recognizer/selected.pt", + "sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "tensor_sha256": "b77ac34fa6ba5478002c01b0ad702a9a7ad0f8ed91ce11d65b66fd7fb4471e03", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "printed", + "path": "stallion/bina04-print-textgate-20261102/run/selected-printed-recognizer.pt", + "sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "tensor_sha256": "8302658e43d391299491dd0d4921dde0cefb35d15c707bc88ae04acf6c608d09", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "degraded", + "path": "stallion/bina04-real-degraded-95k-20261103/recognizer/selected.pt", + "sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "tensor_sha256": "6cb20a3e2d84233758efaabb90994ac3074d9cc4557deb531c859f0bbb7fe5dc", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + } +] diff --git a/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..e061cf9e0131e82cae2c1bd79a3b44c55571e2a6 --- /dev/null +++ b/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:068b9dd28a4464a544732ae3972b7da23629eb2fdd0434d855cdcec17be71fa9 +size 136655 diff --git a/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..01dd4da5210eb46c2fd1f6ee7a0788d3a487b572 --- /dev/null +++ b/components/body/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45e4f1c7d1d8e0689dbe458d99014bef4ecf1e3f3e308a1399a94dfda1056e17 +size 26263424 diff --git a/components/body/models/recognizer-w4-block16.mlpackage/Manifest.json b/components/body/models/recognizer-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..9aab0bf0923a11ad806acdf703797db2bb1cc26d --- /dev/null +++ b/components/body/models/recognizer-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "7F9E401C-5F1D-40F2-BAB4-296CF4EE443D": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + }, + "C8427A65-5938-46B4-A568-974F293FFEB6": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + } + }, + "rootModelIdentifier": "C8427A65-5938-46B4-A568-974F293FFEB6" +} diff --git a/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..52fdc59e9c10b2682f6761856db35dfae765a0de --- /dev/null +++ b/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbb59f5a96148ffd4cbcda007e715e76bc7b9beed799b9700a4b6dd6f087280a +size 136655 diff --git a/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..c03b69564d64e7b5ed6dba155cf0e4a10af41957 --- /dev/null +++ b/components/degraded/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b300ceb473e7c9e3d97220cb34be29f7b49b030fa8693e58ae1b45710da8f55d +size 26263424 diff --git a/components/degraded/models/recognizer-w4-block16.mlpackage/Manifest.json b/components/degraded/models/recognizer-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..a13c0dd1fa9b703adf2d9e0b4c951108cb66eec8 --- /dev/null +++ b/components/degraded/models/recognizer-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "B81BD9C2-F516-4993-913D-48720F04B6EB": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + }, + "E39C1CFD-C8EA-42D0-A2BE-458AAA9087ED": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + } + }, + "rootModelIdentifier": "B81BD9C2-F516-4993-913D-48720F04B6EB" +} diff --git a/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..25ff7d76107e4d938b967f4a1d91c5287de5ae31 --- /dev/null +++ b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c29f36bd45b9469a594b67e420efde84dfd8d663c138e0f1bee325c7d059debe +size 136655 diff --git a/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..e5ec4b95d856ad282763d38a46dba08f33be3643 --- /dev/null +++ b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d15e99ea723d66fedbe3ab66319266a156273f84a352081b69f9650af4802ba1 +size 26263424 diff --git a/components/numeric_math/models/recognizer-w4-block16.mlpackage/Manifest.json b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..6021efe5f763e11a379513f727164874d048655f --- /dev/null +++ b/components/numeric_math/models/recognizer-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "D43BAB18-2A03-4550-8D6B-2C5382EB5516": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + }, + "F80FD108-F2CF-476D-A813-0F126C5BA6F7": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + } + }, + "rootModelIdentifier": "F80FD108-F2CF-476D-A813-0F126C5BA6F7" +} diff --git a/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..640934a118602e78bb2eaf66457922549e93061a --- /dev/null +++ b/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bfd191c319ff8ede42f41f35ac4ed609d1373c02f97f14b012649d705d08374 +size 136655 diff --git a/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..5f069592e79786e0b4b5db0e7c8573b33ca18b11 --- /dev/null +++ b/components/printed/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7c7da642b5bb0f429cdde70b0ea8815cce86175a1eb8b2a98a1d04c88c40f79 +size 26263424 diff --git a/components/printed/models/recognizer-w4-block16.mlpackage/Manifest.json b/components/printed/models/recognizer-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..a3dec08030ccc0c525f0c6d40f438ce78f8a694d --- /dev/null +++ b/components/printed/models/recognizer-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "129E53A2-6ECD-453B-A355-413C35B490C2": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + }, + "9A7DDB3E-8AEE-49FD-8DB8-5C5D7D37CE2B": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + } + }, + "rootModelIdentifier": "129E53A2-6ECD-453B-A355-413C35B490C2" +} diff --git a/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..8e6fc1775ee2d2138cd723a62f6e81807bcaf342 --- /dev/null +++ b/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:236f3f7de9ce5e2b2356333e653d996ff335d0bb6acde2c612c7f3190f57631a +size 136655 diff --git a/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..3f4b16d5f6de0be7f6462d9502aa5112b8727b23 --- /dev/null +++ b/components/short_labels/models/recognizer-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3d5c895f49c743122580765a36e37ab4a5ed6ae88526e940296e949cdd27cdd8 +size 26263424 diff --git a/components/short_labels/models/recognizer-w4-block16.mlpackage/Manifest.json b/components/short_labels/models/recognizer-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..dc6d307a4a91b01e5467890543b086ee9d868033 --- /dev/null +++ b/components/short_labels/models/recognizer-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "8B16FAA1-CC03-401E-A352-4E583220EE42": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + }, + "92B0EED9-262B-44CF-8D73-69D65C318DD5": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + } + }, + "rootModelIdentifier": "8B16FAA1-CC03-401E-A352-4E583220EE42" +} diff --git a/experimental-detectors/line_guard/config.json b/experimental-detectors/line_guard/config.json new file mode 100644 index 0000000000000000000000000000000000000000..2bebaab42e1d1d4a8153eb91ed9c1a33ed555f9e --- /dev/null +++ b/experimental-detectors/line_guard/config.json @@ -0,0 +1,54 @@ +{ + "_name_or_path": "datalab-to/line_det_2.20", + "architectures": [ + "EfficientViTForSemanticSegmentation" + ], + "attention_probs_dropout_prob": 0.0, + "classifier_dropout_prob": 0.0, + "decoder_hidden_size": 512, + "decoder_layer_hidden_size": 128, + "depths": [ + 1, + 1, + 1, + 6, + 6 + ], + "head_dim": 32, + "hidden_dropout_prob": 0.0, + "hidden_sizes": [ + 32, + 64, + 160, + 256 + ], + "initializer_range": 0.02, + "layer_norm_eps": 1e-06, + "model_type": "efficientvit", + "num_channels": 3, + "num_classes": 2, + "num_stages": 4, + "patch_size": [ + 7, + 7 + ], + "pos_weight": 1.0, + "semantic_loss_ignore_index": -1, + "strides": [ + 2, + 2, + 2, + 2, + 2 + ], + "torch_dtype": "float16", + "transformers_version": "4.49.0", + "use_focal": false, + "widths": [ + 32, + 64, + 128, + 256, + 512 + ] +} diff --git a/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..ac54aac76a55e9995ccdc9983fa4c63d63ab88ec --- /dev/null +++ b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bbc26f64bd5168c8df476ce207d70977a29391ac85fc8745d967f2b573f6064 +size 183292 diff --git a/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..f22ba0083bdeb3fd3af76bc7d6e55e63c50fc3db --- /dev/null +++ b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9614d48774aae3a1e28ff645664d9b8f654f71c80bad4585432be258875b58c +size 30454400 diff --git a/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Manifest.json b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..6e646aa4a2bf60c3436e143a81e1469dd865456f --- /dev/null +++ b/experimental-detectors/line_guard/detector-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "B9835E68-04AC-48C8-B053-470F990C6089": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + }, + "CAB21B1A-9480-4150-8DBC-1AB7DF83912B": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + } + }, + "rootModelIdentifier": "CAB21B1A-9480-4150-8DBC-1AB7DF83912B" +} diff --git a/experimental-detectors/line_guard/preprocessor_config.json b/experimental-detectors/line_guard/preprocessor_config.json new file mode 100644 index 0000000000000000000000000000000000000000..15937d4ae6bf71a1bbe36715fa9aeea2d56c3a7c --- /dev/null +++ b/experimental-detectors/line_guard/preprocessor_config.json @@ -0,0 +1,23 @@ +{ + "do_normalize": true, + "do_reduce_labels": true, + "do_rescale": true, + "do_resize": true, + "image_mean": [ + 0.485, + 0.456, + 0.406 + ], + "image_processor_type": "SegformerImageProcessor", + "image_std": [ + 0.229, + 0.224, + 0.225 + ], + "resample": 2, + "rescale_factor": 0.00392156862745098, + "size": { + "height": 1200, + "width": 1200 + } +} diff --git a/experimental-detectors/main_detector/config.json b/experimental-detectors/main_detector/config.json new file mode 100644 index 0000000000000000000000000000000000000000..2bebaab42e1d1d4a8153eb91ed9c1a33ed555f9e --- /dev/null +++ b/experimental-detectors/main_detector/config.json @@ -0,0 +1,54 @@ +{ + "_name_or_path": "datalab-to/line_det_2.20", + "architectures": [ + "EfficientViTForSemanticSegmentation" + ], + "attention_probs_dropout_prob": 0.0, + "classifier_dropout_prob": 0.0, + "decoder_hidden_size": 512, + "decoder_layer_hidden_size": 128, + "depths": [ + 1, + 1, + 1, + 6, + 6 + ], + "head_dim": 32, + "hidden_dropout_prob": 0.0, + "hidden_sizes": [ + 32, + 64, + 160, + 256 + ], + "initializer_range": 0.02, + "layer_norm_eps": 1e-06, + "model_type": "efficientvit", + "num_channels": 3, + "num_classes": 2, + "num_stages": 4, + "patch_size": [ + 7, + 7 + ], + "pos_weight": 1.0, + "semantic_loss_ignore_index": -1, + "strides": [ + 2, + 2, + 2, + 2, + 2 + ], + "torch_dtype": "float16", + "transformers_version": "4.49.0", + "use_focal": false, + "widths": [ + 32, + 64, + 128, + 256, + 512 + ] +} diff --git a/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..3556a952d8b9b72bf02f7b70dbe350811d0e0be4 --- /dev/null +++ b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7df9637d121d036e2bb2e251b9004240f441d83433cde53226e56a36f6c27a8 +size 183292 diff --git a/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..ddd99bbe6a1b0e60b374a03ca6ee3e7187c2d69b --- /dev/null +++ b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0640641e7f2df4053feb5f831e4974739f7839deee0b7c146229db7f10000267 +size 30454400 diff --git a/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Manifest.json b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..c61f776aa1985cdef297c1f123273ea5977c84f2 --- /dev/null +++ b/experimental-detectors/main_detector/detector-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "6AD650CC-ED3F-40BF-8974-8446E47C0705": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + }, + "78907290-76FC-41EB-B44C-49D23AB10120": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + } + }, + "rootModelIdentifier": "78907290-76FC-41EB-B44C-49D23AB10120" +} diff --git a/experimental-detectors/main_detector/preprocessor_config.json b/experimental-detectors/main_detector/preprocessor_config.json new file mode 100644 index 0000000000000000000000000000000000000000..15937d4ae6bf71a1bbe36715fa9aeea2d56c3a7c --- /dev/null +++ b/experimental-detectors/main_detector/preprocessor_config.json @@ -0,0 +1,23 @@ +{ + "do_normalize": true, + "do_reduce_labels": true, + "do_rescale": true, + "do_resize": true, + "image_mean": [ + 0.485, + 0.456, + 0.406 + ], + "image_processor_type": "SegformerImageProcessor", + "image_std": [ + 0.229, + 0.224, + 0.225 + ], + "resample": 2, + "rescale_factor": 0.00392156862745098, + "size": { + "height": 1200, + "width": 1200 + } +} diff --git a/experimental-detectors/printed_detector/config.json b/experimental-detectors/printed_detector/config.json new file mode 100644 index 0000000000000000000000000000000000000000..2bebaab42e1d1d4a8153eb91ed9c1a33ed555f9e --- /dev/null +++ b/experimental-detectors/printed_detector/config.json @@ -0,0 +1,54 @@ +{ + "_name_or_path": "datalab-to/line_det_2.20", + "architectures": [ + "EfficientViTForSemanticSegmentation" + ], + "attention_probs_dropout_prob": 0.0, + "classifier_dropout_prob": 0.0, + "decoder_hidden_size": 512, + "decoder_layer_hidden_size": 128, + "depths": [ + 1, + 1, + 1, + 6, + 6 + ], + "head_dim": 32, + "hidden_dropout_prob": 0.0, + "hidden_sizes": [ + 32, + 64, + 160, + 256 + ], + "initializer_range": 0.02, + "layer_norm_eps": 1e-06, + "model_type": "efficientvit", + "num_channels": 3, + "num_classes": 2, + "num_stages": 4, + "patch_size": [ + 7, + 7 + ], + "pos_weight": 1.0, + "semantic_loss_ignore_index": -1, + "strides": [ + 2, + 2, + 2, + 2, + 2 + ], + "torch_dtype": "float16", + "transformers_version": "4.49.0", + "use_focal": false, + "widths": [ + 32, + 64, + 128, + 256, + 512 + ] +} diff --git a/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel new file mode 100644 index 0000000000000000000000000000000000000000..cf62d9d4f7e078624ee853de63e1866c1eebe6bc --- /dev/null +++ b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/model.mlmodel @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b65e5fc8008ef59de2d91e4c7ec3e44a3d7e037367678564bfd5fb5810b69021 +size 183292 diff --git a/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin new file mode 100644 index 0000000000000000000000000000000000000000..98d41b0342b26f06c0ca0918f6c1f03d20e1f031 --- /dev/null +++ b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Data/com.apple.CoreML/weights/weight.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02ba967fc37e29fe11eca73bdc77334272af1d2533cb9c7004f5eb0eb6d7591d +size 30454400 diff --git a/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Manifest.json b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..8374d6106ecc8326ca7a28678a083fd348fae793 --- /dev/null +++ b/experimental-detectors/printed_detector/detector-w4-block16.mlpackage/Manifest.json @@ -0,0 +1,18 @@ +{ + "fileFormatVersion": "1.0.0", + "itemInfoEntries": { + "73141E41-7FD9-48F3-9AB5-9EB5BB522A59": { + "author": "com.apple.CoreML", + "description": "CoreML Model Weights", + "name": "weights", + "path": "com.apple.CoreML/weights" + }, + "CBF54C80-86F8-4AA1-90FB-5CE3AE0B0F28": { + "author": "com.apple.CoreML", + "description": "CoreML Model Specification", + "name": "model.mlmodel", + "path": "com.apple.CoreML/model.mlmodel" + } + }, + "rootModelIdentifier": "CBF54C80-86F8-4AA1-90FB-5CE3AE0B0F28" +} diff --git a/experimental-detectors/printed_detector/preprocessor_config.json b/experimental-detectors/printed_detector/preprocessor_config.json new file mode 100644 index 0000000000000000000000000000000000000000..15937d4ae6bf71a1bbe36715fa9aeea2d56c3a7c --- /dev/null +++ b/experimental-detectors/printed_detector/preprocessor_config.json @@ -0,0 +1,23 @@ +{ + "do_normalize": true, + "do_reduce_labels": true, + "do_rescale": true, + "do_resize": true, + "image_mean": [ + 0.485, + 0.456, + 0.406 + ], + "image_processor_type": "SegformerImageProcessor", + "image_std": [ + 0.229, + 0.224, + 0.225 + ], + "resample": 2, + "rescale_factor": 0.00392156862745098, + "size": { + "height": 1200, + "width": 1200 + } +} diff --git a/experimental/portable_pipeline.py b/experimental/portable_pipeline.py new file mode 100644 index 0000000000000000000000000000000000000000..6a22b385e53a31310f875c1b4996f393c9222584 --- /dev/null +++ b/experimental/portable_pipeline.py @@ -0,0 +1,176 @@ +"""Use quantized CTC readers inside the pinned, otherwise unchanged Rizeh pipeline. + +Install before constructing Rizeh. Existing crop geometry, routing, decoding, +confidence thresholds and table assembly remain owned by the upstream code. +""" +import collections,hashlib,json,math,sys +from pathlib import Path +import numpy as np + +class CompactCTCOutput: + """Expose only CTC consumers used upstream, from already computed outputs. + + This object does not invent logits. Full probability distributions and + arbitrary tensor operations are deliberately unavailable. + """ + def __init__(self,tokens,confidence): + import torch + self.tokens=torch.from_numpy(tokens.astype(np.int64));self.confidence=torch.from_numpy(confidence.astype(np.float32)) + def float(self):return self + def softmax(self,dim): + if dim!=-1:raise ValueError('Only original CTC class softmax is available') + return self + def max(self,dim): + if dim!=-1:raise ValueError('Only original CTC class maximum is available') + return self.confidence,self.tokens + def argmax(self,dim): + if dim!=-1:raise ValueError('Only original CTC class argmax is available') + return self.tokens + +class ReaderModel: + def __init__(self,root,role,backend,provider,cache_bytes,variant='block16'): + self.root,self.role,self.backend,self.provider=root,role,backend,provider + self.cache=collections.OrderedDict();self.used=0;self.capacity=cache_bytes;self.calls=0;self.hits=0 + self.session=None;self.variant=variant + self.high_precision=False;self.precise_session=None;self.source_checkpoint=None + def to(self,*args,**kwargs):return self + def eval(self):return self + def parameters(self):return iter(()) + def _load(self): + if self.session is not None:return + d=self.root/'components'/self.role + if self.backend=='onnx': + import onnxruntime as ort + if self.provider not in ort.get_available_providers():raise RuntimeError('Unavailable provider: '+self.provider) + name={'hqq32':'recognizer-hqq4-block32.onnx','stable-head':'recognizer-w4-stable-head.onnx','stable-se':'recognizer-w4-stable-se.onnx','accurate':'recognizer-w4-accurate.onnx','fp32':'recognizer-fp32.onnx'}.get(self.variant,'recognizer-w4-block16.onnx') + options=ort.SessionOptions();options.intra_op_num_threads=2;options.inter_op_num_threads=1 + self.session=ort.InferenceSession(str(d/'models'/name),sess_options=options,providers=[self.provider]) + self.invoke=lambda x,w:self.session.run(None,dict(pixels=x,widths=w)) + elif self.backend=='coreml': + import coremltools as ct + self.session=ct.models.MLModel(str(d/'models/recognizer-w4-block16.mlpackage'),compute_units=ct.ComputeUnit.CPU_AND_GPU) + def invoke(x,w): + o=self.session.predict(dict(pixels=x,widths=w.astype(np.int32)));return o['tokens'],o['confidence'],o['lengths'] + self.invoke=invoke + elif self.backend=='litert': + from ai_edge_litert.interpreter import Interpreter + self.session=Interpreter(model_path=str(d/'litert/recognizer-dynamic4-block32.tflite'),num_threads=2) + runners={} + def invoke(x,w): + width=x.shape[-1] + if width not in runners:runners[width]=self.session.get_signature_runner('width'+str(width)) + o=runners[width](args_0=x,args_1=w.astype(np.int32));return o['output_0'],o['output_1'],o['output_2'] + self.invoke=invoke + elif self.backend=='source': + import torch + from recognizer import Recognizer + state=torch.load(self.source_checkpoint,map_location='cpu',weights_only=True)['model'] + device='cuda'if self.provider=='CUDAExecutionProvider'else'cpu' + self.session=Recognizer(classes=state['head.weight'].shape[0],gradient_checkpointing=False).eval() + self.session.load_state_dict(state);self.session.to(device) + def invoke(x,w): + with torch.inference_mode(): + logits,lengths=self.session(torch.from_numpy(x).to(device),torch.from_numpy(w).to(device));confidence,tokens=logits.float().softmax(-1).max(-1) + return tokens.cpu().numpy(),confidence.cpu().numpy(),lengths.cpu().numpy() + self.invoke=invoke + else:raise ValueError(self.backend) + def __call__(self,pixels,widths): + import torch + x=pixels.detach().cpu().numpy();w=widths.detach().cpu().numpy().astype(np.int64) + if x.ndim!=4 or x.shape[1:3]!=(1,64)or len(w)!=len(x):raise ValueError('Original Bx1x64xW input required') + if self.high_precision: + if self.precise_session is None: + self.precise_session=ReaderModel(self.root,self.role,'source',self.provider,self.capacity,'fp32') + self.precise_session.source_checkpoint=self.source_checkpoint + return self.precise_session(pixels,widths) + keys=[];values={};pending={} + for i,n in enumerate(w): + if n<1 or n>x.shape[-1]:raise ValueError('Invalid original width') + crop=np.ascontiguousarray(x[i,0,:,:n]);key=hashlib.sha256(str(crop.shape).encode()+crop.tobytes()).hexdigest();keys.append(key) + if key in self.cache:self.cache.move_to_end(key);values[key]=self.cache[key][0];self.hits+=1 + elif key not in pending:pending[key]=i + self._load() + order=sorted(pending,key=lambda k:w[pending[k]]) + # Core ML is bounded to eight; LiteRT has batch-one signatures. + batch=1 if self.backend=='litert'else 8 + for start in range(0,len(order),batch): + group=order[start:start+batch];ids=[pending[k]for k in group];true=w[ids] + bucket=max(512,2**int(np.ceil(np.log2(int(max(true)))))) + if self.backend in ['coreml','litert']and bucket>8192:raise ValueError('Input exceeds validated8192 width; never truncated') + canvas=np.zeros((len(ids),1,64,bucket),np.float32) + for j,i in enumerate(ids):canvas[j,0,:,:w[i]]=x[i,0,:,:w[i]] + tokens,confidence,lengths=self.invoke(canvas,true);self.calls+=1 + for j,key in enumerate(group): + n=int(lengths[j]);value=(np.array(tokens[j,:n],copy=True),np.array(confidence[j,:n],copy=True),n);values[key]=value + size=value[0].nbytes+value[1].nbytes+128 + if size<=self.capacity: + while self.used+size>self.capacity: + _,(_,old)=self.cache.popitem(last=False);self.used-=old + self.cache[key]=(value,size);self.used+=size + frames=math.ceil(x.shape[-1]/4);tokens=np.zeros((len(x),frames),np.int32);confidence=np.zeros((len(x),frames),np.float32);lengths=[] + for i,key in enumerate(keys): + a,b,n=values[key];tokens[i,:n]=a;confidence[i,:n]=b;lengths.append(n) + return CompactCTCOutput(tokens,confidence),torch.tensor(lengths,dtype=torch.int64) + +def install(root,runtime,backend='onnx',provider='CPUExecutionProvider',cache_bytes=16*1024*1024,variant='block16'): + """Return shared model sessions, keyed by exact published checkpoint hash.""" + root=Path(root);runtime=Path(runtime) + sys.path.insert(0,str(runtime/'stallion/indra-scale')) + import rtl_reader,torch + entries=json.loads((root/'components.json').read_text());lookup={r['sha256']:r['role']for r in entries};sessions={} + def initialize(reader,checkpoint,vocabulary,device='cpu',frame_budget=8192): + digest=hashlib.sha256(Path(checkpoint).read_bytes()).hexdigest() + if digest not in lookup:raise ValueError('Unrecognized published checkpoint: '+digest) + role=lookup[digest] + chosen='block16'if variant=='stable-se'and role not in ['body','printed']else variant + if role not in sessions:sessions[role]=ReaderModel(root,role,backend,provider,cache_bytes,chosen) + sessions[role].source_checkpoint=Path(checkpoint) + reader.alphabet=json.loads(Path(vocabulary).read_text())['chars'];reader.model=sessions[role];reader.frame_budget=frame_budget;reader.device=torch.device('cpu') + rtl_reader.RTLReader.__init__=initialize + # Upstream .to('cuda') calls are harmless; inputs stay on the CPU until ORT + # transfers them directly, avoiding a redundant Torch CPU->GPU->CPU copy. + rtl_reader.RTLReader.device=property(lambda self:torch.device('cpu'),lambda self,value:None) + return sessions + +def namespace_intermediate_cache(root,sessions=None,policy='quantized-only'): + """Partition upstream geometry reread caches by actual backend/weight identity. + + The upstream key includes pixels and geometry but omits reader identity. + Sharing it between original/quantized models can silently reuse old OCR. + Call after Rizeh construction, before its first image. + """ + root=Path(root);identities=[] + for role,model in sorted((sessions or {}).items()): + name={'hqq32':'recognizer-hqq4-block32.onnx','stable-head':'recognizer-w4-stable-head.onnx','stable-se':'recognizer-w4-stable-se.onnx','accurate':'recognizer-w4-accurate.onnx','fp32':'recognizer-fp32.onnx'}.get(model.variant,'recognizer-w4-block16.onnx') + if model.backend=='onnx': + digest=hashlib.sha256((root/'components'/role/'models'/name).read_bytes()).hexdigest() + else:digest=model.backend+':'+role+':'+model.variant + identities.append([role,model.backend,model.provider,digest]) + if not identities:identities=['original-pytorch',json.loads((root/'components.json').read_text())] + if policy!='quantized-only': + for role in sorted(sessions or {}): + precise=(sessions or {})[role].source_checkpoint + identities.append([role,'safety-original-pytorch',hashlib.sha256(precise.read_bytes()).hexdigest()]) + key=hashlib.sha256(json.dumps([policy,identities],sort_keys=True).encode()).hexdigest()[:24] + module=sys.modules.get('geometry_fix') + if module is None:return key + original=module.apply_geometry + if getattr(original,'_cache_partitioned',False):return key + def apply(old,image,reader,expert,cache):return original(old,image,reader,expert,Path(cache)/key) + apply._cache_partitioned=True + for loaded in list(sys.modules.values()): + if loaded is not None and getattr(loaded,'apply_geometry',None)is original:loaded.apply_geometry=apply + return key + +def select_page_precision(sessions,image): + """Image-only safety route, chosen before OCR; no trial quantized pass. + + Color-separated handwritten form pages exposed a pure-W4 parity failure. + This optional hybrid policy uses original FP32 readers for that scope. + Quantized reader artifacts remain available independently of this policy. + """ + from print_scope import handwriting_guard + scope=handwriting_guard(image) + fallback=bool(scope.get('protected')) + for model in sessions.values():model.high_precision=fallback + return dict(policy='color-separated-handwriting-fp32-v1',original_precision=fallback,scope=scope) diff --git a/geometry.py b/geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..6896742f9936b20e23395737f9fc0c84ae28a815 --- /dev/null +++ b/geometry.py @@ -0,0 +1,27 @@ +"""One 64px crop contract for training/inference; width is never clamped or squashed. + +Margins and polarity follow the Apache-2.0 Indra rec_preproc implementation. +Only right-padding batches changes the canvas; widths retain the unpadded size. +""" +import math +import numpy as np +def crop_line64(gray,box,*,pad_y=.2,pad_x=.3,dark=None): + import cv2 + from polarity import is_dark_line + if gray.ndim!=2 or gray.dtype!=np.uint8:raise ValueError('Original uint8 grayscale required') + x0,y0,x1,y1=map(float,box[:4]) + if not all(math.isfinite(v)for v in [x0,y0,x1,y1])or x1<=x0 or y1<=y0:raise ValueError('Invalid line geometry') + height=y1-y0;ix0=math.floor(x0-pad_x*height);ix1=math.ceil(x1+pad_x*height);iy0=math.floor(y0-pad_y*height);iy1=math.ceil(y1+pad_y*height);cw,ch=ix1-ix0,iy1-iy0 + H,W=gray.shape;sx0,sy0,sx1,sy1=max(0,ix0),max(0,iy0),min(W,ix1),min(H,iy1) + if dark is None:dark=is_dark_line(gray,box) + canvas=np.full((ch,cw),0 if dark else 255,dtype=np.uint8) + if sx1>sx0 and sy1>sy0:canvas[sy0-iy0:sy1-iy0,sx0-ix0:sx1-ix0]=gray[sy0:sy1,sx0:sx1] + width=max(1,round(cw*64/ch));resized=cv2.resize(canvas,(width,64),interpolation=cv2.INTER_AREA if ch>64 else cv2.INTER_LINEAR).astype(np.float32)/255. + ink=resized if dark else 1.-resized + receipt=dict(original_WH=[W,H],ink_box=[x0,y0,x1,y1],padded_source_extent=[ix0,iy0,ix1,iy1],padded_source_WH=[cw,ch],resized_WH=[width,64],scale_XY=[width/cw,64/ch],width_clamped=False,aspect_rounding_error_pixels=abs(width-cw*64/ch),dark_polarity=bool(dark)) + return ink,receipt +def pad_batch(crops,multiple=8): + if not crops or any(c.ndim!=2 or c.shape[0]!=64 for c in crops):raise ValueError('Every recognizer crop must be 64px high') + widths=np.array([c.shape[1]for c in crops],dtype=np.int64);padded=math.ceil(int(widths.max())/multiple)*multiple;out=np.zeros((len(crops),1,64,padded),dtype=np.float32) + for i,c in enumerate(crops):out[i,0,:,:c.shape[1]]=c + return out,widths diff --git a/inference.py b/inference.py new file mode 100644 index 0000000000000000000000000000000000000000..5c8935db50075a33a07cd30c67e0917450082cf8 --- /dev/null +++ b/inference.py @@ -0,0 +1,60 @@ +"""Standalone quantized line recognition; the page pipeline is a separate layer.""" +import argparse,collections,hashlib,json +from pathlib import Path +import numpy as np +from rtl import flip + +class Recognizer: + def __init__(self,root=None,role='body',provider='CPUExecutionProvider',cache_entries=512,variant='block16'): + self.root=Path(root or Path(__file__).resolve().parent);self.role=role + config=json.loads((self.root/'quantization_config.json').read_text());self.backend=config['format'];self.variant=config.get('default_variant','block16') + self.alphabet=json.loads((self.root/'vocab.json').read_text())['chars'];d=self.root/'components'/role + self.cache=collections.OrderedDict();self.cache_entries=cache_entries;self.calls=0;self.cache_hits=0 + if self.backend=='onnx': + import onnxruntime as ort + if provider not in ort.get_available_providers():raise RuntimeError('Unavailable provider: '+provider) + options=ort.SessionOptions();options.intra_op_num_threads=2;options.inter_op_num_threads=1 + if variant=='hqq32'and provider!='CPUExecutionProvider':raise ValueError('HQQ32 helper is qualified for ORT CPU only') + name='recognizer-hqq4-block32.onnx'if variant=='hqq32'else'recognizer-w4-block16.onnx' + self.session=ort.InferenceSession(str(d/'models'/name),sess_options=options,providers=[provider]);self.run=lambda x,w:self.session.run(None,dict(pixels=x,widths=w)) + elif self.backend=='coreml': + import coremltools as ct + self.session=ct.models.MLModel(str(d/'models/recognizer-w4-block16.mlpackage'),compute_units=ct.ComputeUnit.CPU_AND_GPU) + def run(x,w): + o=self.session.predict(dict(pixels=x,widths=w.astype(np.int32)));return o['tokens'],o['confidence'],o['lengths'] + self.run=run + elif self.backend=='litert': + from ai_edge_litert.interpreter import Interpreter + self.session=Interpreter(model_path=str(d/'litert/recognizer-dynamic4-block32.tflite'),num_threads=2);self.runners={} + def run(x,w): + width=x.shape[-1] + if width not in self.runners:self.runners[width]=self.session.get_signature_runner('width'+str(width)) + o=self.runners[width](args_0=x,args_1=w.astype(np.int32));return o['output_0'],o['output_1'],o['output_2'] + self.run=run + else:raise ValueError(self.backend) + def predict_ink(self,ink): + ink=np.asarray(ink,dtype=np.float32) + if ink.ndim!=2 or ink.shape[0]!=64 or ink.shape[1]<1 or not np.isfinite(ink).all():raise ValueError('Finite float32 ink map [64,true_width] required') + key=hashlib.sha256(str(ink.shape).encode()+ink.tobytes()).hexdigest() + if key in self.cache: + self.cache_hits+=1;self.cache.move_to_end(key);return dict(self.cache[key]) + width=ink.shape[1];bucket=max(512,2**int(np.ceil(np.log2(width)))) + if bucket>8192:raise ValueError('Width exceeds the validated8192 bound; never truncate a line') + x=np.zeros((1,1,64,bucket),np.float32);x[0,0,:,:width]=ink + tokens,confidence,lengths=self.run(x,np.array([width],np.int64));self.calls+=1 + n=int(lengths[0]);seq=np.asarray(tokens[0,:n]);keep=(seq!=0)&np.r_[True,seq[1:]!=seq[:-1]];ids=seq[keep].tolist() + visual=''.join(self.alphabet[int(i)-1]for i in ids) + result=dict(text=flip(visual,base_rtl=True),visual_text=visual,confidence=float(np.asarray(confidence[0,:n])[keep].mean())if keep.any()else 0.,role=self.role) + if self.cache_entries>0: + self.cache[key]=result + while len(self.cache)>self.cache_entries:self.cache.popitem(last=False) + return dict(result) + def read_line(self,image,box=None): + from geometry import crop_line64 + gray=np.asarray(image.convert('L'));box=box or [0,0,gray.shape[1],gray.shape[0]] + ink,receipt=crop_line64(gray,box);result=self.predict_ink(ink);result['geometry']=receipt;return result + +if __name__=='__main__': + p=argparse.ArgumentParser(description=__doc__);p.add_argument('line_image');p.add_argument('--role',default='body',choices=['body','short_labels','printed','numeric_math','degraded']);p.add_argument('--provider',default='CPUExecutionProvider');p.add_argument('--variant',default='block16',choices=['block16','hqq32']);a=p.parse_args() + from PIL import Image + reader=Recognizer(role=a.role,provider=a.provider,variant=a.variant);print(json.dumps(reader.read_line(Image.open(a.line_image)),ensure_ascii=False,indent=2)) diff --git a/polarity.py b/polarity.py new file mode 100644 index 0000000000000000000000000000000000000000..c276bbddfb845fe47ecc1e781e9c22ae0804db43 --- /dev/null +++ b/polarity.py @@ -0,0 +1,37 @@ +import math +import numpy as np + +def _percentiles(b: np.ndarray, qs=(0.02, 0.5, 0.98)) -> list[float]: + """np.percentile(b, 100 * qs) (linear) of a uint8 array, from its histogram: + no sort of the pixels.""" + n = b.size + cum = np.cumsum(np.bincount(b.ravel(), minlength=256)) + out = [] + for q in qs: + x = q * (n - 1) + i = math.floor(x) + g = x - i + lo = float(np.searchsorted(cum, i, side="right")) + hi = float(np.searchsorted(cum, min(i + 1, n - 1), side="right")) + d = hi - lo + # numpy's lerp: from the nearer end + out.append(hi - d * (1 - g) if g >= 0.5 else lo + d * g) + return out + +def is_dark_line(gray: np.ndarray, box) -> bool: + """Light text on a dark ground (a banner, a dark table head, a slide): the + ground (the median of the line box) lies nearer the dark end than the text + does, so the bright tail is the longer one. A shadowed line keeps dark text + on a dimmer ground. The recognizers read dark text on light paper, so a + light-on-dark line is read inverted.""" + H, W = gray.shape + x0, y0, x1, y1 = (float(v) for v in box[:4]) + b = gray[ + max(0, int(y0)) : min(H, int(y1) + 1), max(0, int(x0)) : min(W, int(x1) + 1) + ] + if not b.size: + return False + lo, med, hi = ( + _percentiles(b) if b.dtype == np.uint8 else np.percentile(b, (2, 50, 98)) + ) + return bool(hi - med > 2 * (med - lo) + 8) diff --git a/quantization_config.json b/quantization_config.json new file mode 100644 index 0000000000000000000000000000000000000000..e2f9dff5b35805e61bf88ed6f70fe24709750e29 --- /dev/null +++ b/quantization_config.json @@ -0,0 +1,79 @@ +{ + "format": "coreml", + "base_model": "Reza2kn/Bina-0.4-Rizeh", + "base_revision": "51b8c314b0552b1884c1f0e28016cb12a143f637", + "weight_bits": 4, + "mixed_precision": true, + "reader_components": [ + { + "role": "short_labels", + "path": "stallion/bina04-order-form-batch-20261101/recognizer/weights-001000.pt", + "sha256": "367084525dc644ef6d69ad981819af07e3c6a41421359594a54ccc989c2fb90a", + "tensor_sha256": "c6c4db8e963a4a7d0c2ee4108972acf6980b688a464b5a184f2f4fa838b0145b", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "body", + "path": "stallion/bina04-pagepath-v3-round3-clean-20261031/run/weights-095000.pt", + "sha256": "036be44e87c05759c18297426d2d531b0c3ac04af172886071de2ecdd6703981", + "tensor_sha256": "f9d6e2479d18deee48d563e46121188bb5b7353ab9725948930ad12261fba51e", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "numeric_math", + "path": "stallion/bina04-numeric-math-recognizer-95k-20261102/recognizer/selected.pt", + "sha256": "6e3869a5cdebff89ce6cfbbcde8ce2d5a1aa9cfe342679d469d5da08bb82b443", + "tensor_sha256": "b77ac34fa6ba5478002c01b0ad702a9a7ad0f8ed91ce11d65b66fd7fb4471e03", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "printed", + "path": "stallion/bina04-print-textgate-20261102/run/selected-printed-recognizer.pt", + "sha256": "28c4ca8f9fbbc8c578bb130d997598d2e9c2c4a2dad0b22cb5cc06818ecb988a", + "tensor_sha256": "8302658e43d391299491dd0d4921dde0cefb35d15c707bc88ae04acf6c608d09", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + }, + { + "role": "degraded", + "path": "stallion/bina04-real-degraded-95k-20261103/recognizer/selected.pt", + "sha256": "8867b309e881b698685e5b6e06a37c9f495e04dcf7027a044ad44c13cf8abd64", + "tensor_sha256": "6cb20a3e2d84233758efaabb90994ac3074d9cc4557deb531c859f0bbb7fe5dc", + "head": [ + 1625, + 512, + 1 + ], + "parameters": 32795225, + "state_elements": 32796250 + } + ], + "default_variant": "block16", + "coreml_minimum": "iOS18/macOS15", + "qualified_widths": "true-width mask; canvas powers of two512..8192; no truncation", + "full_pipeline_all_int4": false, + "full_pipeline_transcription_qualified": false +} diff --git a/recipe/build_recognizer.py b/recipe/build_recognizer.py new file mode 100644 index 0000000000000000000000000000000000000000..b842af6fb51fc2f4fc9bccb0b0b0d1d29a8b1a70 --- /dev/null +++ b/recipe/build_recognizer.py @@ -0,0 +1,87 @@ +import argparse, hashlib, json, sys, time +from pathlib import Path +import numpy as np +import torch +from portable_model import PortableRecognizer, Compact + +R = Path(__file__).resolve().parent +sys.path.insert(0, str(R/'source')) +from recognizer import Recognizer + +def load(path): + state = torch.load(path, map_location='cpu', weights_only=True)['model'] + source = Recognizer(classes=state['head.weight'].shape[0], gradient_checkpointing=False).eval() + source.load_state_dict(state) + return source + +def main(): + p=argparse.ArgumentParser() + p.add_argument('--checkpoint',type=Path,default=R/'source/recognizer-095000.pt') + p.add_argument('--out',type=Path,default=R/'models') + p.add_argument('--coreml',action='store_true') + p.add_argument('--onnx',action='store_true') + p.add_argument('--hqq',action='store_true') + p.add_argument('--blocks',default='16,32,64') + a=p.parse_args();a.out.mkdir(parents=True,exist_ok=True) + torch.set_num_threads(2);torch.manual_seed(18404) + source=load(a.checkpoint);model=PortableRecognizer(source).eval() + controls=[] + with torch.inference_mode(): + for widths in [[1,7,64],[63,257,511],[769,1025,1537]]: + w=torch.tensor(widths,dtype=torch.int64);x=torch.rand(len(w),1,64,((max(widths)+7)//8)*8) + for i,n in enumerate(widths):x[i,:,:,n:]=0 + y,n=source(x,w);z,m=model(x,w) + error=float((y-z).abs().max()); agreement=float((y.argmax(-1)==z.argmax(-1)).float().mean()) + # Near-empty synthetic crops amplify fp32 summation-order noise in SE. + tolerance = .02 if min(widths)<8 else 2e-4 + assert error < tolerance and agreement == 1.0 and torch.equal(n,m), (widths,error,agreement) + controls.append(dict(widths=widths,max_abs_logit_error=error,frame_argmax_agreement=agreement)) + identity=dict(checkpoint=str(a.checkpoint.resolve()),sha256=hashlib.sha256(a.checkpoint.read_bytes()).hexdigest(), + parameters=sum(t.numel()for t in source.parameters()),lowering_controls=controls, + torch=torch.__version__,output_contract=['tokens:int32','confidence:float32','lengths:int32']) + (a.out/'source.json').write_text(json.dumps(identity,indent=2)+'\n') + compact=Compact(model).eval();x=torch.zeros(1,1,64,512);w=torch.tensor([512]) + if a.onnx: + import onnx + from onnxruntime.quantization.matmul_nbits_quantizer import MatMulNBitsQuantizer,DefaultWeightOnlyQuantConfig + from onnxruntime.quantization.quant_utils import load_model_with_shape_infer + fp=a.out/'recognizer-fp32.onnx' + torch.onnx.export(compact,(x,w),str(fp),opset_version=18,dynamo=False, + input_names=['pixels','widths'],output_names=['tokens','confidence','lengths'], + dynamic_axes={'pixels':{0:'batch',3:'width'},'widths':{0:'batch'}, + 'tokens':{0:'batch',1:'frames'},'confidence':{0:'batch',1:'frames'},'lengths':{0:'batch'}}) + graph=onnx.load(fp);onnx.checker.check_model(graph) + for block in map(int,a.blocks.split(',')): + q=MatMulNBitsQuantizer(load_model_with_shape_infer(fp), + algo_config=DefaultWeightOnlyQuantConfig(block_size=block,is_symmetric=True,accuracy_level=4)) + q.process();target=a.out/f'recognizer-w4-block{block}.onnx' + q.model.save_model_to_file(str(target),use_external_data_format=False) + graph=onnx.load(target);onnx.checker.check_model(graph) + counts={} + for node in graph.graph.node:counts[node.op_type]=counts.get(node.op_type,0)+1 + (target.with_suffix('.audit.json')).write_text(json.dumps(dict(bytes=target.stat().st_size, + ops=counts,weight_bits=4,graph_input_bits=32,accuracy_level=4,retained_float_ops=['stem','depthwise convolutions','biases'], + format='ORT MatMulNBits W4 with runtime-dependent internal precision; mixed-weight precision, not all-INT4'),indent=2)+'\n') + if a.hqq: + from onnxruntime.quantization.matmul_nbits_quantizer import HQQWeightOnlyQuantConfig + q=MatMulNBitsQuantizer(load_model_with_shape_infer(fp),algo_config=HQQWeightOnlyQuantConfig(block_size=32,bits=4)) + q.process();q.model.save_model_to_file(str(a.out/'recognizer-hqq4-block32.onnx'),use_external_data_format=False) + if a.coreml: + import coremltools as ct + from coremltools.optimize.coreml import OptimizationConfig,OpLinearQuantizerConfig,linear_quantize_weights + # Dynamic width with exact mask semantics; small bounded batch for mobile. + traced=torch.jit.trace(compact,(x,w)) + ml=ct.convert(traced,inputs=[ct.TensorType(name='pixels',shape=(ct.RangeDim(1,8,default=1),1,64,ct.RangeDim(8,8192,default=512))), + ct.TensorType(name='widths',shape=(ct.RangeDim(1,8,default=1),),dtype=np.int32)], + outputs=[ct.TensorType(name='tokens'),ct.TensorType(name='confidence'),ct.TensorType(name='lengths')], + minimum_deployment_target=ct.target.iOS18,compute_precision=ct.precision.FLOAT32, + compute_units=ct.ComputeUnit.CPU_AND_GPU) + ml.save(str(a.out/'recognizer-fp32.mlpackage')) + for block in map(int,a.blocks.split(',')): + config=OptimizationConfig(global_config=OpLinearQuantizerConfig(mode='linear_symmetric',dtype='int4', + granularity='per_block',block_size=block,weight_threshold=512)) + quant=linear_quantize_weights(ml,config=config) + quant.save(str(a.out/f'recognizer-w4-block{block}.mlpackage')) + print(json.dumps(identity),flush=True) + +if __name__=='__main__':main() diff --git a/recipe/export_litert.py b/recipe/export_litert.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c40cadfffcd2627ad783d2ac32fabb01a74549 --- /dev/null +++ b/recipe/export_litert.py @@ -0,0 +1,45 @@ +"""Linux CPU exporter; use an isolated venv, never the training environment.""" +import os +os.environ.update(CUDA_VISIBLE_DEVICES='',OMP_NUM_THREADS='2',OPENBLAS_NUM_THREADS='1',TF_NUM_INTRAOP_THREADS='2',TF_NUM_INTEROP_THREADS='1') +import argparse,json,time,sys +from pathlib import Path +import torch +import litert_torch +from ai_edge_quantizer import quantizer,recipe +from build_recognizer import load,R +from portable_model import PortableRecognizer,Compact + +def main(): + parser=argparse.ArgumentParser();parser.add_argument('--detector',action='store_true');parser.add_argument('--checkpoint',type=Path);args=parser.parse_args() + torch.set_num_threads(2);out=R/'litert';out.mkdir(exist_ok=True) + if args.detector: + sys.path.append('/home/rezo/bina02-surya-layout-env/lib/python3.10/site-packages') + from export_detector import EfficientViTConfig,EfficientViTForSemanticSegmentation,BASE,S,Model + m=EfficientViTForSemanticSegmentation(EfficientViTConfig.from_pretrained(str(BASE))).eval() + m.load_state_dict(torch.load(args.checkpoint or S/'run/checkpoints/step-001000.pt',map_location='cpu',weights_only=True)['model']) + converter=litert_torch.signature('detector',Model(m).eval(),(torch.zeros(1,3,1200,1200),)) + prefix='detector' + else: + model=Compact(PortableRecognizer(load(args.checkpoint or R/'source/recognizer-095000.pt'))).eval() + model.model.index_dtype=torch.int32 + converter=None + for width in [512,1024,2048,4096,8192]: + x=torch.zeros(1,1,64,width);w=torch.tensor([width]) + if converter is None:converter=litert_torch.signature('width'+str(width),model,(x,w)) + else:converter.signature('width'+str(width),model,(x,w)) + prefix='recognizer' + with torch.no_grad():edge=converter.convert() + fp=out/(prefix+'-fp32.tflite');edge.export(str(fp)) + results=[] + for name,rp in [('weight-only4',recipe.weight_only_wi4_afp32()),('dynamic4-block32',recipe.dynamic_wi4b32_afp32())]: + t=time.monotonic() + try: + q=quantizer.Quantizer(str(fp));q.load_quantization_recipe(rp) + target=out/f'{prefix}-{name}.tflite';q.quantize().export_model(str(target)) + results.append(dict(name=name,path=str(target),bytes=target.stat().st_size,recipe=rp,seconds=time.monotonic()-t)) + except Exception as e:results.append(dict(name=name,error=repr(e))) + (out/(prefix+'-build.json')).write_text(json.dumps(dict(converter='litert-torch 0.10.0',quantizer='ai-edge-quantizer 0.10.0', + input='Five static width signatures512/1024/2048/4096/8192; true widths input; zero right pad, never truncate',results=results),indent=2,default=str)+'\n') + print(json.dumps(results,default=str),flush=True) + +if __name__=='__main__':main() diff --git a/recipe/portable_model.py b/recipe/portable_model.py new file mode 100644 index 0000000000000000000000000000000000000000..341da76d7b6d1086fa717289f208a11da59d3637 --- /dev/null +++ b/recipe/portable_model.py @@ -0,0 +1,53 @@ +"""Algebraic pointwise-Conv -> Linear lowering; unchanged masked SE semantics.""" +import copy +import torch +from torch import nn +from torch.nn import functional as F + +def linear(conv): + layer = nn.Linear(conv.in_channels, conv.out_channels) + with torch.no_grad(): + layer.weight.copy_(conv.weight[..., 0]) + layer.bias.copy_(conv.bias) + return layer + +class PortableBlock(nn.Module): + def __init__(self, block): + super().__init__() + self.dw = copy.deepcopy(block.dw) + for name in ['expand', 'fc1', 'fc2', 'project']: + setattr(self, name, linear(getattr(block, name))) + + def forward(self, x, mask): + z = F.hardswish(self.expand(self.dw(x.transpose(1,2)).transpose(1,2))) + pool = (z * mask).sum(1, keepdim=True) / mask.sum(1, keepdim=True).clamp_min(1.) + gate = torch.sigmoid(self.fc2(F.relu(self.fc1(pool)))) + return (x + self.project(z * gate)) * mask + +class PortableRecognizer(nn.Module): + """Input widths are true unpadded widths; canvas must be a multiple of eight.""" + def __init__(self, source): + super().__init__() + self.index_dtype = torch.int64 + self.stem = copy.deepcopy(source.stem) + self.bn = copy.deepcopy(source.bn) + self.blocks = nn.ModuleList(PortableBlock(b) for b in source.blocks) + self.head = linear(source.head) + + def forward(self, pixels, widths): + z = self.stem(F.pad(pixels, (0,4,0,0))).squeeze(2) + lengths = (widths + 3) // 4 + mask = (torch.arange(z.shape[-1], device=z.device, dtype=self.index_dtype)[None,:] < lengths[:,None])[:,:,None].to(z.dtype) + z = F.hardswish(self.bn(z)).transpose(1,2) * mask + for block in self.blocks: + z = block(z, mask) + return self.head(z), lengths + +class Compact(nn.Module): + def __init__(self, source): + super().__init__() + self.model = source + def forward(self, pixels, widths): + logits, lengths = self.model(pixels, widths) + confidence, tokens = logits.softmax(-1).max(-1) + return tokens.to(torch.int32), confidence, lengths.to(torch.int32) diff --git a/recipe/requirements-litert.txt b/recipe/requirements-litert.txt new file mode 100644 index 0000000000000000000000000000000000000000..42898532e1af3a59519b23a567db156f2b97c560 --- /dev/null +++ b/recipe/requirements-litert.txt @@ -0,0 +1,5 @@ +torch==2.10.0 +numpy==1.26.4 +litert-torch==0.10.0 +ai-edge-quantizer==0.10.0 +ai-edge-litert==2.3.0 diff --git a/recipe/requirements-macos.txt b/recipe/requirements-macos.txt new file mode 100644 index 0000000000000000000000000000000000000000..9204f221bebeb8273ba64588d2ae41a68f5be189 --- /dev/null +++ b/recipe/requirements-macos.txt @@ -0,0 +1,6 @@ +torch==2.7.1 +numpy==2.4.6 +onnx==1.23.2 +onnxruntime==1.31.0 +coremltools==9.0 +protobuf==7.36.2 diff --git a/recipe/source/recognizer.py b/recipe/source/recognizer.py new file mode 100644 index 0000000000000000000000000000000000000000..ab9ad431c91d60b13e7856ae85df02a41ad20238 --- /dev/null +++ b/recipe/source/recognizer.py @@ -0,0 +1,41 @@ +"""Width512/depth20 Indra-family CTC recognizer; native class IDs are retained.""" +import torch +from torch import nn +from torch.nn import functional as F +from torch.utils.checkpoint import checkpoint +class Block(nn.Module): + def __init__(self,width=512,identity=False): + super().__init__();self.dw=nn.Conv1d(width,width,17,padding=8,groups=width);self.expand=nn.Conv1d(width,2*width,1);self.fc1=nn.Conv1d(2*width,width//2,1);self.fc2=nn.Conv1d(width//2,2*width,1);self.project=nn.Conv1d(2*width,width,1) + if identity:nn.init.zeros_(self.project.weight);nn.init.zeros_(self.project.bias) + def forward(self,x,mask): + z=F.hardswish(self.expand(self.dw(x)));pool=(z*mask).sum(2,keepdim=True)/mask.sum(2,keepdim=True).clamp_min(1);return(x+self.project(z*torch.sigmoid(self.fc2(F.relu(self.fc1(pool))))))*mask +class Recognizer(nn.Module): + input_height=64 + def __init__(self,classes=1357,width=512,depth=20,gradient_checkpointing=True): + super().__init__();assert width==512 and depth==20 + self.stem=nn.Conv2d(1,width,(64,8),stride=(64,4));self.bn=nn.BatchNorm1d(width);self.blocks=nn.ModuleList(Block(width,identity=i%2==1)for i in range(depth));self.head=nn.Conv1d(width,classes,1);self.gradient_checkpointing=gradient_checkpointing;self.bn.eval() + def train(self,mode=True):super().train(mode);self.bn.eval();return self + def forward(self,x,widths): + if x.ndim!=4 or x.shape[1]!=1 or x.shape[2]!=64:raise ValueError('Require Bx1x64xW without height truncation') + if widths.ndim!=1 or len(widths)!=len(x)or bool((widths<1).any())or bool((widths>x.shape[-1]).any()):raise ValueError('Invalid original crop widths') + widths=widths.to(device=x.device,dtype=torch.long) + if x.shape[-1]%4:x=F.pad(x,(0,(-x.shape[-1])%4)) + z=self.stem(F.pad(x,(0,4,0,0))).squeeze(2);lengths=(widths+3)//4;assert bool((lengths<=z.shape[-1]).all());mask=(torch.arange(z.shape[-1],device=z.device)[None,:]=1.26 +pillow>=10 +opencv-python-headless>=4.11 +coremltools==9.0 diff --git a/rtl.py b/rtl.py new file mode 100644 index 0000000000000000000000000000000000000000..1c3ec99ac3ed4bcec2d13231e99849ce11bcdaa9 --- /dev/null +++ b/rtl.py @@ -0,0 +1,162 @@ +"""Right-to-left text for a recognizer that reads every line left to right. + +A CTC recognizer emits characters in the order it sees them, left to right, so +the label of a line with Arabic or Hebrew is its characters in visual order. +``flip`` turns logical order (how text is stored and typed) into visual order, +and the same call turns visual order back into logical order: + +- RTL base line (more RTL letters than LTR letters): the line reads right to + left, so the order of its units reverses. A unit is a run of LTR text + (Latin words, digits, and the spaces and punctuation between them), which + keeps its own order, or one other character cluster. +- LTR base line: the line keeps its order, and each run of RTL text reverses. + +A cluster is a base character with its combining marks (Arabic harakat, Hebrew +niqqud), so marks stay after their base. A mirrored character (brackets) at +right-to-left level changes to its mirror image, as a renderer draws it. + +This is a small subset of the Unicode bidi algorithm (UAX #9): it has no +embeddings or isolates, and it resolves neutrals by runs. It is its own +inverse, so the labels and the decoding always agree. +""" + +from __future__ import annotations + +import unicodedata + +_MIRROR = dict(zip("()[]{}<>«»‹›", ")(][}{><»«›‹")) +# Presentation forms (glyph variants: initial, medial, final, ligatures) map to +# base letters. Tatweel stretches a word and carries no letter. +_PRESENTATION = ((0xFB1D, 0xFDFF), (0xFE70, 0xFEFF)) +_TATWEEL = "ـ" + + +def is_rtl(c: str) -> bool: + return unicodedata.bidirectional(c) in ("R", "AL") + + +def _is_ltr(c: str) -> bool: + # Digits (European and Arabic-Indic) read left to right inside RTL text. + return unicodedata.bidirectional(c) in ("L", "EN", "AN") + + +def has_rtl(text: str) -> bool: + return any(is_rtl(c) for c in text) + + +def rtl_base(text: str) -> bool: + """Whether the line reads right to left: more RTL letters than LTR letters. + The counts do not depend on the order, so logical and visual text agree.""" + r = sum(is_rtl(c) for c in text) + lt = sum(unicodedata.bidirectional(c) == "L" for c in text) + return r > lt + + +def normalize(text: str) -> str: + """Presentation forms to base letters (NFKC on those blocks only), no + tatweel, no combining mark without a base character.""" + out = [] + for c in text: + o = ord(c) + if any(a <= o <= b for a, b in _PRESENTATION): + out.append(unicodedata.normalize("NFKC", c)) + elif c != _TATWEEL and (out or unicodedata.category(c) not in ("Mn", "Me")): + out.append(c) + return "".join(out) + + +def clusters(text: str) -> list[str]: + out: list[str] = [] + for c in text: + if out and unicodedata.category(c) in ("Mn", "Me"): + out[-1] += c + else: + out.append(c) + return out + + +def _kind(cl: str) -> str: + c = cl[0] + return "R" if is_rtl(c) else "L" if _is_ltr(c) else "N" + + +def _runs(kinds: list[str], strong: str, stop: set[str]) -> list[tuple[int, int]]: + """[start, end) spans from a ``strong`` cluster to the last ``strong`` cluster + before a cluster of a kind in ``stop``.""" + spans, start, last = [], None, None + for i, k in enumerate(kinds + ["#"]): + if k == strong: + if start is None: + start = i + last = i + elif k in stop or k == "#": + if start is not None: + spans.append((start, last + 1)) + start = last = None + return spans + + +def _mirror(cl: str) -> str: + return _MIRROR.get(cl[0], cl[0]) + cl[1:] + + +def flip(text: str, mirror: bool = True, base_rtl: bool | None = None) -> str: + """Logical order to visual order, and visual order back to logical order. + base_rtl: the paragraph direction, when known (a renderer lays out a line + by its paragraph's direction); None decides by ``rtl_base``.""" + if not has_rtl(text): + return text + cls = clusters(text) + kinds = [_kind(c) for c in cls] + if rtl_base(text) if base_rtl is None else base_rtl: + # Units: LTR runs kept whole, every other cluster alone; reverse the units. + units: list[str] = [] + spans = _runs(kinds, "L", {"R"}) + i = 0 + for a, b in spans + [(len(cls), len(cls))]: + for j in range(i, a): + units.append(_mirror(cls[j]) if mirror else cls[j]) + if a < b: + units.append("".join(cls[a:b])) + i = b + return "".join(reversed(units)) + # LTR base: reverse each RTL run in place. + out = list(cls) + for a, b in _runs(kinds, "R", {"L"}): + seg = cls[a:b][::-1] + out[a:b] = [_mirror(c) for c in seg] if mirror else seg + return "".join(out) + + +def visual_label(logical: str, base_rtl: bool | None = None) -> str: + """The recognizer's label for a line stored in logical order.""" + return flip(normalize(logical), base_rtl=base_rtl) + + +def label_from_visual(raw_visual: str, shapes: bool = False) -> str: + """The label for characters already in visual order, as stored (a PDF text + layer read by glyph position): normalize in logical order, then mirror. + shapes: the text layer stores each bracket as the shape drawn (see + ``brackets_as_shapes``), so it is already mirrored.""" + return visual_label(flip(raw_visual, mirror=shapes)) + + +def brackets_as_shapes(raw_visual_lines: list[str]) -> bool: + """Whether a page's text layer stores RTL brackets as drawn shapes. + + Producers differ: most store the logical character, so the leftmost bracket + of an RTL pair reads ")"; some store the drawn shape, so it reads "(". A + page uses one convention, so its RTL lines without Latin letters vote by + their first bracket.""" + shapes = logical = 0 + for t in raw_visual_lines: + if not rtl_base(t) or any(unicodedata.bidirectional(c) == "L" for c in t): + continue + for c in t: + if c in "([{": + shapes += 1 + break + if c in ")]}": + logical += 1 + break + return shapes > logical diff --git a/vocab.json b/vocab.json new file mode 100644 index 0000000000000000000000000000000000000000..a7b47cb32bc04ac4a868582886e93f619555f723 --- /dev/null +++ b/vocab.json @@ -0,0 +1,1907 @@ +{ + "blank": 0, + "chars": [ + " ", + "!", + "\"", + "#", + "$", + "%", + "&", + "'", + "(", + ")", + "*", + "+", + ",", + "-", + ".", + "/", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ":", + ";", + "<", + "=", + ">", + "?", + "@", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "[", + "\\", + "]", + "^", + "_", + "`", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "{", + "|", + "}", + "~", + "¡", + "¢", + "£", + "¤", + "¥", + "¦", + "§", + "¨", + "©", + "ª", + "«", + "¬", + "®", + "¯", + "°", + "±", + "²", + "³", + "´", + "µ", + "¶", + "·", + "¸", + "¹", + "º", + "»", + "¼", + "½", + "¾", + "¿", + "À", + "Á", + "Â", + "Ã", + "Ä", + "Å", + "Æ", + "Ç", + "È", + "É", + "Ê", + "Ë", + "Ì", + "Í", + "Î", + "Ï", + "Ð", + "Ñ", + "Ò", + "Ó", + "Ô", + "Õ", + "Ö", + "×", + "Ø", + "Ù", + "Ú", + "Û", + "Ü", + "Ý", + "Þ", + "ß", + "à", + "á", + "â", + "ã", + "ä", + "å", + "æ", + "ç", + "è", + "é", + "ê", + "ë", + "ì", + "í", + "î", + "ï", + "ð", + "ñ", + "ò", + "ó", + "ô", + "õ", + "ö", + "÷", + "ø", + "ù", + "ú", + "û", + "ü", + "ý", + "þ", + "ÿ", + "Ā", + "ā", + "Ă", + "ă", + "Ą", + "ą", + "Ć", + "ć", + "Ĉ", + "ĉ", + "Ċ", + "ċ", + "Č", + "č", + "Ď", + "ď", + "Đ", + "đ", + "Ē", + "ē", + "Ĕ", + "ĕ", + "Ė", + "ė", + "Ę", + "ę", + "Ě", + "ě", + "Ĝ", + "ĝ", + "Ğ", + "ğ", + "Ġ", + "ġ", + "Ģ", + "ģ", + "Ĥ", + "ĥ", + "Ħ", + "ħ", + "Ĩ", + "ĩ", + "Ī", + "ī", + "Ĭ", + "ĭ", + "Į", + "į", + "İ", + "ı", + "IJ", + "ij", + "Ĵ", + "ĵ", + "Ķ", + "ķ", + "ĸ", + "Ĺ", + "ĺ", + "Ļ", + "ļ", + "Ľ", + "ľ", + "Ŀ", + "ŀ", + "Ł", + "ł", + "Ń", + "ń", + "Ņ", + "ņ", + "Ň", + "ň", + "ʼn", + "Ŋ", + "ŋ", + "Ō", + "ō", + "Ŏ", + "ŏ", + "Ő", + "ő", + "Œ", + "œ", + "Ŕ", + "ŕ", + "Ŗ", + "ŗ", + "Ř", + "ř", + "Ś", + "ś", + "Ŝ", + "ŝ", + "Ş", + "ş", + "Š", + "š", + "Ţ", + "ţ", + "Ť", + "ť", + "Ŧ", + "ŧ", + "Ũ", + "ũ", + "Ū", + "ū", + "Ŭ", + "ŭ", + "Ů", + "ů", + "Ű", + "ű", + "Ų", + "ų", + "Ŵ", + "ŵ", + "Ŷ", + "ŷ", + "Ÿ", + "Ź", + "ź", + "Ż", + "ż", + "Ž", + "ž", + "ſ", + "ƀ", + "Ɓ", + "Ƃ", + "ƃ", + "Ƅ", + "ƅ", + "Ɔ", + "Ƈ", + "ƈ", + "Ɖ", + "Ɗ", + "Ƌ", + "ƌ", + "ƍ", + "Ǝ", + "Ə", + "Ɛ", + "Ƒ", + "ƒ", + "Ɠ", + "Ɣ", + "ƕ", + "Ɩ", + "Ɨ", + "Ƙ", + "ƙ", + "ƚ", + "ƛ", + "Ɯ", + "Ɲ", + "ƞ", + "Ɵ", + "Ơ", + "ơ", + "Ƣ", + "ƣ", + "Ƥ", + "ƥ", + "Ʀ", + "Ƨ", + "ƨ", + "Ʃ", + "ƪ", + "ƫ", + "Ƭ", + "ƭ", + "Ʈ", + "Ư", + "ư", + "Ʊ", + "Ʋ", + "Ƴ", + "ƴ", + "Ƶ", + "ƶ", + "Ʒ", + "Ƹ", + "ƹ", + "ƺ", + "ƻ", + "Ƽ", + "ƽ", + "ƾ", + "ƿ", + "ǀ", + "ǁ", + "ǂ", + "ǃ", + "DŽ", + "Dž", + "dž", + "LJ", + "Lj", + "lj", + "NJ", + "Nj", + "nj", + "Ǎ", + "ǎ", + "Ǐ", + "ǐ", + "Ǒ", + "ǒ", + "Ǔ", + "ǔ", + "Ǖ", + "ǖ", + "Ǘ", + "ǘ", + "Ǚ", + "ǚ", + "Ǜ", + "ǜ", + "ǝ", + "Ǟ", + "ǟ", + "Ǡ", + "ǡ", + "Ǣ", + "ǣ", + "Ǥ", + "ǥ", + "Ǧ", + "ǧ", + "Ǩ", + "ǩ", + "Ǫ", + "ǫ", + "Ǭ", + "ǭ", + "Ǯ", + "ǯ", + "ǰ", + "DZ", + "Dz", + "dz", + "Ǵ", + "ǵ", + "Ƕ", + "Ƿ", + "Ǹ", + "ǹ", + "Ǻ", + "ǻ", + "Ǽ", + "ǽ", + "Ǿ", + "ǿ", + "Ȁ", + "ȁ", + "Ȃ", + "ȃ", + "Ȅ", + "ȅ", + "Ȇ", + "ȇ", + "Ȉ", + "ȉ", + "Ȋ", + "ȋ", + "Ȍ", + "ȍ", + "Ȏ", + "ȏ", + "Ȑ", + "ȑ", + "Ȓ", + "ȓ", + "Ȕ", + "ȕ", + "Ȗ", + "ȗ", + "Ș", + "ș", + "Ț", + "ț", + "Ȝ", + "ȝ", + "Ȟ", + "ȟ", + "Ƞ", + "ȡ", + "Ȣ", + "ȣ", + "Ȥ", + "ȥ", + "Ȧ", + "ȧ", + "Ȩ", + "ȩ", + "Ȫ", + "ȫ", + "Ȭ", + "ȭ", + "Ȯ", + "ȯ", + "Ȱ", + "ȱ", + "Ȳ", + "ȳ", + "ȴ", + "ȵ", + "ȶ", + "ȷ", + "ȸ", + "ȹ", + "Ⱥ", + "Ȼ", + "ȼ", + "Ƚ", + "Ⱦ", + "ȿ", + "ɀ", + "Ɂ", + "ɂ", + "Ƀ", + "Ʉ", + "Ʌ", + "Ɇ", + "ɇ", + "Ɉ", + "ɉ", + "Ɋ", + "ɋ", + "Ɍ", + "ɍ", + "Ɏ", + "ɏ", + "Ḁ", + "ḁ", + "Ḃ", + "ḃ", + "Ḅ", + "ḅ", + "Ḇ", + "ḇ", + "Ḉ", + "ḉ", + "Ḋ", + "ḋ", + "Ḍ", + "ḍ", + "Ḏ", + "ḏ", + "Ḑ", + "ḑ", + "Ḓ", + "ḓ", + "Ḕ", + "ḕ", + "Ḗ", + "ḗ", + "Ḙ", + "ḙ", + "Ḛ", + "ḛ", + "Ḝ", + "ḝ", + "Ḟ", + "ḟ", + "Ḡ", + "ḡ", + "Ḣ", + "ḣ", + "Ḥ", + "ḥ", + "Ḧ", + "ḧ", + "Ḩ", + "ḩ", + "Ḫ", + "ḫ", + "Ḭ", + "ḭ", + "Ḯ", + "ḯ", + "Ḱ", + "ḱ", + "Ḳ", + "ḳ", + "Ḵ", + "ḵ", + "Ḷ", + "ḷ", + "Ḹ", + "ḹ", + "Ḻ", + "ḻ", + "Ḽ", + "ḽ", + "Ḿ", + "ḿ", + "Ṁ", + "ṁ", + "Ṃ", + "ṃ", + "Ṅ", + "ṅ", + "Ṇ", + "ṇ", + "Ṉ", + "ṉ", + "Ṋ", + "ṋ", + "Ṍ", + "ṍ", + "Ṏ", + "ṏ", + "Ṑ", + "ṑ", + "Ṓ", + "ṓ", + "Ṕ", + "ṕ", + "Ṗ", + "ṗ", + "Ṙ", + "ṙ", + "Ṛ", + "ṛ", + "Ṝ", + "ṝ", + "Ṟ", + "ṟ", + "Ṡ", + "ṡ", + "Ṣ", + "ṣ", + "Ṥ", + "ṥ", + "Ṧ", + "ṧ", + "Ṩ", + "ṩ", + "Ṫ", + "ṫ", + "Ṭ", + "ṭ", + "Ṯ", + "ṯ", + "Ṱ", + "ṱ", + "Ṳ", + "ṳ", + "Ṵ", + "ṵ", + "Ṷ", + "ṷ", + "Ṹ", + "ṹ", + "Ṻ", + "ṻ", + "Ṽ", + "ṽ", + "Ṿ", + "ṿ", + "Ẁ", + "ẁ", + "Ẃ", + "ẃ", + "Ẅ", + "ẅ", + "Ẇ", + "ẇ", + "Ẉ", + "ẉ", + "Ẋ", + "ẋ", + "Ẍ", + "ẍ", + "Ẏ", + "ẏ", + "Ẑ", + "ẑ", + "Ẓ", + "ẓ", + "Ẕ", + "ẕ", + "ẖ", + "ẗ", + "ẘ", + "ẙ", + "ẚ", + "ẛ", + "ẜ", + "ẝ", + "ẞ", + "ẟ", + "Ạ", + "ạ", + "Ả", + "ả", + "Ấ", + "ấ", + "Ầ", + "ầ", + "Ẩ", + "ẩ", + "Ẫ", + "ẫ", + "Ậ", + "ậ", + "Ắ", + "ắ", + "Ằ", + "ằ", + "Ẳ", + "ẳ", + "Ẵ", + "ẵ", + "Ặ", + "ặ", + "Ẹ", + "ẹ", + "Ẻ", + "ẻ", + "Ẽ", + "ẽ", + "Ế", + "ế", + "Ề", + "ề", + "Ể", + "ể", + "Ễ", + "ễ", + "Ệ", + "ệ", + "Ỉ", + "ỉ", + "Ị", + "ị", + "Ọ", + "ọ", + "Ỏ", + "ỏ", + "Ố", + "ố", + "Ồ", + "ồ", + "Ổ", + "ổ", + "Ỗ", + "ỗ", + "Ộ", + "ộ", + "Ớ", + "ớ", + "Ờ", + "ờ", + "Ở", + "ở", + "Ỡ", + "ỡ", + "Ợ", + "ợ", + "Ụ", + "ụ", + "Ủ", + "ủ", + "Ứ", + "ứ", + "Ừ", + "ừ", + "Ử", + "ử", + "Ữ", + "ữ", + "Ự", + "ự", + "Ỳ", + "ỳ", + "Ỵ", + "ỵ", + "Ỷ", + "ỷ", + "Ỹ", + "ỹ", + "Ỻ", + "ỻ", + "Ỽ", + "ỽ", + "Ỿ", + "ỿ", + "Α", + "Β", + "Γ", + "Δ", + "Ε", + "Ζ", + "Η", + "Θ", + "Ι", + "Κ", + "Λ", + "Μ", + "Ν", + "Ξ", + "Ο", + "Π", + "Ρ", + "Σ", + "Τ", + "Υ", + "Φ", + "Χ", + "Ψ", + "Ω", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "ς", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "‐", + "‑", + "‒", + "–", + "—", + "―", + "‖", + "‘", + "’", + "‚", + "‛", + "“", + "”", + "„", + "‟", + "†", + "‡", + "•", + "‣", + "…", + "‰", + "′", + "″", + "‹", + "›", + "⁄", + "※", + "⁰", + "⁴", + "⁵", + "⁶", + "⁷", + "⁸", + "⁹", + "⁺", + "⁻", + "⁽", + "⁾", + "ⁿ", + "₀", + "₁", + "₂", + "₃", + "₄", + "₅", + "₆", + "₇", + "₈", + "₉", + "€", + "₹", + "₽", + "₩", + "₺", + "₪", + "₱", + "₫", + "₴", + "₦", + "₡", + "₸", + "™", + "℃", + "℉", + "№", + "ℓ", + "℮", + "⅓", + "⅔", + "⅛", + "←", + "↑", + "→", + "↓", + "↔", + "⇒", + "⇔", + "↵", + "−", + "∓", + "∗", + "∘", + "∙", + "√", + "∞", + "∝", + "∠", + "∧", + "∨", + "∩", + "∪", + "∫", + "≈", + "≠", + "≡", + "≤", + "≥", + "⊂", + "⊃", + "⊆", + "⊇", + "⊕", + "⊗", + "⊥", + "⋅", + "∂", + "∆", + "∇", + "∈", + "∉", + "∋", + "∏", + "∑", + "∀", + "∃", + "∅", + "■", + "□", + "▪", + "▫", + "▲", + "△", + "▶", + "►", + "▼", + "▽", + "◀", + "◄", + "◆", + "◇", + "○", + "◦", + "●", + "★", + "☆", + "✓", + "✔", + "✗", + "✘", + "❖", + "➢", + "➤", + "؆", + "؇", + "؈", + "؉", + "؊", + "؋", + "،", + "؍", + "؎", + "؏", + "ؐ", + "ؑ", + "ؒ", + "ؓ", + "ؔ", + "ؕ", + "ؖ", + "ؗ", + "ؘ", + "ؙ", + "ؚ", + "؛", + "؝", + "؞", + "؟", + "ؠ", + "ء", + "آ", + "أ", + "ؤ", + "إ", + "ئ", + "ا", + "ب", + "ة", + "ت", + "ث", + "ج", + "ح", + "خ", + "د", + "ذ", + "ر", + "ز", + "س", + "ش", + "ص", + "ض", + "ط", + "ظ", + "ع", + "غ", + "ػ", + "ؼ", + "ؽ", + "ؾ", + "ؿ", + "ف", + "ق", + "ك", + "ل", + "م", + "ن", + "ه", + "و", + "ى", + "ي", + "ً", + "ٌ", + "ٍ", + "َ", + "ُ", + "ِ", + "ّ", + "ْ", + "ٓ", + "ٔ", + "ٕ", + "ٖ", + "ٗ", + "٘", + "ٙ", + "ٚ", + "ٛ", + "ٜ", + "ٝ", + "ٞ", + "ٟ", + "٠", + "١", + "٢", + "٣", + "٤", + "٥", + "٦", + "٧", + "٨", + "٩", + "٪", + "٫", + "٬", + "٭", + "ٮ", + "ٯ", + "ٰ", + "ٱ", + "ٲ", + "ٳ", + "ٴ", + "ٵ", + "ٶ", + "ٷ", + "ٸ", + "ٹ", + "ٺ", + "ٻ", + "ټ", + "ٽ", + "پ", + "ٿ", + "ڀ", + "ځ", + "ڂ", + "ڃ", + "ڄ", + "څ", + "چ", + "ڇ", + "ڈ", + "ډ", + "ڊ", + "ڋ", + "ڌ", + "ڍ", + "ڎ", + "ڏ", + "ڐ", + "ڑ", + "ڒ", + "ړ", + "ڔ", + "ڕ", + "ږ", + "ڗ", + "ژ", + "ڙ", + "ښ", + "ڛ", + "ڜ", + "ڝ", + "ڞ", + "ڟ", + "ڠ", + "ڡ", + "ڢ", + "ڣ", + "ڤ", + "ڥ", + "ڦ", + "ڧ", + "ڨ", + "ک", + "ڪ", + "ګ", + "ڬ", + "ڭ", + "ڮ", + "گ", + "ڰ", + "ڱ", + "ڲ", + "ڳ", + "ڴ", + "ڵ", + "ڶ", + "ڷ", + "ڸ", + "ڹ", + "ں", + "ڻ", + "ڼ", + "ڽ", + "ھ", + "ڿ", + "ۀ", + "ہ", + "ۂ", + "ۃ", + "ۄ", + "ۅ", + "ۆ", + "ۇ", + "ۈ", + "ۉ", + "ۊ", + "ۋ", + "ی", + "ۍ", + "ێ", + "ۏ", + "ې", + "ۑ", + "ے", + "ۓ", + "۔", + "ە", + "ۖ", + "ۗ", + "ۘ", + "ۙ", + "ۚ", + "ۛ", + "ۜ", + "۞", + "۟", + "۠", + "ۡ", + "ۢ", + "ۣ", + "ۤ", + "ۥ", + "ۦ", + "ۧ", + "ۨ", + "۩", + "۪", + "۫", + "۬", + "ۭ", + "ۮ", + "ۯ", + "۰", + "۱", + "۲", + "۳", + "۴", + "۵", + "۶", + "۷", + "۸", + "۹", + "ۺ", + "ۻ", + "ۼ", + "۽", + "۾", + "ۿ", + "ݐ", + "ݑ", + "ݒ", + "ݓ", + "ݔ", + "ݕ", + "ݖ", + "ݗ", + "ݘ", + "ݙ", + "ݚ", + "ݛ", + "ݜ", + "ݝ", + "ݞ", + "ݟ", + "ݠ", + "ݡ", + "ݢ", + "ݣ", + "ݤ", + "ݥ", + "ݦ", + "ݧ", + "ݨ", + "ݩ", + "ݪ", + "ݫ", + "ݬ", + "ݭ", + "ݮ", + "ݯ", + "ݰ", + "ݱ", + "ݲ", + "ݳ", + "ݴ", + "ݵ", + "ݶ", + "ݷ", + "ݸ", + "ݹ", + "ݺ", + "ݻ", + "ݼ", + "ݽ", + "ݾ", + "ݿ", + "֑", + "֒", + "֓", + "֔", + "֕", + "֖", + "֗", + "֘", + "֙", + "֚", + "֛", + "֜", + "֝", + "֞", + "֟", + "֠", + "֡", + "֢", + "֣", + "֤", + "֥", + "֦", + "֧", + "֨", + "֩", + "֪", + "֫", + "֬", + "֭", + "֮", + "֯", + "ְ", + "ֱ", + "ֲ", + "ֳ", + "ִ", + "ֵ", + "ֶ", + "ַ", + "ָ", + "ֹ", + "ֺ", + "ֻ", + "ּ", + "ֽ", + "־", + "ֿ", + "׀", + "ׁ", + "ׂ", + "׃", + "ׄ", + "ׅ", + "׆", + "ׇ", + "א", + "ב", + "ג", + "ד", + "ה", + "ו", + "ז", + "ח", + "ט", + "י", + "ך", + "כ", + "ל", + "ם", + "מ", + "ן", + "נ", + "ס", + "ע", + "ף", + "פ", + "ץ", + "צ", + "ק", + "ר", + "ש", + "ת", + "ׯ", + "װ", + "ױ", + "ײ", + "׳", + "״", + "‌", + "”", + "", + "­", + "ɑ", + "ɒ", + "ə", + "ɛ", + "ʃ", + "ʒ", + "ʔ", + "ʿ", + "˝", + "ˣ", + "́", + "ί", + "ϵ", + "А", + "В", + "Г", + "Д", + "И", + "К", + "М", + "Н", + "О", + "П", + "Р", + "С", + "Т", + "У", + "Ш", + "Э", + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "й", + "к", + "л", + "м", + "н", + "о", + "п", + "р", + "с", + "т", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "ъ", + "ы", + "ь", + "э", + "ю", + "я", + "ё", + "ғ", + "қ", + "ҷ", + "ӣ", + "ӯ", + "Հ", + "Ո", + "Ս", + "ա", + "գ", + "ե", + "զ", + "է", + "ի", + "կ", + "հ", + "յ", + "ն", + "ո", + "ս", + "վ", + "տ", + "ր", + "ւ", + "ք", + "ـ", + "ᵀ", + "ᵗ", + "ᵢ", + "​", + "‍", + "‎", + "‏", + "‫", + "‬", + "‭", + "‮", + "", + "ⁱ", + "ₖ", + "ₘ", + "ₙ", + "ₜ", + "ℝ", + "∥", + "━", + "┏", + "┓", + "┻", + "◽", + "☐", + "♀", + "➜", + "ⱼ", + "、", + "。", + "《", + "》", + "う", + "お", + "き", + "こ", + "し", + "じ", + "そ", + "た", + "だ", + "っ", + "て", + "と", + "な", + "の", + "ば", + "ひ", + "ま", + "め", + "や", + "わ", + "ア", + "ィ", + "ウ", + "カ", + "キ", + "グ", + "サ", + "ス", + "ヂ", + "ツ", + "デ", + "ト", + "ビ", + "ブ", + "ペ", + "リ", + "ル", + "ン", + "下", + "丸", + "丹", + "主", + "事", + "京", + "仮", + "八", + "公", + "典", + "内", + "北", + "南", + "博", + "口", + "古", + "名", + "向", + "和", + "園", + "坂", + "城", + "場", + "塩", + "外", + "大", + "奈", + "子", + "家", + "居", + "山", + "岳", + "嵐", + "川", + "巻", + "座", + "庭", + "志", + "戸", + "手", + "摩", + "日", + "明", + "本", + "条", + "東", + "桜", + "梅", + "楠", + "模", + "檜", + "毬", + "沢", + "浅", + "濱", + "物", + "王", + "田", + "登", + "白", + "皇", + "盟", + "相", + "県", + "神", + "競", + "紫", + "美", + "脈", + "花", + "苑", + "草", + "蒲", + "藤", + "蘇", + "蛇", + "術", + "見", + "話", + "赤", + "連", + "部", + "都", + "里", + "野", + "題", + "館", + "馬", + "駅", + "", + "", + "", + "️", + "ﺯ", + "(", + ")", + "*", + "0", + "7", + ":", + "", + "ʾ", + "̄", + "𐬀", + "𐬌", + "𐬛", + "𐬨", + "𐬰" + ], + "old_chars_preserved": 1356, + "appended_chars": [ + "”", + "", + "­", + "ɑ", + "ɒ", + "ə", + "ɛ", + "ʃ", + "ʒ", + "ʔ", + "ʿ", + "˝", + "ˣ", + "́", + "ί", + "ϵ", + "А", + "В", + "Г", + "Д", + "И", + "К", + "М", + "Н", + "О", + "П", + "Р", + "С", + "Т", + "У", + "Ш", + "Э", + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "й", + "к", + "л", + "м", + "н", + "о", + "п", + "р", + "с", + "т", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "ъ", + "ы", + "ь", + "э", + "ю", + "я", + "ё", + "ғ", + "қ", + "ҷ", + "ӣ", + "ӯ", + "Հ", + "Ո", + "Ս", + "ա", + "գ", + "ե", + "զ", + "է", + "ի", + "կ", + "հ", + "յ", + "ն", + "ո", + "ս", + "վ", + "տ", + "ր", + "ւ", + "ք", + "ـ", + "ᵀ", + "ᵗ", + "ᵢ", + "​", + "‍", + "‎", + "‏", + "‫", + "‬", + "‭", + "‮", + "", + "ⁱ", + "ₖ", + "ₘ", + "ₙ", + "ₜ", + "ℝ", + "∥", + "━", + "┏", + "┓", + "┻", + "◽", + "☐", + "♀", + "➜", + "ⱼ", + "、", + "。", + "《", + "》", + "う", + "お", + "き", + "こ", + "し", + "じ", + "そ", + "た", + "だ", + "っ", + "て", + "と", + "な", + "の", + "ば", + "ひ", + "ま", + "め", + "や", + "わ", + "ア", + "ィ", + "ウ", + "カ", + "キ", + "グ", + "サ", + "ス", + "ヂ", + "ツ", + "デ", + "ト", + "ビ", + "ブ", + "ペ", + "リ", + "ル", + "ン", + "下", + "丸", + "丹", + "主", + "事", + "京", + "仮", + "八", + "公", + "典", + "内", + "北", + "南", + "博", + "口", + "古", + "名", + "向", + "和", + "園", + "坂", + "城", + "場", + "塩", + "外", + "大", + "奈", + "子", + "家", + "居", + "山", + "岳", + "嵐", + "川", + "巻", + "座", + "庭", + "志", + "戸", + "手", + "摩", + "日", + "明", + "本", + "条", + "東", + "桜", + "梅", + "楠", + "模", + "檜", + "毬", + "沢", + "浅", + "濱", + "物", + "王", + "田", + "登", + "白", + "皇", + "盟", + "相", + "県", + "神", + "競", + "紫", + "美", + "脈", + "花", + "苑", + "草", + "蒲", + "藤", + "蘇", + "蛇", + "術", + "見", + "話", + "赤", + "連", + "部", + "都", + "里", + "野", + "題", + "館", + "馬", + "駅", + "", + "", + "", + "️", + "ﺯ", + "(", + ")", + "*", + "0", + "7", + ":", + "" + ], + "dev_lines_with_unseen_training_chars": 0, + "target_policy": "raw source retained; NFC then invertible rtl.flip(base_rtl=True); no silent character removal", + "append_only_new_chars": [ + "ʾ", + "̄", + "𐬀", + "𐬌", + "𐬛", + "𐬨", + "𐬰" + ], + "space_ID": 1, + "ZWNJ_ID": 1356, + "source_vocabulary_sha256": "2d8b1a087e8b8b56a6ffb0294b022e1b2970a91dca4065c1b1dcc22f16f7c47f" +}