11 KiB
11 KiB
Invoice Master POC v2
自动账单信息提取系统 - 使用 YOLOv11 + PaddleOCR 从瑞典 PDF 发票中提取结构化数据。
运行环境
本项目必须在 WSL + Conda 环境中运行。
系统要求
| 环境 | 要求 |
|---|---|
| WSL | WSL 2 + Ubuntu 22.04 |
| Conda | Miniconda 或 Anaconda |
| Python | 3.10+ (通过 Conda 管理) |
| GPU | NVIDIA GPU + CUDA 12.x (强烈推荐) |
| 数据库 | PostgreSQL (存储标注结果) |
功能特点
- 双模式 PDF 处理: 支持文本层 PDF 和扫描图 PDF
- 自动标注: 利用已有 CSV 结构化数据自动生成 YOLO 训练数据
- 多池处理架构: CPU 池处理文本 PDF,GPU 池处理扫描 PDF
- 数据库存储: 标注结果存储在 PostgreSQL,支持增量处理
- YOLO 检测: 使用 YOLOv11 检测发票字段区域
- OCR 识别: 使用 PaddleOCR 3.x 提取检测区域的文本
- Web 应用: 提供 REST API 和可视化界面
- 增量训练: 支持在已训练模型基础上继续训练
支持的字段
| 类别 ID | 字段名 | 说明 |
|---|---|---|
| 0 | invoice_number | 发票号码 |
| 1 | invoice_date | 发票日期 |
| 2 | invoice_due_date | 到期日期 |
| 3 | ocr_number | OCR 参考号 (瑞典支付系统) |
| 4 | bankgiro | Bankgiro 号码 |
| 5 | plusgiro | Plusgiro 号码 |
| 6 | amount | 金额 |
安装
# 1. 进入 WSL
wsl -d Ubuntu-22.04
# 2. 创建 Conda 环境
conda create -n invoice-py311 python=3.11 -y
conda activate invoice-py311
# 3. 进入项目目录
cd /mnt/c/Users/yaoji/git/ColaCoder/invoice-master-poc-v2
# 4. 安装依赖
pip install -r requirements.txt
# 5. 安装 Web 依赖
pip install uvicorn fastapi python-multipart pydantic
快速开始
1. 准备数据
~/invoice-data/
├── raw_pdfs/
│ ├── {DocumentId}.pdf
│ └── ...
├── structured_data/
│ └── document_export_YYYYMMDD.csv
└── dataset/
└── temp/ (渲染的图片)
CSV 格式:
DocumentId,InvoiceDate,InvoiceNumber,InvoiceDueDate,OCR,Bankgiro,Plusgiro,Amount
3be53fd7-...,2025-12-13,100017500321,2026-01-03,100017500321,53939484,,114
2. 自动标注
# 使用双池模式 (CPU + GPU)
python -m src.cli.autolabel \
--dual-pool \
--cpu-workers 3 \
--gpu-workers 1
# 单线程模式
python -m src.cli.autolabel --workers 4
3. 训练模型
# 从预训练模型开始训练
python -m src.cli.train \
--model yolo11n.pt \
--epochs 100 \
--batch 16 \
--name invoice_yolo11n_full \
--dpi 150
4. 增量训练
当添加新数据后,可以在已训练模型基础上继续训练:
# 从已训练的 best.pt 继续训练
python -m src.cli.train \
--model runs/train/invoice_yolo11n_full/weights/best.pt \
--epochs 30 \
--batch 16 \
--name invoice_yolo11n_v2 \
--dpi 150
增量训练建议:
| 场景 | 建议 |
|---|---|
| 添加少量新数据 (<20%) | 继续训练 10-30 epochs |
| 添加大量新数据 (>50%) | 继续训练 50-100 epochs |
| 修正大量标注错误 | 从头训练 |
| 添加新的字段类型 | 从头训练 |
5. 推理
# 命令行推理
python -m src.cli.infer \
--model runs/train/invoice_yolo11n_full/weights/best.pt \
--input path/to/invoice.pdf \
--output result.json \
--gpu
6. Web 应用
# 启动 Web 服务器
python run_server.py --port 8000
# 开发模式 (自动重载)
python run_server.py --debug --reload
# 禁用 GPU
python run_server.py --no-gpu
访问 http://localhost:8000 使用 Web 界面。
Web API 端点
| 方法 | 端点 | 描述 |
|---|---|---|
| GET | / |
Web UI 界面 |
| GET | /api/v1/health |
健康检查 |
| POST | /api/v1/infer |
上传文件并推理 |
| GET | /api/v1/results/{filename} |
获取可视化图片 |
训练配置
YOLO 训练参数
python -m src.cli.train [OPTIONS]
Options:
--model, -m 基础模型 (默认: yolo11n.pt)
--epochs, -e 训练轮数 (默认: 100)
--batch, -b 批大小 (默认: 16)
--imgsz 图像尺寸 (默认: 1280)
--dpi PDF 渲染 DPI (默认: 150)
--name 训练名称
--limit 限制文档数 (用于测试)
--device 设备 (0=GPU, cpu)
训练最佳实践
-
禁用翻转增强 (文本检测):
fliplr=0.0, flipud=0.0 -
使用 Early Stopping:
patience=20 -
启用 AMP (混合精度训练):
amp=True -
保存检查点:
save_period=10
训练结果示例
使用 15,571 张训练图片,100 epochs 后的结果:
| 指标 | 值 |
|---|---|
| mAP@0.5 | 98.7% |
| mAP@0.5-0.95 | 87.4% |
| Precision | 97.5% |
| Recall | 95.5% |
项目结构
invoice-master-poc-v2/
├── src/
│ ├── cli/ # 命令行工具
│ │ ├── autolabel.py # 自动标注
│ │ ├── train.py # 模型训练
│ │ ├── infer.py # 推理
│ │ └── serve.py # Web 服务器
│ ├── pdf/ # PDF 处理
│ │ ├── extractor.py # 文本提取
│ │ ├── renderer.py # 图像渲染
│ │ └── detector.py # 类型检测
│ ├── ocr/ # PaddleOCR 封装
│ ├── normalize/ # 字段规范化
│ ├── matcher/ # 字段匹配
│ ├── yolo/ # YOLO 相关
│ │ ├── annotation_generator.py
│ │ └── db_dataset.py
│ ├── inference/ # 推理管道
│ │ ├── pipeline.py
│ │ ├── yolo_detector.py
│ │ └── field_extractor.py
│ ├── processing/ # 多池处理架构
│ │ ├── worker_pool.py
│ │ ├── cpu_pool.py
│ │ ├── gpu_pool.py
│ │ ├── task_dispatcher.py
│ │ └── dual_pool_coordinator.py
│ ├── web/ # Web 应用
│ │ ├── app.py # FastAPI 应用
│ │ ├── routes.py # API 路由
│ │ ├── services.py # 业务逻辑
│ │ ├── schemas.py # 数据模型
│ │ └── config.py # 配置
│ └── data/ # 数据处理
├── config.py # 配置文件
├── run_server.py # Web 服务器启动脚本
├── runs/ # 训练输出
│ └── train/
│ └── invoice_yolo11n_full/
│ └── weights/
│ ├── best.pt
│ └── last.pt
└── requirements.txt
多池处理架构
项目使用 CPU + GPU 双池架构处理不同类型的 PDF:
┌─────────────────────────────────────────────────────┐
│ DualPoolCoordinator │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ CPU Pool │ │ GPU Pool │ │
│ │ (3 workers) │ │ (1 worker) │ │
│ │ │ │ │ │
│ │ Text PDFs │ │ Scanned PDFs │ │
│ │ ~50-87 it/s │ │ ~1-2 it/s │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ TaskDispatcher: 根据 PDF 类型分配任务 │
└─────────────────────────────────────────────────────┘
关键设计
- spawn 启动方式: 兼容 CUDA 多进程
- as_completed(): 无死锁结果收集
- 进程初始化器: 每个 worker 加载一次模型
- 协调器持久化: 跨 CSV 文件复用 worker 池
配置文件
config.py
# 数据库配置
DATABASE = {
'host': '192.168.68.31',
'port': 5432,
'database': 'docmaster',
'user': 'docmaster',
'password': '******',
}
# 路径配置
PATHS = {
'csv_dir': '~/invoice-data/structured_data',
'pdf_dir': '~/invoice-data/raw_pdfs',
'output_dir': '~/invoice-data/dataset',
}
CLI 命令参考
autolabel
python -m src.cli.autolabel [OPTIONS]
Options:
--csv, -c CSV 文件路径 (支持 glob)
--pdf-dir, -p PDF 文件目录
--output, -o 输出目录
--workers, -w 单线程模式 worker 数 (默认: 4)
--dual-pool 启用双池模式
--cpu-workers CPU 池 worker 数 (默认: 3)
--gpu-workers GPU 池 worker 数 (默认: 1)
--dpi 渲染 DPI (默认: 150)
--limit, -l 限制处理文档数
train
python -m src.cli.train [OPTIONS]
Options:
--model, -m 基础模型路径
--epochs, -e 训练轮数 (默认: 100)
--batch, -b 批大小 (默认: 16)
--imgsz 图像尺寸 (默认: 1280)
--dpi PDF 渲染 DPI (默认: 150)
--name 训练名称
--limit 限制文档数
infer
python -m src.cli.infer [OPTIONS]
Options:
--model, -m 模型路径
--input, -i 输入 PDF/图像
--output, -o 输出 JSON 路径
--confidence 置信度阈值 (默认: 0.5)
--dpi 渲染 DPI (默认: 300)
--gpu 使用 GPU
serve
python run_server.py [OPTIONS]
Options:
--host 绑定地址 (默认: 0.0.0.0)
--port 端口 (默认: 8000)
--model, -m 模型路径
--confidence 置信度阈值 (默认: 0.3)
--dpi 渲染 DPI (默认: 150)
--no-gpu 禁用 GPU
--reload 开发模式自动重载
--debug 调试模式
Python API
from src.inference import InferencePipeline
# 初始化
pipeline = InferencePipeline(
model_path='runs/train/invoice_yolo11n_full/weights/best.pt',
confidence_threshold=0.3,
use_gpu=True,
dpi=150
)
# 处理 PDF
result = pipeline.process_pdf('invoice.pdf')
# 处理图片
result = pipeline.process_image('invoice.png')
# 获取结果
print(result.fields) # {'InvoiceNumber': '12345', 'Amount': '1234.56', ...}
print(result.confidence) # {'InvoiceNumber': 0.95, 'Amount': 0.92, ...}
print(result.to_json()) # JSON 格式输出
开发状态
- 文本层 PDF 自动标注
- 扫描图 OCR 自动标注
- 多池处理架构 (CPU + GPU)
- PostgreSQL 数据库存储
- YOLO 训练 (98.7% mAP@0.5)
- 推理管道
- 字段规范化和验证
- Web 应用 (FastAPI + 前端 UI)
- 增量训练支持
- 表格 items 处理
- 模型量化部署
许可证
MIT License