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).

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.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Spaces using nutrientdocs/form-field-v1-nano 2