File size: 5,150 Bytes
b80941f
 
 
ff65f98
 
 
 
 
 
 
 
 
 
 
7f05070
 
 
 
 
ff65f98
 
 
 
 
 
 
 
 
 
 
 
7f05070
ff65f98
7f05070
ff65f98
7f05070
ff65f98
7f05070
 
 
 
 
 
 
 
 
ff65f98
7f05070
 
 
 
 
ff65f98
7f05070
 
 
 
 
 
 
 
ff65f98
7f05070
ff65f98
7f05070
 
 
 
 
ff65f98
7f05070
 
 
 
 
ff65f98
7f05070
ff65f98
7f05070
 
 
 
ff65f98
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
---
license: mit
---
# Introduction

This repository hosts the [EasyOCR](https://github.com/JaidedAI/EasyOCR) models — the
[CRAFT detector](https://github.com/clovaai/CRAFT-pytorch) and the [CRNN recognizer](https://www.jaided.ai/easyocr/modelhub/) — for the
[React Native ExecuTorch](https://www.npmjs.com/package/react-native-executorch) library,
exported to `.pte` for the **ExecuTorch** runtime (XNNPACK, CoreML and Vulkan backends).

If you'd like to run these models in your own ExecuTorch runtime, refer to the
[official documentation](https://pytorch.org/executorch/stable/index.html) for setup instructions.

Each language ships as **one fused `.pte`** (CRAFT *detect* + CRNN *recognize* in a single
file) per backend, with a single **dynamic** `detect` method and one fixed-width `recognize`
method (no per-size method buckets). The `.pte` is a pure tensor→tensor function; all
pre/post-processing (resize, normalize, box extraction, crop, CTC decode) is the client's job
and is driven by `config.json`. EasyOCR is the *fallback* pipeline —
[PP-OCRv6](https://huggingface.co/software-mansion/react-native-executorch-pp-ocrv6) is primary.

## Languages

| code | charset size | code | charset size |
|---|---|---|---|
| english | 96 | korean | 1008 |
| latin | 351 | telugu | 165 |
| japanese | 2214 | kannada | 167 |
| zh_sim | 6718 | cyrillic | 207 |

All languages share the same CRAFT detector and CRNN architecture — they differ **only** in
the recognizer charset. The detector half of each fused PTE is identical across languages.
Charset index `i` maps to logit `i + 1` (logit `0` is the CTC blank).

## Methods & I/O contract

| method | input | output |
|---|---|---|
| `detect` (CRAFT) | `[1,3,H,W]` f32 RGB, **ImageNet-normalized by the client**: `(x/255 − mean)/std`, `mean=[0.485,0.456,0.406]`, `std=[0.229,0.224,0.225]` | score `[1,H/2,W/2,2]` (region + affinity, NHWC) and feature `[1,32,H/2,W/2]` |
| `recognize` (CRNN) | `[1,3,64,512]` f32 RGB, client-normalized `(x/255 − 0.5)/0.5` (RGB→gray conv is baked) | `[1,127,V]` probs (softmax baked) |

**Nothing is baked for input normalization** — the client normalizes before calling, with
*different* norms per method (ImageNet for detect, `0.5/0.5` for recognize).

## Shape discovery (companion methods)

Every method carries exactly **one** no-arg discovery companion:

- `get_dynamic_dims_<method>` — dynamic method. One `int32 [rank, 3]` tensor per tensor
  input; rows are `[min, max, step]` (static dims `[n, n, 1]`).
- `get_enum_shapes_<method>` — enumerated/fixed method. One `int32 [N, rank]` tensor per
  tensor input; each row is a complete legal shape (cross-dimension coupling is exact —
  `1280×320` listed does **not** imply `320×1280`). Snap inputs to the nearest row.

| backend | `detect` | `recognize` |
|---|---|---|
| `xnnpack` | `get_dynamic_dims_detect` → H, W ∈ `[320, 1280]` step 32 | `get_enum_shapes_recognize``[[1,3,64,512]]` |
| `vulkan` | `get_dynamic_dims_detect` → H ∈ `[800, 1280]`, W ∈ `[320, 1280]` step 32 | `get_enum_shapes_recognize``[[1,3,64,512]]` |
| `coreml` | `get_enum_shapes_detect``800²`, `1280²`, `1280×320` | `get_enum_shapes_recognize``[[1,3,64,512]]` |

`detect` runs once per image; `recognize` runs once per text line (the client snaps every
crop to width 512 — the CRNN's BiLSTM only delegates at a fixed time dimension).

## Backends

| backend | target | detect | recognize | warm latency (detect @800² / recognize) |
|---|---|---|---|---|
| `xnnpack` | CPU | int8, dynamic (see note) | int8 @512 | ~810 ms / ~24 ms (Galaxy S24) |
| `coreml` | Apple ANE | weight-only int8, enumerated | weight-only int8 @512 | ~83 ms / ~27 ms (Apple M-series ANE) |
| `vulkan` | Android GPU | fp16, dynamic (resize) | int8 @512 on **XNNPACK** (mixed-delegate) | ~750 ms / ~24 ms (Galaxy S24, Xclipse 940) |

> **XNNPACK detect accuracy note:** the int8 detector is calibrated for sizes **≤ 800 px**
> (its accurate operating band). Larger inputs up to 1280 are accepted but **best-effort**
> static-activation int8 is not stable at ≥ 960 px (this was equally true, though unmeasured,
> of the previous per-bucket builds). Prefer resizing pages to ≤ 800 on CPU; the Vulkan and
> CoreML detectors are accurate over their full advertised ranges.

## CoreML notes (iOS)

- The CoreML `.pte` is a **multifunction** Core ML model (`detect` + `recognize` share one
  precompiled `.mlmodelc`). Requires **iOS 18+** and an ExecuTorch runtime ≥ 1.3.
- First-ever load on a device triggers a one-time per-shape ANE specialization (OS-cached
  afterwards) — warm each model once after install.

## Compatibility

If you intend to use these models outside of React Native ExecuTorch, make sure your runtime is
compatible with the **ExecuTorch** version used to export the `.pte` files. For more details, see
the compatibility note in the
[ExecuTorch GitHub repository](https://github.com/pytorch/executorch/blob/main/runtime/COMPATIBILITY.md).
If you work with React Native ExecuTorch, the library constants guarantee compatibility with the
runtime used behind the scenes.