1. 项目概述
在全志开发板上部署LPRNet车牌识别模型是一个典型的边缘计算应用场景。LPRNet作为一种轻量级深度学习模型,特别适合在资源受限的嵌入式设备上运行。这个项目主要解决两个核心问题:如何在ARM架构的开发板上搭建完整的深度学习推理环境,以及如何优化模型推理流程以适应嵌入式设备的性能限制。
我选择全志开发板作为部署平台,主要考虑到其性价比高、功耗低的特点,非常适合智能停车、交通监控等边缘计算场景。与华为云的NPU推理方案不同,我们这里使用的是纯CPU推理方案,更贴近大多数开发者的实际使用环境。
2. 环境搭建准备
2.1 硬件准备
全志系列开发板有多种型号,包括H2+、T3等。以全志H2+为例,它采用四核Cortex-A7架构,主频1.2GHz,内存1GB。虽然性能不如高端服务器,但对于LPRNet这样的轻量级模型已经足够。
注意:不同型号的全志开发板在指令集支持上可能有细微差别,建议先确认开发板的具体型号和CPU架构。
2.2 系统基础环境
推荐使用Ubuntu 18.04或20.04系统,这两个版本对ARM架构的支持较为完善。系统安装完成后,需要先进行基础配置:
sudo apt update sudo apt upgrade -y sudo apt install -y build-essential cmake git wget2.3 Python环境搭建
由于开发板资源有限,建议使用Miniconda而不是完整的Anaconda:
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-armv7l.sh bash Miniconda3-latest-Linux-armv7l.sh安装完成后,创建一个专用的Python环境:
conda create -n lprnet python=3.7 conda activate lprnet3. 深度学习环境配置
3.1 基础依赖安装
在ARM架构上安装深度学习库需要特别注意兼容性问题。以下是经过验证可用的版本组合:
pip install numpy==1.19.5 pip install opencv-python==4.5.3.56 pip install pillow==8.4.03.2 PyTorch安装
全志开发板使用的是ARMv7架构,不能直接使用PyTorch官方提供的预编译包。需要通过源码编译安装:
sudo apt install -y libopenblas-dev libblas-dev m4 cmake cython git clone --recursive https://github.com/pytorch/pytorch cd pytorch git checkout v1.7.1 python setup.py install编译过程可能需要数小时,建议在性能较好的机器上交叉编译后再移植到开发板。
3.3 ONNX Runtime安装
为了获得更好的推理性能,可以安装ONNX Runtime:
pip install onnxruntime==1.8.14. LPRNet模型部署
4.1 模型获取与转换
LPRNet原始模型通常是PyTorch格式,我们需要将其转换为ONNX格式以便优化:
import torch from LPRNet import build_lprnet model = build_lprnet(lpr_max_len=8, phase=False) model.load_state_dict(torch.load("LPRNet.pth", map_location="cpu")) dummy_input = torch.randn(1, 3, 24, 94) torch.onnx.export(model, dummy_input, "LPRNet.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch"}, "output": {0: "batch"}})4.2 模型量化
为了进一步提升推理速度,可以对模型进行动态量化:
from onnxruntime.quantization import quantize_dynamic, QuantType quantize_dynamic("LPRNet.onnx", "LPRNet_quant.onnx", weight_type=QuantType.QUInt8)5. 推理流程实现
5.1 图像预处理
车牌识别需要特定的预处理流程:
import cv2 import numpy as np def preprocess(image): # 转换为YUV颜色空间 yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) # 直方图均衡化 yuv[:,:,0] = cv2.equalizeHist(yuv[:,:,0]) # 调整尺寸 resized = cv2.resize(yuv, (94, 24)) # 归一化 normalized = resized.astype(np.float32) / 255.0 # 调整通道顺序 transposed = normalized.transpose(2, 0, 1) return np.expand_dims(transposed, axis=0)5.2 推理引擎封装
创建一个高效的推理引擎类:
import onnxruntime as ort class LPRNetEngine: def __init__(self, model_path): self.session = ort.InferenceSession(model_path) self.input_name = self.session.get_inputs()[0].name def predict(self, image): input_data = preprocess(image) outputs = self.session.run(None, {self.input_name: input_data}) return postprocess(outputs[0])5.3 后处理与车牌解析
模型输出需要转换为可读的车牌字符串:
CHARS = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] def postprocess(output): indices = np.argmax(output, axis=1) last_idx = -1 plate_no = [] for idx in indices: if idx != last_idx and idx != len(CHARS) - 1: plate_no.append(CHARS[idx]) last_idx = idx return "".join(plate_no)6. 性能优化技巧
6.1 线程绑定
通过线程绑定可以显著提升推理性能:
import os os.environ["OMP_NUM_THREADS"] = "4" os.environ["MKL_NUM_THREADS"] = "4"6.2 内存优化
在资源受限的设备上,内存管理尤为重要:
# 在推理完成后手动释放资源 del session import gc gc.collect()6.3 批处理优化
虽然全志开发板性能有限,但合理的批处理仍能提升吞吐量:
def batch_predict(engine, images): batch = np.concatenate([preprocess(img) for img in images], axis=0) outputs = engine.session.run(None, {engine.input_name: batch}) return [postprocess(output) for output in outputs[0]]7. 常见问题与解决方案
7.1 模型加载失败
问题现象:加载ONNX模型时报错"Invalid protobuf file"
解决方案:
- 检查模型文件是否完整
- 确认ONNX Runtime版本与模型兼容
- 尝试重新导出ONNX模型
7.2 推理速度慢
优化方案:
- 使用量化后的模型
- 调整OMP_NUM_THREADS参数
- 关闭开发板上的其他服务释放资源
7.3 识别准确率低
改进方法:
- 检查预处理流程是否正确
- 确认训练数据与部署场景匹配
- 考虑在特定场景下重新微调模型
8. 实际部署建议
在全志开发板上部署LPRNet时,我有几点实用建议:
- 温度监控:长期运行时要监控CPU温度,必要时添加散热措施
- 电源管理:使用稳定的电源适配器,电压波动可能导致推理错误
- 日志记录:实现完善的日志系统,便于问题排查
- 看门狗机制:添加守护进程监控推理服务状态
对于需要7×24小时运行的车牌识别系统,可以考虑以下部署架构:
摄像头 -> 开发板(初步识别) -> 云端服务器(二次校验)这种边缘+云端的混合架构既能保证实时性,又能提高识别准确率。