tract, onnxruntime, etc.).| File | Size | Description |
|---|---|---|
cpdaily_captcha_ocr.onnx | 2.24 MB | fp32 full-precision master / fp32 全精度母本 |
cpdaily_captcha_ocr_fp16.onnx | 1.07 MB | fp16-stored, fp32-compute (lossless, recommended) / fp16 存储 fp32 计算, 无损, 推荐部署 |
charset.json | — | Character table, index 0 = CTC blank / 字符表, index 0 为 CTC blank |
config.json | — | Input size, preprocessing, decode info / 输入尺寸、预处理、解码信息 |
The fp16 file stores weights as fp16 withCast(fp16→fp32)nodes; inference engines constant-fold them at optimization time, so computation stays fp32 (no accuracy loss) while the file is half the size. This avoids engines that don't support fp16 compute ops (GRU/Conv). Standard fp16 conversion and int8 quantization were tested and fail to load intract— this fp16-cast format is the compatible compression path.fp16 版以 fp16 存权重 +Cast节点, 推理时常量折叠回 fp32 计算(精度无损), 体积砍半, 且规避了部分引擎不支持 fp16/量化算子的限制。
| Architecture | Depthwise-separable CNN + 2-layer BiGRU + FC, CTC decode |
| Charset | 62 classes: A-Z + a-z + 0-9 (+1 CTC blank = 63) |
| Input | grayscale, resized to 32 × 160, normalized to [0,1] |
| Output | [T, 63] log-softmax, CTC greedy decode |
| Accuracy | 99.37% full-string (99.7% char-level) on a hand-verified validation set |
| Size | fp32 2.24 MB / fp16 1.07 MB (lossless compression) |
1import json, numpy as np, onnxruntime as ort
2from PIL import Image
3
4chars = json.load(open("charset.json")) # ["<blank>", "A", "B", ...]
5sess = ort.InferenceSession("cpdaily_captcha_ocr_fp16.onnx",
6 providers=["CPUExecutionProvider"])
7inp = sess.get_inputs()[0].name
8
9def recognize(path):
10 img = Image.open(path).convert("L").resize((160, 32), Image.BILINEAR)
11 x = (np.asarray(img, dtype=np.float32) / 255.0)[None, None, :, :]
12 logits = sess.run(None, {inp: x})[0][0] # [T, 63]
13 idx = logits.argmax(-1)
14 out, prev = [], -1
15 for p in idx: # CTC greedy: dedup + drop blank
16 if p != prev and p != 0:
17 out.append(chars[p])
18 prev = p
19 return "".join(out)
20
21print(recognize("captcha.png"))1use tract_onnx::prelude::*;
2
3let model = tract_onnx::onnx()
4 .model_for_path("cpdaily_captcha_ocr_fp16.onnx")?
5 .with_input_fact(0, InferenceFact::dt_shape(f32::datum_type(), tvec!(1, 1, 32, 160)))?
6 .into_optimized()?
7 .into_runnable()?;
8// preprocess to [1,1,32,160] f32 in [0,1], run, then CTC-greedy decode the [T,63] output.