尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于深度学习的自然场景中文OCR识别系统设计与实现

基于深度学习的自然场景中文OCR识别系统设计与实现 简介本资源是一套完整的基于Python深度学习的自然场景中文OCR识别系统面向本科毕设、科研入门及轻量级项目落地开发者解决复杂背景下中文字含竖排、繁体的端到端识别难题。压缩包共715个文件涵盖23个核心Python脚本含model.py、utils.py、config.py等模块化代码、35张PNG/17张JPG测试图像、3个ONNX/MNN模型文件、135个XML标注数据及Linux/C推理程序.cpp/.sh/.bat另有Web前端HTML/CSS/JS文件与仿宋_GB2312.ttf字体支持中文渲染整体大小48.08MB。已有64人学习下载。用户可直接运行Web界面上传图片识别复现CRNN模型训练与推理全流程配套详细运行说明文档覆盖环境配置、模型加载、前后端联调及边缘设备移植要点目录结构分层清晰含data、model、web、cpp、linux等独立模块便于理解系统架构与二次开发。 自然场景下的中文OCR和扫描件识别完全是两码事。我最早拿手机拍了一块店铺招牌丢给传统OCR引擎结果识别出来的内容基本没法看——光照不均匀、透视畸变、艺术字体、竖排牌匾传统方案面对这些情况几乎毫无招架之力。后来转向深度学习方案把检测和识别拆成两个模型才真正把准确率拉到了可用水平。这篇文章就从这个实际项目展开一个基于Python深度学习实现的自然场景中文文字OCR识别系统带前端Web界面支持横版和竖版文字。完整源码、运行说明和预训练模型都在包里拿到就能跑。这套系统解决的是真实世界的文字识别需求手机随手拍的照片、街边招牌、路牌、海报、书籍封面、漫画对话框、竖排古建筑牌匾。它能做的事概括起来就一句话——输入一张图片输出图片里所有文字内容以及对应的位置坐标。适合正在入门OCR方向的开发者、需要在自有产品里集成文字识别能力的工程师以及准备做图像处理方向课程设计的同学参考。下面我把整个系统的设计思路、核心实现、训练过程和踩坑经历完整梳理一遍。1. 系统整体设计与技术选型1.1 为什么用Python加深度学习做场景文字识别先聊聊技术选型背后的逻辑。传统OCR方案比如Tesseract处理规整的印刷体文档扫描件时效果确实还行但放到自然场景里就直接暴露短板。自然场景的文字有几个显著特点背景复杂文字经常跟招牌纹理、墙面图案混在一起光照条件不可控有阴影、反光、暗部字体千变万化楷书、行书、艺术字、带描边的字版面不规整文字是斜的、弯的甚至一整列竖排下来图片分辨率也参差不齐手机拍的、监控截图的都有。传统方法依赖阈值分割、连通域分析、模板匹配这些手段面对上述情况很难稳定工作。一副边缘被遮挡的招牌连通域直接断成好几块阴影落在字面上阈值分割出来的文字残缺不全。这些问题不是调调参数就能解决的是特征表达能力的上限问题。深度学习方案的优势在于整个流程端到端可训练检测模块通过卷积神经网络直接回归文本区域的位置识别模块对裁剪出来的文字图像做特征提取和序列解码。网络在大量真实场景数据上学到的特征表达对光照变化、字体差异、复杂背景的鲁棒性远优于人工设计的特征。这也是为什么近几年的OCR技术基本都被深度学习方法统治了。Python在这个领域的生态优势无法忽略。PyTorch、TensorFlow、OpenCV、PaddleOCR这些工具链都围绕Python展开实验迭代、模型调试、快速部署都很方便。做OCR研究的公开代码、预训练模型、数据集绝大多数都是Python生态的用Python能最快站在前人的肩膀上做工程落地。1.2 整体架构检测加识别两阶段方案目前自然场景OCR的主流方案是两阶段管线先用文本检测模型从整图中定位出文字区域再把每个文字区域裁切出来送入识别模型得到字符序列。这套系统也沿用了这个架构。为什么不用端到端的单模型方案端到端文本识别比如把检测和识别融合进一个网络虽然看起来更简洁但实现复杂度高训练数据要求更严格而且解耦性差——检测模块想单独调优或者替换的时候会很被动。两阶段方案的好处是每一段都可以独立优化检测不准就换更强的检测模型识别不准就单独迭代识别模型互不干扰。工程上维护起来也更舒服。检测阶段用的是DBNet全称Differentiable Binarization。它对输入图像生成一个文字区域概率图再通过可微二值化操作把概率图转成分割掩码最后用轮廓提取拿到文本框。DBNet能在复杂背景下比较准确地框出文字区域而且对有向文本和竖排文本都有不错的支持这正好契合本项目要处理自然场景的需求。识别阶段采用CRNN加CTC的结构。CRNN是经典三件套卷积层从输入图像中提取特征序列双向LSTM对特征序列建模上下文依赖CTC损失函数解决输入序列和输出序列长度不一致的时序对齐问题。CTC最大的优势是不需要逐字符的位置标注只要提供最终的文本内容就能训练极大降低了数据标注成本。为什么不选基于Transformer的方案CRNN结构更简单训练稳定性好对中文场景下数据量要求没那么苛刻。Transformer虽然在大规模数据上表现更强但中文识别任务字符集大常用汉字就有三千多个数据量不够时Transformer很容易过拟合。CRNN配合CTC在中等规模数据集上就能达到不错的精度推理速度也快CPU上也能实时跑。对于工程落地来说稳定省事比什么都重要。1.3 竖版文字支持的设计思路竖版文字是自然场景OCR中特别容易被忽略但实际又经常遇到的需求。古建筑牌匾、店铺竖招牌、书脊标题、海报装帧、漫画对话气泡到处都有竖排中文。国内外很多OCR系统第一版都没有考虑竖排场景遇到竖排文字就束手无策。竖版识别的难点在于检测模型如果只按水平方向回归文本区域竖排文字就会被压缩成一条特别窄长的小图。这种图正常缩放到识别模型的输入尺寸后每个字符都被水平挤压变形识别模型基本猜不出是什么字。这个系统的做法分三步检测阶段输出带旋转角度的文本框用四顶点坐标表示不做强制水平矫正根据文本框的宽高比判断文字方向高度明显大于宽度时判定为竖排文本对竖排文本框做90度旋转后再送入识别模型把竖排问题转化成横排问题处理识别结果再映射回原图坐标输出关键收益在于识别模型不需要单独训练一套竖排权重一套横排识别模型就能覆盖竖排场景工程量节省一大截。这个思路本质上就是问题转换把不擅长的输入形态转成擅长处理的形态。2. 环境搭建与运行准备2.1 Python深度学习环境配置项目使用的基础环境是Python 3.8加PyTorch 1.10训练用的显卡是RTX 306012G显存。说实话这个配置在深度学习里算入门级但跑这个项目的训练和推理完全够用。如果没有GPU纯CPU也能跑就是单张图推理时间会长一些后面会具体聊部署优化的方式。关键依赖库清单如下torch、torchvision深度学习框架模型训练和推理的核心opencv-python图像读取、缩放、轮廓查找、透视变换等图像处理操作numpy数组运算坐标变换和概率图后处理依赖它Pillow前端上传图片的读取和处理Flask提供Web后端服务pyclipper、shapelyDBNet后处理中多边形裁剪和IOU计算用到的几何工具库安装环节有几个容易踩的坑先给大家提个醒。PyTorch的CUDA版本必须和显卡驱动匹配安装前先查清楚自己机器的CUDA版本用nvidia-smi看一眼。opencv-python和shapely在某些Python版本下没有预编译的wheel包直接pip安装可能报错建议锁定版本安装。国内网络环境下pip默认源下载速度经常让人崩溃建议一开始就把镜像源换成清华或阿里云的。另外不要忘记安装gunicornFlask自带的开发服务器并发能力太弱后面部署时会用到。2.2 源码结构和模型文件说明项目压缩包解压后的目录结构大致如下ocr_system/ ├── app.py # Flask Web服务入口 ├── predictor.py # OCR推理封装类 ├── models/ │ ├── det/ │ │ └── dbnet_resnet50.pth # 文本检测模型 │ ├── rec/ │ │ ├── crnn_resnet34.pth # 文本识别模型 │ │ └── charset.txt # 字符集文件 ├── templates/ │ └── index.html # 前端页面 ├── static/ │ ├── css/ │ └── js/ ├── requirements.txt # 依赖清单 └── README.md # 运行说明检测模型参数文件大约80MB识别模型约40MB。这两个模型都是在公开数据集基础上额外加了一批自己标注的真实场景数据微调得到的。检测模型能覆盖自然场景中的招牌、路牌、海报、电子屏幕等常见文字区域识别模型支持简体中文字符集约3000个常用字加上数字、英文大小写和常用标点。charset.txt这个文件很容易被忽略但极其重要。识别模型的输出维度就是字符集的大小如果实际使用场景里包含字符集以外的生僻字或特殊符号识别结果会是空或者错字。遇到这种情况需要把新字符加进字符集文件对应调整模型输出层维度并重新训练识别模型的最后一层。3. 核心实现细节与关键代码解析3.1 文本检测模块的推理实现检测模块的核心流程是读图、缩放、网络前向传播、后处理、输出文本框列表。图像缩放这个环节有个细节必须注意。DBNet训练时通常把图像短边缩放到640像素长边限制在2560以内。推理的时候缩放的配置要和训练时保持一致否则检测尺度不一致会导致小字漏检或者大字被切成多块这个偏差在自然场景图片上尤其明显因为原图分辨率往往差异很大。后处理部分包含概率图二值化、轮廓查找和文本框构建。DBNet的可微二值化是训练时用的技巧推理阶段直接用固定阈值对概率图做二值化阈值取0.3能获得比较均衡的检测效果低于这个值容易把背景也框进来高于这个值则可能漏掉边缘比较模糊的文字。轮廓查找使用的是cv2.findContours函数找到的是多边形点集还需要用最小外接矩形把它转成带角度的文本框。这里对面积过小或者宽高比过于离谱的候选框要过滤掉不然一张照片里会跑出大量噪声框。我习惯把面积阈值设成50像素同时加入了一个限制条件检测框面积小于图像面积万分之三的直接丢弃这样能有效减少背景痕迹带来的误检。import cv2 import numpy as np import torch def detect_text(image, det_model, device): # 预处理归一化 resize h, w image.shape[:2] # 短边缩放保持长宽比 target_h 640 if h w else 1280 scale target_h / max(h, w) new_w, new_h int(w * scale), int(h * scale) img_resized cv2.resize(image, (new_w, new_h)) # BGR转RGBHWC转CHW归一化 tensor torch.from_numpy( cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB).transpose(2, 0, 1) ).float().div(255).unsqueeze(0).to(device) with torch.no_grad(): prob_map det_model(tensor)[0, 0].cpu().numpy() # 二值化 轮廓提取 binary (prob_map 0.3).astype(np.uint8) * 255 contours, _ cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) boxes [] for cnt in contours: area cv2.contourArea(cnt) if area 50: continue # 最小外接矩形保留旋转信息 rect cv2.minAreaRect(cnt) box cv2.boxPoints(rect) boxes.append(box / scale) # 坐标映射回原图 # 合并重叠框 if boxes: boxes nms(boxes, threshold0.5) return boxes这段代码有三个地方值得展开说。第一NMS非极大值抑制不能省一张复杂场景图上检测模型经常会对同一行文字输出多个重叠框不做NMS会导致同一行文字被识别好几次输出结果会有明显的重复噪声。第二检测框坐标一定要除以缩放比映射回原图坐标不然前端在展示检测框叠加效果时会发现框的位置完全对不上。第三cv2.findContours在不同版本的OpenCV中返回值形式不一样新版OpenCV返回两个值而旧版返回三个值写代码的时候要留意自己环境里装的OpenCV版本。3.2 竖版文字判断与旋转处理拿到检测框之后下一步是判断每个框里文字的排列方向。最直接的方法是看最小外接矩形返回的宽和高取其中较大的作为文本方向。自然场景下文本行一般是长条形横排文本的宽度明显大于高度竖排文本则反过来。判断逻辑可以按宽高比来def is_vertical(box): # box: 四顶点坐标按顺序排列 (x1, y1), (x2, y2), (x3, y3), (x4, y4) box width np.hypot(x2 - x1, y2 - y1) height np.hypot(x4 - x1, y4 - y1) return height width * 1.2阈值系数1.2是靠实测调出来的。设得太灵敏会把略微倾斜的横排文字误判成竖排导致旋转后反而识别错乱设得太迟钝则真正竖排的窄长框识别不了。实际调节时建议在测试集上同时看误检率和漏检率找到一个平衡点。判定竖排之后处理流程是先把带角度的文本框矫正成水平矩形然后再顺时针旋转90度。这里有个细节容易出错旋转方向必须统一。如果横排识别模型是基于从左到右的文字顺序训练的竖排文字旋转后也必须保持从左到右阅读的方向否则识别模型输出的文字序列会是反的。为了保证旋转方向正确我写了一个辅助函数先通过透视变换把检测框内的图像矫正为正矩形再判断矫正后的高和宽决定旋转方向。矫正时用cv2.getPerspectiveTransform加cv2.warpPerspective实现这样即使检测框带角度也能得到相对工整的文字图像。def crop_rotate_text(image, box): # 矫正带角度的文本框 h int(np.hypot(box[3][1] - box[0][1], box[3][0] - box[0][0])) w int(np.hypot(box[1][1] - box[0][1], box[1][0] - box[0][0])) src box.astype(np.float32) dst np.array([[0, 0], [w - 1, 0], [w - 1, h - 1], [0, h - 1]], dtypenp.float32) M cv2.getPerspectiveTransform(src, dst) crop cv2.warpPerspective(image, M, (w, h)) if h w: # 竖排旋转90度转成横排 crop cv2.rotate(crop, cv2.ROTATE_90_CLOCKWISE) return crop3.3 识别模型与CTC解码识别模型的输入是一张高度固定为32像素、宽度按原图比例缩放的灰度图。之所以固定高度而不是固定宽度是因为文本行的长度差异很大卷积网络对不同宽度输入有一定容忍度但高度固定可以让特征图的高维信息对齐。识别模型输出的是一串按时间步排列的字符概率分布需要经过解码才能得到最终文本。CTC解码的核心思路是去除重复字符和空白分隔符。最常见的解码方式是贪婪搜索每个时间步直接取概率最大的字符然后合并连续重复字符、去掉空白字符。这样做简单高效大多数场景下效果已经够用。但中文识别任务有个特殊难点常见字里有很多结构相似的字符比如“未”和“末”、“日”和“曰”、“己”和“已”。这些字在概率分布中得分往往非常接近单靠视觉特征很难区分贪婪搜索很容易翻车。如果对准确率要求更高可以在解码时引入语言模型或者常用词先验。更稳妥的做法是用beam search保持多个候选序列在最后打分时把相邻字符的共现概率考虑进去。这个系统默认使用贪婪搜索保证速度同时在接口层预留了一个use_beam_search参数部署时可以根据场景开关。3.4 前端Web界面与接口设计模型部分搞定了最后要落到能用的工程层。系统使用Flask提供Web服务前端页面支持两种玩法上传图片识别、粘贴图片URL识别。后端接口设计得很简洁就一个核心接口接口地址POST /api/ocr请求参数图片文件字段名是image支持jpg、png、bmp格式返回结果JSON包一个items数组每个元素包含文本框坐标、识别文字、置信度返回结果和前端展示是解耦的接口不关心前端怎么渲染。前端拿到坐标数据后用Canvas在图片上画出检测框和识别文字方便你直观地检查识别效果有没有问题。{ items: [ { bbox: [[120, 80], [320, 80], [320, 120], [120, 120]], text: 人民路, confidence: 0.96 } ] }前端页面用原生HTML加一点JavaScript实现没有引入Vue、React这类大框架好处是零构建、打开即用也方便按照自己的需求改界面样式。这里必须提一个部署层面的坑Flask自带的开发服务器是单进程单线程的多个用户同时上传图片时会出现排队阻塞拖慢整个系统的响应。生产环境部署时建议用gunicorn启动服务或者至少加上线程池。实测单张图片在GPU上的推理耗时约150到300毫秒CPU上约1到2秒如果并发量上来了Flask自带服务器是扛不住的。4. 数据准备与模型训练过程4.1 训练数据来源与预处理策略做自然场景OCR数据永远是决定效果上限的因素。这个项目的训练数据主要由三部分构成公开数据集、网络图片爬取、自己拍摄标注。公开数据集用的是ICDAR系列的场景文字检测和识别数据还有中文场景文字识别常用的合成数据集。合成数据是用文本渲染引擎在真实背景图上随机生成文字图片这个方法特别实用因为标注是自动生成的大量可控。网络图片抓取部分抓了一些街景图、商铺照片、海报图片然后人工筛选出包含清晰文字的图片。文字检测数据用多边形标注工具逐张标注位置识别数据则以行为单位标注文字内容。最终的数据规模控制在检测部分约8万张图像识别部分约30万张文字行图像。数据规模不是越大越好关键是覆盖场景要多样化——光照条件、拍摄角度、字体类型、文字方向都要有足够的样本。竖排文字的样本量刻意补到了总量的10%左右没有这部分数据竖排模块的效果是出不来的。预处理阶段做了几件固定的事统一图像尺寸、归一化像素值到0到1范围、随机做亮度对比度扰动、随机裁剪和旋转。数据增强是提升自然场景泛化能力的最佳武器尤其是光照扰动和透视变换模拟了手机拍摄的真实情况。4.2 模型训练的详细配置检测模型DBNet的训练配置输入尺寸统一为640乘640批量大小设成8优化器用Adam初始学习率0.001训练80个epoch学习率在第40和第60个epoch分别衰减十倍。损失函数用的是DBNet原论文的组合损失包含二值化交叉熵损失、可微二值化损失和文本框形状损失。识别模型CRNN的训练配置输入高度固定32像素宽度按比例调整但不超过320像素批量大小64优化器用Adadelta初始学习率1.0训练50个epoch。CTC loss作为损失函数这里不需要计算每个字符的对齐位置直接拿模型输出序列和真实文本序列做对比就可以。训练过程中监控的指标不只是整体准确率还重点观察了几个子集的准确率——竖排样本、低光照样本、艺术字体样本。如果某个子集的准确率明显低于平均水平说明在这一类场景上训练数据还不够需要回去补数据或者加强数据增强。这种做法比只盯一个整体指标要有效得多。4.3 推理加速与模型轻量化训练完成之后要考虑推理效率。完整的模型在CPU上跑一张图需要1到2秒对Web服务来说有点慢。我先给识别模型做了输入尺寸的优化原图高度32固定不变但宽度上限从320降到了240。大部分中文文本行的宽度都在这个范围以内超过上限的按比例压缩。这么一改推理速度提升了30%准确率几乎没有损失。另一个优化是把模型导出为TorchScript格式操作方法是det_model.eval() scripted_det torch.jit.trace(det_model, example_input) scripted_det.save(dbnet_resnet50_scripted.pth)TorchScript导出后可以不依赖原始的Python模型类定义部署时更干净同时推理速度也有小幅提升。如果追求极致加速还可以在GPU上用TensorRT做进一步的量化。这个项目没有上TensorRT但在环境说明里提到了这个方向方便有需要的同学继续深挖。测试环境下CPU推理一张1280像素宽的照片大约需要0.8秒GPU上约150毫秒。这个速度对大多数Web应用来说是可以接受的。5. 常见问题与排查技巧实录5.1 环境与启动问题速查项目跑起来之前最容易卡壳的就是环境问题。这里把我在实际部署中遇到过的问题整理成了一张表方便大家对照排查。问题现象根本原因解决办法torch.cuda.is_available()返回FalseCUDA版本和PyTorch不匹配用pip安装对应CUDA版本的torch或降级PyTorch到匹配的版本import cv2报错提示找不到cv2模块opencv-python未安装或版本冲突重新执行pip install opencv-python注意清理旧版本启动Flask时报Address already in use端口被占用换一个端口启动或者杀掉占用端口的进程上传图片后报错文件无法获取前端和后端字段名不一致检查前端FormData的字段名是否为image大小写要一致检测框坐标显示错位缩放后的坐标没有映射回原图在detect_text函数末尾对检测框坐标除以缩放比识别结果为空白字符集文件与模型不匹配确认charset.txt内容和识别模型的输出层维度一致内存占用持续上涨推理时没有及时释放GPU显存设置torch.cuda.empty_cache()避免保留中间变量引用端口占用这个问题在服务器上特别常见。我之前部署到一台服务器时发现8000端口被一个旧服务占着Flask启动直接报错。解决办法很简单换一个不常用的端口比如8090。如果不想改代码也可以在启动命令里指定app.run(port8090)。5.2 识别效果的调优经验模型跑通了效果不满意怎么办这是大家问得最多的问题。我按排查优先级整理了思路从硬件资源到算法参数一层层往下调。第一排查光照问题。自然场景图的光照差异极大暗光环境下的识别准确率会明显下跌。如果应用场景以暗光为主可以在识别前加一个图像增强的预处理步骤最简单的做法是用灰度图的CLAHE自适应直方图均衡化。实测在暗光测试集上加了这个预处理的准确率能提升3到5个百分点。第二排查检测框的完整性。如果检测出来的文本框把文字截断了识别模型看到的就是残缺的字符必定识别错误。这时需要把概率图的二值化阈值调低一点比如从0.3降到0.25让检测框更宽松一些宁可稍微包含一点背景也不要截断文字。第三排查字符集覆盖范围。这个项目默认字符集是3000个常用汉字如果图片里包含生僻字或者特殊符号识别结果基本是错的。解决办法是把字符加进charset.txt重新训练识别模型。如果不想重新训练至少可以把字符集文件里的字换成本领域常用的高频字集合牺牲覆盖面换取更精准的领域效果。第四排查输入图像的清晰度。图片里的文字如果本身就模糊或者分辨率过低任何模型都救不回来。建议在系统入口处加一个图像质量检查检测到图片过小时提示用户重新上传更清晰的图片。5.3 竖版文字识别的专项调参记录竖版文字是这套系统花了不少心思优化的一部分单独拿出来聊聊调参心得。竖排判断的阈值系数1.2是一个比较敏感的参数。如果场景里有一种特殊排版比如古建筑牌匾上从右往左竖排的文字判断逻辑还要额外考虑阅读顺序。我从实际测试中发现竖排文本的检测框往往比横排文本更窄长这种情况下检测模型有时会把一个完整的竖排文本行切成多个小框每个小框里只有一个字符。这种碎片化会导致识别结果完全不连贯。解决的办法是在检测后处理里加一个框合并逻辑如果两个文本框的中心点x坐标接近、且上下位置有重叠就把它们合并成一个竖排大框。这个合并逻辑其实就是一个按空间关系聚类的过程不需要复杂算法简单的距离比较就可以实现。竖排文字旋转之后送入识别模型时有个细节也需要注意。旋转后的图像宽度很多时候只有20到40像素这个宽度在识别模型的感受野里偏小特征提取不够充分。为了改善这个问题我把这类窄图在送入模型前做了水平方向的重复拼接补充把宽度补到至少64像素效果确实有提升这个技巧实际工程中很有用。6. 系统扩展方向与后续改进建议6.1 从单张图片到视频流的识别目前系统接收的是单张图片但很多实际场景需要连续的视频流识别比如监控画面里的文字提取、车载摄像头拍到的路牌识别、直播画面里的字幕提取。改造思路是在现有OCR管线前后加上视频帧处理层。视频帧处理层做两件事一是抽帧每隔N帧识别一次避免逐帧识别的算力浪费二是结果融合对同一个文字目标在连续多帧中的识别结果做投票整合能够有效消除单帧识别错误和闪烁。我在实验中发现视频流OCR的关键不在于OCR模型本身而在于节奏控制。抽帧太频繁GPU占用高且识别结果重复抽帧太少快速移动的文字会漏检。针对常规监控场景每秒3到5帧的抽帧率性价比最高。6.2 引入注意力机制进一步提高识别准确率CRNN加CTC的结构在速度和稳定性上很优秀但在处理长文本行和形近字时纯CTC解码缺少全局语义信息的辅助。如果项目对准确率的要求极高可以尝试在识别模块引入注意力机制也就是经典的编码器解码器架构替换为CTC head。注意力方案在训练时需要一个额外步骤就是生成每个字符的输出位置标注成本比CTC方案高不少。但好处也很明显带注意力的解码器能利用全局上下文信息在长文本行上通常比CTC稳得多形近字的区分能力也更强。如果手头的数据标注资源充足这值得一试。6.3 压缩模型体积以便边缘设备部署项目打包里的模型总大小约120MB在服务器上跑没问题但部署到边缘设备比如嵌入式网关、智能摄像头、树莓派这类设备上就偏大了。模型压缩的两个主要方向量化和蒸馏。量化方面可以使用PyTorch的静态量化工具把模型权重从FP32压到INT8体积缩小到原来的四分之一推理速度能提升2到3倍代价是准确率会损失1到2个百分点。蒸馏的思路是让一个大模型当老师教一个小模型优化自己的权重在保持较小模型体积的同时尽量保留大模型的精度。我实际测过把检测和识别模型都量化到INT8在RK3588这类边缘设备上单帧图片的完整OCR推理耗时可以控制在500毫秒以内基本达到了实时可用级别。系统后续还可以扩展的方向挺多比如多语言混排识别、表格结构还原、印章文字检测都是真实业务中高频出现的需求。有一点我在这套系统的开发过程中体会特别深OCR系统的工程落地难点往往不在模型本身而在对实际场景的充分理解和对各种边界条件的处理。把所有能用规则解决的细节都处理干净模型的压力就会小很多整套系统的上限自然就上来了。如果各位在部署或改造这套系统的过程中有更好的想法欢迎一起交流。本文还有配套的精品资源点击获取
返回列表