diff --git a/README.md b/README.md index 8860f10..051c77c 100644 --- a/README.md +++ b/README.md @@ -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` | 批量多图 | ~Nx(N=进程数) | N × 2GB | 内存/内存带宽 | +| 配置 | 适用场景 | 理论加速比 | 内存开销 | 实际限制 | +| -------------------- | -------- | --------------- | ---------- | -------------- | +| `set_num_threads(N)` | 单张图片 | ~1.5x | 无额外开销 | 自回归解码瓶颈 | +| `batch_ocr.py` | 批量多图 | ~Nx(N=进程数) | N × 2GB | 内存/内存带宽,需错峰避免打满系统 | > ⚠️ 每个进程独立加载模型(~2GB),32GB 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 警告 | 无实际影响 | 仅影响首次编译加速,可忽略 | diff --git a/batch_ocr.py b/batch_ocr.py index 1a75d98..85f03d4 100644 --- a/batch_ocr.py +++ b/batch_ocr.py @@ -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__": diff --git a/images/名片01.jpg b/images/名片01.jpg new file mode 100644 index 0000000..206da9b Binary files /dev/null and b/images/名片01.jpg differ diff --git a/images/名片02.jpg b/images/名片02.jpg new file mode 100644 index 0000000..9f9ab28 Binary files /dev/null and b/images/名片02.jpg differ diff --git a/logs/名片01.log b/logs/名片01.log new file mode 100644 index 0000000..0a31ad2 --- /dev/null +++ b/logs/名片01.log @@ -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 \ No newline at end of file diff --git a/logs/名片02.log b/logs/名片02.log new file mode 100644 index 0000000..e20b018 --- /dev/null +++ b/logs/名片02.log @@ -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 \ No newline at end of file diff --git a/运行返回内容.log b/logs/手写01.log similarity index 100% rename from 运行返回内容.log rename to logs/手写01.log diff --git a/logs/批量识别.log b/logs/批量识别.log new file mode 100644 index 0000000..68d7949 --- /dev/null +++ b/logs/批量识别.log @@ -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 +============================================================ \ No newline at end of file diff --git a/main.py b/main.py index f56fb0e..eaf21ca 100644 --- a/main.py +++ b/main.py @@ -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