Go to file
kuuhaku d7ff077dd6 first commit 2026-07-15 10:32:14 +08:00
images first commit 2026-07-15 10:32:14 +08:00
.gitignore first commit 2026-07-15 10:32:14 +08:00
.python-version first commit 2026-07-15 10:32:14 +08:00
README.md first commit 2026-07-15 10:32:14 +08:00
batch_ocr.py first commit 2026-07-15 10:32:14 +08:00
main.py first commit 2026-07-15 10:32:14 +08:00
pyproject.toml first commit 2026-07-15 10:32:14 +08:00
uv.lock first commit 2026-07-15 10:32:14 +08:00
运行返回内容.log first commit 2026-07-15 10:32:14 +08:00

README.md

ocr-VL1.6

本地 CPU 部署 PaddlePaddle/PaddleOCR-VL-1.6 的 OCR 识别项目,包含完整的性能 Benchmark 和多级优化方案。

项目结构

ocr-VL1.6/
├── main.py            # 单图 OCR + Benchmark已集成 set_num_threads 加速)
├── batch_ocr.py       # 批量 OCR多进程并行加速
├── pyproject.toml     # 项目配置uv 管理)
├── images/
│   └── 手写01.png     # 测试图片手写中文1758×646
└── README.md

技术栈

组件 版本 说明
Python 3.13
PaddlePaddle 3.2.1 CPU 版(无 CUDA已编译 oneDNN/MKL-DNN
PaddleOCR 3.7.0 doc-parser extra
PaddleOCR-VL-1.6 0.9B 主 OCR 视觉语言模型(~1.8GB
PP-DocLayoutV3 - 版面检测模型(~126MB

模型缓存目录:~/.paddlex/official_models/

快速开始

前提条件

  • Python ≥ 3.13
  • uv 包管理器

安装

uv sync

运行

# 单张图片 OCR自动使用全部 CPU 核心)
uv run python main.py

# 批量 OCR多进程并行
uv run python batch_ocr.py images/ --workers 4

首次运行会自动从 ModelScope 下载模型文件(约 2GB后续使用缓存。

工作原理

PaddleOCRVL pipeline 分两阶段:

输入图片 → [PP-DocLayoutV3 版面检测] → [PaddleOCR-VL-1.6-0.9B 文字识别] → 结构化输出
  1. 版面检测 — PP-DocLayoutV3 检测页面中的文本块区域(坐标 + 标签 + 置信度)
  2. OCR 识别 — PaddleOCR-VL-1.6-0.9BGQA 架构视觉语言模型)逐块识别文字
  3. 结果输出 — 返回 PaddleOCRVLResult,包含布局信息和识别文本

输出结构

字段 类型 说明
layout_det_res.boxes list[dict] 版面文本区域cls_id, label, score, coordinate, polygon_points
parsing_res_list list[PaddleOCRVLBlock] 识别文本块(.label, .bbox, .content, .polygon_points
model_settings dict 推理配置开关(版面检测/图表/印章等)
width / height int 图片尺寸

性能优化迭代

测试机器Windows 11, CPU 20 核(逻辑线程), RAM 32GB, PaddlePaddle 3.2.1 CPU

迭代 0初始状态无任何优化

直接调用 pipeline.predict(),未设置任何线程参数。

阶段 耗时
模型初始化(加载权重) ~60s
首次推理(含 JIT 编译) ~285s
后续推理 ~238s~4 min

迭代 1算子级并行 — core.set_num_threads()

探索过程:

尝试 方法 结果
paddle.set_num_threads() Paddle 3.x 已移除该 API
环境变量 OMP_NUM_THREADS / MKL_NUM_THREADS Paddle 3.x 内部使用 oneDNN不读取这些变量
from paddle import core; core.set_num_threads(N) 有效! oneDNN 底层算子matmul 等)受该 API 控制

矩阵乘法微基准测试4000×4000

线程数 耗时 (matmul) 加速比
1 0.952s 1.0x
4 0.419s 2.3x
8 0.323s 2.9x
16 0.240s 4.0x
20 0.223s 4.3x

应用到 OCR 后的实际效果:

设置 core.set_num_threads(20) 后重新评测:

阶段 优化前 优化后 提速
模型初始化 ~60s ~40s 1.5x
推理 ~238s ~162s~2.7 min 1.5x

为什么不是 4.3x 矩阵乘法只是 OCR pipeline 的一部分。自回归解码(逐 token 生成天然串行、I/O 等待、版面检测中的非矩阵运算等不受线程数影响。


迭代 2批量多进程并行 — batch_ocr.py

思路: 多张图片时,用 multiprocessing.Pool 启动多个独立进程,每个进程加载一份 pipeline 实例,同时处理不同图片。

策略:

  • 每个子进程独立调用 core.set_num_threads(总核心 / 进程数),避免线程争抢
  • 例如 4 进程 × 5 线程 = 20 核心全部利用
# 4 进程并行
uv run python batch_ocr.py images/ --workers 4
配置 适用场景 理论加速比 内存开销 实际限制
set_num_threads(N) 单张图片 ~1.5x 无额外开销 自回归解码瓶颈
batch_ocr.py 批量多图 ~NxN=进程数) N × 2GB 内存/内存带宽

⚠️ 每个进程独立加载模型(~2GB32GB RAM 建议 --workers ≤ 4


优化总结

初始:  238s/image (单线程, 无优化)
  │
  ├─ 迭代1: set_num_threads(20)  →  162s  (1.5x, 单图最优)
  │
  └─ 迭代2: batch_ocr.py (4进程) →  ~40s/image (5.9x, 批量场景)

单图理论极限约 2.7 分钟(受自回归解码串行特征限制),批量场景通过粗粒度并行可进一步摊薄。

已知局限

问题 影响 说明
CPU 推理极慢 单图 ~2.7 min优化后 0.9B VL 模型不适合 CPU 实时场景
自回归解码串行 无法更细粒度并行 生成阶段逐 token 依赖,多线程收益有限
内存占用大 每进程需 ~2GB 限制了 batch_ocr.py 并行度
Windows 控制台乱码 中文输出显示为乱码 GBK 编码问题,文件写入/pipe 正常
ccache 警告 无实际影响 仅影响首次编译加速,可忽略