form-field-v1-nano β open-weight
A 0.90M-parameter form-field detector that punches far above its weight. Locates Text, Choice
(checkbox/radio), and Signature widgets on document pages β on empty, filled, and handwritten forms β
at 3.7 MB and ~90 pages/sec on a laptop CPU. Apache-2.0, downloadable, runs via ONNX Runtime with no
custom code.
Part of the form-field-v1 family (-nano open Β· -small / -medium commercial, higher accuracy).
- π― Try it: form-field-v1-demo
- π Leaderboard: form-field-v1-leaderboard
- π Benchmark: form-field-v1-benchmark
Why it's notable
At 0.90M params it detects Text, Choice, and Signature across empty, filled, and handwritten
forms β at 3.7 MB and ~90 pages/sec on a laptop CPU.
| Model | Params | Empty mAP50-95 | Filled | Handwritten |
|---|---|---|---|---|
| form-field-v1-nano | 0.90M | 0.353 | 0.560 | 0.526 |
| FFDNet-S (baseline) | 6M | 0.339 | 0.312 | 0.262 |
| FFDNet-L (baseline) | 25M | 0.373 | 0.285 | 0.285 |
COCO mAP50-95, one shared pycocotools scorer across all models. On empty, per-class it reaches Text 0.469 / Choice 0.407 / Signature 0.182.
What's in this repo
| File | |
|---|---|
model.onnx |
ONNX graph (fp32), input 1Γ3Γ640Γ640, decode baked in |
model_fp16.onnx |
fp16 ONNX (1.9 MB), near-lossless |
best_ckpt.pth |
training checkpoint |
exp.py |
model/training config (YOLOX exp) |
Classes: 0 = Text, 1 = ChoiceButton, 2 = Signature.
Usage (torch)
The checkpoint is a YOLOX-Nano model (best_ckpt.pth + exp.py); run it with the
yolox package.
import torch, numpy as np
from PIL import Image
from yolox.exp import get_exp
from yolox.utils import postprocess
exp = get_exp("exp.py"); model = exp.get_model().eval()
model.load_state_dict(torch.load("best_ckpt.pth", map_location="cpu")["model"])
S = 640
img = Image.open("page.png").convert("RGB")
r = min(S / img.width, S / img.height) # letterbox to SxS, pad 114, raw 0-255 (no normalize)
rs = img.resize((int(img.width * r), int(img.height * r)))
canvas = Image.new("RGB", (S, S), (114, 114, 114)); canvas.paste(rs, (0, 0))
x = torch.from_numpy(np.asarray(canvas, np.float32).transpose(2, 0, 1)[None])
with torch.no_grad():
dets = postprocess(model(x), num_classes=3, conf_thre=0.3, nms_thre=0.6)[0] # x1,y1,x2,y2,obj,cls_score,cls
# divide boxes by r to map back to page pixels; class 0=Text, 1=ChoiceButton, 2=Signature
Usage (ONNX Runtime)
import numpy as np, onnxruntime as ort
from PIL import Image
sess = ort.InferenceSession("model.onnx", providers=["CPUExecutionProvider"])
S = 640
img = Image.open("page.png").convert("RGB")
r = min(S / img.width, S / img.height)
rs = img.resize((int(img.width * r), int(img.height * r)))
canvas = Image.new("RGB", (S, S), (114, 114, 114)); canvas.paste(rs, (0, 0))
x = np.asarray(canvas, np.float32).transpose(2, 0, 1)[None]
out = sess.run(None, {sess.get_inputs()[0].name: x})[0] # [1, 8400, 8] β already DECODED (boxes in 640px)
# rows: [cx, cy, w, h, obj, cls_Text, cls_Choice, cls_Signature].
score = out[0, :, 4:5] * out[0, :, 5:8] # obj * class prob; take argmax class, NMS per class,
# convert cx,cy,w,h -> x1,y1,x2,y2, then divide by r to map back to page pixels.
Verified: running this ONNX end-to-end on the full benchmark reproduces the torch model β
fp32 mAP50-95 = 0.4788, fp16 (model_fp16.onnx) = 0.4777 (torch = 0.479). The ONNX is exported with
decode baked in (tools/export_onnx.py --decode_in_inference), so no external grid-decode is needed.
Footprint: model_fp16.onnx (1.9 MB) halves the fp32 file with near-lossless accuracy (0.4777 vs 0.4788).
fp16 is a size/GPU optimization β no CPU-speed change. For an even smaller bundle, INT8 shrinks further but its
speed only materializes on an int8-optimized mobile backend (CoreML / NNAPI / TFLite-XNNPACK), not desktop
ORT-CPU.
License & data
Apache-2.0. Trained on synthetic form renders (empty + filled + handwritten); no PII. Reproduction details in
the project's docs/YOLOX.md.
About the author
This project is maintained and funded by Nutrient - The deterministic document infrastructure enterprises run their highest-stakes workflows on: replayable output, clear exceptions, and full audit trails on the messy, regulated documents where AI alone breaks.