Store the recognizers' and layout model's weights in fp16 (half the download)
Browse filesWeights are stored as fp16 and cast to float32 at load; ONNX Runtime folds the casts. CPU text identical on 325/325 lines, layout pages identical. lines/ unchanged. Model card updated for netra-ocr 1.2.0.
- README.md +23 -22
- layout/model.onnx +2 -2
- layout/netra-model.json +1 -1
- recognition-blockwise/decoder_step.onnx +2 -2
- recognition-blockwise/encoder.onnx +2 -2
- recognition-blockwise/netra-model.json +2 -2
- recognition/decoder_step.onnx +2 -2
- recognition/encoder.onnx +2 -2
- recognition/netra-model.json +2 -2
README.md
CHANGED
|
@@ -12,7 +12,6 @@ tags:
|
|
| 12 |
- khmer-ocr
|
| 13 |
- document-layout
|
| 14 |
- onnx
|
| 15 |
-
- netra-runtime
|
| 16 |
- netra-lab
|
| 17 |
---
|
| 18 |
|
|
@@ -24,56 +23,58 @@ tags:
|
|
| 24 |
|
| 25 |
<p align="center">
|
| 26 |
<a href="https://github.com/netra-ai-lab/Netra-OCR"><b>GitHub</b></a> |
|
| 27 |
-
<a href="https://github.com/netra-ai-lab/Netra-Runtime"><b>Netra Runtime</b></a> |
|
| 28 |
<a href="https://pypi.org/project/netra-ocr/"><b>PyPI</b></a> |
|
| 29 |
<a href="https://huggingface.co/Darayut/khmer-text-recognition"><b>PyTorch weights</b></a>
|
| 30 |
</p>
|
| 31 |
|
| 32 |
# Netra OCR
|
| 33 |
|
| 34 |
-
The models behind the Netra OCR app, exported
|
| 35 |
|
| 36 |
-
Each folder is one
|
| 37 |
|
| 38 |
-
| Folder | Task | What it is | Variants |
|
| 39 |
-
|---|---|---|---|
|
| 40 |
-
| `recognition/` | text recognition | Khmer + English line recognizer, 19M params, greedy decoding with a KV cache | – |
|
| 41 |
-
| `recognition-blockwise/` | text recognition | the same recognizer plus a blockwise proposal head (same output, fewer decoder passes) | – |
|
| 42 |
-
| `lines/` | object detection | YOLO text-line and logo detector | `fp16` (CUDA default) |
|
| 43 |
-
| `layout/` | object detection | DocLayout-YOLO (DocStructBench) page-layout analyzer | `fp16` (CUDA default) |
|
|
|
|
|
|
|
| 44 |
|
| 45 |
## Usage
|
| 46 |
|
| 47 |
```bash
|
| 48 |
-
pip install "netra-
|
| 49 |
```
|
| 50 |
|
| 51 |
```python
|
| 52 |
-
import
|
| 53 |
|
| 54 |
-
recognizer =
|
| 55 |
print(recognizer("line.png").text)
|
| 56 |
|
| 57 |
-
detector =
|
| 58 |
for box in detector("page.png"):
|
| 59 |
print(box.label, box.score, box.box)
|
| 60 |
```
|
| 61 |
|
| 62 |
```js
|
| 63 |
-
|
| 64 |
-
|
|
|
|
| 65 |
const { text } = await recognizer.recognize(imageElement);
|
| 66 |
```
|
| 67 |
|
| 68 |
-
`hf://` downloads only the folder you ask for, once, into the Hugging Face cache. For whole pages (detection, layout, reading order, Word/HTML/Markdown export) use the
|
| 69 |
|
| 70 |
## Parity and speed
|
| 71 |
|
| 72 |
Measured against the PyTorch models on `test_set/khob_eval` (325 lines) and 10 test pages, on an i7-13700KF and an RTX 3060.
|
| 73 |
|
| 74 |
- **Recognizer:** text identical to PyTorch greedy decoding on 325/325 lines, on CPU and CUDA, single and batched. Per line: CPU 36.7 → about 13 ms, CUDA 23 → 12.8 ms.
|
| 75 |
-
- **Blockwise:** identical text, 2.32 tokens per decoder pass. Not faster than the KV-cached greedy decoder on CPU
|
| 76 |
-
- **Full page pipeline:** CPU 2.18 → 1.14 s/page, GPU 1.24 → 0.70 s/page. 7 of 10 pages identical to the PyTorch pipeline, 0.43% characters different overall (letterbox resize is
|
| 77 |
- **fp16:** default on CUDA for the detectors (DocLayout 65 → 39 ms). Not used on WebGPU, where it is broken in onnxruntime-web 1.31.
|
| 78 |
- **Browser:** WebAssembly gives the same text on 325/325 lines and detector boxes at IoU 1.0; WebGPU in Chrome gave the same text on 100/100 lines.
|
| 79 |
|
|
@@ -83,11 +84,11 @@ The recognizer's CER is the PyTorch model's: see [Darayut/khmer-text-recognition
|
|
| 83 |
|
| 84 |
| File | Contents |
|
| 85 |
|---|---|
|
| 86 |
-
| `*/netra-model.json` |
|
| 87 |
| `*/*.onnx` | opset-18 graphs (`encoder`/`decoder_step` for recognition, `model` for detection) |
|
| 88 |
-
| `recognition*/vocab.json` | tokenizer vocabulary (class names of the detectors are in the
|
| 89 |
|
| 90 |
-
The
|
| 91 |
|
| 92 |
## License and attribution
|
| 93 |
|
|
|
|
| 12 |
- khmer-ocr
|
| 13 |
- document-layout
|
| 14 |
- onnx
|
|
|
|
| 15 |
- netra-lab
|
| 16 |
---
|
| 17 |
|
|
|
|
| 23 |
|
| 24 |
<p align="center">
|
| 25 |
<a href="https://github.com/netra-ai-lab/Netra-OCR"><b>GitHub</b></a> |
|
|
|
|
| 26 |
<a href="https://pypi.org/project/netra-ocr/"><b>PyPI</b></a> |
|
| 27 |
<a href="https://huggingface.co/Darayut/khmer-text-recognition"><b>PyTorch weights</b></a>
|
| 28 |
</p>
|
| 29 |
|
| 30 |
# Netra OCR
|
| 31 |
|
| 32 |
+
The models behind the Netra OCR app, exported to ONNX. Each folder holds the ONNX graphs plus a `netra-model.json` config with the settings the app's pre- and post-processing need (line height and chunk width, decoder shape, class names, thresholds). The [`netra-ocr`](https://pypi.org/project/netra-ocr/) package runs them on ONNX Runtime on CPU and CUDA, and its [`web/`](https://github.com/netra-ai-lab/Netra-OCR/tree/master/web) folder runs the same files in the browser (WebGPU / WebAssembly), with no PyTorch.
|
| 33 |
|
| 34 |
+
Each folder is one model:
|
| 35 |
|
| 36 |
+
| Folder | Task | What it is | Download | Variants |
|
| 37 |
+
|---|---|---|---|---|
|
| 38 |
+
| `recognition/` | text recognition | Khmer + English line recognizer, 19M params, greedy decoding with a KV cache | 41 MB | – |
|
| 39 |
+
| `recognition-blockwise/` | text recognition | the same recognizer plus a blockwise proposal head (same output, fewer decoder passes) | 44 MB | – |
|
| 40 |
+
| `lines/` | object detection | YOLO text-line and logo detector | 38 MB (19 MB on CUDA) | `fp16` (CUDA default) |
|
| 41 |
+
| `layout/` | object detection | DocLayout-YOLO (DocStructBench) page-layout analyzer | 39 MB | `fp16` (CUDA default) |
|
| 42 |
+
|
| 43 |
+
A full page pipeline on the CPU downloads about 118 MB. The recognizers' and the layout model's weights are *stored* in half precision and cast back to float32 when the model loads, so they run in float32 at the same speed; only the weights' rounding changes. On 325 test lines, the text matches the float32 files on 325/325 lines on the CPU and 321/325 on CUDA (on the other 4, the number of errors against the labels is unchanged). The layout model gives identical pages. The line detector stays float32, because half-precision storage moved boxes on 2 of 10 test pages.
|
| 44 |
|
| 45 |
## Usage
|
| 46 |
|
| 47 |
```bash
|
| 48 |
+
pip install "netra-ocr[cpu]" # or [gpu] for CUDA
|
| 49 |
```
|
| 50 |
|
| 51 |
```python
|
| 52 |
+
from netra_ocr.inference import Detector, Recognizer
|
| 53 |
|
| 54 |
+
recognizer = Recognizer("hf://Netra-Lab/Netra-OCR/recognition") # device: "auto" (default), "cpu", "cuda"
|
| 55 |
print(recognizer("line.png").text)
|
| 56 |
|
| 57 |
+
detector = Detector("hf://Netra-Lab/Netra-OCR/lines")
|
| 58 |
for box in detector("page.png"):
|
| 59 |
print(box.label, box.score, box.box)
|
| 60 |
```
|
| 61 |
|
| 62 |
```js
|
| 63 |
+
// web/src/index.js in the Netra-OCR repo
|
| 64 |
+
import { loadRecognizer } from "./web/src/index.js";
|
| 65 |
+
const recognizer = await loadRecognizer("hf://Netra-Lab/Netra-OCR/recognition");
|
| 66 |
const { text } = await recognizer.recognize(imageElement);
|
| 67 |
```
|
| 68 |
|
| 69 |
+
`hf://` downloads only the folder you ask for, and only the files your device runs, once, into the Hugging Face cache. For whole pages (detection, layout, reading order, Word/HTML/Markdown export) use `netra_ocr.KhmerOCRPipeline`, the `netra_ocr serve` web app or the Netra OCR Docker image.
|
| 70 |
|
| 71 |
## Parity and speed
|
| 72 |
|
| 73 |
Measured against the PyTorch models on `test_set/khob_eval` (325 lines) and 10 test pages, on an i7-13700KF and an RTX 3060.
|
| 74 |
|
| 75 |
- **Recognizer:** text identical to PyTorch greedy decoding on 325/325 lines, on CPU and CUDA, single and batched. Per line: CPU 36.7 → about 13 ms, CUDA 23 → 12.8 ms.
|
| 76 |
+
- **Blockwise:** identical text, 2.32 tokens per decoder pass. Not faster than the KV-cached greedy decoder on CPU, CUDA or WebGPU (82 vs 85 ms per line in Chrome).
|
| 77 |
+
- **Full page pipeline:** CPU 2.18 → 1.14 s/page, GPU 1.24 → 0.70 s/page. 7 of 10 pages identical to the PyTorch pipeline, 0.43% characters different overall (the letterbox resize is Netra OCR's own float64 bilinear resize rather than OpenCV's, which moves about 1% of borderline boxes).
|
| 78 |
- **fp16:** default on CUDA for the detectors (DocLayout 65 → 39 ms). Not used on WebGPU, where it is broken in onnxruntime-web 1.31.
|
| 79 |
- **Browser:** WebAssembly gives the same text on 325/325 lines and detector boxes at IoU 1.0; WebGPU in Chrome gave the same text on 100/100 lines.
|
| 80 |
|
|
|
|
| 84 |
|
| 85 |
| File | Contents |
|
| 86 |
|---|---|
|
| 87 |
+
| `*/netra-model.json` | config: pre/post-processing settings, graphs, precision variants, sha256 of every file |
|
| 88 |
| `*/*.onnx` | opset-18 graphs (`encoder`/`decoder_step` for recognition, `model` for detection) |
|
| 89 |
+
| `recognition*/vocab.json` | tokenizer vocabulary (class names of the detectors are in the config) |
|
| 90 |
|
| 91 |
+
The Python reader is [`netra_ocr/inference/`](https://github.com/netra-ai-lab/Netra-OCR/tree/master/netra_ocr/inference); the exporters are in [`training/netra_ocr_train/scripts/`](https://github.com/netra-ai-lab/Netra-OCR/tree/master/training/netra_ocr_train/scripts).
|
| 92 |
|
| 93 |
## License and attribution
|
| 94 |
|
layout/model.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:87b1b6b983f7120547342ab23d0564fb2b3766f23048a297590d73919aee8383
|
| 3 |
+
size 39405559
|
layout/netra-model.json
CHANGED
|
@@ -48,6 +48,6 @@
|
|
| 48 |
},
|
| 49 |
"files": {
|
| 50 |
"model.fp16.onnx": "6fbbe1a2d71b09f937e50b46b81adad0a54f06fcbae406a0fa3c2aafaa1585f2",
|
| 51 |
-
"model.onnx": "
|
| 52 |
}
|
| 53 |
}
|
|
|
|
| 48 |
},
|
| 49 |
"files": {
|
| 50 |
"model.fp16.onnx": "6fbbe1a2d71b09f937e50b46b81adad0a54f06fcbae406a0fa3c2aafaa1585f2",
|
| 51 |
+
"model.onnx": "87b1b6b983f7120547342ab23d0564fb2b3766f23048a297590d73919aee8383"
|
| 52 |
}
|
| 53 |
}
|
recognition-blockwise/decoder_step.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9333350eb3398dfd41cb9734755493e562d10c4dd221234df06e0ae2a3d3d55c
|
| 3 |
+
size 16785190
|
recognition-blockwise/encoder.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a2b599925350e191c8dbc86126842cef7eb4b621a8e5ef276ce4b5d730beb9c6
|
| 3 |
+
size 27335904
|
recognition-blockwise/netra-model.json
CHANGED
|
@@ -44,8 +44,8 @@
|
|
| 44 |
"license": "MIT"
|
| 45 |
},
|
| 46 |
"files": {
|
| 47 |
-
"decoder_step.onnx": "
|
| 48 |
-
"encoder.onnx": "
|
| 49 |
"vocab.json": "d55b8578e66dd4069f3abdaf01d0993f8526587dbebec78dcbcd15c514a6268b"
|
| 50 |
}
|
| 51 |
}
|
|
|
|
| 44 |
"license": "MIT"
|
| 45 |
},
|
| 46 |
"files": {
|
| 47 |
+
"decoder_step.onnx": "9333350eb3398dfd41cb9734755493e562d10c4dd221234df06e0ae2a3d3d55c",
|
| 48 |
+
"encoder.onnx": "a2b599925350e191c8dbc86126842cef7eb4b621a8e5ef276ce4b5d730beb9c6",
|
| 49 |
"vocab.json": "d55b8578e66dd4069f3abdaf01d0993f8526587dbebec78dcbcd15c514a6268b"
|
| 50 |
}
|
| 51 |
}
|
recognition/decoder_step.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:adf53d37dc558f562d2a1eddcde723d36eda2c2d922a6fe3c9864bbe51e12647
|
| 3 |
+
size 13227369
|
recognition/encoder.onnx
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3e6c1b4984cdaf7578d9f591e1c3117df3b90c2a04fb2a18f274b19e4888c475
|
| 3 |
+
size 27335166
|
recognition/netra-model.json
CHANGED
|
@@ -43,8 +43,8 @@
|
|
| 43 |
"license": "MIT"
|
| 44 |
},
|
| 45 |
"files": {
|
| 46 |
-
"decoder_step.onnx": "
|
| 47 |
-
"encoder.onnx": "
|
| 48 |
"vocab.json": "d55b8578e66dd4069f3abdaf01d0993f8526587dbebec78dcbcd15c514a6268b"
|
| 49 |
}
|
| 50 |
}
|
|
|
|
| 43 |
"license": "MIT"
|
| 44 |
},
|
| 45 |
"files": {
|
| 46 |
+
"decoder_step.onnx": "adf53d37dc558f562d2a1eddcde723d36eda2c2d922a6fe3c9864bbe51e12647",
|
| 47 |
+
"encoder.onnx": "3e6c1b4984cdaf7578d9f591e1c3117df3b90c2a04fb2a18f274b19e4888c475",
|
| 48 |
"vocab.json": "d55b8578e66dd4069f3abdaf01d0993f8526587dbebec78dcbcd15c514a6268b"
|
| 49 |
}
|
| 50 |
}
|