去年帮本地一所中学做试卷数字化归档时,发现市面上通用OCR对中小学生手写体的识别准确率普遍低于60%。特别是数学公式和潦草笔迹,几乎无法直接使用。经过两周的实测对比,最终选择PaddleOCR作为基础框架进行微调,将识别准确率提升到89%以上。这套方法后来被周边多所学校采用,今天就把完整实施方案分享给大家。
手写体识别在教育场景有三大刚需:
相比打印体OCR,手写体识别要解决三个特殊问题:
推荐使用Python 3.8+PaddlePaddle 2.4的组合,实测在RTX 3060显卡上训练速度比CPU快17倍:
bash复制conda create -n paddleocr python=3.8
conda activate paddleocr
pip install paddlepaddle-gpu==2.4.2.post112 -f https://www.paddlepaddle.org.cn/whl/linux/mkl/avx/stable.html
pip install "paddleocr>=2.6"
注意:如果使用Windows系统,需要额外安装VC++14运行库。遇到过显卡驱动不兼容的情况,建议CUDA版本保持在11.2以上。
有效的数据集需要包含以下特征:
我们采用的采集方法:
对比了PP-OCRv3和PP-OCRv4两个系列:
最终选择v4版本,因其在测试集上对分式识别的准确率比v3高23%:
python复制from paddleocr import PaddleOCR
ocr = PaddleOCR(
rec_model_dir='./pretrain/PP-OCRv4_rec',
rec_char_dict_path='./ppocr/utils/dict/chinese_cht.txt',
rec_image_shape="3,48,320"
)
在finetune阶段需要特别关注的参数:
| 参数名 | 推荐值 | 作用说明 |
|---|---|---|
| learning_rate | 0.0005 | 大于通用OCR的默认值,适应新数据分布 |
| train_batch_size | 32 | 显存不足时可降至16 |
| eval_batch_size | 64 | 验证阶段可用更大batch |
| num_epochs | 300 | 手写体需要更多迭代次数 |
训练脚本关键部分:
python复制# 在configs/rec/PP-OCRv4/rec_r34_vd_none_bilstm_ctc.yml中修改:
Train:
dataset:
name: SimpleDataSet
data_dir: ./train_data/
label_file_list: ["./train_data/train_list.txt"]
loader:
batch_size_per_card: 32
Optimizer:
learning_rate:
name: Cosine
learning_rate: 0.0005
warmup_epoch: 5
针对试卷中的高频特殊符号,需要修改字典文件:
ppocr/utils/dict/chinese_cht.txt中添加:
实测发现直接使用原始模型推理速度较慢(约200ms/图),通过以下优化降至80ms:
bash复制paddle2onnx --model_dir ./output/rec_v4 \
--model_filename inference.pdmodel \
--params_filename inference.pdiparams \
--save_file ./onnx_model/rec_v4.onnx \
--opset_version 13
python复制from paddle.inference import Config
config = Config("model.pdmodel", "model.pdiparams")
config.enable_tensorrt_engine(
workspace_size=1 << 30,
max_batch_size=32,
min_subgraph_size=3,
precision_mode=Config.Precision.Float32)
原始输出存在字符粘连问题,添加规则引擎处理:
python复制def extract_choice(text):
patterns = [
r"([A-D])[\s\.]",
r"^[^A-D]*([A-D])",
r"([√×✓✗])"
]
for p in patterns:
match = re.search(p, text)
if match: return match.group(1)
return ""
现象:同一区域多次识别结果不一致
解决方法:
python复制def preprocess(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, img = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
return cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
典型错误案例:把"x+y"识别为"义十y"
优化方案:
python复制from pycorrector import Corrector
cor = Corrector()
formula = cor.correct("义十y") # 输出"x+y"
针对笔画不连贯问题:
训练命令示例:
bash复制python tools/train.py -c configs/rec/PP-OCRv4/rec_r34_vd_none_bilstm_ctc.yml \
-o Global.pretrained_model=./pretrain/PP-OCRv4_rec/best_accuracy \
Global.save_model_dir=./output/rec_v4_student \
Optimizer.lr.name=Cosine \
Optimizer.lr.learning_rate=0.001
在某初中数学试卷批改系统中,我们实现了以下流程:
json复制{
"question_id": "Q05",
"answer_type": "formula",
"content": "x=√(a²+b²)",
"confidence": 0.87
}
部署时发现三个实用技巧: