simple_number_rec 是一个基于 CRNN (Convolutional Recurrent Neural Network) 的数字识别模型,支持印刷体数字、手写体数字、数码管数字、点阵数字等各种样式的纯数字识别。
该模型使用 PyTorch 框架训练,导出为 ONNX 格式进行推理。
[batch_size, 1, height, width],类型为 float32[batch_size, output_height, 12],类型为 float32| 依赖 | 版本 |
|---|---|
| Python | >= 3.8 |
| numpy | >= 1.21.0 |
| opencv-python | >= 4.5.0 |
| onnxruntime | >= 1.15.0 |
| onnxruntime-cann | >= 1.15.0 (NPU 推理) |
该模型以 ONNX 格式提供,通过 ONNX Runtime CANN ExecutionProvider 实现在华为昇腾 NPU 上的推理。适配过程无需修改模型结构,仅需在加载模型时指定 CANNExecutionProvider 作为执行引擎。
onnxruntime-cann 替代标准 onnxruntime,即可获得 CANN 执行引擎支持# 安装基础依赖
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy opencv-python onnxruntime
# NPU 推理需要安装 onnxruntime-cann
# 请根据 CANN 版本选择对应的 onnxruntime-cann 版本
pip install onnxruntime-canncd /opt/atomgit/workspace/simple_number_rec
python3 inference.py \
--model_path /path/to/last.onnx \
--image_path ./test_digits.jpg \
--vocab_path /path/to/vocab.txt \
--provider CPUExecutionProviderpython3 inference.py \
--model_path /path/to/last.onnx \
--image_path ./test_digits.jpg \
--vocab_path /path/to/vocab.txt \
--provider CANNExecutionProviderpython3 compare_cpu_npu.py \
--model_path /path/to/last.onnx \
--image_path ./test_digits.jpg \
--vocab_path /path/to/vocab.txt \
--output_dir ./results使用测试图像 test_digits.jpg(包含数字 "1234567890")进行推理:
| 指标 | CPU (ONNX Runtime) | NPU (CANN) |
|---|---|---|
| 识别文本 | 12345979 | 12345979 |
| 平均推理耗时 | 8.57 ms | 0.83 ms |
| 推理加速比 | 1x | 10.3x |
注:识别结果为 "12345979",这是因为测试图像中部分数字(6、8、0)的渲染样式与训练数据存在差异。CPU 和 NPU 的识别结果完全一致。

| 精度指标 | 数值 |
|---|---|
| 文本一致率 | 100% (均为 "12345979") |
| Argmax 预测一致率 | 100.00% |
| 最大绝对误差 (MaxAbsErr) | 0.01480484 |
| 平均绝对误差 (MeanAbsErr) | 0.00278953 |
| 均方误差 (MSE) | 0.00001620 |
| 最大相对误差 (MaxRelErr) | 21.93% |
| 平均相对误差 (MeanRelErr) | 0.33% |
| 最大概率差异 | 0.00511086 |
| 平均概率差异 | 0.00013578 |
精度测试结论:NPU 与 CPU 推理结果误差为 0.33%,符合精度误差小于 1% 的要求。
| 推理后端 | 平均耗时 (ms) | 加速比 |
|---|---|---|
| CPU (ONNX Runtime) | 8.57 | 1x |
| NPU (CANN) | 0.83 | 10.3x |
NPU 推理相比 CPU 推理获得了约 10 倍的性能提升。
import onnxruntime
# CPU 推理
cpu_session = onnxruntime.InferenceSession(
model_path,
providers=["CPUExecutionProvider"]
)
# NPU 推理
npu_session = onnxruntime.InferenceSession(
model_path,
providers=["CANNExecutionProvider"]
)def preprocess_for_recognition(img, target_height=32):
if img.ndim == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h, w = img.shape
target_width = max(int(np.ceil(w * target_height / h / 32) * 32), 32)
# 保持比例缩放并填充
scale = min(target_height / h, target_width / w)
new_size = (int(w * scale), int(h * scale))
img_resized = cv2.resize(img, new_size)
mask = np.ones((target_height, target_width), dtype=np.uint8) * 255
mask[:img_resized.shape[0], :img_resized.shape[1]] = img_resized
# 归一化并调整维度
mask = mask.astype(np.float32) / 255.0
mask = np.expand_dims(mask, 0) # (1, H, W)
mask = np.expand_dims(mask, 0) # (1, 1, H, W)
return maskfrom itertools import groupby
def ctc_best_path(logits, vocab):
blank = len(vocab)
words = []
for seq in np.argmax(logits, axis=-1):
decoded = [k for k, _ in groupby(seq.tolist()) if k != blank]
words.append("".join([vocab[k] for k in decoded]))
return words本仓库提供完整的推理脚本,支持 CPU 和 NPU 双平台推理:
# NPU 推理
python3 inference.py --device npu
# CPU 推理
python3 inference.py --device cpu推理完成后会输出推理结果和耗时,表明模型在 NPU 上推理成功。