Publish DE·HTR browser release
Browse filesVerified int8 ONNX and PyTorch artifacts, full metric evidence, writer-disjoint training manifest, license registers, and a runnable inference example.
- NOTICE +13 -0
- README.md +37 -10
- THIRD_PARTY_NOTICES.md +21 -0
- config.json +1 -1
- examples/infer_onnx.py +117 -0
- results/m2/summary.json +43 -0
- results/m4/browser.json +7 -4
- results/m4/demo.png +2 -2
- results/m4/preds_browser.jsonl +50 -50
- results/m6/huggingface.json +60 -4
- third_party/onnxruntime/LICENSE +21 -0
- training-data/FONTS.md +1 -1
- training-data/SOURCES.md +76 -8
NOTICE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
DE·HTR
|
| 2 |
+
Copyright 2026 naeyn
|
| 3 |
+
|
| 4 |
+
This product includes ONNX Runtime Web, Copyright (c) Microsoft Corporation,
|
| 5 |
+
licensed under the MIT License.
|
| 6 |
+
|
| 7 |
+
The browser demo includes the Patrick Hand font, Copyright (c) 2010-2012
|
| 8 |
+
Patrick Wagesreiter (mail@patrickwagesreiter.at), licensed under the SIL Open
|
| 9 |
+
Font License, Version 1.1.
|
| 10 |
+
|
| 11 |
+
The complete third-party license texts accompany the distributed files. See
|
| 12 |
+
THIRD_PARTY_NOTICES.md in the source and model repositories and the linked
|
| 13 |
+
license files in the browser demo.
|
README.md
CHANGED
|
@@ -28,7 +28,7 @@ DE·HTR is a compact line-level recognizer for **modern German handwriting**. Th
|
|
| 28 |
|
| 29 |
## Why this model exists
|
| 30 |
|
| 31 |
-
Large general-purpose vision-language models will often be more accurate on unconstrained handwriting because they bring language priors and broad visual knowledge. DE·HTR instead targets a different operating point: a small inspectable artifact, predictable latency, offline execution, no per-call cost, and no image upload. On the same frozen 601-line test split, the measured 4-bit Qwen2.5-VL-7B baseline reached 9.44% CER (95% CI 8.33–10.65), while the three DE·HTR CTC seeds averaged 8.15% CER
|
| 32 |
|
| 33 |
## Intended use and scope
|
| 34 |
|
|
@@ -51,10 +51,13 @@ The model must not be represented as a full-page OCR system. It has no layout de
|
|
| 51 |
|---|---|
|
| 52 |
| `model.onnx` | int8 ONNX release model; batch size 1, dynamic image width |
|
| 53 |
| `pytorch_model.pt` | selected seed-42 PyTorch inference checkpoint |
|
| 54 |
-
| `config.json` | alphabet, normalization, tensor names, and image geometry |
|
|
|
|
|
|
|
| 55 |
| `results/` | committed metric JSON, predictions, confidence intervals, and browser evidence |
|
| 56 |
| `training-data/` | frozen writer split and complete dataset/font/dependency license registers |
|
| 57 |
-
| `LICENSE` | Apache License 2.0
|
|
|
|
| 58 |
|
| 59 |
Artifact digests:
|
| 60 |
|
|
@@ -63,11 +66,29 @@ Artifact digests:
|
|
| 63 |
| `model.onnx` | 9,843,872 | `05cce04d3938a64edaee79caf2a74587eaa9f8c46c146d6e04f0512bfce51d82` |
|
| 64 |
| `pytorch_model.pt` | 38,978,889 | `9765f609c21ab0fe04ed66260d4000025c63a54b4fa370e9a73788da2dc6065f` |
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
## Model architecture
|
| 67 |
|
| 68 |
The recognizer has 9,730,308 parameters:
|
| 69 |
|
| 70 |
-
1. an ImageNet-pretrained ResNet-18 visual stem through layer 3;
|
| 71 |
2. a width-preserving projection to 384 features;
|
| 72 |
3. a three-layer bidirectional GRU with hidden size 384;
|
| 73 |
4. a 196-class CTC head (195 characters plus blank).
|
|
@@ -82,7 +103,7 @@ The frozen manifest is published at `training-data/split_manifest.json`. Full so
|
|
| 82 |
|
| 83 |
Real line data:
|
| 84 |
|
| 85 |
-
- ScaDS.AI German Line- and Word-Level Handwriting Dataset, Zenodo
|
| 86 |
- 5,843 lines from 385 writers;
|
| 87 |
- writer-disjoint split: 309/38/38 writers and 4,675/567/601 lines for train/validation/test;
|
| 88 |
- ten visually corrupt or unalignable training pairs were excluded from CTC loss only; the frozen manifest was not changed.
|
|
@@ -109,7 +130,7 @@ All headline results use the immutable writer-disjoint 601-line real test set. C
|
|
| 109 |
| `microsoft/trocr-base-handwritten`, zero-shot English | 26.46% (25.08–27.89) | 85.62% (82.62–88.62) | 2.67 GB | 2,130 ms |
|
| 110 |
| Qwen2.5-VL-7B-Instruct 4-bit, zero-shot | 9.44% (8.33–10.65) | 23.64% (21.55–25.82) | 5.64 GB | 2,909 ms |
|
| 111 |
|
| 112 |
-
Baseline latency was measured on an Apple M1; implementations and environments are recorded in each JSON result.
|
| 113 |
|
| 114 |
### CTC training runs
|
| 115 |
|
|
@@ -122,7 +143,9 @@ Baseline latency was measured on an Apple M1; implementations and environments a
|
|
| 122 |
| 50% synthetic, seed 44 | 7.10% | 8.25% (7.45–9.13) | 32.62% (30.50–34.75) |
|
| 123 |
| TrOCR-small trained reference, seed 42 | 11.10% | 11.51% (10.61–12.45) | 34.17% (32.34–36.08) |
|
| 124 |
|
| 125 |
-
The three selected-ratio CTC seeds have mean test CER **8.15%** with sample standard deviation **0.14 percentage points**. The trained encoder-decoder is an accuracy reference only and is not a release artifact.
|
|
|
|
|
|
|
| 126 |
|
| 127 |
### ONNX and browser parity
|
| 128 |
|
|
@@ -132,9 +155,9 @@ The three selected-ratio CTC seeds have mean test CER **8.15%** with sample stan
|
|
| 132 |
| ONNX fp32, Python ORT | 601 | 8.5035% | 0.0000 points | about 49 ms |
|
| 133 |
| ONNX int8, Python ORT | 601 | 8.5681% | +0.0646 points vs fp32 | about 72 ms |
|
| 134 |
| ONNX int8, Node ORT | 601 | 8.5681% | identical to Python ORT | about 70 ms |
|
| 135 |
-
| ONNX int8, browser WASM | 50 | 5.7937% | +0.0397 points vs Node on the same 50 lines |
|
| 136 |
|
| 137 |
-
Browser evaluation used headless Chrome 151 on an Apple M1. The first 50 frozen test-manifest lines were evaluated; browser and Node differed on one prediction because browser Canvas and Pillow resizing are not bit-identical. The parity gate is an absolute CER delta no greater than 0.2 percentage points, matching the fp32 parity tolerance. Browser cold model load was
|
| 138 |
|
| 139 |
## Limitations and risks
|
| 140 |
|
|
@@ -150,4 +173,8 @@ Browser evaluation used headless Chrome 151 on an Apple M1. The first 50 frozen
|
|
| 150 |
|
| 151 |
The released code and model artifacts are licensed under Apache-2.0. This permits commercial use. Training sources retain their original licenses; using this model does not relicense those source datasets. The release includes their required attribution and license records in `training-data/SOURCES.md` and `training-data/FONTS.md`.
|
| 152 |
|
| 153 |
-
The two ScaDS.AI Tier-1 datasets are CC BY 4.0. German Wikipedia source text is CC BY-SA 4.0. The bundled Patrick Hand demo font and all synthetic-rendering fonts are SIL OFL 1.1. ONNX Runtime Web is MIT licensed. See the published registers for record URLs, versions, and access dates.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
## Why this model exists
|
| 30 |
|
| 31 |
+
Large general-purpose vision-language models will often be more accurate on unconstrained handwriting because they bring language priors and broad visual knowledge. DE·HTR instead targets a different operating point: a small inspectable artifact, predictable latency, offline execution, no per-call cost, and no image upload. On the same frozen 601-line test split, the measured 4-bit Qwen2.5-VL-7B baseline reached 9.44% CER (95% CI 8.33–10.65), while the three DE·HTR CTC seeds averaged 8.15% CER (seed 42: 7.40–9.10). Those intervals overlap substantially and no paired significance test was run, so the two should be read as **statistically indistinguishable on this test set** rather than as an accuracy win. The release argument is size, offline execution, and latency; this is not a claim that this model beats current large VLMs generally.
|
| 32 |
|
| 33 |
## Intended use and scope
|
| 34 |
|
|
|
|
| 51 |
|---|---|
|
| 52 |
| `model.onnx` | int8 ONNX release model; batch size 1, dynamic image width |
|
| 53 |
| `pytorch_model.pt` | selected seed-42 PyTorch inference checkpoint |
|
| 54 |
+
| `config.json` | alphabet, normalization, tensor names, and image geometry; its `model` field resolves `model.onnx` |
|
| 55 |
+
| `examples/infer_onnx.py` | runnable end-to-end inference example (preprocessing + greedy CTC decode) |
|
| 56 |
+
| `examples/0107-000.png` | one held-out **test**-split line for a first run, CC BY 4.0 (see `training-data/SOURCES.md`) |
|
| 57 |
| `results/` | committed metric JSON, predictions, confidence intervals, and browser evidence |
|
| 58 |
| `training-data/` | frozen writer split and complete dataset/font/dependency license registers |
|
| 59 |
+
| `LICENSE`, `NOTICE` | Apache License 2.0 and copyright/attribution notices |
|
| 60 |
+
| `THIRD_PARTY_NOTICES.md`, `third_party/` | third-party component licenses in full |
|
| 61 |
|
| 62 |
Artifact digests:
|
| 63 |
|
|
|
|
| 66 |
| `model.onnx` | 9,843,872 | `05cce04d3938a64edaee79caf2a74587eaa9f8c46c146d6e04f0512bfce51d82` |
|
| 67 |
| `pytorch_model.pt` | 38,978,889 | `9765f609c21ab0fe04ed66260d4000025c63a54b4fa370e9a73788da2dc6065f` |
|
| 68 |
|
| 69 |
+
## Usage
|
| 70 |
+
|
| 71 |
+
```bash
|
| 72 |
+
pip install onnxruntime pillow numpy huggingface_hub
|
| 73 |
+
huggingface-cli download naeyn/de-htr-web examples/infer_onnx.py examples/0107-000.png --local-dir de-htr
|
| 74 |
+
python de-htr/examples/infer_onnx.py de-htr/examples/0107-000.png
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
The script downloads `model.onnx` and `config.json` on first run and prints the transcription. On the bundled example it emits:
|
| 78 |
+
|
| 79 |
+
```
|
| 80 |
+
Process (eigene Schreibweise PROCESS) ist eine crormediale
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
which matches this repo's committed int8 prediction for that line (`results/m3/preds_onnx_int8_python.jsonl`); the reference transcription is `... eine crossmediale`, so the one visible error is expected rather than a setup problem. To run fully offline, pass `--model` and `--config` explicitly.
|
| 84 |
+
|
| 85 |
+
Doing it yourself takes four steps, all implemented in that file: convert to RGB and resize to height 64 preserving aspect ratio (cap width 2048, centered white padding); normalize with the ImageNet mean/std in `config.json`; run the session with input `images` and output `log_probs`; then greedy-CTC decode over the first `ceil(width / 4)` timesteps, collapsing repeats and dropping blanks (`blank_index` 0, so character `i` of `alphabet` is class `i + 1`).
|
| 86 |
+
|
| 87 |
## Model architecture
|
| 88 |
|
| 89 |
The recognizer has 9,730,308 parameters:
|
| 90 |
|
| 91 |
+
1. an ImageNet-pretrained ResNet-18 visual stem through layer 3 (torchvision `ResNet18_Weights.IMAGENET1K_V1`; see [License and attribution](#license-and-attribution) for its provenance);
|
| 92 |
2. a width-preserving projection to 384 features;
|
| 93 |
3. a three-layer bidirectional GRU with hidden size 384;
|
| 94 |
4. a 196-class CTC head (195 characters plus blank).
|
|
|
|
| 103 |
|
| 104 |
Real line data:
|
| 105 |
|
| 106 |
+
- ScaDS.AI German Line- and Word-Level Handwriting Dataset (v1.0) by Thomas Burghardt and Ahmad Alzin, Zenodo, doi:10.5281/zenodo.18301532, licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/);
|
| 107 |
- 5,843 lines from 385 writers;
|
| 108 |
- writer-disjoint split: 309/38/38 writers and 4,675/567/601 lines for train/validation/test;
|
| 109 |
- ten visually corrupt or unalignable training pairs were excluded from CTC loss only; the frozen manifest was not changed.
|
|
|
|
| 130 |
| `microsoft/trocr-base-handwritten`, zero-shot English | 26.46% (25.08–27.89) | 85.62% (82.62–88.62) | 2.67 GB | 2,130 ms |
|
| 131 |
| Qwen2.5-VL-7B-Instruct 4-bit, zero-shot | 9.44% (8.33–10.65) | 23.64% (21.55–25.82) | 5.64 GB | 2,909 ms |
|
| 132 |
|
| 133 |
+
Baseline latency was measured on an Apple M1; implementations and environments are recorded in each JSON result. These latencies are not measured on equal footing: Tesseract runs as a fresh subprocess per line, so its 162 ms includes process spawn and model reload, while the neural baselines amortize model load across the run. The Tesseract figure is an upper bound and the comparison flatters this model.
|
| 134 |
|
| 135 |
### CTC training runs
|
| 136 |
|
|
|
|
| 143 |
| 50% synthetic, seed 44 | 7.10% | 8.25% (7.45–9.13) | 32.62% (30.50–34.75) |
|
| 144 |
| TrOCR-small trained reference, seed 42 | 11.10% | 11.51% (10.61–12.45) | 34.17% (32.34–36.08) |
|
| 145 |
|
| 146 |
+
The three selected-ratio CTC seeds have mean test CER **8.15%** with sample standard deviation **0.14 percentage points** (`final_seeds.test_cer_std_sample` in `results/m2/summary.json`; the population figure, 0.117, is recorded alongside it). The trained encoder-decoder is an accuracy reference only and is not a release artifact.
|
| 147 |
+
|
| 148 |
+
Two runs reached their fixed epoch cap while validation CER was still improving, recorded in `convergence.runs` of the same file. The TrOCR-small reference peaked on its final epoch (12 of 12), so its 11.51% is an upper bound and the CTC advantage over it is an upper bound too — it measures one encoder-decoder under a fixed budget, not encoder-decoder architectures in general. The selected CTC seed also peaked on its final epoch (40 of 40), so the released model's own CER is not a converged value either; seeds 43 and 44 peaked at 38 and 36.
|
| 149 |
|
| 150 |
### ONNX and browser parity
|
| 151 |
|
|
|
|
| 155 |
| ONNX fp32, Python ORT | 601 | 8.5035% | 0.0000 points | about 49 ms |
|
| 156 |
| ONNX int8, Python ORT | 601 | 8.5681% | +0.0646 points vs fp32 | about 72 ms |
|
| 157 |
| ONNX int8, Node ORT | 601 | 8.5681% | identical to Python ORT | about 70 ms |
|
| 158 |
+
| ONNX int8, browser WASM | 50 | 5.7937% | +0.0397 points vs Node on the same 50 lines | 253 ms |
|
| 159 |
|
| 160 |
+
Browser evaluation used headless Chrome 151 on an Apple M1. The first 50 frozen test-manifest lines were evaluated; browser and Node differed on one prediction because browser Canvas and Pillow resizing are not bit-identical. The parity gate is an absolute CER delta no greater than 0.2 percentage points, matching the fp32 parity tolerance. Browser cold model load was 243 ms from a local static server. The verifier observed no HTTP request after readiness and no console/page errors. See `results/m4/browser.json` for exact measurements.
|
| 161 |
|
| 162 |
## Limitations and risks
|
| 163 |
|
|
|
|
| 173 |
|
| 174 |
The released code and model artifacts are licensed under Apache-2.0. This permits commercial use. Training sources retain their original licenses; using this model does not relicense those source datasets. The release includes their required attribution and license records in `training-data/SOURCES.md` and `training-data/FONTS.md`.
|
| 175 |
|
| 176 |
+
The two ScaDS.AI Tier-1 datasets are CC BY 4.0, created by Thomas Burghardt and Ahmad Alzin (line- and word-level, doi:10.5281/zenodo.18301532) and by Till Nestler and Thomas Burghardt (full-page, doi:10.5281/zenodo.18283705). German Wikipedia source text is CC BY-SA 4.0; the ShareAlike condition attaches to that text, which is not redistributed in this model release. The bundled Patrick Hand demo font and all synthetic-rendering fonts are SIL OFL 1.1. ONNX Runtime Web is MIT licensed. See the published registers for record URLs, versions, and access dates.
|
| 177 |
+
|
| 178 |
+
### Pretrained-weight provenance
|
| 179 |
+
|
| 180 |
+
The visual stem is initialized from torchvision's ImageNet-1k pretrained ResNet-18 checkpoint, so those weights are carried inside `model.onnx`. That checkpoint is distributed by torchvision under BSD-3-Clause, which permits commercial redistribution and is the basis for including it in this Apache-2.0 release. The underlying ImageNet-1k *images* are governed by ImageNet's non-commercial research terms and are not redistributed here. Whether restrictions on training images propagate to weights trained on them is legally unsettled; this release follows the prevailing practice, and torchvision's own BSD-3-Clause distribution of these weights, in treating them as freely reusable. This is a weaker guarantee than the rest of the license register, where every input was selected to be unambiguously permissive, and it is stated here rather than left implicit. Training the stem from scratch (`pretrained=False`) removes the dependency at an unmeasured accuracy cost. Full detail is in `training-data/SOURCES.md`.
|
THIRD_PARTY_NOTICES.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Third-party notices
|
| 2 |
+
|
| 3 |
+
The DE·HTR code and model are licensed under Apache-2.0. The browser distribution also redistributes the following third-party assets under their own licenses.
|
| 4 |
+
|
| 5 |
+
## ONNX Runtime Web 1.27.0
|
| 6 |
+
|
| 7 |
+
- Copyright: Microsoft Corporation
|
| 8 |
+
- License: MIT
|
| 9 |
+
- Upstream: https://github.com/microsoft/onnxruntime/tree/v1.27.0
|
| 10 |
+
- Complete license text: [`third_party/onnxruntime/LICENSE`](third_party/onnxruntime/LICENSE)
|
| 11 |
+
- Distributed browser files: `vendor/ort.wasm.min.mjs`, `vendor/ort-wasm-simd-threaded.mjs`, and `vendor/ort-wasm-simd-threaded.wasm`
|
| 12 |
+
|
| 13 |
+
## Patrick Hand
|
| 14 |
+
|
| 15 |
+
- Copyright: Copyright (c) 2010-2012 Patrick Wagesreiter (mail@patrickwagesreiter.at)
|
| 16 |
+
- License: SIL Open Font License 1.1
|
| 17 |
+
- Upstream: https://github.com/google/fonts/tree/main/ofl/patrickhand
|
| 18 |
+
- Complete license text: [`data/fonts/licenses/Patrick_Hand_OFL.txt`](data/fonts/licenses/Patrick_Hand_OFL.txt)
|
| 19 |
+
- Distributed browser file: `assets/patrick-hand.ttf`
|
| 20 |
+
|
| 21 |
+
The build copies both complete license texts into `dist/` beside the corresponding redistributed files. The deployed page links to those copies from its footer.
|
config.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"format_version": 1,
|
| 3 |
-
"model": ".
|
| 4 |
"input_name": "images",
|
| 5 |
"output_name": "log_probs",
|
| 6 |
"image_height": 64,
|
|
|
|
| 1 |
{
|
| 2 |
"format_version": 1,
|
| 3 |
+
"model": "model.onnx",
|
| 4 |
"input_name": "images",
|
| 5 |
"output_name": "log_probs",
|
| 6 |
"image_height": 64,
|
examples/infer_onnx.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Run the published DE·HTR ONNX model on one pre-cropped line image."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import json
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Any
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import onnxruntime as ort
|
| 13 |
+
from huggingface_hub import hf_hub_download
|
| 14 |
+
from PIL import Image
|
| 15 |
+
|
| 16 |
+
DEFAULT_REPO = "naeyn/de-htr-web"
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def resolve_artifacts(
|
| 20 |
+
repo_id: str,
|
| 21 |
+
model_path: Path | None,
|
| 22 |
+
config_path: Path | None,
|
| 23 |
+
) -> tuple[Path, Path]:
|
| 24 |
+
if (model_path is None) != (config_path is None):
|
| 25 |
+
raise ValueError("--model and --config must be supplied together")
|
| 26 |
+
if model_path is not None and config_path is not None:
|
| 27 |
+
return model_path, config_path
|
| 28 |
+
return (
|
| 29 |
+
Path(hf_hub_download(repo_id=repo_id, filename="model.onnx")),
|
| 30 |
+
Path(hf_hub_download(repo_id=repo_id, filename="config.json")),
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def preprocess(image: Image.Image, config: dict[str, Any]) -> tuple[np.ndarray, int]:
|
| 35 |
+
image_height = int(config["image_height"])
|
| 36 |
+
max_width = int(config["max_width"])
|
| 37 |
+
rgb = image.convert("RGB")
|
| 38 |
+
width, height = rgb.size
|
| 39 |
+
if width <= 0 or height <= 0:
|
| 40 |
+
raise ValueError(f"invalid image size: {(width, height)}")
|
| 41 |
+
|
| 42 |
+
resized_width = max(1, round(width * image_height / height))
|
| 43 |
+
resized = rgb.resize((resized_width, image_height), Image.Resampling.BILINEAR)
|
| 44 |
+
if resized_width > max_width:
|
| 45 |
+
shrink_height = max(1, round(image_height * max_width / resized_width))
|
| 46 |
+
resized = resized.resize((max_width, shrink_height), Image.Resampling.BILINEAR)
|
| 47 |
+
canvas = Image.new("RGB", (max_width, image_height), (255, 255, 255))
|
| 48 |
+
canvas.paste(resized, (0, (image_height - shrink_height) // 2))
|
| 49 |
+
resized = canvas
|
| 50 |
+
|
| 51 |
+
array = np.asarray(resized, dtype=np.float32) / np.float32(255.0)
|
| 52 |
+
mean = np.asarray(config["normalization"]["mean"], dtype=np.float32)
|
| 53 |
+
std = np.asarray(config["normalization"]["std"], dtype=np.float32)
|
| 54 |
+
array = (array - mean) / std
|
| 55 |
+
tensor = np.ascontiguousarray(array.transpose(2, 0, 1)[None, ...])
|
| 56 |
+
return tensor, int(tensor.shape[-1])
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def greedy_decode(
|
| 60 |
+
log_probs: np.ndarray,
|
| 61 |
+
*,
|
| 62 |
+
width: int,
|
| 63 |
+
alphabet: str,
|
| 64 |
+
blank_index: int,
|
| 65 |
+
output_stride: int,
|
| 66 |
+
) -> str:
|
| 67 |
+
valid_steps = min((width + output_stride - 1) // output_stride, log_probs.shape[0])
|
| 68 |
+
labels = np.argmax(log_probs[:valid_steps, 0, :], axis=-1)
|
| 69 |
+
characters: list[str] = []
|
| 70 |
+
previous = blank_index
|
| 71 |
+
for raw_label in labels:
|
| 72 |
+
label = int(raw_label)
|
| 73 |
+
if label != previous and label != blank_index:
|
| 74 |
+
alphabet_index = label - 1
|
| 75 |
+
if not 0 <= alphabet_index < len(alphabet):
|
| 76 |
+
raise ValueError(f"model emitted out-of-range class {label}")
|
| 77 |
+
characters.append(alphabet[alphabet_index])
|
| 78 |
+
previous = label
|
| 79 |
+
return "".join(characters)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def transcribe(image_path: Path, model_path: Path, config_path: Path) -> str:
|
| 83 |
+
config = json.loads(config_path.read_text(encoding="utf-8"))
|
| 84 |
+
with Image.open(image_path) as image:
|
| 85 |
+
tensor, width = preprocess(image, config)
|
| 86 |
+
|
| 87 |
+
session = ort.InferenceSession(str(model_path), providers=["CPUExecutionProvider"])
|
| 88 |
+
(log_probs,) = session.run(
|
| 89 |
+
[config["output_name"]],
|
| 90 |
+
{config["input_name"]: tensor},
|
| 91 |
+
)
|
| 92 |
+
return greedy_decode(
|
| 93 |
+
log_probs,
|
| 94 |
+
width=width,
|
| 95 |
+
alphabet=config["alphabet"],
|
| 96 |
+
blank_index=int(config["blank_index"]),
|
| 97 |
+
output_stride=int(config["output_stride"]),
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def main() -> int:
|
| 102 |
+
parser = argparse.ArgumentParser(
|
| 103 |
+
description="Transcribe one pre-cropped modern German handwriting line"
|
| 104 |
+
)
|
| 105 |
+
parser.add_argument("image", type=Path)
|
| 106 |
+
parser.add_argument("--repo", default=DEFAULT_REPO)
|
| 107 |
+
parser.add_argument("--model", type=Path)
|
| 108 |
+
parser.add_argument("--config", type=Path)
|
| 109 |
+
args = parser.parse_args()
|
| 110 |
+
|
| 111 |
+
model_path, config_path = resolve_artifacts(args.repo, args.model, args.config)
|
| 112 |
+
print(transcribe(args.image, model_path, config_path))
|
| 113 |
+
return 0
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
if __name__ == "__main__":
|
| 117 |
+
raise SystemExit(main())
|
results/m2/summary.json
CHANGED
|
@@ -88,6 +88,47 @@
|
|
| 88 |
"improvement_definition": "floor_cer - ctc_3seed_mean_test_cer",
|
| 89 |
"source": "results/baseline_tesseract.json"
|
| 90 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
"encoder_decoder_reference": {
|
| 92 |
"cer_gap": -0.033573830120727,
|
| 93 |
"cer_gap_definition": "ctc_3seed_mean_test_cer - seq2seq_test_cer",
|
|
@@ -126,6 +167,8 @@
|
|
| 126 |
],
|
| 127 |
"test_cer_mean": 0.08150567739928449,
|
| 128 |
"test_cer_std_population": 0.0011702493543744173,
|
|
|
|
|
|
|
| 129 |
"test_cers": [
|
| 130 |
0.08212785814279049,
|
| 131 |
0.07986647044043217,
|
|
|
|
| 88 |
"improvement_definition": "floor_cer - ctc_3seed_mean_test_cer",
|
| 89 |
"source": "results/baseline_tesseract.json"
|
| 90 |
},
|
| 91 |
+
"convergence": {
|
| 92 |
+
"note": "best_epoch equal to total_epochs means validation CER was still improving when the fixed epoch cap was reached, so that run's reported CER is an upper bound rather than a converged value.",
|
| 93 |
+
"runs": [
|
| 94 |
+
{
|
| 95 |
+
"best_epoch": 37,
|
| 96 |
+
"hit_epoch_cap": false,
|
| 97 |
+
"run": "ctc_ratio0_seed42",
|
| 98 |
+
"total_epochs": 40
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"best_epoch": 40,
|
| 102 |
+
"hit_epoch_cap": true,
|
| 103 |
+
"run": "ctc_ratio0.5_seed42",
|
| 104 |
+
"total_epochs": 40
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"best_epoch": 37,
|
| 108 |
+
"hit_epoch_cap": false,
|
| 109 |
+
"run": "ctc_ratio0.8_seed42",
|
| 110 |
+
"total_epochs": 40
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"best_epoch": 38,
|
| 114 |
+
"hit_epoch_cap": false,
|
| 115 |
+
"run": "ctc_ratio0.5_seed43",
|
| 116 |
+
"total_epochs": 40
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"best_epoch": 36,
|
| 120 |
+
"hit_epoch_cap": false,
|
| 121 |
+
"run": "ctc_ratio0.5_seed44",
|
| 122 |
+
"total_epochs": 40
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"best_epoch": 12,
|
| 126 |
+
"hit_epoch_cap": true,
|
| 127 |
+
"run": "seq2seq_reference_seed42",
|
| 128 |
+
"total_epochs": 12
|
| 129 |
+
}
|
| 130 |
+
]
|
| 131 |
+
},
|
| 132 |
"encoder_decoder_reference": {
|
| 133 |
"cer_gap": -0.033573830120727,
|
| 134 |
"cer_gap_definition": "ctc_3seed_mean_test_cer - seq2seq_test_cer",
|
|
|
|
| 167 |
],
|
| 168 |
"test_cer_mean": 0.08150567739928449,
|
| 169 |
"test_cer_std_population": 0.0011702493543744173,
|
| 170 |
+
"test_cer_std_reported": "test_cer_std_sample",
|
| 171 |
+
"test_cer_std_sample": 0.0014332568950193858,
|
| 172 |
"test_cers": [
|
| 173 |
0.08212785814279049,
|
| 174 |
0.07986647044043217,
|
results/m4/browser.json
CHANGED
|
@@ -11,10 +11,10 @@
|
|
| 11 |
"model": "models/dehtr_ctc_int8.onnx",
|
| 12 |
"n_lines": 50,
|
| 13 |
"fixture_selection": "first 50 frozen test-manifest lines",
|
| 14 |
-
"cold_model_load_ms":
|
| 15 |
"inference_ms_per_line": {
|
| 16 |
-
"median":
|
| 17 |
-
"mean":
|
| 18 |
},
|
| 19 |
"browser_cer": 0.05793650793650794,
|
| 20 |
"node_cer_same_50": 0.057539682539682536,
|
|
@@ -35,6 +35,9 @@
|
|
| 35 |
"no_external_requests_after_ready": true,
|
| 36 |
"browser_node_cer_within_0_2_points_50": true,
|
| 37 |
"ui_upload_result_matches_browser": true,
|
| 38 |
-
"no_console_or_page_errors": true
|
|
|
|
|
|
|
|
|
|
| 39 |
}
|
| 40 |
}
|
|
|
|
| 11 |
"model": "models/dehtr_ctc_int8.onnx",
|
| 12 |
"n_lines": 50,
|
| 13 |
"fixture_selection": "first 50 frozen test-manifest lines",
|
| 14 |
+
"cold_model_load_ms": 242.90000009536743,
|
| 15 |
"inference_ms_per_line": {
|
| 16 |
+
"median": 252.60000014305115,
|
| 17 |
+
"mean": 288.6080000305176
|
| 18 |
},
|
| 19 |
"browser_cer": 0.05793650793650794,
|
| 20 |
"node_cer_same_50": 0.057539682539682536,
|
|
|
|
| 35 |
"no_external_requests_after_ready": true,
|
| 36 |
"browser_node_cer_within_0_2_points_50": true,
|
| 37 |
"ui_upload_result_matches_browser": true,
|
| 38 |
+
"no_console_or_page_errors": true,
|
| 39 |
+
"font_ofl_bundled": true,
|
| 40 |
+
"runtime_mit_bundled": true,
|
| 41 |
+
"release_notices_bundled": true
|
| 42 |
}
|
| 43 |
}
|
results/m4/demo.png
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
results/m4/preds_browser.jsonl
CHANGED
|
@@ -1,50 +1,50 @@
|
|
| 1 |
-
{"id":"0107-000","ref":"Process (eigene Schreibweise PROCESS) ist eine crossmediale","browser_hyp":"Process (eigene Schreibweise PROCESS) ist eine crormediale","node_hyp":"Process (eigene Schreibweise PROCESS) ist eine crormediale","inference_ms":
|
| 2 |
-
{"id":"0107-001","ref":"Fachmedienmarke mit mehreren Fachzeitschriften,","browser_hyp":"Fachmedienmarbe mit nachreren Fachzeitschriften","node_hyp":"Fachmedienmarbe mit nachreren Fachzeitschriften","inference_ms":
|
| 3 |
-
{"id":"0107-002","ref":"Websites und Branchenevents in deutscher und englischer Sprache.","browser_hyp":"Websites und Brancheneuents in deutscher und englischer Sprache","node_hyp":"Websites und Brancheneuents in deutscher und englischer Sprache","inference_ms":
|
| 4 |
-
{"id":"0107-003","ref":"Die deutschen Printausgaben erscheinen monatlich bei der Vogel","browser_hyp":"Die deutschen Prinlausgaben erscheinen monatlich bei der Vogel","node_hyp":"Die deutschen Prinlausgaben erscheinen monatlich bei der Vogel","inference_ms":
|
| 5 |
-
{"id":"0107-004","ref":"Communications Group. Im Mittelpunkt stehen anwendungsorientierte","browser_hyp":"Communications Graup. Ion Mittelpunkt stehen anwendengsorientierke","node_hyp":"Communications Graup. Ion Mittelpunkt stehen anwendengsorientierke","inference_ms":
|
| 6 |
-
{"id":"0107-005","ref":"Technikinformationen für die Chemie-, Pharmatechnik und","browser_hyp":"Technikinformationen für die Chemie-, Pharmatechnit und","node_hyp":"Technikinformationen für die Chemie-, Pharmatechnit und","inference_ms":
|
| 7 |
-
{"id":"0107-006","ref":"Verfahrenstechnik. Dabei werden die Leser über Automatisierung,","browser_hyp":"Verfehrenetechnit. Dabeir werden die leser über Bulomatisserung","node_hyp":"Verfehrenetechnit. Dabeir werden die leser über Bulomatisserung","inference_ms":
|
| 8 |
-
{"id":"0107-007","ref":"MSR, Anlagenbau, Apparatebau, Strömungstechnik, aber auch über","browser_hyp":"MSR, Aulegenbeu, Apparatebau, Stämungstechnik, aber auch über","node_hyp":"MSR, Aulegenbeu, Apparatebau, Stämungstechnik, aber auch über","inference_ms":
|
| 9 |
-
{"id":"0107-008","ref":"mechanische und thermische Verfahrenstechnik sowie hochaktuelle","browser_hyp":"mechanische und Hermische Verfahrenstechuik sowie hechattuellen","node_hyp":"mechanische und Hermische Verfahrenstechuik sowie hechattuellen","inference_ms":
|
| 10 |
-
{"id":"0107-009","ref":"Themen wie Digitalisierung und Modularisierung in der","browser_hyp":"Themen wie Digilalisierung und Modulansierung in der","node_hyp":"Themen wie Digilalisierung und Modulansierung in der","inference_ms":
|
| 11 |
-
{"id":"0107-010","ref":"Prozessindustrie informiert. Das Fachmedium richtet sich an Fach-","browser_hyp":"Prozessindustrie infarmert. Das Fachmedium richtet sich amn Fach-","node_hyp":"Prozessindustrie infarmert. Das Fachmedium richtet sich amn Fach-","inference_ms":
|
| 12 |
-
{"id":"0107-011","ref":"und Führungskräfte, Techniker und Ingenieure, die in Unternehmen","browser_hyp":"und Führungskräfte, Techniter und Sugeniemre, die in Untergehmen","node_hyp":"und Führungskräfte, Techniter und Sugeniemre, die in Untergehmen","inference_ms":
|
| 13 |
-
{"id":"0107-012","ref":"der Prozessindustrie mit den Schwerpunkten Chemie-, Pharma- und","browser_hyp":"der Prozessindustrie mit den Schwerpunkten Chemne-, Phorua- und","node_hyp":"der Prozessindustrie mit den Schwerpunkten Chemne-, Phorua- und","inference_ms":
|
| 14 |
-
{"id":"0107-013","ref":"Lebensmittelindustrie sowie in Unternehmen der Öl- und Gasindustrie in den","browser_hyp":"Lebensmittelindustrie sowie in Unternehme","node_hyp":"Lebensmittelindustrie sowie in Unternehme","inference_ms":
|
| 15 |
-
{"id":"0129-000","ref":"Leuchtfeuerwärter","browser_hyp":"(euchtfeuerwärter","node_hyp":"(euchtfeuerwärter","inference_ms":
|
| 16 |
-
{"id":"0129-001","ref":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","browser_hyp":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","node_hyp":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","inference_ms":
|
| 17 |
-
{"id":"0129-002","ref":"Leuchtturmwärter) haben die Aufgabe, das zur","browser_hyp":"Leuchtturmwärter) haben die Aufgabe, das zur","node_hyp":"Leuchtturmwärter) haben die Aufgabe, das zur","inference_ms":
|
| 18 |
-
{"id":"0129-003","ref":"Sicherung des Schiffsverkehrs dienende Leuchtfeuer","browser_hyp":"Sicherung des Schiftsverkehrs dienender Leuchtfeuer","node_hyp":"Sicherung des Schiftsverkehrs dienender Leuchtfeuer","inference_ms":
|
| 19 |
-
{"id":"0129-004","ref":"von Sonnenuntergang bis Sonnenaufgang hell und klar","browser_hyp":"von Sonnenuntergang bis Sonnenaufgang hell und har","node_hyp":"von Sonnenuntergang bis Sonnenaufgang hell und har","inference_ms":
|
| 20 |
-
{"id":"0129-005","ref":"brennen zu lassen sowie kleinere Arbeiten am","browser_hyp":"brennen zu lassen sowie kleinere Arbeiten am","node_hyp":"brennen zu lassen sowie kleinere Arbeiten am","inference_ms":
|
| 21 |
-
{"id":"0129-006","ref":"Leuchtturm vorzunehmen. Sie wurden früher und","browser_hyp":"Leuchtturm vorzunehmen. Sie wurden früher und","node_hyp":"Leuchtturm vorzunehmen. Sie wurden früher und","inference_ms":
|
| 22 |
-
{"id":"0129-007","ref":"werden umgangssprachlich auch als Leuchtturmwärter","browser_hyp":"werden umgangssprachlich auch als Leuchtturmwärter","node_hyp":"werden umgangssprachlich auch als Leuchtturmwärter","inference_ms":
|
| 23 |
-
{"id":"0129-008","ref":"bezeichnet.","browser_hyp":"bezeichnet ","node_hyp":"bezeichnet ","inference_ms":121.
|
| 24 |
-
{"id":"0129-009","ref":"Seit dem Ende des 20. Jahrhunderts gibt es den","browser_hyp":"seit dem Ende des 20. Jahrhunderts gibt es den","node_hyp":"seit dem Ende des 20. Jahrhunderts gibt es den","inference_ms":
|
| 25 |
-
{"id":"0129-010","ref":"Beruf des Leuchtturmwärters in Deutschland nicht","browser_hyp":"Beruf des Leuchtturewärters in Deutschland nicht","node_hyp":"Beruf des Leuchtturewärters in Deutschland nicht","inference_ms":
|
| 26 |
-
{"id":"0129-011","ref":"mehr, da dessen Arbeit durch die Fortschritte der","browser_hyp":"mehr, da dessen Arbeit durch die Fortschrilte der","node_hyp":"mehr, da dessen Arbeit durch die Fortschrilte der","inference_ms":
|
| 27 |
-
{"id":"0129-012","ref":"Technik immer weiter vereinfacht wurde. Heute werden","browser_hyp":"Technik immer weiter vereinfacht wurde. Heute werden","node_hyp":"Technik immer weiter vereinfacht wurde. Heute werden","inference_ms":
|
| 28 |
-
{"id":"0129-013","ref":"alle Türme automatisch von zentralen Stationen","browser_hyp":"alle Türme automatisch von Zentralen Stationen","node_hyp":"alle Türme automatisch von Zentralen Stationen","inference_ms":
|
| 29 |
-
{"id":"0129-014","ref":"(Verkehrszentralen) überwacht und nur noch bei Bedarf","browser_hyp":"(Verkehrszentralen) überwacht und uur nock bei Bedorf","node_hyp":"(Verkehrszentralen) überwacht und uur nock bei Bedorf","inference_ms":
|
| 30 |
-
{"id":"0129-015","ref":"gewartet. Leuchtfeuerwärter lebten in der Regel mit","browser_hyp":"gewartet. Leucht feuerwärter Lebten in der Regel mit","node_hyp":"gewartet. Leucht feuerwärter Lebten in der Regel mit","inference_ms":
|
| 31 |
-
{"id":"0129-016","ref":"ihrer Familie in unmittelbarer Nähe des zu wartenden","browser_hyp":"ihrer Familie in mmiltelbarer Nähe des zu wartenden","node_hyp":"ihrer Familie in mmiltelbarer Nähe des zu wartenden","inference_ms":
|
| 32 |
-
{"id":"0129-017","ref":"Leuchtfeuers.","browser_hyp":"Leucht feuers.","node_hyp":"Leucht feuers.","inference_ms":
|
| 33 |
-
{"id":"0129-018","ref":"Weltweit gibt","browser_hyp":"Weltweit gibt","node_hyp":"Weltweit gibt","inference_ms":
|
| 34 |
-
{"id":"0132-000","ref":"Arnljótr gellini","browser_hyp":"Arnljötrgellin","node_hyp":"Arnljötrgellin","inference_ms":97.
|
| 35 |
-
{"id":"0132-001","ref":"gellini (norwegisch/schwedisch Arnljot Gelline; 29. Juli 1930 bei","browser_hyp":"gellini (norwegisch/schwedisch Arnlijot Gelline; 29. Juli 1930 be ","node_hyp":"gellini (norwegisch/schwedisch Arnlijot Gelline; 29. Juli 1930 be ","inference_ms":
|
| 36 |
-
{"id":"0132-002","ref":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","browser_hyp":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","node_hyp":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","inference_ms":
|
| 37 |
-
{"id":"0132-003","ref":"Heimskringla. Er war ein Friedloser, der in der Gegend von","browser_hyp":"Heimskringla. Er war ein Friedloser, der in der Gegend von","node_hyp":"Heimskringla. Er war ein Friedloser, der in der Gegend von","inference_ms":
|
| 38 |
-
{"id":"0132-004","ref":"Jämtland lebte. Er wird als ein gutgekleideter, hochgewachsener","browser_hyp":"Jämtland lebte . Er war als ein gutgekleideter, hochgewachsener","node_hyp":"Jämtland lebte . Er war als ein gutgekleideter, hochgewachsener","inference_ms":
|
| 39 |
-
{"id":"0132-005","ref":"Mann beschrieben. Sein Beiname gellini spricht für seine","browser_hyp":"Mann beschrieben. Sein Beiname gellini spricht für seine","node_hyp":"Mann beschrieben. Sein Beiname gellini spricht für seine","inference_ms":
|
| 40 |
-
{"id":"0132-006","ref":"Herkunft aus der Ortschaft Gällö.","browser_hyp":"Herkunft aus der Ortschaft Gällö","node_hyp":"Herkunft aus der Ortschaft Gällö","inference_ms":
|
| 41 |
-
{"id":"0132-007","ref":"Entsprechend der Saga soll er im Winter 1026/1027 dem Snorrason,","browser_hyp":"Entsprechend der Saga soll er im Winter 1026/27 den Snorrason ","node_hyp":"Entsprechend der Saga soll er im Winter 1026/27 den Snorrason ","inference_ms":
|
| 42 |
-
{"id":"0132-008","ref":"welcher von König Olav Haraldsson als Steuereintreiber nach","browser_hyp":"welder von König dav Haralderon als Steuereintreiber nach","node_hyp":"welder von König dav Haralderon als Steuereintreiber nach","inference_ms":
|
| 43 |
-
{"id":"0132-009","ref":"Jämtland geschickt worden war, auf der Flucht von Jämtland","browser_hyp":"Jämtland geschickt worden war, auf der Flucht von Jämtland","node_hyp":"Jämtland geschickt worden war, auf der Flucht von Jämtland","inference_ms":
|
| 44 |
-
{"id":"0132-010","ref":"nach Nidaros (Trondheim) geholfen haben. gellini führte","browser_hyp":"nach Nidaros (Trondheim) gehobten haben. gelliniführte","node_hyp":"nach Nidaros (Trondheim) geholten haben. gelliniführte","inference_ms":
|
| 45 |
-
{"id":"0132-011","ref":"Snorrason und dessen Gefolgsmann durchs Gebirge.","browser_hyp":"Snovrason und dessen Getolgsmam durchs Gebirge ","node_hyp":"Snovrason und dessen Getolgsmam durchs Gebirge ","inference_ms":
|
| 46 |
-
{"id":"0132-012","ref":"Da es nicht schnell genug voranging, wies er die beiden","browser_hyp":"Da es schnell genung voranging, wies er die beiden","node_hyp":"Da es schnell genung voranging, wies er die beiden","inference_ms":
|
| 47 |
-
{"id":"0137-001","ref":"Sullivan-Expedition","browser_hyp":"Sulliven-Expedition","node_hyp":"Sulliven-Expedition","inference_ms":
|
| 48 |
-
{"id":"0137-002","ref":"ie Sullivan-Expedition, auch bekannt als Sullivan-Clinton","browser_hyp":"Die Sullivon-Expedition, auch bekonnt als Sullivan-Clim","node_hyp":"Die Sullivon-Expedition, auch bekonnt als Sullivan-Clim","inference_ms":
|
| 49 |
-
{"id":"0137-003","ref":"Expedition, war ein Feldzug unter der Führung der","browser_hyp":"Expedition, war ein Feldzug unter der Führung der","node_hyp":"Expedition, war ein Feldzug unter der Führung der","inference_ms":
|
| 50 |
-
{"id":"0137-004","ref":"Generäle John Sullivan und James Clinton gegen Loyalisten","browser_hyp":"Generäle John Sullivan und James (linton gegen Loyolisten","node_hyp":"Generäle John Sullivan und James (linton gegen Loyolisten","inference_ms":
|
|
|
|
| 1 |
+
{"id":"0107-000","ref":"Process (eigene Schreibweise PROCESS) ist eine crossmediale","browser_hyp":"Process (eigene Schreibweise PROCESS) ist eine crormediale","node_hyp":"Process (eigene Schreibweise PROCESS) ist eine crormediale","inference_ms":433,"width":1280}
|
| 2 |
+
{"id":"0107-001","ref":"Fachmedienmarke mit mehreren Fachzeitschriften,","browser_hyp":"Fachmedienmarbe mit nachreren Fachzeitschriften","node_hyp":"Fachmedienmarbe mit nachreren Fachzeitschriften","inference_ms":236.80000019073486,"width":688}
|
| 3 |
+
{"id":"0107-002","ref":"Websites und Branchenevents in deutscher und englischer Sprache.","browser_hyp":"Websites und Brancheneuents in deutscher und englischer Sprache","node_hyp":"Websites und Brancheneuents in deutscher und englischer Sprache","inference_ms":287.09999990463257,"width":845}
|
| 4 |
+
{"id":"0107-003","ref":"Die deutschen Printausgaben erscheinen monatlich bei der Vogel","browser_hyp":"Die deutschen Prinlausgaben erscheinen monatlich bei der Vogel","node_hyp":"Die deutschen Prinlausgaben erscheinen monatlich bei der Vogel","inference_ms":270.59999990463257,"width":789}
|
| 5 |
+
{"id":"0107-004","ref":"Communications Group. Im Mittelpunkt stehen anwendungsorientierte","browser_hyp":"Communications Graup. Ion Mittelpunkt stehen anwendengsorientierke","node_hyp":"Communications Graup. Ion Mittelpunkt stehen anwendengsorientierke","inference_ms":243.80000019073486,"width":711}
|
| 6 |
+
{"id":"0107-005","ref":"Technikinformationen für die Chemie-, Pharmatechnik und","browser_hyp":"Technikinformationen für die Chemie-, Pharmatechnit und","node_hyp":"Technikinformationen für die Chemie-, Pharmatechnit und","inference_ms":252.10000038146973,"width":734}
|
| 7 |
+
{"id":"0107-006","ref":"Verfahrenstechnik. Dabei werden die Leser über Automatisierung,","browser_hyp":"Verfehrenetechnit. Dabeir werden die leser über Bulomatisserung","node_hyp":"Verfehrenetechnit. Dabeir werden die leser über Bulomatisserung","inference_ms":206.2999997138977,"width":606}
|
| 8 |
+
{"id":"0107-007","ref":"MSR, Anlagenbau, Apparatebau, Strömungstechnik, aber auch über","browser_hyp":"MSR, Aulegenbeu, Apparatebau, Stämungstechnik, aber auch über","node_hyp":"MSR, Aulegenbeu, Apparatebau, Stämungstechnik, aber auch über","inference_ms":220.69999980926514,"width":646}
|
| 9 |
+
{"id":"0107-008","ref":"mechanische und thermische Verfahrenstechnik sowie hochaktuelle","browser_hyp":"mechanische und Hermische Verfahrenstechuik sowie hechattuellen","node_hyp":"mechanische und Hermische Verfahrenstechuik sowie hechattuellen","inference_ms":217.5,"width":634}
|
| 10 |
+
{"id":"0107-009","ref":"Themen wie Digitalisierung und Modularisierung in der","browser_hyp":"Themen wie Digilalisierung und Modulansierung in der","node_hyp":"Themen wie Digilalisierung und Modulansierung in der","inference_ms":208.5,"width":605}
|
| 11 |
+
{"id":"0107-010","ref":"Prozessindustrie informiert. Das Fachmedium richtet sich an Fach-","browser_hyp":"Prozessindustrie infarmert. Das Fachmedium richtet sich amn Fach-","node_hyp":"Prozessindustrie infarmert. Das Fachmedium richtet sich amn Fach-","inference_ms":243.19999980926514,"width":710}
|
| 12 |
+
{"id":"0107-011","ref":"und Führungskräfte, Techniker und Ingenieure, die in Unternehmen","browser_hyp":"und Führungskräfte, Techniter und Sugeniemre, die in Untergehmen","node_hyp":"und Führungskräfte, Techniter und Sugeniemre, die in Untergehmen","inference_ms":253.09999990463257,"width":741}
|
| 13 |
+
{"id":"0107-012","ref":"der Prozessindustrie mit den Schwerpunkten Chemie-, Pharma- und","browser_hyp":"der Prozessindustrie mit den Schwerpunkten Chemne-, Phorua- und","node_hyp":"der Prozessindustrie mit den Schwerpunkten Chemne-, Phorua- und","inference_ms":228.10000038146973,"width":667}
|
| 14 |
+
{"id":"0107-013","ref":"Lebensmittelindustrie sowie in Unternehmen der Öl- und Gasindustrie in den","browser_hyp":"Lebensmittelindustrie sowie in Unternehme","node_hyp":"Lebensmittelindustrie sowie in Unternehme","inference_ms":215.5,"width":618}
|
| 15 |
+
{"id":"0129-000","ref":"Leuchtfeuerwärter","browser_hyp":"(euchtfeuerwärter","node_hyp":"(euchtfeuerwärter","inference_ms":134.09999990463257,"width":370}
|
| 16 |
+
{"id":"0129-001","ref":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","browser_hyp":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","node_hyp":"Leuchtfeuerwärter (im allgemeinen Sprachgebrauch:","inference_ms":413.90000009536743,"width":1218}
|
| 17 |
+
{"id":"0129-002","ref":"Leuchtturmwärter) haben die Aufgabe, das zur","browser_hyp":"Leuchtturmwärter) haben die Aufgabe, das zur","node_hyp":"Leuchtturmwärter) haben die Aufgabe, das zur","inference_ms":414.5,"width":1214}
|
| 18 |
+
{"id":"0129-003","ref":"Sicherung des Schiffsverkehrs dienende Leuchtfeuer","browser_hyp":"Sicherung des Schiftsverkehrs dienender Leuchtfeuer","node_hyp":"Sicherung des Schiftsverkehrs dienender Leuchtfeuer","inference_ms":344.5,"width":1012}
|
| 19 |
+
{"id":"0129-004","ref":"von Sonnenuntergang bis Sonnenaufgang hell und klar","browser_hyp":"von Sonnenuntergang bis Sonnenaufgang hell und har","node_hyp":"von Sonnenuntergang bis Sonnenaufgang hell und har","inference_ms":380.2999997138977,"width":1122}
|
| 20 |
+
{"id":"0129-005","ref":"brennen zu lassen sowie kleinere Arbeiten am","browser_hyp":"brennen zu lassen sowie kleinere Arbeiten am","node_hyp":"brennen zu lassen sowie kleinere Arbeiten am","inference_ms":503.1000003814697,"width":1477}
|
| 21 |
+
{"id":"0129-006","ref":"Leuchtturm vorzunehmen. Sie wurden früher und","browser_hyp":"Leuchtturm vorzunehmen. Sie wurden früher und","node_hyp":"Leuchtturm vorzunehmen. Sie wurden früher und","inference_ms":388.5,"width":1138}
|
| 22 |
+
{"id":"0129-007","ref":"werden umgangssprachlich auch als Leuchtturmwärter","browser_hyp":"werden umgangssprachlich auch als Leuchtturmwärter","node_hyp":"werden umgangssprachlich auch als Leuchtturmwärter","inference_ms":377.80000019073486,"width":1109}
|
| 23 |
+
{"id":"0129-008","ref":"bezeichnet.","browser_hyp":"bezeichnet ","node_hyp":"bezeichnet ","inference_ms":121.09999990463257,"width":339}
|
| 24 |
+
{"id":"0129-009","ref":"Seit dem Ende des 20. Jahrhunderts gibt es den","browser_hyp":"seit dem Ende des 20. Jahrhunderts gibt es den","node_hyp":"seit dem Ende des 20. Jahrhunderts gibt es den","inference_ms":373.30000019073486,"width":1096}
|
| 25 |
+
{"id":"0129-010","ref":"Beruf des Leuchtturmwärters in Deutschland nicht","browser_hyp":"Beruf des Leuchtturewärters in Deutschland nicht","node_hyp":"Beruf des Leuchtturewärters in Deutschland nicht","inference_ms":431.09999990463257,"width":1267}
|
| 26 |
+
{"id":"0129-011","ref":"mehr, da dessen Arbeit durch die Fortschritte der","browser_hyp":"mehr, da dessen Arbeit durch die Fortschrilte der","node_hyp":"mehr, da dessen Arbeit durch die Fortschrilte der","inference_ms":456.30000019073486,"width":1332}
|
| 27 |
+
{"id":"0129-012","ref":"Technik immer weiter vereinfacht wurde. Heute werden","browser_hyp":"Technik immer weiter vereinfacht wurde. Heute werden","node_hyp":"Technik immer weiter vereinfacht wurde. Heute werden","inference_ms":438.80000019073486,"width":1296}
|
| 28 |
+
{"id":"0129-013","ref":"alle Türme automatisch von zentralen Stationen","browser_hyp":"alle Türme automatisch von Zentralen Stationen","node_hyp":"alle Türme automatisch von Zentralen Stationen","inference_ms":524.1000003814697,"width":1508}
|
| 29 |
+
{"id":"0129-014","ref":"(Verkehrszentralen) überwacht und nur noch bei Bedarf","browser_hyp":"(Verkehrszentralen) überwacht und uur nock bei Bedorf","node_hyp":"(Verkehrszentralen) überwacht und uur nock bei Bedorf","inference_ms":345.09999990463257,"width":1007}
|
| 30 |
+
{"id":"0129-015","ref":"gewartet. Leuchtfeuerwärter lebten in der Regel mit","browser_hyp":"gewartet. Leucht feuerwärter Lebten in der Regel mit","node_hyp":"gewartet. Leucht feuerwärter Lebten in der Regel mit","inference_ms":351.8999996185303,"width":1027}
|
| 31 |
+
{"id":"0129-016","ref":"ihrer Familie in unmittelbarer Nähe des zu wartenden","browser_hyp":"ihrer Familie in mmiltelbarer Nähe des zu wartenden","node_hyp":"ihrer Familie in mmiltelbarer Nähe des zu wartenden","inference_ms":579,"width":1697}
|
| 32 |
+
{"id":"0129-017","ref":"Leuchtfeuers.","browser_hyp":"Leucht feuers.","node_hyp":"Leucht feuers.","inference_ms":108.80000019073486,"width":311}
|
| 33 |
+
{"id":"0129-018","ref":"Weltweit gibt","browser_hyp":"Weltweit gibt","node_hyp":"Weltweit gibt","inference_ms":118.80000019073486,"width":337}
|
| 34 |
+
{"id":"0132-000","ref":"Arnljótr gellini","browser_hyp":"Arnljötrgellin","node_hyp":"Arnljötrgellin","inference_ms":97.90000009536743,"width":270}
|
| 35 |
+
{"id":"0132-001","ref":"gellini (norwegisch/schwedisch Arnljot Gelline; 29. Juli 1930 bei","browser_hyp":"gellini (norwegisch/schwedisch Arnlijot Gelline; 29. Juli 1930 be ","node_hyp":"gellini (norwegisch/schwedisch Arnlijot Gelline; 29. Juli 1930 be ","inference_ms":262.30000019073486,"width":759}
|
| 36 |
+
{"id":"0132-002","ref":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","browser_hyp":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","node_hyp":"Stiklestad) ist eine Figur aus der Saga von Olaf dem Heiligen der","inference_ms":253.89999961853027,"width":738}
|
| 37 |
+
{"id":"0132-003","ref":"Heimskringla. Er war ein Friedloser, der in der Gegend von","browser_hyp":"Heimskringla. Er war ein Friedloser, der in der Gegend von","node_hyp":"Heimskringla. Er war ein Friedloser, der in der Gegend von","inference_ms":220.90000009536743,"width":647}
|
| 38 |
+
{"id":"0132-004","ref":"Jämtland lebte. Er wird als ein gutgekleideter, hochgewachsener","browser_hyp":"Jämtland lebte . Er war als ein gutgekleideter, hochgewachsener","node_hyp":"Jämtland lebte . Er war als ein gutgekleideter, hochgewachsener","inference_ms":221.7000002861023,"width":651}
|
| 39 |
+
{"id":"0132-005","ref":"Mann beschrieben. Sein Beiname gellini spricht für seine","browser_hyp":"Mann beschrieben. Sein Beiname gellini spricht für seine","node_hyp":"Mann beschrieben. Sein Beiname gellini spricht für seine","inference_ms":224.09999990463257,"width":642}
|
| 40 |
+
{"id":"0132-006","ref":"Herkunft aus der Ortschaft Gällö.","browser_hyp":"Herkunft aus der Ortschaft Gällö","node_hyp":"Herkunft aus der Ortschaft Gällö","inference_ms":191,"width":558}
|
| 41 |
+
{"id":"0132-007","ref":"Entsprechend der Saga soll er im Winter 1026/1027 dem Snorrason,","browser_hyp":"Entsprechend der Saga soll er im Winter 1026/27 den Snorrason ","node_hyp":"Entsprechend der Saga soll er im Winter 1026/27 den Snorrason ","inference_ms":266.5,"width":773}
|
| 42 |
+
{"id":"0132-008","ref":"welcher von König Olav Haraldsson als Steuereintreiber nach","browser_hyp":"welder von König dav Haralderon als Steuereintreiber nach","node_hyp":"welder von König dav Haralderon als Steuereintreiber nach","inference_ms":243.59999990463257,"width":705}
|
| 43 |
+
{"id":"0132-009","ref":"Jämtland geschickt worden war, auf der Flucht von Jämtland","browser_hyp":"Jämtland geschickt worden war, auf der Flucht von Jämtland","node_hyp":"Jämtland geschickt worden war, auf der Flucht von Jämtland","inference_ms":230.40000009536743,"width":670}
|
| 44 |
+
{"id":"0132-010","ref":"nach Nidaros (Trondheim) geholfen haben. gellini führte","browser_hyp":"nach Nidaros (Trondheim) gehobten haben. gelliniführte","node_hyp":"nach Nidaros (Trondheim) geholten haben. gelliniführte","inference_ms":205.80000019073486,"width":599}
|
| 45 |
+
{"id":"0132-011","ref":"Snorrason und dessen Gefolgsmann durchs Gebirge.","browser_hyp":"Snovrason und dessen Getolgsmam durchs Gebirge ","node_hyp":"Snovrason und dessen Getolgsmam durchs Gebirge ","inference_ms":187.09999990463257,"width":539}
|
| 46 |
+
{"id":"0132-012","ref":"Da es nicht schnell genug voranging, wies er die beiden","browser_hyp":"Da es schnell genung voranging, wies er die beiden","node_hyp":"Da es schnell genung voranging, wies er die beiden","inference_ms":199,"width":580}
|
| 47 |
+
{"id":"0137-001","ref":"Sullivan-Expedition","browser_hyp":"Sulliven-Expedition","node_hyp":"Sulliven-Expedition","inference_ms":168,"width":490}
|
| 48 |
+
{"id":"0137-002","ref":"ie Sullivan-Expedition, auch bekannt als Sullivan-Clinton","browser_hyp":"Die Sullivon-Expedition, auch bekonnt als Sullivan-Clim","node_hyp":"Die Sullivon-Expedition, auch bekonnt als Sullivan-Clim","inference_ms":407.80000019073486,"width":1192}
|
| 49 |
+
{"id":"0137-003","ref":"Expedition, war ein Feldzug unter der Führung der","browser_hyp":"Expedition, war ein Feldzug unter der Führung der","node_hyp":"Expedition, war ein Feldzug unter der Führung der","inference_ms":340.90000009536743,"width":977}
|
| 50 |
+
{"id":"0137-004","ref":"Generäle John Sullivan und James Clinton gegen Loyalisten","browser_hyp":"Generäle John Sullivan und James (linton gegen Loyolisten","node_hyp":"Generäle John Sullivan und James (linton gegen Loyolisten","inference_ms":388.19999980926514,"width":1141}
|
results/m6/huggingface.json
CHANGED
|
@@ -2,9 +2,64 @@
|
|
| 2 |
"date": "2026-07-29",
|
| 3 |
"repo_id": "naeyn/de-htr-web",
|
| 4 |
"repo_url": "https://huggingface.co/naeyn/de-htr-web",
|
| 5 |
-
"
|
| 6 |
-
"
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
"artifacts": {
|
| 9 |
"models/dehtr_ctc_int8.onnx": {
|
| 10 |
"sha256": "05cce04d3938a64edaee79caf2a74587eaa9f8c46c146d6e04f0512bfce51d82",
|
|
@@ -14,5 +69,6 @@
|
|
| 14 |
"sha256": "9765f609c21ab0fe04ed66260d4000025c63a54b4fa370e9a73788da2dc6065f",
|
| 15 |
"size_bytes": 38978889
|
| 16 |
}
|
| 17 |
-
}
|
|
|
|
| 18 |
}
|
|
|
|
| 2 |
"date": "2026-07-29",
|
| 3 |
"repo_id": "naeyn/de-htr-web",
|
| 4 |
"repo_url": "https://huggingface.co/naeyn/de-htr-web",
|
| 5 |
+
"file_count": 55,
|
| 6 |
+
"files": [
|
| 7 |
+
"LICENSE",
|
| 8 |
+
"NOTICE",
|
| 9 |
+
"README.md",
|
| 10 |
+
"THIRD_PARTY_NOTICES.md",
|
| 11 |
+
"config.json",
|
| 12 |
+
"examples/0107-000.png",
|
| 13 |
+
"examples/infer_onnx.py",
|
| 14 |
+
"model.onnx",
|
| 15 |
+
"pytorch_model.pt",
|
| 16 |
+
"results/baseline_tesseract.json",
|
| 17 |
+
"results/baseline_trocr.json",
|
| 18 |
+
"results/baseline_vlm.json",
|
| 19 |
+
"results/m2/ctc_ratio0.5_seed42.json",
|
| 20 |
+
"results/m2/ctc_ratio0.5_seed43.json",
|
| 21 |
+
"results/m2/ctc_ratio0.5_seed44.json",
|
| 22 |
+
"results/m2/ctc_ratio0.8_seed42.json",
|
| 23 |
+
"results/m2/ctc_ratio0_seed42.json",
|
| 24 |
+
"results/m2/seq2seq_reference.json",
|
| 25 |
+
"results/m2/summary.json",
|
| 26 |
+
"results/m3/export.json",
|
| 27 |
+
"results/m3/node_runtime.json",
|
| 28 |
+
"results/m3/onnx_fp32_python.json",
|
| 29 |
+
"results/m3/onnx_int8_node.json",
|
| 30 |
+
"results/m3/onnx_int8_python.json",
|
| 31 |
+
"results/m3/preds_onnx_fp32_python.jsonl",
|
| 32 |
+
"results/m3/preds_onnx_int8_node.jsonl",
|
| 33 |
+
"results/m3/preds_onnx_int8_python.jsonl",
|
| 34 |
+
"results/m3/preds_pytorch_cpu.jsonl",
|
| 35 |
+
"results/m3/pytorch_cpu.json",
|
| 36 |
+
"results/m3/refs_test.jsonl",
|
| 37 |
+
"results/m3/summary.json",
|
| 38 |
+
"results/m4/browser.json",
|
| 39 |
+
"results/m4/demo.png",
|
| 40 |
+
"results/m4/preds_browser.jsonl",
|
| 41 |
+
"results/m6/huggingface.json",
|
| 42 |
+
"results/preds_tesseract.jsonl",
|
| 43 |
+
"results/preds_trocr.jsonl",
|
| 44 |
+
"results/preds_vlm.jsonl",
|
| 45 |
+
"results/refs_test.jsonl",
|
| 46 |
+
"third_party/onnxruntime/LICENSE",
|
| 47 |
+
"training-data/FONTS.md",
|
| 48 |
+
"training-data/SOURCES.md",
|
| 49 |
+
"training-data/font-licenses/Architects_Daughter_OFL.txt",
|
| 50 |
+
"training-data/font-licenses/Caveat_OFL.txt",
|
| 51 |
+
"training-data/font-licenses/Covered_By_Your_Grace_OFL.txt",
|
| 52 |
+
"training-data/font-licenses/Gloria_Hallelujah_OFL.txt",
|
| 53 |
+
"training-data/font-licenses/Indie_Flower_OFL.txt",
|
| 54 |
+
"training-data/font-licenses/Kalam_OFL.txt",
|
| 55 |
+
"training-data/font-licenses/La_Belle_Aurore_OFL.txt",
|
| 56 |
+
"training-data/font-licenses/Patrick_Hand_OFL.txt",
|
| 57 |
+
"training-data/font-licenses/Reenie_Beanie_OFL.txt",
|
| 58 |
+
"training-data/font-licenses/Shadows_Into_Light_OFL.txt",
|
| 59 |
+
"training-data/font-licenses/Shadows_Into_Light_Two_OFL.txt",
|
| 60 |
+
"training-data/font-licenses/Waiting_for_the_Sunrise_OFL.txt",
|
| 61 |
+
"training-data/split_manifest.json"
|
| 62 |
+
],
|
| 63 |
"artifacts": {
|
| 64 |
"models/dehtr_ctc_int8.onnx": {
|
| 65 |
"sha256": "05cce04d3938a64edaee79caf2a74587eaa9f8c46c146d6e04f0512bfce51d82",
|
|
|
|
| 69 |
"sha256": "9765f609c21ab0fe04ed66260d4000025c63a54b4fa370e9a73788da2dc6065f",
|
| 70 |
"size_bytes": 38978889
|
| 71 |
}
|
| 72 |
+
},
|
| 73 |
+
"note": "Published in a single commit together with the files it lists. The resulting commit oid is recorded in results/m6/huggingface_verification.json, which is verified against the live repo after the push and is not itself published."
|
| 74 |
}
|
third_party/onnxruntime/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) Microsoft Corporation
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
training-data/FONTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
# Handwriting fonts for synthetic training data
|
| 2 |
|
| 3 |
-
These fonts are used to render German text for **synthetic training data**
|
| 4 |
|
| 5 |
1. **License** — SIL Open Font License 1.1 only (sourced from the Google Fonts `ofl/` tree). Personal-use-only fonts are categorically rejected.
|
| 6 |
2. **German charset** — cmap coverage of Ä Ö Ü ä ö ü ß (`U+00C4 U+00D6 U+00DC U+00E4 U+00F6 U+00FC U+00DF`) via `fontTools.ttLib.TTFont.getBestCmap()`.
|
|
|
|
| 1 |
# Handwriting fonts for synthetic training data
|
| 2 |
|
| 3 |
+
These fonts are used to render German text for **synthetic training data** (Tier 3). Every font listed below was **individually verified** for:
|
| 4 |
|
| 5 |
1. **License** — SIL Open Font License 1.1 only (sourced from the Google Fonts `ofl/` tree). Personal-use-only fonts are categorically rejected.
|
| 6 |
2. **German charset** — cmap coverage of Ä Ö Ü ä ö ü ß (`U+00C4 U+00D6 U+00DC U+00E4 U+00F6 U+00FC U+00DF`) via `fontTools.ttLib.TTFont.getBestCmap()`.
|
training-data/SOURCES.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# License register — `de-htr-web`
|
| 2 |
|
| 3 |
**Project:** `de-htr-web`
|
| 4 |
-
**Purpose:** Record every dataset, font source, code dependency, external tool, and baseline model used by the project, with license id, source URL, and access date
|
| 5 |
**Date:** 2026-07-28
|
| 6 |
|
| 7 |
---
|
|
@@ -10,10 +10,30 @@
|
|
| 10 |
|
| 11 |
Licenses below are copied from `.metadata.license.id` on the live Zenodo API record (`GET https://zenodo.org/api/records/<id>`), accessed 2026-07-28.
|
| 12 |
|
| 13 |
-
| Dataset | Zenodo record URL | DOI | Content | License | Confirmed on record page | Access date |
|
| 14 |
-
|---------|-------------------|-----|---------|---------|--------------------------|-------------|
|
| 15 |
-
| ScaDS.AI German Line- and Word-Level Handwriting Dataset | https://zenodo.org/records/18301532 | 10.5281/zenodo.18301532 | 775 writers; 5,843 line images; 37,406 word images | `cc-by-4.0` | yes (API `.metadata.license.id` = `cc-by-4.0`) | 2026-07-28 |
|
| 16 |
-
| ScaDS.AI German Full-Page Handwriting Dataset | https://zenodo.org/records/18283705 | 10.5281/zenodo.18283705 | 77 pages;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
**Coverage note (measured, not from the record description):** the 775 pages/writers describe the
|
| 19 |
full collection, but line crops + line-level ground truth exist for **385** of those pages. The
|
|
@@ -25,7 +45,7 @@ with the line set (verified: `fullpage_writer_overlap == []`), so it remains a c
|
|
| 25 |
|
| 26 |
## Tier 2 — excluded datasets
|
| 27 |
|
| 28 |
-
|
| 29 |
|
| 30 |
| Dataset | Record | Reason excluded |
|
| 31 |
|---------|--------|-----------------|
|
|
@@ -33,7 +53,7 @@ Facts from plan.md §1.2. None of these are used in v1.
|
|
| 33 |
| READ dataset Bozen | Zenodo https://zenodo.org/records/218236 | License not verified; research-only risk — excluded |
|
| 34 |
| read_dataset_german_konzilsprotokolle | Zenodo https://zenodo.org/records/215383 | Not verified — excluded |
|
| 35 |
| StABS Ratsbücher O10 / Urfehdenbuch X | Zenodo https://zenodo.org/records/5153263 | Not verified — excluded |
|
| 36 |
-
| HTR_Validation_Set_StAZH_RRB_German_Kurrent_XIX | (Staatsarchiv Zürich; no verified Zenodo/record URL
|
| 37 |
| ubtue/Ground-Truth Senatsprotokolle | GitHub | Not verified — excluded |
|
| 38 |
| IAM Handwriting Database | IAM registration | Modern English + restrictive research-only registration — excluded (wrong language, wrong license) |
|
| 39 |
|
|
@@ -41,7 +61,7 @@ Facts from plan.md §1.2. None of these are used in v1.
|
|
| 41 |
|
| 42 |
## Tier 3 — synthetic data
|
| 43 |
|
| 44 |
-
|
| 45 |
|
| 46 |
- **Fonts:** see `data/FONTS.md`. SIL OFL 1.1 only.
|
| 47 |
- **German Wikipedia text corpus:** 10,234 clean rendering lines in
|
|
@@ -49,6 +69,11 @@ Per plan.md §1.3:
|
|
| 49 |
page revisions. `data/german_wikipedia_sources.json` records every title, page ID,
|
| 50 |
revision ID, and canonical URL. License: CC BY-SA 4.0
|
| 51 |
(https://creativecommons.org/licenses/by-sa/4.0/); SA applies to the source text.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
- **Real-word-image composition** from the 37,406 Tier-1 word images: license follows CC BY 4.0 (same as the Tier-1 word images).
|
| 53 |
|
| 54 |
**Hard rule:** synthetic data never appears in validation or test.
|
|
@@ -88,11 +113,54 @@ Versions from `uv.lock` / `package-lock.json`. Licenses from package metadata an
|
|
| 88 |
|------|------|---------|--------------|-------------|
|
| 89 |
| tesseract OCR 5.3.4 | Conventional OCR baseline (M1) | Apache-2.0 | https://github.com/tesseract-ocr/tesseract | 2026-07-28 |
|
| 90 |
| tessdata_best `deu` traineddata | German language data for Tesseract | Apache-2.0 | https://github.com/tesseract-ocr/tessdata_best | 2026-07-28 |
|
|
|
|
| 91 |
| microsoft/trocr-base-handwritten | TrOCR English handwritten zero-shot baseline (M1) | `mit` (`.cardData.license`) | https://huggingface.co/api/models/microsoft/trocr-base-handwritten | 2026-07-28 |
|
|
|
|
| 92 |
| mlx-community/Qwen2.5-VL-7B-Instruct-4bit | VLM zero-shot baseline, MLX 4-bit (M1) | `apache-2.0` (`.cardData.license`) | https://huggingface.co/api/models/mlx-community/Qwen2.5-VL-7B-Instruct-4bit | 2026-07-28 |
|
| 93 |
| Qwen/Qwen2.5-VL-7B-Instruct | Base VLM for the MLX quantized variant | `apache-2.0` (`.cardData.license`) | https://huggingface.co/api/models/Qwen/Qwen2.5-VL-7B-Instruct | 2026-07-28 |
|
| 94 |
| ~~Qwen/Qwen2.5-VL-3B-Instruct~~ (rejected) | Considered as the VLM baseline, **not used** | **Non-permissive** — `.cardData.license` absent; `.cardData.license_name` = `qwen-research` (research-only). Rejected in favour of the apache-2.0 7B variant; see DECISIONS.md D2 | https://huggingface.co/api/models/Qwen/Qwen2.5-VL-3B-Instruct | 2026-07-28 |
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
---
|
| 97 |
|
| 98 |
Every entry is verified with a source URL and access date as noted above. Unverifiable items are marked UNVERIFIED rather than guessed.
|
|
|
|
| 1 |
# License register — `de-htr-web`
|
| 2 |
|
| 3 |
**Project:** `de-htr-web`
|
| 4 |
+
**Purpose:** Record every dataset, font source, code dependency, external tool, and baseline model used by the project, with license id, source URL, and access date.
|
| 5 |
**Date:** 2026-07-28
|
| 6 |
|
| 7 |
---
|
|
|
|
| 10 |
|
| 11 |
Licenses below are copied from `.metadata.license.id` on the live Zenodo API record (`GET https://zenodo.org/api/records/<id>`), accessed 2026-07-28.
|
| 12 |
|
| 13 |
+
| Dataset | Creators | Zenodo record URL | DOI | Content | License | Confirmed on record page | Access date |
|
| 14 |
+
|---------|----------|-------------------|-----|---------|---------|--------------------------|-------------|
|
| 15 |
+
| ScaDS.AI German Line- and Word-Level Handwriting Dataset (v1.0) | Burghardt, Thomas; Alzin, Ahmad | https://zenodo.org/records/18301532 | 10.5281/zenodo.18301532 | 775 writers; 5,843 line images; 37,406 word images | `cc-by-4.0` | yes (API `.metadata.license.id` = `cc-by-4.0`) | 2026-07-28 |
|
| 16 |
+
| ScaDS.AI German Full-Page Handwriting Dataset | Nestler, Till; Burghardt, Thomas | https://zenodo.org/records/18283705 | 10.5281/zenodo.18283705 | 77 pages; **not used** in the v1 release (see status note) | `cc-by-4.0` | yes (API `.metadata.license.id` = `cc-by-4.0`) | 2026-07-28 |
|
| 17 |
+
|
| 18 |
+
**Required CC BY 4.0 attribution.** CC BY 4.0 §3(a)(1)(A)(i) requires retaining
|
| 19 |
+
identification of the creators. The attribution statements for these two records are:
|
| 20 |
+
|
| 21 |
+
> "ScaDS.AI German Line- and Word-Level Handwriting Dataset" (v1.0, published 2026-01-19)
|
| 22 |
+
> by Thomas Burghardt and Ahmad Alzin, Zenodo, doi:10.5281/zenodo.18301532, licensed under
|
| 23 |
+
> [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
| 24 |
+
|
| 25 |
+
> "ScaDS.AI German Full-Page Handwriting Dataset" (published 2026-01-17) by Till Nestler
|
| 26 |
+
> and Thomas Burghardt, Zenodo, doi:10.5281/zenodo.18283705, licensed under
|
| 27 |
+
> [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
| 28 |
+
|
| 29 |
+
Creator names were read from `.metadata.creators[].name` on the live Zenodo API records.
|
| 30 |
+
|
| 31 |
+
**Status note — full-page dataset.** The 77-page full-page set was reserved as a
|
| 32 |
+
held-out set for the optional M5 full-page milestone. M5 was skipped (DECISIONS.md D12), so
|
| 33 |
+
this record contributed **no training, validation, or test data** to the v1 release. It was
|
| 34 |
+
downloaded only to verify that it shares no writer with the line set
|
| 35 |
+
(`fullpage_writer_overlap == []` in `data/split_manifest.json`). Its attribution is retained
|
| 36 |
+
here because the data was obtained and inspected.
|
| 37 |
|
| 38 |
**Coverage note (measured, not from the record description):** the 775 pages/writers describe the
|
| 39 |
full collection, but line crops + line-level ground truth exist for **385** of those pages. The
|
|
|
|
| 45 |
|
| 46 |
## Tier 2 — excluded datasets
|
| 47 |
|
| 48 |
+
None of these are used in v1.
|
| 49 |
|
| 50 |
| Dataset | Record | Reason excluded |
|
| 51 |
|---------|--------|-----------------|
|
|
|
|
| 53 |
| READ dataset Bozen | Zenodo https://zenodo.org/records/218236 | License not verified; research-only risk — excluded |
|
| 54 |
| read_dataset_german_konzilsprotokolle | Zenodo https://zenodo.org/records/215383 | Not verified — excluded |
|
| 55 |
| StABS Ratsbücher O10 / Urfehdenbuch X | Zenodo https://zenodo.org/records/5153263 | Not verified — excluded |
|
| 56 |
+
| HTR_Validation_Set_StAZH_RRB_German_Kurrent_XIX | (Staatsarchiv Zürich; no verified Zenodo/record URL) | Not verified — excluded |
|
| 57 |
| ubtue/Ground-Truth Senatsprotokolle | GitHub | Not verified — excluded |
|
| 58 |
| IAM Handwriting Database | IAM registration | Modern English + restrictive research-only registration — excluded (wrong language, wrong license) |
|
| 59 |
|
|
|
|
| 61 |
|
| 62 |
## Tier 3 — synthetic data
|
| 63 |
|
| 64 |
+
Synthetic-data inputs:
|
| 65 |
|
| 66 |
- **Fonts:** see `data/FONTS.md`. SIL OFL 1.1 only.
|
| 67 |
- **German Wikipedia text corpus:** 10,234 clean rendering lines in
|
|
|
|
| 69 |
page revisions. `data/german_wikipedia_sources.json` records every title, page ID,
|
| 70 |
revision ID, and canonical URL. License: CC BY-SA 4.0
|
| 71 |
(https://creativecommons.org/licenses/by-sa/4.0/); SA applies to the source text.
|
| 72 |
+
**`data/german_wikipedia_lines.txt` is committed to this repository and is therefore
|
| 73 |
+
redistributed under CC BY-SA 4.0, not under the repository's Apache-2.0 license.** The
|
| 74 |
+
full attribution and ShareAlike notice sits beside it in
|
| 75 |
+
`data/german_wikipedia_lines.LICENSE.txt`; see also "Files in this repository not covered
|
| 76 |
+
by Apache-2.0" below.
|
| 77 |
- **Real-word-image composition** from the 37,406 Tier-1 word images: license follows CC BY 4.0 (same as the Tier-1 word images).
|
| 78 |
|
| 79 |
**Hard rule:** synthetic data never appears in validation or test.
|
|
|
|
| 113 |
|------|------|---------|--------------|-------------|
|
| 114 |
| tesseract OCR 5.3.4 | Conventional OCR baseline (M1) | Apache-2.0 | https://github.com/tesseract-ocr/tesseract | 2026-07-28 |
|
| 115 |
| tessdata_best `deu` traineddata | German language data for Tesseract | Apache-2.0 | https://github.com/tesseract-ocr/tessdata_best | 2026-07-28 |
|
| 116 |
+
| **torchvision `ResNet18_Weights.IMAGENET1K_V1`** | **Pretrained visual stem of the released model — these weights are redistributed inside `models/dehtr_ctc_int8.onnx`** | Weights are published as part of the torchvision distribution under `BSD-3-Clause` (https://github.com/pytorch/vision/blob/main/LICENSE). See the ImageNet provenance note below. | https://github.com/pytorch/vision — used via `torchvision.models.resnet18(weights=ResNet18_Weights.DEFAULT)` (`src/dehtr/model.py`) | 2026-07-29 |
|
| 117 |
| microsoft/trocr-base-handwritten | TrOCR English handwritten zero-shot baseline (M1) | `mit` (`.cardData.license`) | https://huggingface.co/api/models/microsoft/trocr-base-handwritten | 2026-07-28 |
|
| 118 |
+
| microsoft/trocr-small-handwritten | Fine-tuned encoder-decoder **accuracy reference** (M2); **not released** | **UNVERIFIED / no declared license.** The HF API returns no `.cardData.license`, no `.cardData.license_name`, and no license tag. Upstream TrOCR code and checkpoints originate from `microsoft/unilm`, which is `MIT` (https://github.com/microsoft/unilm/blob/master/LICENSE), but the model repo itself asserts nothing. Recorded as UNVERIFIED rather than assumed. Used only to train a non-released comparison reference; no weights derived from it are distributed. | https://huggingface.co/api/models/microsoft/trocr-small-handwritten | 2026-07-29 |
|
| 119 |
| mlx-community/Qwen2.5-VL-7B-Instruct-4bit | VLM zero-shot baseline, MLX 4-bit (M1) | `apache-2.0` (`.cardData.license`) | https://huggingface.co/api/models/mlx-community/Qwen2.5-VL-7B-Instruct-4bit | 2026-07-28 |
|
| 120 |
| Qwen/Qwen2.5-VL-7B-Instruct | Base VLM for the MLX quantized variant | `apache-2.0` (`.cardData.license`) | https://huggingface.co/api/models/Qwen/Qwen2.5-VL-7B-Instruct | 2026-07-28 |
|
| 121 |
| ~~Qwen/Qwen2.5-VL-3B-Instruct~~ (rejected) | Considered as the VLM baseline, **not used** | **Non-permissive** — `.cardData.license` absent; `.cardData.license_name` = `qwen-research` (research-only). Rejected in favour of the apache-2.0 7B variant; see DECISIONS.md D2 | https://huggingface.co/api/models/Qwen/Qwen2.5-VL-3B-Instruct | 2026-07-28 |
|
| 122 |
|
| 123 |
+
### ImageNet provenance note (release-relevant)
|
| 124 |
+
|
| 125 |
+
The released model's visual stem is initialized from torchvision's ImageNet-1k pretrained
|
| 126 |
+
ResNet-18 checkpoint, so those pretrained weights are **carried inside the released
|
| 127 |
+
artifact** — unlike the TrOCR and Qwen baselines, which are only evaluated against and never
|
| 128 |
+
redistributed. Two distinct licensing layers apply and are recorded separately:
|
| 129 |
+
|
| 130 |
+
1. **The checkpoint file** is distributed by the torchvision project under torchvision's
|
| 131 |
+
`BSD-3-Clause` license. BSD-3-Clause permits commercial redistribution with attribution,
|
| 132 |
+
which is the basis on which this project's Apache-2.0 release includes those weights.
|
| 133 |
+
2. **The ImageNet-1k images** the checkpoint was trained on are governed by the ImageNet
|
| 134 |
+
terms of access, which restrict the *images* to non-commercial research use. ImageNet
|
| 135 |
+
images are not redistributed by this project.
|
| 136 |
+
|
| 137 |
+
Whether restrictions on training images propagate to model weights trained on them is
|
| 138 |
+
legally unsettled and untested in court. The prevailing practice — and torchvision's own
|
| 139 |
+
distribution of these weights under BSD-3-Clause — treats the weights as freely reusable,
|
| 140 |
+
and this release relies on that reading. This is a **weaker guarantee** than the rest of the
|
| 141 |
+
register, where every input was chosen to be unambiguously permissive (DECISIONS.md D2). It is recorded explicitly here rather than left implicit. Anyone with a
|
| 142 |
+
stricter risk posture can retrain the stem from scratch: `CTCRecognizer(pretrained=False)`
|
| 143 |
+
in `src/dehtr/model.py` removes the ImageNet dependency entirely, at an accuracy cost that
|
| 144 |
+
this project has not measured.
|
| 145 |
+
|
| 146 |
+
---
|
| 147 |
+
|
| 148 |
+
## Files in this repository not covered by Apache-2.0
|
| 149 |
+
|
| 150 |
+
The Apache License 2.0 in `LICENSE` covers this project's own code and released model
|
| 151 |
+
artifacts. It does not relicense third-party inputs redistributed alongside them. Paths below
|
| 152 |
+
are relative to the GitHub source repository; neither file is part of the Hugging Face model
|
| 153 |
+
release:
|
| 154 |
+
|
| 155 |
+
| Path | License | Notice |
|
| 156 |
+
|------|---------|--------|
|
| 157 |
+
| `data/german_wikipedia_lines.txt` | `CC BY-SA 4.0` | `data/german_wikipedia_lines.LICENSE.txt` |
|
| 158 |
+
| `data/fonts/*.ttf` | `SIL OFL 1.1` | `data/fonts/licenses/`, `data/FONTS.md` |
|
| 159 |
+
|
| 160 |
+
Third-party assets redistributed by the **browser distribution** (ONNX Runtime Web, and the
|
| 161 |
+
Patrick Hand demo font) are recorded separately in `THIRD_PARTY_NOTICES.md`, with their
|
| 162 |
+
complete license texts under `third_party/`.
|
| 163 |
+
|
| 164 |
---
|
| 165 |
|
| 166 |
Every entry is verified with a source URL and access date as noted above. Unverifiable items are marked UNVERIFIED rather than guessed.
|