Files
invoice-master-poc-v2/README.md
Yaojia Wang b26fd61852 WOP
2026-01-13 00:10:27 +01:00

419 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 池处理文本 PDFGPU 池处理扫描 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 | 金额 |
## 安装
```bash
# 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 格式:
```csv
DocumentId,InvoiceDate,InvoiceNumber,InvoiceDueDate,OCR,Bankgiro,Plusgiro,Amount
3be53fd7-...,2025-12-13,100017500321,2026-01-03,100017500321,53939484,,114
```
### 2. 自动标注
```bash
# 使用双池模式 (CPU + GPU)
python -m src.cli.autolabel \
--dual-pool \
--cpu-workers 3 \
--gpu-workers 1
# 单线程模式
python -m src.cli.autolabel --workers 4
```
### 3. 训练模型
```bash
# 从预训练模型开始训练
python -m src.cli.train \
--model yolo11n.pt \
--epochs 100 \
--batch 16 \
--name invoice_yolo11n_full \
--dpi 150
```
### 4. 增量训练
当添加新数据后,可以在已训练模型基础上继续训练:
```bash
# 从已训练的 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. 推理
```bash
# 命令行推理
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 应用
```bash
# 启动 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 训练参数
```bash
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)
```
### 训练最佳实践
1. **禁用翻转增强** (文本检测):
```python
fliplr=0.0, flipud=0.0
```
2. **使用 Early Stopping**:
```python
patience=20
```
3. **启用 AMP** (混合精度训练):
```python
amp=True
```
4. **保存检查点**:
```python
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
```python
# 数据库配置
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
```bash
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
```bash
python -m src.cli.train [OPTIONS]
Options:
--model, -m 基础模型路径
--epochs, -e 训练轮数 (默认: 100)
--batch, -b 批大小 (默认: 16)
--imgsz 图像尺寸 (默认: 1280)
--dpi PDF 渲染 DPI (默认: 150)
--name 训练名称
--limit 限制文档数
```
### infer
```bash
python -m src.cli.infer [OPTIONS]
Options:
--model, -m 模型路径
--input, -i 输入 PDF/图像
--output, -o 输出 JSON 路径
--confidence 置信度阈值 (默认: 0.5)
--dpi 渲染 DPI (默认: 300)
--gpu 使用 GPU
```
### serve
```bash
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
```python
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 格式输出
```
## 开发状态
- [x] 文本层 PDF 自动标注
- [x] 扫描图 OCR 自动标注
- [x] 多池处理架构 (CPU + GPU)
- [x] PostgreSQL 数据库存储
- [x] YOLO 训练 (98.7% mAP@0.5)
- [x] 推理管道
- [x] 字段规范化和验证
- [x] Web 应用 (FastAPI + 前端 UI)
- [x] 增量训练支持
- [ ] 表格 items 处理
- [ ] 模型量化部署
## 许可证
MIT License