ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

在Ubuntu 20.04上部署PP-OCRv5并封装可交付的离线OCR服务

在Ubuntu 20.04上部署PP-OCRv5并封装可交付的离线OCR服务 简介面向需要在 Ubuntu 20.04 上快速搭建 OCR 识别服务、有一定 Linux 基础的技术人员这份资源提供打包完整的 PP-OCRv5 服务程序。压缩包约 324.37MB共 61 个文件以 so 动态库、json 参数配置、yml 配置文件、pdiparams 模型参数和 txt 字典文件为主内置 server 与 mobile 两套检测及识别推理模型并预置 OpenVINO、Paddle Inference 及 TBB、OpenCV 等运行依赖库解压配置后即可在 Linux 环境直接调用。已有 439 人学习下载适合文档数字化、票据识别、自动录入等文字提取场景。通过自带服务程序与配套模型可省去自行编译、收集依赖和下载模型的繁琐步骤不仅降低 OCR 服务部署门槛也为二次开发提供完整的基础运行环境用户可按需调整配置将文字识别能力快速集成到实际业务中适用于快速验证与生产落地。1. 为什么是 PP-OCRv5 ubuntu20.04一个离线可交付的 OCR 服务长什么样把 PP-OCRv5 部署到 ubuntu20.04 上封装成一个能响应 HTTP 请求的 OCR 识别服务再把服务代码、模型权重、Python 依赖环境一起打成一个lw.PP-OCRService.tar.gz交付出去——这是内网和离线场景下最常见的 OCR 落地姿势。你拿到的不是一个安装脚本而是一个解压即用的服务包在目标机器上解压 tar 包、启动脚本、一个本地识别接口就有了。这套方案解决两个核心问题一是图片数据不出内网满足本地化识别的要求二是省去从零配置 Paddle 环境的折腾。适合谁看要在 ubuntu20.04 上交付本地 OCR 识别服务的实施人员以及被各种依赖版本折磨过、想找一条可复现路径的开发者。下面按从选型到部署、从接口到排查的顺序把这套方案完整过一遍踩坑的部分我会写得细一些。2. 先看版本再动手PP-OCRv5、PP-StructureV3、paddleocr-vl 到底怎么选2.1 三条技术路线的边界识别、理解、版面不是一回事拿到lw.PP-OCRService.tar.gz之前先要确认一个基本问题标题里的“OCR 识别服务”到底指哪条技术路线。PaddleOCR 3.x 之后官方能力分成三个方向很多人在这里混淆过PP-OCRv5、PP-StructureV3、paddleocr-vl名字都带“OCR”解决的问题完全不同。PP-OCRv5 是轻量级文本检测与识别模型族延续了检测det→ 方向分类cls→ 识别rec三段式结构。它回答的问题是“文本在哪、字是什么”输出的是文本框坐标、文字内容和置信度。这是纯识别服务的主力也是lw.PP-OCRService.tar.gz这类交付包默认会打包的能力。PP-StructureV3 则是文档结构解析负责版面区域划分、表格转 HTML、公式识别和阅读顺序还原输入是一整份 PDF 或扫描件输出是结构化文档。paddleocr-vl 走的是视觉语言大模型路线强调对复杂文档的语义理解可以做文档问答、长文档信息抽取但硬件门槛明显更高。三者的关系用一句话概括PP-OCRv5 管“字”PP-StructureV3 管“版”paddleocr-vl 管“义”。做识别服务主线走 PP-OCRv5如果客户要的是“PDF 转 Markdown”这类结构化输出才需要引入 PP-StructureV3如果要做的是合同问答、文档语义检索才轮到 paddleocr-vl。下面的表把这层区别列清楚对比维度PP-OCRv5PP-StructureV3paddleocr-vl核心定位文本检测 方向分类 文本识别版面分析 表格识别 公式识别文档视觉语言理解典型输出文本框坐标、文字、置信度版面区域类别、表格 HTML、公式自然语言回答、结构化抽取结果硬件要求CPU 可跑GPU 更快建议 GPUCPU 慢需要较大显存适用场景截图、证件、发票、扫描件取字复杂 PDF 转结构化数据文档问答、长文档理解传统方案里大家常用的 tesseract在中文场景尤其在竖排文本、模糊截图、带旋转角度的照片上识别效果明显输给 PP-OCRv5。既然标题已经明确指向 PP-OCRv5靠它来做识别主引擎是合理的。真正容易翻车的点其实在服务化封装模型加载方式、接口参数、并发模型这些才是决定交付质量的地方。2.2 tar.gz 分发是离线 OCR 的务实解lw.PP-OCRService.tar.gz这种交付形式一看就是给离线内网环境准备的。为什么不是 docker 镜像为什么不是 pip 在线安装因为实际交付对象往往是客户的一台 ubuntu20.04 服务器没有外网、没有镜像仓库甚至 docker 都没装。tar.gz 是兼容性最好、理解成本最低的格式。常见做法是在开发机上装好虚拟环境venv把依赖、模型权重、服务入口脚本都放好然后tar -czf打成包。到客户机器上解压激活环境启动服务即可。相比 docker 镜像tar.gz 不需要 docker daemon也没有内网 registry 的传输问题相比 requirements.txt 在线安装它不需要目标机器能连到外网或内网 pip 源而且模型权重也一并打包进去了。需要注意的一个细节是很多人在开发机上直接pip download攒了一堆 wheel到生产机上一个一个装结果GLIBCXX版本对不上、Python 版本不一致折腾半天。而 venv 目录本身带上目标机器的绝对路径只要开发机和目标机都是同一个 Ubuntu 20.04 同一个 Python 小版本解压后基本可以直接运行。下面把三种交付方式的差异列出来方便你评估自己的场景交付方式离线友好度前置要求典型问题tar.gzvenv 模型权重高解压工具需要开发机与目标机系统版本一致docker 镜像中docker daemon、镜像传输内网没 registry 时传输麻烦requirements.txt 在线下载低外网或内网 pip 源、模型可下载离线环境直接失败如果你的客户环境是纯内网、机器是 ubuntu20.04tar.gz 就是我一般会优先推荐的方案。但要提醒一点打包前一定确认目标机的 Python 版本和 glibc 版本20.04 默认 Python 3.8如果客户机器被人为升级过 Pythonvenv 里的二进制可能不兼容。2.3 选型核对清单跑识别服务前确认的 5 件事在解压lw.PP-OCRService.tar.gz之前花五分钟把下面几项过一遍能避免后面一大半的坑。这套检查逻辑不依赖具体的包内容适用于你拿到的任何一个服务交付包。# 1. 确认系统版本和架构 lsb_release -a uname -mubuntu20.04 的 x86_64 是最常见目标但如果客户机器是 ARM比如 RK3588 这类工控板Paddle 的 pip 包兼容性就要特殊处理。第二步看 Python 版本虚拟环境里如果带的是 3.8就用 3.8。# 2. 检查 Python 版本 python3 -V第三步看包内容。不要上来就tar -xzf先打印清单重点确认三样东西模型权重目录、服务入口脚本、依赖说明文件。# 3. 查看 tar 包内容清单不急于解压 tar -tzvf lw.PP-OCRService.tar.gz | head -50常见的交付包结构会包含models/模型权重、app.py或server.py服务入口、requirements.txt依赖清单、run.sh启动脚本。具体文件名以你拿到的包为准但检查逻辑是通用的。第四步确认是 CPU 版还是 GPU 版看依赖清单里是paddlepaddle还是paddlepaddle-gpu第五步确认端口号提前问清楚目标机器上 8000/8866/8080 哪个没被占用。四、五两步没有固定的命令但有个笨办法值得养成习惯解压后先du -sh看整体大小CPU 版带模型通常在 1GB 到 3GB 之间模型权重占大头如果包只有几十 MB大概率模型需要联网下载这在内网环境里基本等于不可用。3. 在 ubuntu20.04 上部署 PP-OCRv5 服务的最小路径3.1 准备 Python 3.8 虚拟环境与 Paddle 安装ubuntu20.04 刚装完系统时默认自带 Python 3.8这是最省心的组合。PaddlePaddle 对 3.8 支持非常成熟不建议在这个系统上手动把默认 Python 改成 3.10 或 3.11apt 里很多系统工具依赖 3.8改动后容易引发连锁故障。先确认系统自带版本python3 -V # Python 3.8.10如果系统提示找不到 python3说明 minimal 安装没有带先补上sudo apt update sudo apt install -y python3 python3-venv python3-pip接下来创建虚拟环境。这一步很重要Paddle 的依赖和系统其他 Python 包容易互相污染虚拟环境是后悔药后面想重来直接删目录就行。python3 -m venv ~/ocr-svc/venv source ~/ocr-svc/venv/bin/activate pip install --upgrade pip虚拟环境建好后安装 PaddlePaddle。CPU 部署直接装 CPU 版GPU 版需要先nvidia-smi确认驱动支持的最高 CUDA 版本再按 Paddle 官方对应关系选paddlepaddle-gpu。这里最容易翻车的点是把 GPU 版装在了没有驱动的机器上import 阶段直接报libcudart.so找不到。# CPU 版离线内网机器推荐先装这个跑通 pip install paddlepaddle # GPU 版先确认驱动支持的 CUDA 版本再按官方对应表安装 nvidia-smi pip install paddlepaddle-gpu装完立刻验证 import 是否能过python -c import paddle; print(paddle.__version__)如果这里报错后面都不要继续。最常见的两种错libcudart.so相关错误说明装成了 GPU 版但没有对应驱动GLIBCXX_3.4.29 not found说明系统的 libstdc 太旧常见于从 18.04 升上来的系统。前者卸载重装 CPU 版即可后者用虚拟环境配合conda环境能绕过去。接下来装 paddleocr 本体。实际部署时强烈建议锁版本大版本对齐到 3.x避免 2.x 的旧 API 和新代码打架pip install paddleocr3.0,4.0装完后可以顺手验证一次模型是否能正常加载。3.x 版本的 PaddleOCR 会在第一次调用时把模型权重下载到用户目录下的模型缓存目录开发机有网时先让它跑一次把权重缓存好后面打包才能带上。这一步是很多离线交付翻车的根源开发机上测试一切正常打包时忘了带模型缓存客户机器一启动就卡在联网下载上。3.2 解压 tar.gz 后先别急着启动按这三步检查包内容拿到lw.PP-OCRService.tar.gz第一反应是解压启动这个动作太危险。先看一下包内容确认里面带不带模型权重、服务代码是哪个文件、启动脚本指向什么端口tar -tzvf lw.PP-OCRService.tar.gz | grep -E models/|app.py|run.sh|requirements.txt如果grep结果里能看到模型权重目录和服务脚本说明这个包是完整的自包含交付。如果列表里没有模型权重、只有一个 requirements.txt这就是一个半成品包目标机器必须有外网或内网 pip 源才能跑起来离线场景直接劝退。确认没问题后解压到目标目录mkdir -p ~/ocr-service tar -xzf lw.PP-OCRService.tar.gz -C ~/ocr-service/解压后打开启动脚本看一眼确认虚拟环境路径和端口。很多包里的run.sh写的是开发机的绝对路径比如/home/dev/venv/bin/python到了客户机器上路径对不上就起不来。检查逻辑可以用一条命令把所有硬编码路径找出来grep -n /home/\|/root/ ~/ocr-service/run.sh ~/ocr-service/app.py发现路径不对要么改成当前机器路径要么把run.sh改成先激活相对路径下的虚拟环境再启动。这里要花两分钟改脚本后面能省两小时排错。3.3 启动脚本与第一次联调启动前手动跑一次服务入口不要用 nohup 或 systemd 包裹前台启动能看到完整日志方便第一时间发现问题。常见做法是cd ~/ocr-service bash run.sh如果 run.sh 内部做的是python app.py日志里能看到 Paddle 的模型加载信息以及类似Uvicorn running on http://0.0.0.0:8000的提示说明服务已经起来了。端口以你实际拿到的脚本为准一般是 8000、8080 或 8866 中的某一个。服务起来后第一件事是本地联调。准备一张带文字的截图或扫描件用 curl 打一发curl -X POST http://127.0.0.1:8000/ocr/file \ -F image/tmp/test.png返回的 JSON 里能看到识别出的文本列表和坐标信息就说明服务链路通了。如果返回 500先看服务端日志90% 的情况是模型路径不对或者输入图片格式问题。这一步通过之后再谈接口封装、参数调优和并发能力。4. 把识别能力变成接口FastAPI 封装与调用参数4.1 服务代码加载一次模型持续接受请求PaddleOCR 3.x 的 API 和 2.x 差别非常大2.x 时代用PaddleOCR(det_model_dir...)这种方式初始化3.x 改成了PaddleOCR(text_detection_model_name..., text_recognition_model_name...)预测入口也从ocr.ocr(img)变成了ocr.predict(input...)。如果你拿到的服务包代码里还在用 2.x 的写法建议先升级适配否则后面想加新参数都加不上。下面是一个最小可用的 FastAPI 服务代码核心思路是全局只创建一个 PaddleOCR 实例进程启动时加载模型之后每个请求复用这个实例。这里有个重要细节PaddleOCR 实例不要在每个请求里新建模型加载和显存分配的开销很大频繁创建会拖垮服务这也是很多本地识别服务内存越跑越高的一个原因。from fastapi import FastAPI, File, UploadFile from paddleocr import PaddleOCR import numpy as np import cv2 app FastAPI() # 全局单例进程启动时加载一次模型请求复用 ocr PaddleOCR( text_detection_model_namePP-OCRv5_mobile_det, text_recognition_model_namePP-OCRv5_mobile_rec, use_doc_orientation_classifyTrue, # 自动判断 0/90/180/270 度 use_doc_unwarpingFalse, # 卷曲矫正很慢默认关 ) app.post(/ocr/file) def ocr_file( file: UploadFile File(...), use_orientation: bool True, ): data file.file.read() img cv2.imdecode(np.frombuffer(data, np.uint8), cv2.IMREAD_COLOR) if img is None: return {error: invalid image} result ocr.predict( inputimg, use_doc_orientation_classifyuse_orientation, use_textline_orientationuse_orientation, ) r result[0] return { texts: r[rec_texts], scores: r[rec_scores], boxes: r[dt_polys], }这段代码的要点有三个。一是cv2.imdecode直接解析上传的字节流避免把临时文件写到磁盘内网服务同时处理几十张图时少写临时文件能减少不少 IO 压力。二是use_doc_orientation_classify控制整张图的旋转校正use_textline_orientation控制单行文字的方向判断这两个参数对拍照件、扫描件尤其重要后面细说。三是返回时把rec_texts文字、rec_scores置信度、dt_polys边框坐标一起吐出来下游业务不管是做关键字提取还是归档都够用了。4.2 客户端怎么调文件上传、base64、超时设置服务端接口写好后客户端调用要看实际场景。命令行验证用 curl 最快curl -X POST http://127.0.0.1:8000/ocr/file \ -F image/tmp/test.png \ -F use_orientationtrue内网服务联调时 curl 是好用的但生产代码里一般用 Python requests尤其是要从内存里的图片字节直接上传时不需要落盘import requests with open(/tmp/test.png, rb) as f: resp requests.post( http://127.0.0.1:8000/ocr/file, files{file: f}, params{use_orientation: true}, timeout30, # 识别耗时和图片大小强相关超时设长一点 ) data resp.json() print(data[texts])timeout30是值得单独说一句的参数。PP-OCRv5 在 CPU 上识别一张 1080p 的截图检测加识别合计可能耗时 1 到 3 秒如果是 4000px 长图耗时可能到 10 秒以上。默认的 requests 超时是无限等待但在一堆服务互相调用的环境里不设超时会拖垮整个调用链。30 秒是一个相对安全的取值具体按你服务的硬件来调。4.3 两个必调参数和三个场景参数组合PaddleOCR 3.x 在预测时暴露了很多开关实际使用中真正需要关注的只有几个。use_doc_orientation_classify和use_textline_orientation是必调的。前者解决整个页面被旋转了 90 度或 180 度的问题比如手机拍的照片方向不对后者解决单行文字被旋转的问题比如竖排文本中的个别行方向异常。这两个开关不开识别乱码的概率会高很多而且这种乱码是“有结果但结果是错的”不容易被监控发现比直接报错更隐蔽。use_doc_unwarping是卷曲矫正开关处理的是书本、纸张被拍弯的情况。它效果不错但推理耗时显著增加CPU 机器上不建议默认打开。遇到曲面文本场景可以单独为这类请求设置一个参数位按需开启。三个场景参数组合供参考场景推荐参数组合说明系统截图、网页截图use_orientationFalse截图方向固定省掉方向分类耗时手机拍照件、扫描件use_orientationTrue方向分类和行方向都打开识别率优先书本、弯曲纸张拍摄use_orientationTrueuse_doc_unwarpingTrue卷曲矫正只看准不准不追求速度参数组合建议以常量形式写死在服务配置里不要暴露成 HTTP 参数让调用方随便传。调用方不懂 OCR 参数传错方向分类开关反而会引入误识别。如果是给内部系统用固定参数、只暴露image一个入参是更踏实的设计。5. 部署避坑与常见问题排查5.1 环境类问题GLIBCXX、CUDA 不匹配、pip 装错版本现象 1import paddle直接报错日志里有libcudart.so: cannot open shared object file或CUDA driver version is insufficient。原因装的是paddlepaddle-gpu但机器上没有 NVIDIA 驱动或者驱动版本太老不支持 Paddle 编译时对应的 CUDA 版本。解决先nvidia-smi确认驱动是否存在以及右上角 Driver Version 是否够新。驱动没问题就按 Paddle 官网的 CUDA 对应关系重新安装匹配版本驱动不支持就直接卸载 GPU 版换 CPU 版。内网客户机器上 CPU 版反而省心PP-OCRv5 在 CPU 上识别单张图也就是秒级耗时多数业务完全够用。现象 2import paddle报GLIBCXX_3.4.29 not found。原因系统 libstdc 版本太老。常见于客户机器不是全新安装的 20.04而是从 18.04 原地升级上来的老库文件残留。解决优先使用虚拟环境或 conda 环境因为 conda 会自带较新的 libstdc能在环境层面绕过系统库。如果用了 venv 仍然报这个错用strings /usr/lib/x86_64-linux-gnu/libstdc.so.6 | grep GLIBCXX查系统库支持的版本确认缺了之后再通过 apt 升级libstdc6。注意不要手动拷贝开发机的 so 文件覆盖生产机这样做相当于把黑匣子搬到了生产环境出问题很难追溯。现象 3调用服务接口时报错提示PaddleOCR object has no attribute predict。原因装的是 paddleocr 2.x代码按 3.x 的 API 写的版本错位。解决pip show paddleocr查看版本2.x 环境下旧接口用ocr.ocr()新接口用ocr.predict()。这个坑每次换机器都会遇到节奏就是先确认版本再改代码。把版本约束写死在 requirements.txt 里是唯一的根治办法。5.2 推理类问题识别乱码、空结果、内存上涨现象 4识别结果里有字但全是乱码或者某些行识别为空。原因图片方向问题。整张图旋转了 90 度、单行文字是竖排的、或者文本区域有透视形变检测模型找到了区域但识别模型读不对。解决把use_doc_orientation_classifyTrue和use_textline_orientationTrue打开。特别注意竖排中文场景PP-OCRv5 对竖排文本支持有限如果业务里大量出现竖排建议单独准备竖排样本回来测试不要想当然认为模型是万能的。这类问题属于“有结果但结果错”我一般会在服务层面对低置信度结果比如rec_scores平均分低于 0.7打上标记让调用方知道这段识别结果不可信。现象 5服务跑了一天后内存或显存持续上涨最终 OOM 被杀。原因两种情况。一是代码里每个请求都新建了 PaddleOCR 实例模型权重反复加载上一次实例没有被回收二是多线程并发调用同一个实例Paddle 推理内部的缓存不断累积。解决模型实例必须全局单例启动时加载一次这是最基本的。并发场景下 3.x 的predict是否线程安全要看具体版本稳妥做法是用一个全局锁或者把请求排队控制住并发度。实测下来单实例串行处理CPU 版每秒大约能处理 1 到 3 张截图大部分内部系统够用了。5.3 服务类问题超时、并发、磁盘空间现象 6客户机器是 RK3588 或类似工控板拿到 tar 包解压时提示磁盘空间不足。原因工控板或云主机的系统盘通常只有 10GB-20GB而一个带着 venv 和模型权重的服务包解压后可能占用好几个 GB。标题里的 ubuntu20.04 环境经常出现在这种低配机器上磁盘规划容易被忽略。解决解压前先df -h看磁盘分区模型和服务放在数据盘而不是系统盘。另外确认 tar 包解压前先du -sh看一眼大小别等写满了才发现。这个坑不是技术深度问题但翻车率极高——机器能起来、服务也能装偏偏就是磁盘满导致模型写不进缓存。现象 7服务接口偶尔超时客户端报Read timed out。原因大图识别耗时太长。一张 5000px 宽的长截图检测阶段会切出大量候选区域识别阶段挨个过模型耗时可能达到几十秒。解决客户端上传前先压缩限制最长边不超过 2000px服务端侧可以对超大图做一次降采样再进模型。识别服务是 CPU 密集场景处理时间与图片内容复杂度相关不是简单的线性增长所以给调用方的建议永远是“能压缩就压缩”。6. 让服务更稳从能跑到跑稳的几个细节服务跑通只是第一步真正交付给客户之前建议把下面几个动作彻底做一遍其中第一件事就是让服务进程在意外退出后能自动拉起在 systemd 里注册成服务就解决了。下面这个 unit 文件可以直接套用注意 ExecStart 的路径改成实际部署路径[Unit] DescriptionPP-OCRv5 Service Afternetwork.target [Service] Typesimple Userubuntu WorkingDirectory/home/ubuntu/ocr-service EnvironmentOMP_NUM_THREADS4 EnvironmentMKL_NUM_THREADS4 ExecStart/home/ubuntu/ocr-service/venv/bin/python /home/ubuntu/ocr-service/app.py Restartalways RestartSec3 [Install] WantedBymulti-user.targetOMP_NUM_THREADS和MKL_NUM_THREADS这两个环境变量值得专门说一下。Paddle 的 CPU 推理依赖 OpenMP默认线程数按 CPU 核心数来但核心数多不一定快线程切换和内存带宽反而会成为瓶颈。我一般会在 4 核到 8 核的机器上把线程数限制在 4用压测结果反过来修正。GPU 机器不用设这两个变量但要注意显存分配use_doc_unwarping在 GPU 上关闭能显著降低显存占用。验证习惯方面我现在的做法是每次重启服务后先跑一张固定的测试图核对识别文本里是否包含某几个关键字段确认模型权重加载正确、接口完整可用再把它挂到上游系统。这个动作看着简单实际上能挡住一大半“服务起了但识别结果全错”的静默故障。第一次压测时用 ab 或自己写脚本并发跑 20 个请求就够了重点看两个数平均耗时是否在接受范围内、内存是否在请求结束后回落到稳定值而不是持续上涨——后者是内存泄漏的早期信号。望这几点能帮你在 ubuntu20.04 上把 PP-OCRv5 服务稳稳跑起来希望帮到你。本文还有配套的精品资源点击获取
返回列表