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

View File

@ -2,6 +2,8 @@
本地 CPU 部署 [PaddlePaddle/PaddleOCR-VL-1.6](https://github.com/PaddlePaddle/PaddleOCR) 的 OCR 识别项目,包含完整的性能 Benchmark 和多级优化方案。 本地 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)
## 项目结构 ## 项目结构
``` ```
@ -17,7 +19,7 @@ ocr-VL1.6/
## 技术栈 ## 技术栈
| 组件 | 版本 | 说明 | | 组件 | 版本 | 说明 |
|------|------|------| | ---------------- | ----- | ---------------------------------------- |
| Python | 3.13 | | | Python | 3.13 | |
| PaddlePaddle | 3.2.1 | CPU 版(无 CUDA已编译 oneDNN/MKL-DNN | | PaddlePaddle | 3.2.1 | CPU 版(无 CUDA已编译 oneDNN/MKL-DNN |
| PaddleOCR | 3.7.0 | 带 `doc-parser` extra | | PaddleOCR | 3.7.0 | 带 `doc-parser` extra |
@ -45,8 +47,8 @@ uv sync
# 单张图片 OCR自动使用全部 CPU 核心) # 单张图片 OCR自动使用全部 CPU 核心)
uv run python main.py uv run python main.py
# 批量 OCR多进程并行 # 批量 OCR多进程并行,安全默认值
uv run python batch_ocr.py images/ --workers 4 uv run python batch_ocr.py images/
``` ```
首次运行会自动从 ModelScope 下载模型文件(约 2GB后续使用缓存。 首次运行会自动从 ModelScope 下载模型文件(约 2GB后续使用缓存。
@ -66,7 +68,7 @@ uv run python batch_ocr.py images/ --workers 4
### 输出结构 ### 输出结构
| 字段 | 类型 | 说明 | | 字段 | 类型 | 说明 |
|------|------|------| | ---------------------- | ---------------------- | ------------------------------------------------------------ |
| `layout_det_res.boxes` | list[dict] | 版面文本区域cls_id, label, score, coordinate, polygon_points | | `layout_det_res.boxes` | list[dict] | 版面文本区域cls_id, label, score, coordinate, polygon_points |
| `parsing_res_list` | list[PaddleOCRVLBlock] | 识别文本块($.label, $.bbox, $.content, $.polygon_points | | `parsing_res_list` | list[PaddleOCRVLBlock] | 识别文本块($.label, $.bbox, $.content, $.polygon_points |
| `model_settings` | dict | 推理配置开关(版面检测/图表/印章等) | | `model_settings` | dict | 推理配置开关(版面检测/图表/印章等) |
@ -81,7 +83,7 @@ uv run python batch_ocr.py images/ --workers 4
直接调用 `pipeline.predict()`,未设置任何线程参数。 直接调用 `pipeline.predict()`,未设置任何线程参数。
| 阶段 | 耗时 | | 阶段 | 耗时 |
|------|------| | ----------------------- | --------------- |
| 模型初始化(加载权重) | ~60s | | 模型初始化(加载权重) | ~60s |
| 首次推理(含 JIT 编译) | ~285s | | 首次推理(含 JIT 编译) | ~285s |
| 后续推理 | ~238s~4 min | | 后续推理 | ~238s~4 min |
@ -91,7 +93,7 @@ uv run python batch_ocr.py images/ --workers 4
**探索过程:** **探索过程:**
| 尝试 | 方法 | 结果 | | 尝试 | 方法 | 结果 |
|------|------|------| | ---- | -------------------------------------------------- | ---------------------------------------------------- |
| ❌ | `paddle.set_num_threads()` | Paddle 3.x 已移除该 API | | ❌ | `paddle.set_num_threads()` | Paddle 3.x 已移除该 API |
| ❌ | 环境变量 `OMP_NUM_THREADS` / `MKL_NUM_THREADS` | Paddle 3.x 内部使用 oneDNN不读取这些变量 | | ❌ | 环境变量 `OMP_NUM_THREADS` / `MKL_NUM_THREADS` | Paddle 3.x 内部使用 oneDNN不读取这些变量 |
| ✅ | `from paddle import core; core.set_num_threads(N)` | **有效!** oneDNN 底层算子matmul 等)受该 API 控制 | | ✅ | `from paddle import core; core.set_num_threads(N)` | **有效!** oneDNN 底层算子matmul 等)受该 API 控制 |
@ -99,7 +101,7 @@ uv run python batch_ocr.py images/ --workers 4
**矩阵乘法微基准测试4000×4000** **矩阵乘法微基准测试4000×4000**
| 线程数 | 耗时 (matmul) | 加速比 | | 线程数 | 耗时 (matmul) | 加速比 |
|--------|--------------|--------| | ------ | ------------- | -------- |
| 1 | 0.952s | 1.0x | | 1 | 0.952s | 1.0x |
| 4 | 0.419s | 2.3x | | 4 | 0.419s | 2.3x |
| 8 | 0.323s | 2.9x | | 8 | 0.323s | 2.9x |
@ -111,7 +113,7 @@ uv run python batch_ocr.py images/ --workers 4
设置 `core.set_num_threads(20)` 后重新评测: 设置 `core.set_num_threads(20)` 后重新评测:
| 阶段 | 优化前 | 优化后 | 提速 | | 阶段 | 优化前 | 优化后 | 提速 |
|------|--------|--------|------| | ---------- | ------ | --------------------- | -------- |
| 模型初始化 | ~60s | ~40s | 1.5x | | 模型初始化 | ~60s | ~40s | 1.5x |
| 推理 | ~238s | **~162s~2.7 min** | **1.5x** | | 推理 | ~238s | **~162s~2.7 min** | **1.5x** |
@ -123,21 +125,35 @@ uv run python batch_ocr.py images/ --workers 4
**思路:** 多张图片时,用 `multiprocessing.Pool` 启动多个独立进程,每个进程加载一份 pipeline 实例,同时处理不同图片。 **思路:** 多张图片时,用 `multiprocessing.Pool` 启动多个独立进程,每个进程加载一份 pipeline 实例,同时处理不同图片。
**遇到的问题 & 修复(迭代 2.1**
| 问题 | 原因 | 修复 |
|------|------|------|
| 系统卡顿/黑屏/无响应 | `Pool.starmap` 同时启动 N 个进程,同步加载 N×2GB 模型CPU + 内存瞬间打满 | ① 进程错峰启动(随机延迟 0~15s`psutil` 降低进程优先级 ③ 预留 1 核给 OS ④ `imap_unordered` 替代 `starmap` |
**策略:** **策略:**
- 每个子进程独立调用 `core.set_num_threads(总核心 / 进程数)`,避免线程争抢 - 每个子进程独立调用 `core.set_num_threads((总核心-1) / 进程数)`,预留核心给 OS
- 例如 4 进程 × 5 线程 = 20 核心全部利用 - 例如 2 进程 × 9 线程 = 18 核,留 2 核给系统
- `--stagger` 控制错峰窗口,默认 15s
```bash ```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
# 自定义错峰窗口(值越大内存峰值越低,但总耗时增加)
uv run python batch_ocr.py images/ --workers 4 --stagger 30
``` ```
| 配置 | 适用场景 | 理论加速比 | 内存开销 | 实际限制 | | 配置 | 适用场景 | 理论加速比 | 内存开销 | 实际限制 |
|------|---------|-----------|---------|---------| | -------------------- | -------- | --------------- | ---------- | -------------- |
| `set_num_threads(N)` | 单张图片 | ~1.5x | 无额外开销 | 自回归解码瓶颈 | | `set_num_threads(N)` | 单张图片 | ~1.5x | 无额外开销 | 自回归解码瓶颈 |
| `batch_ocr.py` | 批量多图 | ~NxN=进程数) | N × 2GB | 内存/内存带宽 | | `batch_ocr.py` | 批量多图 | ~NxN=进程数) | N × 2GB | 内存/内存带宽,需错峰避免打满系统 |
> ⚠️ 每个进程独立加载模型(~2GB32GB RAM 建议 `--workers ≤ 4` > ⚠️ 每个进程独立加载模型(~2GB32GB RAM 建议 `--workers ≤ 4`
> 默认 `--workers 2` 为安全值,不会导致系统卡顿。
--- ---
@ -156,7 +172,7 @@ uv run python batch_ocr.py images/ --workers 4
## 已知局限 ## 已知局限
| 问题 | 影响 | 说明 | | 问题 | 影响 | 说明 |
|------|------|------| | ------------------ | ----------------------- | ------------------------------------- |
| CPU 推理极慢 | 单图 ~2.7 min优化后 | 0.9B VL 模型不适合 CPU 实时场景 | | CPU 推理极慢 | 单图 ~2.7 min优化后 | 0.9B VL 模型不适合 CPU 实时场景 |
| 自回归解码串行 | 无法更细粒度并行 | 生成阶段逐 token 依赖,多线程收益有限 | | 自回归解码串行 | 无法更细粒度并行 | 生成阶段逐 token 依赖,多线程收益有限 |
| 内存占用大 | 每进程需 ~2GB | 限制了 `batch_ocr.py` 并行度 | | 内存占用大 | 每进程需 ~2GB | 限制了 `batch_ocr.py` 并行度 |

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 time
import os import os
import sys import sys
import random
import argparse import argparse
from multiprocessing import Pool, cpu_count from multiprocessing import Pool, cpu_count
from pathlib import Path from pathlib import Path
# ── Worker 初始化(在子进程中执行) ──
def ocr_single(image_path: str, threads: int) -> dict: def _init_worker(threads: int, stagger_max: float):
"""单张图片 OCR在子进程中执行""" """
每个 Worker 启动时随机延迟 设线程数 降优先级 加载模型
随机延迟是关键避免 N 个进程同时读磁盘/分配内存
4×2GB=8GB 的内存峰值分散到 0~15s 的时间窗口中
"""
delay = random.uniform(0, stagger_max)
time.sleep(delay)
# 算子级线程数
from paddle import core from paddle import core
core.set_num_threads(threads) 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 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() t0 = time.perf_counter()
result = pipeline.predict(image_path) result = _pipeline.predict(image_path)
elapsed = time.perf_counter() - t0 elapsed = time.perf_counter() - t0
blocks = [] blocks = []
for block in result[0]["parsing_res_list"]: for block in result[0]["parsing_res_list"]:
if block.content.strip(): 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 { return {
"path": str(image_path), "path": str(image_path),
@ -40,53 +81,127 @@ def ocr_single(image_path: str, threads: int) -> dict:
} }
# ── 主流程 ──
def main(): 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("dir", type=str, help="图片目录")
parser.add_argument("--workers", type=int, default=4, help="并行进程数 (默认 4)") parser.add_argument(
parser.add_argument("--threads", type=int, default=None, help="每进程线程数 (默认: 总核心/workers)") "--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() args = parser.parse_args()
# ── 扫描图片 ──
image_dir = Path(args.dir) image_dir = Path(args.dir)
if not image_dir.is_dir(): if not image_dir.is_dir():
print(f"[ERROR] 目录不存在: {args.dir}") print(f"[ERROR] 目录不存在: {args.dir}")
sys.exit(1) 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: if not images:
print(f"[ERROR] 目录中没有图片: {args.dir}") print(f"[ERROR] 目录中没有图片: {args.dir}")
sys.exit(1) sys.exit(1)
# ── 资源规划 ──
workers = min(args.workers, len(images)) 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)
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" 图片数量: {len(images)}")
print(f" 并行进程: {workers}") print(f" 并行进程: {workers}")
print(f" 每进程线程: {threads}") print(f" 每进程线程: {threads}")
print(f"总核心利用: {workers * threads} / {cpu_count()}") 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) print("=" * 60)
if not mem_ok:
resp = input("内存不足,是否继续?[y/N] ").strip().lower()
if resp != "y":
print("已取消。")
sys.exit(0)
# ── 执行 ──
t0 = time.perf_counter() t0 = time.perf_counter()
# 每个子进程独立加载模型 + 推理 with Pool(
with Pool(workers) as pool: processes=workers,
tasks = [(str(img), threads) for img in images] initializer=_init_worker,
results = pool.starmap(ocr_single, tasks) 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 total_elapsed = time.perf_counter() - t0
# 输出结果 # ── 输出 ──
print("\n" + "=" * 60) 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)") print(f"\n[文件] {r['path']} ({r['elapsed']:.1f}s)")
for block in r["blocks"]: 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("\n" + "=" * 60)
print(f"总图片: {len(images)} | 总耗时: {total_elapsed:.1f}s") 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_elapsed / len(images):.1f}s")
print(f"单进程串行预计: {sum(r['elapsed'] for r in results):.1f}s") print(f" 串行预计: {total_per_image:.1f}s")
print(f"并行加速比: {sum(r['elapsed'] for r in results) / total_elapsed:.2f}x") if total_elapsed > 0:
print(f" 加速比: {total_per_image / total_elapsed:.2f}x")
print("=" * 60)
if __name__ == "__main__": 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 paddle import core
from paddleocr import PaddleOCRVL from paddleocr import PaddleOCRVL
IMAGE_PATH = "images/手写01.png" IMAGE_PATH = "images/名片02.jpg"
WARMUP_ROUNDS = 0 WARMUP_ROUNDS = 0
BENCHMARK_ROUNDS = 1 BENCHMARK_ROUNDS = 1