fix:修复批量处理导致的电脑死机、程序未响应问题

This commit is contained in:
kuuhaku 2026-07-15 12:18:58 +08:00
parent d7ff077dd6
commit 7f804d285e
9 changed files with 502 additions and 80 deletions

116
README.md
View File

@ -2,6 +2,8 @@
本地 CPU 部署 [PaddlePaddle/PaddleOCR-VL-1.6](https://github.com/PaddlePaddle/PaddleOCR) 的 OCR 识别项目,包含完整的性能 Benchmark 和多级优化方案。
> 在线 Demo: [HuggingFace Space](https://huggingface.co/spaces/PaddlePaddle/PaddleOCR-VL-1.6_Online_Demo) · 模型权重: [HuggingFace](https://huggingface.co/PaddlePaddle/PaddleOCR-VL-1.6)
## 项目结构
```
@ -16,13 +18,13 @@ ocr-VL1.6/
## 技术栈
| 组件 | 版本 | 说明 |
|------|------|------|
| 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 |
| 组件 | 版本 | 说明 |
| ---------------- | ----- | ---------------------------------------- |
| 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/`
@ -45,8 +47,8 @@ uv sync
# 单张图片 OCR自动使用全部 CPU 核心)
uv run python main.py
# 批量 OCR多进程并行
uv run python batch_ocr.py images/ --workers 4
# 批量 OCR多进程并行,安全默认值
uv run python batch_ocr.py images/
```
首次运行会自动从 ModelScope 下载模型文件(约 2GB后续使用缓存。
@ -65,12 +67,12 @@ uv run python batch_ocr.py images/ --workers 4
### 输出结构
| 字段 | 类型 | 说明 |
|------|------|------|
| `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 | 图片尺寸 |
| 字段 | 类型 | 说明 |
| ---------------------- | ---------------------- | ------------------------------------------------------------ |
| `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 | 图片尺寸 |
## 性能优化迭代
@ -80,40 +82,40 @@ uv run python batch_ocr.py images/ --workers 4
直接调用 `pipeline.predict()`,未设置任何线程参数。
| 阶段 | 耗时 |
|------|------|
| 模型初始化(加载权重) | ~60s |
| 首次推理(含 JIT 编译) | ~285s |
| 后续推理 | ~238s~4 min |
| 阶段 | 耗时 |
| ----------------------- | --------------- |
| 模型初始化(加载权重) | ~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 控制 |
| 尝试 | 方法 | 结果 |
| ---- | -------------------------------------------------- | ---------------------------------------------------- |
| ❌ | `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** |
| 线程数 | 耗时 (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** |
| 阶段 | 优化前 | 优化后 | 提速 |
| ---------- | ------ | --------------------- | -------- |
| 模型初始化 | ~60s | ~40s | 1.5x |
| 推理 | ~238s | **~162s~2.7 min** | **1.5x** |
**为什么不是 4.3x** 矩阵乘法只是 OCR pipeline 的一部分。自回归解码(逐 token 生成天然串行、I/O 等待、版面检测中的非矩阵运算等不受线程数影响。
@ -123,21 +125,35 @@ uv run python batch_ocr.py images/ --workers 4
**思路:** 多张图片时,用 `multiprocessing.Pool` 启动多个独立进程,每个进程加载一份 pipeline 实例,同时处理不同图片。
**遇到的问题 & 修复(迭代 2.1**
| 问题 | 原因 | 修复 |
|------|------|------|
| 系统卡顿/黑屏/无响应 | `Pool.starmap` 同时启动 N 个进程,同步加载 N×2GB 模型CPU + 内存瞬间打满 | ① 进程错峰启动(随机延迟 0~15s`psutil` 降低进程优先级 ③ 预留 1 核给 OS ④ `imap_unordered` 替代 `starmap` |
**策略:**
- 每个子进程独立调用 `core.set_num_threads(总核心 / 进程数)`,避免线程争抢
- 例如 4 进程 × 5 线程 = 20 核心全部利用
- 每个子进程独立调用 `core.set_num_threads((总核心-1) / 进程数)`,预留核心给 OS
- 例如 2 进程 × 9 线程 = 18 核,留 2 核给系统
- `--stagger` 控制错峰窗口,默认 15s
```bash
# 4 进程并行
# 2 进程并行(安全默认值)
uv run python batch_ocr.py images/
# 4 进程并行(需 32GB+ RAM
uv run python batch_ocr.py images/ --workers 4
# 自定义错峰窗口(值越大内存峰值越低,但总耗时增加)
uv run python batch_ocr.py images/ --workers 4 --stagger 30
```
| 配置 | 适用场景 | 理论加速比 | 内存开销 | 实际限制 |
|------|---------|-----------|---------|---------|
| `set_num_threads(N)` | 单张图片 | ~1.5x | 无额外开销 | 自回归解码瓶颈 |
| `batch_ocr.py` | 批量多图 | ~NxN=进程数) | N × 2GB | 内存/内存带宽 |
| 配置 | 适用场景 | 理论加速比 | 内存开销 | 实际限制 |
| -------------------- | -------- | --------------- | ---------- | -------------- |
| `set_num_threads(N)` | 单张图片 | ~1.5x | 无额外开销 | 自回归解码瓶颈 |
| `batch_ocr.py` | 批量多图 | ~NxN=进程数) | N × 2GB | 内存/内存带宽,需错峰避免打满系统 |
> ⚠️ 每个进程独立加载模型(~2GB32GB RAM 建议 `--workers ≤ 4`
> 默认 `--workers 2` 为安全值,不会导致系统卡顿。
---
@ -155,10 +171,10 @@ uv run python batch_ocr.py images/ --workers 4
## 已知局限
| 问题 | 影响 | 说明 |
|------|------|------|
| CPU 推理极慢 | 单图 ~2.7 min优化后 | 0.9B VL 模型不适合 CPU 实时场景 |
| 自回归解码串行 | 无法更细粒度并行 | 生成阶段逐 token 依赖,多线程收益有限 |
| 内存占用大 | 每进程需 ~2GB | 限制了 `batch_ocr.py` 并行度 |
| Windows 控制台乱码 | 中文输出显示为乱码 | GBK 编码问题,文件写入/pipe 正常 |
| ccache 警告 | 无实际影响 | 仅影响首次编译加速,可忽略 |
| 问题 | 影响 | 说明 |
| ------------------ | ----------------------- | ------------------------------------- |
| CPU 推理极慢 | 单图 ~2.7 min优化后 | 0.9B VL 模型不适合 CPU 实时场景 |
| 自回归解码串行 | 无法更细粒度并行 | 生成阶段逐 token 依赖,多线程收益有限 |
| 内存占用大 | 每进程需 ~2GB | 限制了 `batch_ocr.py` 并行度 |
| Windows 控制台乱码 | 中文输出显示为乱码 | GBK 编码问题,文件写入/pipe 正常 |
| ccache 警告 | 无实际影响 | 仅影响首次编译加速,可忽略 |

View File

@ -1,37 +1,78 @@
"""
批量 OCR 识别 多进程并行加速
批量 OCR 识别 多进程并行加速系统友好版
原理每个进程独立加载一份 pipeline 实例同时处理不同图片
适用场景一次处理多张图片如文件夹批量 OCR
修复要点:
1. 进程错峰启动随机延迟避免同时加载 N 个模型导致内存/CUP 打满
2. 降低子进程优先级保证系统 UI 正常响应
3. 预留 1-2 个核心给 OS避免 CPU 完全饱和
4. imap_unordered 逐任务分发而非一次性灌满
用法:
python batch_ocr.py <图片目录> [--workers 4] [--threads 10]
python batch_ocr.py <图片目录> [--workers 4] [--threads 5]
安全建议:
- 32GB RAM 建议 --workers <= 4
- 16GB RAM 建议 --workers <= 2
- 不确定时先用 --workers 1 测试
"""
import time
import os
import sys
import random
import argparse
from multiprocessing import Pool, cpu_count
from pathlib import Path
# ── Worker 初始化(在子进程中执行) ──
def ocr_single(image_path: str, threads: int) -> dict:
"""单张图片 OCR在子进程中执行"""
def _init_worker(threads: int, stagger_max: float):
"""
每个 Worker 启动时随机延迟 设线程数 降优先级 加载模型
随机延迟是关键避免 N 个进程同时读磁盘/分配内存
4×2GB=8GB 的内存峰值分散到 0~15s 的时间窗口中
"""
delay = random.uniform(0, stagger_max)
time.sleep(delay)
# 算子级线程数
from paddle import core
core.set_num_threads(threads)
# 降低进程优先级(不影响计算吞吐,但让 OS 调度更公平)
try:
import psutil
p = psutil.Process()
if sys.platform == "win32":
p.nice(psutil.BELOW_NORMAL_PRIORITY_CLASS)
else:
p.nice(10)
except ImportError:
pass
except Exception:
pass
# 加载 pipeline~2GB耗时 ~40s
from paddleocr import PaddleOCRVL
global _pipeline
_pipeline = PaddleOCRVL(pipeline_version="v1.6")
pipeline = PaddleOCRVL(pipeline_version="v1.6")
def _ocr_task(image_path: str) -> dict:
"""单张图片 OCR使用全局 pipeline"""
global _pipeline
t0 = time.perf_counter()
result = pipeline.predict(image_path)
result = _pipeline.predict(image_path)
elapsed = time.perf_counter() - t0
blocks = []
for block in result[0]["parsing_res_list"]:
if block.content.strip():
blocks.append({"label": block.label, "bbox": block.bbox, "content": block.content})
blocks.append({
"label": block.label,
"bbox": block.bbox,
"content": block.content,
})
return {
"path": str(image_path),
@ -40,53 +81,127 @@ def ocr_single(image_path: str, threads: int) -> dict:
}
# ── 主流程 ──
def main():
parser = argparse.ArgumentParser(description="Batch OCR with multiprocessing")
total_cores = cpu_count()
parser = argparse.ArgumentParser(
description="批量 OCR — 多进程并行(系统友好版)",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
python batch_ocr.py images/ # 默认 2 进程
python batch_ocr.py images/ --workers 4 # 4 进程(需 32GB RAM
python batch_ocr.py images/ --workers 2 --threads 8 # 指定每进程线程数
""",
)
parser.add_argument("dir", type=str, help="图片目录")
parser.add_argument("--workers", type=int, default=4, help="并行进程数 (默认 4)")
parser.add_argument("--threads", type=int, default=None, help="每进程线程数 (默认: 总核心/workers)")
parser.add_argument(
"--workers", type=int, default=2,
help="并行进程数 (默认 2安全值最大建议不超过 RAM_GB/2)",
)
parser.add_argument(
"--threads", type=int, default=None,
help=f"每进程线程数 (默认: (总核心-1)/workers保证 OS 有 1 核可用)",
)
parser.add_argument(
"--stagger", type=float, default=15.0,
help="进程启动错峰窗口秒数 (默认 15s值越大内存峰值越低)",
)
args = parser.parse_args()
# ── 扫描图片 ──
image_dir = Path(args.dir)
if not image_dir.is_dir():
print(f"[ERROR] 目录不存在: {args.dir}")
sys.exit(1)
images = list(image_dir.glob("*.png")) + list(image_dir.glob("*.jpg")) + list(image_dir.glob("*.jpeg"))
extensions = ("*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tiff", "*.tif", "*.webp")
images = []
for ext in extensions:
images.extend(image_dir.glob(ext))
images = sorted(images)
if not images:
print(f"[ERROR] 目录中没有图片: {args.dir}")
sys.exit(1)
# ── 资源规划 ──
workers = min(args.workers, len(images))
threads = args.threads or max(1, cpu_count() // workers)
reserved_for_os = 1 # 至少给 OS 留 1 个逻辑核心
if args.threads:
threads = args.threads
else:
threads = max(1, (total_cores - reserved_for_os) // workers)
print(f"图片数量: {len(images)}")
print(f"并行进程: {workers}")
print(f"每进程线程: {threads}")
print(f"总核心利用: {workers * threads} / {cpu_count()}")
total_cpu_used = workers * threads
stagger = args.stagger
# 内存估算
model_mem_per_worker = 2.0 # GB, 模型 ~1.8GB + 运行时开销
estimated_mem = workers * model_mem_per_worker + 2 # +2GB for OS
try:
import psutil
avail_gb = psutil.virtual_memory().available / (1024**3)
mem_ok = avail_gb > estimated_mem
except ImportError:
avail_gb = None
mem_ok = True # 无法检测,假定 OK
# ── 打印配置 ──
print("=" * 60)
print(f" 图片数量: {len(images)}")
print(f" 并行进程: {workers}")
print(f" 每进程线程: {threads}")
print(f" CPU 占用: {total_cpu_used} / {total_cores} 核 (保留 {total_cores - total_cpu_used} 给 OS)")
print(f" 错峰窗口: {stagger}s")
print(f" 预估内存: ~{estimated_mem:.0f}GB (可用: {avail_gb:.0f}GB)" if avail_gb else f" 预估内存: ~{estimated_mem:.0f}GB")
if not mem_ok:
print(f" [WARNING] 可用内存不足!建议降低 --workers 到 {max(1, int((avail_gb - 2) / model_mem_per_worker))}")
print("=" * 60)
if not mem_ok:
resp = input("内存不足,是否继续?[y/N] ").strip().lower()
if resp != "y":
print("已取消。")
sys.exit(0)
# ── 执行 ──
t0 = time.perf_counter()
# 每个子进程独立加载模型 + 推理
with Pool(workers) as pool:
tasks = [(str(img), threads) for img in images]
results = pool.starmap(ocr_single, tasks)
with Pool(
processes=workers,
initializer=_init_worker,
initargs=(threads, stagger),
) as pool:
# imap_unordered: 逐任务分发,先完成的先返回
# chunk 大 → 吞吐高但内存峰值高chunk=1 → 最平滑
image_paths = [str(img) for img in images]
results = list(pool.imap_unordered(_ocr_task, image_paths, chunksize=1))
total_elapsed = time.perf_counter() - t0
# 输出结果
# ── 输出 ──
print("\n" + "=" * 60)
for r in results:
for r in sorted(results, key=lambda x: x["path"]):
print(f"\n[文件] {r['path']} ({r['elapsed']:.1f}s)")
for block in r["blocks"]:
print(f" [{block['label']}] {block['content'][:60]}{'...' if len(block['content']) > 60 else ''}")
preview = block["content"].replace("\n", "\\n")
if len(preview) > 80:
preview = preview[:80] + "..."
print(f" [{block['label']}] {preview}")
total_per_image = sum(r["elapsed"] for r in results)
print("\n" + "=" * 60)
print(f"总图片: {len(images)} | 总耗时: {total_elapsed:.1f}s")
print(f"平均每图: {total_elapsed / len(images):.1f}s")
print(f"单进程串行预计: {sum(r['elapsed'] for r in results):.1f}s")
print(f"并行加速比: {sum(r['elapsed'] for r in results) / total_elapsed:.2f}x")
print(f" 总图片: {len(images)}")
print(f" 总耗时: {total_elapsed:.1f}s ({total_elapsed/60:.1f}min)")
print(f" 平均每图: {total_elapsed / len(images):.1f}s")
print(f" 串行预计: {total_per_image:.1f}s")
if total_elapsed > 0:
print(f" 加速比: {total_per_image / total_elapsed:.2f}x")
print("=" * 60)
if __name__ == "__main__":

BIN
images/名片01.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
images/名片02.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

85
logs/名片01.log Normal file
View File

@ -0,0 +1,85 @@
PS D:\Dev\ocr-VL1.6> uv run python .\main.py
信息: 用提供的模式无法找到文件。
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\cpp_extension\extension_utils.py:718: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
warnings.warn(warning_message)
[Threads] oneDNN compiled, using 20 threads (CPU cores: 20)
============================================================
初始化模型...
Creating model: ('PP-DocLayoutV3', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PP-DocLayoutV3`.
Creating model: ('PaddleOCR-VL-1.6-0.9B', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6`.
Bucketed engine_config has no entry for resolved engine 'paddle_dynamic'; using an empty config for that engine.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\config.json
Loading weights file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\model.safetensors
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.split.html first.
warnings.warn(
Loaded weights file from disk, setting weights to model.
All model checkpoint weights were used when initializing PaddleOCRVLForConditionalGeneration.
All the weights of PaddleOCRVLForConditionalGeneration were initialized from the model checkpoint at C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6.
If your task is similar to the task the model of the checkpoint was trained on, you can already use PaddleOCRVLForConditionalGeneration for predictions without further training.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\generation_config.json
[OK] 模型初始化耗时: 40.03s
============================================================
开始 OCR 识别: images/名片01.jpg
预热 0 轮 + 正式测试 1 轮
推理 1/1... D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\tensor\creation.py:1088: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach(), rather than paddle.to_tensor(sourceTensor).
return tensor(
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.max.html first.
warnings.warn(
81.30s
============================================================
[Benchmark]
图片尺寸: 591 x 360
检测文本块: 7 个
识别文本块: 6 个
推理次数: 1
最快: 81.30s
最慢: 81.30s
平均: 81.30s
============================================================
[识别结果]
[text] ([397, 17, 549, 38])
材质250g黄彩石纹
[header_image] ([39, 65, 184, 106])
[image] ([433, 100, 529, 152])
[paragraph_title] ([30, 188, 306, 244])
太原承方科技有限公司
山西承方印刷物资有限公司
[text] ([30, 282, 302, 306])
地址:太原市南十方街东中环口西南角
[text] ([32, 302, 471, 332])
Q Q: 800806277 手机: 13703585513 网址: www.cfprint.cn

85
logs/名片02.log Normal file
View File

@ -0,0 +1,85 @@
PS D:\Dev\ocr-VL1.6> uv run python .\main.py
信息: 用提供的模式无法找到文件。
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\cpp_extension\extension_utils.py:718: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
warnings.warn(warning_message)
[Threads] oneDNN compiled, using 20 threads (CPU cores: 20)
============================================================
初始化模型...
Creating model: ('PP-DocLayoutV3', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PP-DocLayoutV3`.
Creating model: ('PaddleOCR-VL-1.6-0.9B', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6`.
Bucketed engine_config has no entry for resolved engine 'paddle_dynamic'; using an empty config for that engine.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\config.json
Loading weights file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\model.safetensors
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.split.html first.
warnings.warn(
Loaded weights file from disk, setting weights to model.
All model checkpoint weights were used when initializing PaddleOCRVLForConditionalGeneration.
All the weights of PaddleOCRVLForConditionalGeneration were initialized from the model checkpoint at C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6.
If your task is similar to the task the model of the checkpoint was trained on, you can already use PaddleOCRVLForConditionalGeneration for predictions without further training.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\generation_config.json
[OK] 模型初始化耗时: 51.99s
============================================================
开始 OCR 识别: images/名片02.jpg
预热 0 轮 + 正式测试 1 轮
推理 1/1... D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\tensor\creation.py:1088: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach(), rather than paddle.to_tensor(sourceTensor).
return tensor(
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.max.html first.
warnings.warn(
111.56s
============================================================
[Benchmark]
图片尺寸: 1440 x 864
检测文本块: 6 个
识别文本块: 6 个
推理次数: 1
最快: 111.56s
最慢: 111.56s
平均: 111.56s
============================================================
[识别结果]
[paragraph_title] ([87, 59, 333, 130])
白滑影
[paragraph_title] ([713, 176, 1006, 300])
姜美丽
13388866888
[paragraph_title] ([312, 423, 655, 720])
夏佳人
[paragraph_title] ([710, 494, 1346, 563])
女子时尚瘦身健美馆
[text] ([713, 572, 1342, 615])
地址上海市湘江大街88号滨江大厦
[text] ([714, 619, 1208, 660])
电话83566666 83588888

121
logs/批量识别.log Normal file
View File

@ -0,0 +1,121 @@
PS D:\Dev\ocr-VL1.6> uv run python batch_ocr.py images/
============================================================
图片数量: 3
并行进程: 2
每进程线程: 9
CPU 占用: 18 / 20 核 (保留 2 给 OS)
错峰窗口: 15.0s
预估内存: ~6GB (可用: 17GB)
============================================================
信息: 用提供的模式无法找到文件。
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\cpp_extension\extension_utils.py:718: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
warnings.warn(warning_message)
Creating model: ('PP-DocLayoutV3', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PP-DocLayoutV3`.
信息: 用提供的模式无法找到文件。
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\cpp_extension\extension_utils.py:718: UserWarning: No ccache found. Please be aware that recompiling all source files may be required. You can download and install ccache from: https://github.com/ccache/ccache/blob/master/doc/INSTALL.md
warnings.warn(warning_message)
Creating model: ('PaddleOCR-VL-1.6-0.9B', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6`.
Bucketed engine_config has no entry for resolved engine 'paddle_dynamic'; using an empty config for that engine.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\config.json
Loading weights file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\model.safetensors
Creating model: ('PP-DocLayoutV3', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PP-DocLayoutV3`.
Creating model: ('PaddleOCR-VL-1.6-0.9B', None, None)
Model files already exist. Using cached files. To redownload, please delete the directory manually: `C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6`.
Bucketed engine_config has no entry for resolved engine 'paddle_dynamic'; using an empty config for that engine.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\config.json
Loading weights file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\model.safetensors
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
use GQA - num_heads: 16- num_key_value_heads: 2
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.split.html first.
warnings.warn(
Loaded weights file from disk, setting weights to model.
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.split.html first.
warnings.warn(
Loaded weights file from disk, setting weights to model.
All model checkpoint weights were used when initializing PaddleOCRVLForConditionalGeneration.
All the weights of PaddleOCRVLForConditionalGeneration were initialized from the model checkpoint at C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6.
If your task is similar to the task the model of the checkpoint was trained on, you can already use PaddleOCRVLForConditionalGeneration for predictions without further training.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\generation_config.json
All model checkpoint weights were used when initializing PaddleOCRVLForConditionalGeneration.
All the weights of PaddleOCRVLForConditionalGeneration were initialized from the model checkpoint at C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6.
If your task is similar to the task the model of the checkpoint was trained on, you can already use PaddleOCRVLForConditionalGeneration for predictions without further training.
Loading configuration file C:\Users\kuuhaku_0\.paddlex\official_models\PaddleOCR-VL-1.6\generation_config.json
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\tensor\creation.py:1088: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach(), rather than paddle.to_tensor(sourceTensor).
return tensor(
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.max.html first.
warnings.warn(
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\tensor\creation.py:1088: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach(), rather than paddle.to_tensor(sourceTensor).
return tensor(
D:\Dev\ocr-VL1.6\.venv\Lib\site-packages\paddle\utils\decorator_utils.py:420: Warning:
Non compatible API. Please refer to https://www.paddlepaddle.org.cn/documentation/docs/en/develop/guides/model_convert/convert_from_pytorch/api_difference/torch/torch.max.html first.
warnings.warn(
============================================================
[文件] images\名片01.jpg (65.1s)
[text] 材质250g黄彩石纹
[paragraph_title] 太原承方科技有限公司\n山西承方印刷物资有限公司
[text] 地址:太原市南十方街东中环口西南角
[text] Q Q: 800806277 手机: 13703585513 网址: www.cfprint.cn
[文件] images\名片02.jpg (83.2s)
[paragraph_title] 白滑影
[paragraph_title] 姜美丽\n13388866888
[paragraph_title] 夏佳人
[paragraph_title] 女子时尚瘦身健美馆
[text] 地址上海市湘江大街88号滨江大厦
[text] 电话83566666 83588888
[文件] images\手写01.png (156.6s)
[text] 最优质的草场。但是这两年由于旱獭和草原黄鼠的逐年\n保护,人们的行为需要矫正。\n部分。末日的时刻。\n佛巴林卡塔尔等海
[text] 很多消费者没有认识到医学验光的重要性,导致诸多后果。\n特许商品的销售便逐渐升温。文化软实力作出重要贡献。
============================================================
总图片: 3
总耗时: 275.6s (4.6min)
平均每图: 91.9s
串行预计: 304.9s
加速比: 1.11x
============================================================

View File

@ -3,7 +3,7 @@ import os
from paddle import core
from paddleocr import PaddleOCRVL
IMAGE_PATH = "images/手写01.png"
IMAGE_PATH = "images/名片02.jpg"
WARMUP_ROUNDS = 0
BENCHMARK_ROUNDS = 1