mlboydaisuke's picture
Upload README.md with huggingface_hub
1877087 verified
|
Raw
History Blame Contribute Delete
3.2 kB
metadata
license: apache-2.0
tags:
  - executorch
  - xnnpack
  - pte
  - on-device
  - object-detection
  - text-detection

docTR DB-MobileNetV3-Large — ExecuTorch

Text detection: where the words are. The other half of the pair is CRNN-MobileNetV3-Small, which reads them.

  • Source: mindee/doctr db_mobilenet_v3_large, 4.2M parameters
  • License: Apache-2.0
  • Input: [1, 3, 1024, 1024], normalised with docTR's own mean (0.798, 0.785, 0.772) and std (0.264, 0.2749, 0.287) — not ImageNet's
  • Output: [1, 1, 1024, 1024], one probability per pixel of belonging to a word

Differentiable Binarization returns a shrunk region per word; turning the map into boxes is docTR's postprocessor, which unshrinks the polygons. That stays on the caller, the way the shelf's other detectors leave NMS outside.

Verification (Mac arm64, 2026-08-23)

build size latency worst corr
XNNPACK fp32 16.1 MB 46.9 ms 1.000000
Core ML fp32 8.6 MB 13.1 ms 0.999714

Eager fp32 for the same input is 309 ms. Delegation is 100% (224/224 ops, one subgraph).

Read end to end, both .pte files through docTR's own post-processing, on a London street photograph (convert/check_doctr.py):

boxes: 10
read: TIUZABXPRESS | Chrisiophers | Place | STREE! | LAG | BAR!

The signs in that photograph say PIZZA EXPRESS and Christopher's Place. Approximate, and that is the point of quoting it: correlation against eager says the tensors match, and says nothing about whether the map thresholds to any boxes at all.

Not shipped, and why

  • int8: worst corr 0.627. It is 4.3 MB against 16.1, which is the trade this shelf would normally take, but not at that number.
  • fp16: corr 0.999879 and it passes, but the file is the same 16.1 MB — the weights are convolutions XNNPACK already runs in fp32, so there is nothing to buy.

The mistake worth repeating back

The harness gates on correlation against eager for random input. This file scored 1.000000 there and then produced a map that thresholded to zero boxes on a real photograph. The cause was not the export:

                corr     pte max   pixels > 0.3
as built      0.024711    0.2385         0
.contiguous() 1.000000    0.5639      1816

np.transpose leaves the array in HWC order with permuted strides, and ExecuTorch reads a tensor in memory order rather than by its strides. Random and all-zero inputs are contiguous, so the gate never saw it. Anything built with transpose needs np.ascontiguousarray before it reaches a .pte.

Conversion

python convert/export_doctr.py detect
python convert/check_doctr.py <image>

docTR's forward runs its post-processing in numpy whether or not it was asked to, which torch.export refuses (.numpy() is not supported for tensor subclasses). The model carries an exportable flag that skips it and returns raw logits; the wrapper sets that and applies the sigmoid itself.

(conversion scripts: executorch-models)