Paddle ocr, easyicr and doctr gpu support. (#4)
All checks were successful
build_docker / essential (push) Successful in 0s
build_docker / build_cpu (push) Successful in 5m0s
build_docker / build_gpu (push) Successful in 22m55s
build_docker / build_easyocr (push) Successful in 18m47s
build_docker / build_easyocr_gpu (push) Successful in 19m0s
build_docker / build_raytune (push) Successful in 3m27s
build_docker / build_doctr (push) Successful in 19m42s
build_docker / build_doctr_gpu (push) Successful in 14m49s
All checks were successful
build_docker / essential (push) Successful in 0s
build_docker / build_cpu (push) Successful in 5m0s
build_docker / build_gpu (push) Successful in 22m55s
build_docker / build_easyocr (push) Successful in 18m47s
build_docker / build_easyocr_gpu (push) Successful in 19m0s
build_docker / build_raytune (push) Successful in 3m27s
build_docker / build_doctr (push) Successful in 19m42s
build_docker / build_doctr_gpu (push) Successful in 14m49s
This commit was merged in pull request #4.
This commit is contained in:
@@ -18,6 +18,8 @@ El procesamiento de documentos en español presenta particularidades que complic
|
||||
|
||||
La Tabla 1 resume los principales desafíos lingüísticos del OCR en español:
|
||||
|
||||
**Tabla 1.** *Desafíos lingüísticos específicos del OCR en español.*
|
||||
|
||||
| Desafío | Descripción | Impacto en OCR |
|
||||
|---------|-------------|----------------|
|
||||
| Caracteres especiales | ñ, á, é, í, ó, ú, ü, ¿, ¡ | Confusión con caracteres similares (n/ñ, a/á) |
|
||||
@@ -25,7 +27,7 @@ La Tabla 1 resume los principales desafíos lingüísticos del OCR en español:
|
||||
| Abreviaturas | Dr., Sra., Ud., etc. | Puntos internos confunden segmentación |
|
||||
| Nombres propios | Tildes en apellidos (García, Martínez) | Bases de datos sin soporte Unicode |
|
||||
|
||||
*Tabla 1. Desafíos lingüísticos específicos del OCR en español. Fuente: Elaboración propia.*
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
Además de los aspectos lingüísticos, los documentos académicos y administrativos en español presentan características tipográficas que complican el reconocimiento: variaciones en fuentes entre encabezados, cuerpo y notas al pie; presencia de tablas con bordes y celdas; logotipos institucionales; marcas de agua; y elementos gráficos como firmas o sellos. Estos elementos generan ruido que puede propagarse en aplicaciones downstream como la extracción de entidades nombradas o el análisis semántico.
|
||||
|
||||
@@ -37,6 +39,8 @@ La adaptación de modelos preentrenados a dominios específicos típicamente req
|
||||
|
||||
La Tabla 2 ilustra los requisitos típicos para diferentes estrategias de mejora de OCR:
|
||||
|
||||
**Tabla 2.** *Comparación de estrategias de mejora de modelos OCR.*
|
||||
|
||||
| Estrategia | Datos requeridos | Hardware | Tiempo | Expertise |
|
||||
|------------|------------------|----------|--------|-----------|
|
||||
| Fine-tuning completo | >10,000 imágenes etiquetadas | GPU (≥16GB VRAM) | Días-Semanas | Alto |
|
||||
@@ -44,7 +48,7 @@ La Tabla 2 ilustra los requisitos típicos para diferentes estrategias de mejora
|
||||
| Transfer learning | >500 imágenes etiquetadas | GPU (≥8GB VRAM) | Horas | Medio |
|
||||
| **Optimización de hiperparámetros** | **<100 imágenes de validación** | **CPU suficiente** | **Horas** | **Bajo-Medio** |
|
||||
|
||||
*Tabla 2. Comparación de estrategias de mejora de modelos OCR. Fuente: Elaboración propia.*
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
### La oportunidad: optimización sin fine-tuning
|
||||
|
||||
@@ -88,6 +92,8 @@ Una solución técnicamente superior pero impracticable tiene valor limitado. Es
|
||||
|
||||
Este trabajo se centra específicamente en:
|
||||
|
||||
**Tabla 3.** *Delimitación del alcance del trabajo.*
|
||||
|
||||
| Aspecto | Dentro del alcance | Fuera del alcance |
|
||||
|---------|-------------------|-------------------|
|
||||
| **Tipo de documento** | Documentos académicos digitales (PDF) | Documentos escaneados, manuscritos |
|
||||
@@ -96,7 +102,7 @@ Este trabajo se centra específicamente en:
|
||||
| **Método de mejora** | Optimización de hiperparámetros | Fine-tuning, aumento de datos |
|
||||
| **Hardware** | Ejecución en CPU | Aceleración GPU |
|
||||
|
||||
*Tabla 3. Delimitación del alcance del trabajo. Fuente: Elaboración propia.*
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
### Relevancia y beneficiarios
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ Este capítulo establece los objetivos del trabajo siguiendo la metodología SMA
|
||||
|
||||
### Justificación SMART del Objetivo General
|
||||
|
||||
**Tabla 4.** *Justificación SMART del objetivo general.*
|
||||
|
||||
| Criterio | Cumplimiento |
|
||||
|----------|--------------|
|
||||
| **Específico (S)** | Se define claramente qué se quiere lograr: optimizar PaddleOCR mediante ajuste de hiperparámetros para documentos en español |
|
||||
@@ -16,6 +18,8 @@ Este capítulo establece los objetivos del trabajo siguiendo la metodología SMA
|
||||
| **Relevante (R)** | El impacto es demostrable: mejora la extracción de texto en documentos académicos sin costes adicionales de infraestructura |
|
||||
| **Temporal (T)** | El plazo es un cuatrimestre, correspondiente al TFM |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
## Objetivos específicos
|
||||
|
||||
### OE1: Comparar soluciones OCR de código abierto
|
||||
@@ -100,45 +104,32 @@ flowchart LR
|
||||
|
||||
#### Clase ImageTextDataset
|
||||
|
||||
Se implementó una clase Python para cargar pares imagen-texto:
|
||||
|
||||
```python
|
||||
class ImageTextDataset:
|
||||
def __init__(self, root):
|
||||
# Carga pares (imagen, texto) de carpetas pareadas
|
||||
|
||||
def __getitem__(self, idx):
|
||||
# Retorna (PIL.Image, str)
|
||||
```
|
||||
Se implementó una clase Python para cargar pares imagen-texto que retorna tuplas (PIL.Image, str) desde carpetas pareadas. La implementación completa está disponible en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A).
|
||||
|
||||
### Fase 2: Benchmark Comparativo
|
||||
|
||||
#### Modelos Evaluados
|
||||
|
||||
**Tabla 5.** *Modelos OCR evaluados en el benchmark inicial.*
|
||||
|
||||
| Modelo | Versión | Configuración |
|
||||
|--------|---------|---------------|
|
||||
| EasyOCR | - | Idiomas: ['es', 'en'] |
|
||||
| PaddleOCR | PP-OCRv5 | Modelos server_det + server_rec |
|
||||
| DocTR | - | db_resnet50 + sar_resnet31 |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
#### Métricas de Evaluación
|
||||
|
||||
Se utilizó la biblioteca `jiwer` para calcular:
|
||||
|
||||
```python
|
||||
from jiwer import wer, cer
|
||||
|
||||
def evaluate_text(reference, prediction):
|
||||
return {
|
||||
'WER': wer(reference, prediction),
|
||||
'CER': cer(reference, prediction)
|
||||
}
|
||||
```
|
||||
Se utilizó la biblioteca `jiwer` para calcular CER y WER comparando el texto de referencia con la predicción del modelo OCR. La implementación está disponible en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A).
|
||||
|
||||
### Fase 3: Espacio de Búsqueda
|
||||
|
||||
#### Hiperparámetros Seleccionados
|
||||
|
||||
**Tabla 6.** *Hiperparámetros seleccionados para optimización.*
|
||||
|
||||
| Parámetro | Tipo | Rango/Valores | Descripción |
|
||||
|-----------|------|---------------|-------------|
|
||||
| `use_doc_orientation_classify` | Booleano | [True, False] | Clasificación de orientación del documento |
|
||||
@@ -149,76 +140,42 @@ def evaluate_text(reference, prediction):
|
||||
| `text_det_unclip_ratio` | Fijo | 0.0 | Coeficiente de expansión (fijado) |
|
||||
| `text_rec_score_thresh` | Continuo | [0.0, 0.7] | Umbral de confianza de reconocimiento |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
#### Configuración de Ray Tune
|
||||
|
||||
```python
|
||||
from ray import tune
|
||||
from ray.tune.search.optuna import OptunaSearch
|
||||
|
||||
search_space = {
|
||||
"use_doc_orientation_classify": tune.choice([True, False]),
|
||||
"use_doc_unwarping": tune.choice([True, False]),
|
||||
"textline_orientation": tune.choice([True, False]),
|
||||
"text_det_thresh": tune.uniform(0.0, 0.7),
|
||||
"text_det_box_thresh": tune.uniform(0.0, 0.7),
|
||||
"text_det_unclip_ratio": tune.choice([0.0]),
|
||||
"text_rec_score_thresh": tune.uniform(0.0, 0.7),
|
||||
}
|
||||
|
||||
tuner = tune.Tuner(
|
||||
trainable_paddle_ocr,
|
||||
tune_config=tune.TuneConfig(
|
||||
metric="CER",
|
||||
mode="min",
|
||||
search_alg=OptunaSearch(),
|
||||
num_samples=64,
|
||||
max_concurrent_trials=2
|
||||
)
|
||||
)
|
||||
```
|
||||
El espacio de búsqueda se definió utilizando `tune.choice()` para parámetros booleanos y `tune.uniform()` para parámetros continuos, con OptunaSearch como algoritmo de optimización configurado para minimizar CER en 64 trials. La implementación completa está disponible en `src/raytune/raytune_ocr.py` (ver Anexo A).
|
||||
|
||||
### Fase 4: Ejecución de Optimización
|
||||
|
||||
#### Arquitectura de Ejecución
|
||||
|
||||
Debido a incompatibilidades entre Ray y PaddleOCR en el mismo proceso, se implementó una arquitectura basada en subprocesos:
|
||||
Se implementó una arquitectura basada en contenedores Docker para aislar los servicios OCR y facilitar la reproducibilidad (ver sección 4.2.3 para detalles de la arquitectura).
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: "Arquitectura de ejecución con subprocesos"
|
||||
---
|
||||
flowchart LR
|
||||
A["Ray Tune (proceso principal)"]
|
||||
#### Ejecución con Docker Compose
|
||||
|
||||
A --> B["Subprocess 1: paddle_ocr_tuning.py --config"]
|
||||
B --> B_out["Retorna JSON con métricas"]
|
||||
|
||||
A --> C["Subprocess 2: paddle_ocr_tuning.py --config"]
|
||||
C --> C_out["Retorna JSON con métricas"]
|
||||
```
|
||||
|
||||
#### Script de Evaluación (paddle_ocr_tuning.py)
|
||||
|
||||
El script recibe hiperparámetros por línea de comandos:
|
||||
Los servicios se orquestan mediante Docker Compose (`src/docker-compose.tuning.*.yml`):
|
||||
|
||||
```bash
|
||||
python paddle_ocr_tuning.py \
|
||||
--pdf-folder ./dataset \
|
||||
--textline-orientation True \
|
||||
--text-det-box-thresh 0.5 \
|
||||
--text-det-thresh 0.4 \
|
||||
--text-rec-score-thresh 0.6
|
||||
# Iniciar servicio OCR
|
||||
docker compose -f docker-compose.tuning.doctr.yml up -d doctr-gpu
|
||||
|
||||
# Ejecutar optimización (64 trials)
|
||||
docker compose -f docker-compose.tuning.doctr.yml run raytune --service doctr --samples 64
|
||||
|
||||
# Detener servicios
|
||||
docker compose -f docker-compose.tuning.doctr.yml down
|
||||
```
|
||||
|
||||
Y retorna métricas en formato JSON:
|
||||
El servicio OCR expone una API REST que retorna métricas en formato JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"CER": 0.0125,
|
||||
"WER": 0.1040,
|
||||
"TIME": 331.09,
|
||||
"CER": 0.0149,
|
||||
"WER": 0.0762,
|
||||
"TIME": 15.8,
|
||||
"PAGES": 5,
|
||||
"TIME_PER_PAGE": 66.12
|
||||
"TIME_PER_PAGE": 3.16
|
||||
}
|
||||
```
|
||||
|
||||
@@ -235,23 +192,67 @@ Y retorna métricas en formato JSON:
|
||||
|
||||
#### Hardware
|
||||
|
||||
**Tabla 7.** *Especificaciones de hardware del entorno de desarrollo.*
|
||||
|
||||
| Componente | Especificación |
|
||||
|------------|----------------|
|
||||
| CPU | Intel Core (especificar modelo) |
|
||||
| RAM | 16 GB |
|
||||
| GPU | No disponible (ejecución en CPU) |
|
||||
| CPU | AMD Ryzen 7 5800H |
|
||||
| RAM | 16 GB DDR4 |
|
||||
| GPU | NVIDIA RTX 3060 Laptop (5.66 GB VRAM) |
|
||||
| Almacenamiento | SSD |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
#### Software
|
||||
|
||||
**Tabla 8.** *Versiones de software utilizadas.*
|
||||
|
||||
| Componente | Versión |
|
||||
|------------|---------|
|
||||
| Sistema Operativo | Windows 10/11 |
|
||||
| Python | 3.11.9 |
|
||||
| Sistema Operativo | Ubuntu 24.04.3 LTS |
|
||||
| Python | 3.12.3 |
|
||||
| PaddleOCR | 3.3.2 |
|
||||
| PaddlePaddle | 3.2.2 |
|
||||
| Ray | 2.52.1 |
|
||||
| Optuna | 4.6.0 |
|
||||
| Optuna | 4.7.0 |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
#### Justificación de Ejecución Local vs Cloud
|
||||
|
||||
La decisión de ejecutar los experimentos en hardware local en lugar de utilizar servicios cloud se fundamenta en un análisis de costos y beneficios operativos.
|
||||
|
||||
**Tabla 9.** *Costos de GPU en plataformas cloud.*
|
||||
|
||||
| Plataforma | GPU | Costo/Hora | Costo Mensual |
|
||||
|------------|-----|------------|---------------|
|
||||
| AWS EC2 g4dn.xlarge | NVIDIA T4 (16 GB) | $0.526 | ~$384 |
|
||||
| Google Colab Pro | T4/P100 | ~$1.30 | $10 + CU extras |
|
||||
| Google Colab Pro+ | T4/V100/A100 | ~$1.30 | $50 + CU extras |
|
||||
|
||||
*Fuente: Elaboración propia a partir de precios públicos de AWS y Google Cloud (enero 2026).*
|
||||
|
||||
Para las tareas específicas de este proyecto, los costos estimados en cloud serían:
|
||||
|
||||
**Tabla 10.** *Análisis de costos del proyecto en plataformas cloud.*
|
||||
|
||||
| Tarea | Tiempo GPU | Costo AWS | Costo Colab Pro |
|
||||
|-------|------------|-----------|-----------------|
|
||||
| Ajuste hiperparámetros (64×3 trials) | ~3 horas | ~$1.58 | ~$3.90 |
|
||||
| Evaluación completa (45 páginas) | ~5 min | ~$0.04 | ~$0.11 |
|
||||
| Desarrollo y depuración (20 horas/mes) | 20 horas | ~$10.52 | ~$26.00 |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
Las ventajas de la ejecución local incluyen:
|
||||
|
||||
1. **Costo cero de GPU**: La RTX 3060 ya está disponible en el equipo de desarrollo
|
||||
2. **Sin límites de tiempo**: AWS y Colab imponen timeouts de sesión que interrumpen experimentos largos
|
||||
3. **Acceso instantáneo**: Sin tiempo de aprovisionamiento de instancias cloud
|
||||
4. **Almacenamiento local**: Dataset y resultados en disco sin costos de transferencia
|
||||
5. **Iteración rápida**: Reinicio inmediato de contenedores Docker para depuración
|
||||
|
||||
Para un proyecto de investigación con múltiples iteraciones de ajuste de hiperparámetros, la ejecución local ahorra aproximadamente $50-100 mensuales comparado con servicios cloud, además de ofrecer mayor flexibilidad en la velocidad de iteración durante el desarrollo.
|
||||
|
||||
### Limitaciones Metodológicas
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ Se seleccionaron tres soluciones OCR de código abierto representativas del esta
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
**Imágenes Docker disponibles en el registro del proyecto:**
|
||||
- PaddleOCR: `seryus.ddns.net/unir/paddle-ocr-gpu`, `seryus.ddns.net/unir/paddle-ocr-cpu`
|
||||
- EasyOCR: `seryus.ddns.net/unir/easyocr-gpu`
|
||||
- DocTR: `seryus.ddns.net/unir/doctr-gpu`
|
||||
|
||||
### Criterios de Éxito
|
||||
|
||||
Los criterios establecidos para evaluar las soluciones fueron:
|
||||
@@ -65,121 +70,25 @@ Se utilizó el documento "Instrucciones para la redacción y elaboración del TF
|
||||
|
||||
#### Proceso de Conversión
|
||||
|
||||
La conversión del PDF a imágenes se realizó mediante PyMuPDF (fitz):
|
||||
|
||||
```python
|
||||
import fitz # PyMuPDF
|
||||
|
||||
def pdf_to_images(pdf_path, output_dir, dpi=300):
|
||||
doc = fitz.open(pdf_path)
|
||||
for page_num, page in enumerate(doc):
|
||||
# Matriz de transformación para 300 DPI
|
||||
mat = fitz.Matrix(dpi/72, dpi/72)
|
||||
pix = page.get_pixmap(matrix=mat)
|
||||
pix.save(f"{output_dir}/page_{page_num:04d}.png")
|
||||
```
|
||||
|
||||
La resolución de 300 DPI fue seleccionada como estándar para OCR de documentos, proporcionando suficiente detalle para caracteres pequeños sin generar archivos excesivamente grandes.
|
||||
La conversión del PDF a imágenes se realizó mediante PyMuPDF (fitz) a 300 DPI, resolución estándar para OCR que proporciona suficiente detalle para caracteres pequeños sin generar archivos excesivamente grandes. La implementación está disponible en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A).
|
||||
|
||||
#### Extracción del Ground Truth
|
||||
|
||||
El texto de referencia se extrajo directamente del PDF mediante PyMuPDF:
|
||||
|
||||
```python
|
||||
def extract_text(pdf_path):
|
||||
doc = fitz.open(pdf_path)
|
||||
text = ""
|
||||
for page in doc:
|
||||
blocks = page.get_text("dict")["blocks"]
|
||||
for block in blocks:
|
||||
if "lines" in block:
|
||||
for line in block["lines"]:
|
||||
for span in line["spans"]:
|
||||
text += span["text"]
|
||||
text += "\n"
|
||||
return text
|
||||
```
|
||||
|
||||
Esta aproximación preserva la estructura de líneas del documento original, aunque puede introducir errores en layouts muy complejos (tablas anidadas, texto en columnas).
|
||||
El texto de referencia se extrajo directamente del PDF mediante PyMuPDF, preservando la estructura de líneas del documento original. Esta aproximación puede introducir errores en layouts muy complejos (tablas anidadas, texto en columnas). La implementación está disponible en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A).
|
||||
|
||||
#### Configuración de los Modelos
|
||||
|
||||
Según el código en `ocr_benchmark_notebook.ipynb`:
|
||||
La configuración de cada modelo se detalla en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A):
|
||||
|
||||
**EasyOCR**:
|
||||
```python
|
||||
import easyocr
|
||||
- **EasyOCR**: Configurado con soporte para español e inglés, permitiendo reconocer palabras en ambos idiomas que puedan aparecer en documentos académicos (referencias, términos técnicos).
|
||||
|
||||
easyocr_reader = easyocr.Reader(['es', 'en']) # Spanish and English
|
||||
results = easyocr_reader.readtext(image_path)
|
||||
text = ' '.join([r[1] for r in results])
|
||||
```
|
||||
- **PaddleOCR (PP-OCRv5)**: Se utilizaron los modelos "server" (PP-OCRv5_server_det y PP-OCRv5_server_rec) que ofrecen mayor precisión a costa de mayor tiempo de inferencia. La versión utilizada fue PaddleOCR 3.2.0.
|
||||
|
||||
La configuración incluye soporte para español e inglés, permitiendo reconocer palabras en ambos idiomas que puedan aparecer en documentos académicos (referencias, términos técnicos).
|
||||
|
||||
**PaddleOCR (PP-OCRv5)**:
|
||||
```python
|
||||
from paddleocr import PaddleOCR
|
||||
|
||||
paddleocr_model = PaddleOCR(
|
||||
text_detection_model_name="PP-OCRv5_server_det",
|
||||
text_recognition_model_name="PP-OCRv5_server_rec",
|
||||
use_doc_orientation_classify=False,
|
||||
use_doc_unwarping=False,
|
||||
use_textline_orientation=True,
|
||||
)
|
||||
|
||||
result = paddleocr_model.predict(image_path)
|
||||
text = '\n'.join([line['rec_texts'][0] for line in result[0]['rec_res']])
|
||||
```
|
||||
|
||||
Se utilizaron los modelos "server" que ofrecen mayor precisión a costa de mayor tiempo de inferencia. La versión utilizada fue PaddleOCR 3.2.0.
|
||||
|
||||
**DocTR**:
|
||||
```python
|
||||
from doctr.models import ocr_predictor
|
||||
|
||||
doctr_model = ocr_predictor(
|
||||
det_arch="db_resnet50",
|
||||
reco_arch="sar_resnet31",
|
||||
pretrained=True
|
||||
)
|
||||
|
||||
result = doctr_model([image])
|
||||
text = result.render()
|
||||
```
|
||||
|
||||
Se seleccionaron las arquitecturas db_resnet50 para detección y sar_resnet31 para reconocimiento, representando una configuración de alta precisión.
|
||||
- **DocTR**: Se seleccionaron las arquitecturas db_resnet50 para detección y sar_resnet31 para reconocimiento, representando una configuración de alta precisión.
|
||||
|
||||
#### Métricas de Evaluación
|
||||
|
||||
Se utilizó la biblioteca `jiwer` para calcular CER y WER de manera estandarizada:
|
||||
|
||||
```python
|
||||
from jiwer import wer, cer
|
||||
|
||||
def evaluate_text(reference, prediction):
|
||||
"""
|
||||
Calcula métricas de error entre texto de referencia y predicción.
|
||||
|
||||
Args:
|
||||
reference: Texto ground truth
|
||||
prediction: Texto predicho por el OCR
|
||||
|
||||
Returns:
|
||||
dict con WER y CER
|
||||
"""
|
||||
# Normalización básica
|
||||
ref_clean = reference.lower().strip()
|
||||
pred_clean = prediction.lower().strip()
|
||||
|
||||
return {
|
||||
'WER': wer(ref_clean, pred_clean),
|
||||
'CER': cer(ref_clean, pred_clean)
|
||||
}
|
||||
```
|
||||
|
||||
La normalización a minúsculas y eliminación de espacios extremos asegura una comparación justa que no penaliza diferencias de capitalización.
|
||||
Se utilizó la biblioteca `jiwer` para calcular CER y WER de manera estandarizada. La normalización a minúsculas y eliminación de espacios extremos asegura una comparación justa que no penaliza diferencias de capitalización. La implementación está disponible en `src/ocr_benchmark_notebook.ipynb` (ver Anexo A).
|
||||
|
||||
### Resultados del Benchmark
|
||||
|
||||
@@ -322,7 +231,7 @@ Esta sección ha presentado:
|
||||
|
||||
### Introducción
|
||||
|
||||
Esta sección describe el proceso de optimización de hiperparámetros de PaddleOCR utilizando Ray Tune con el algoritmo de búsqueda Optuna. Los experimentos fueron implementados en el notebook `src/paddle_ocr_fine_tune_unir_raytune.ipynb` y los resultados se almacenaron en `src/raytune_paddle_subproc_results_20251207_192320.csv`.
|
||||
Esta sección describe el proceso de optimización de hiperparámetros de PaddleOCR utilizando Ray Tune con el algoritmo de búsqueda Optuna. Los experimentos fueron implementados en [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py) con la librería de utilidades [`src/raytune_ocr.py`](https://github.com/seryus/MastersThesis/blob/main/src/raytune_ocr.py), y los resultados se almacenaron en [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results).
|
||||
|
||||
La optimización de hiperparámetros representa una alternativa al fine-tuning tradicional que no requiere:
|
||||
- Acceso a GPU dedicada
|
||||
@@ -339,59 +248,68 @@ El experimento se ejecutó en el siguiente entorno:
|
||||
|
||||
| Componente | Versión/Especificación |
|
||||
|------------|------------------------|
|
||||
| Sistema operativo | Windows 10/11 |
|
||||
| Python | 3.11.9 |
|
||||
| Sistema operativo | Ubuntu 24.04.3 LTS |
|
||||
| Python | 3.12.3 |
|
||||
| PaddlePaddle | 3.2.2 |
|
||||
| PaddleOCR | 3.3.2 |
|
||||
| Ray | 2.52.1 |
|
||||
| Optuna | 4.6.0 |
|
||||
| CPU | Intel Core (multinúcleo) |
|
||||
| RAM | 16 GB |
|
||||
| GPU | No disponible (ejecución CPU) |
|
||||
| Optuna | 4.7.0 |
|
||||
| CPU | AMD Ryzen 7 5800H |
|
||||
| RAM | 16 GB DDR4 |
|
||||
| GPU | NVIDIA RTX 3060 Laptop (5.66 GB VRAM) |
|
||||
|
||||
*Fuente: Outputs del notebook `src/paddle_ocr_fine_tune_unir_raytune.ipynb`.*
|
||||
*Fuente: Configuración del entorno de ejecución. Resultados en `src/results/` generados por `src/run_tuning.py`.*
|
||||
|
||||
#### Arquitectura de Ejecución
|
||||
|
||||
Debido a incompatibilidades entre Ray y PaddleOCR cuando se ejecutan en el mismo proceso, se implementó una arquitectura basada en subprocesos:
|
||||
La arquitectura basada en contenedores Docker es fundamental para este proyecto debido a los conflictos de dependencias inherentes entre los diferentes componentes:
|
||||
|
||||
- **Conflictos entre motores OCR**: PaddleOCR, DocTR y EasyOCR tienen dependencias mutuamente incompatibles (diferentes versiones de PyTorch/PaddlePaddle, OpenCV, etc.)
|
||||
- **Incompatibilidades CUDA/cuDNN**: Cada motor OCR requiere versiones específicas de CUDA y cuDNN que no pueden coexistir en un mismo entorno virtual
|
||||
- **Aislamiento de Ray Tune**: Ray Tune tiene sus propias dependencias que pueden entrar en conflicto con las librerías de inferencia OCR
|
||||
|
||||
Esta arquitectura containerizada permite ejecutar cada componente en su entorno aislado óptimo, comunicándose via API REST:
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: "Arquitectura de ejecución con subprocesos"
|
||||
title: "Arquitectura de ejecución con Docker Compose"
|
||||
---
|
||||
flowchart LR
|
||||
A["Ray Tune (proceso principal)"]
|
||||
subgraph Docker["Docker Compose"]
|
||||
A["RayTune Container"]
|
||||
B["OCR Service Container"]
|
||||
end
|
||||
|
||||
A --> B["Subprocess 1: paddle_ocr_tuning.py --config"]
|
||||
B --> B_out["Retorna JSON con métricas"]
|
||||
|
||||
A --> C["Subprocess 2: paddle_ocr_tuning.py --config"]
|
||||
C --> C_out["Retorna JSON con métricas"]
|
||||
A -->|"HTTP POST /evaluate"| B
|
||||
B -->|"JSON {CER, WER, TIME}"| A
|
||||
A -.->|"Health check /health"| B
|
||||
```
|
||||
|
||||
El script `src/paddle_ocr_tuning.py` actúa como wrapper que:
|
||||
1. Recibe hiperparámetros por línea de comandos
|
||||
2. Inicializa PaddleOCR con la configuración especificada
|
||||
3. Evalúa sobre el dataset
|
||||
4. Retorna métricas en formato JSON
|
||||
La arquitectura containerizada (`src/docker-compose.tuning.*.yml`) ofrece:
|
||||
1. Aislamiento de dependencias entre Ray Tune y los motores OCR
|
||||
2. Health checks automáticos para asegurar disponibilidad del servicio
|
||||
3. Comunicación via API REST (endpoints `/health` y `/evaluate`)
|
||||
4. Soporte para GPU mediante nvidia-docker
|
||||
|
||||
```bash
|
||||
python paddle_ocr_tuning.py \
|
||||
--pdf-folder ./dataset \
|
||||
--textline-orientation True \
|
||||
--text-det-box-thresh 0.5 \
|
||||
--text-det-thresh 0.4 \
|
||||
--text-rec-score-thresh 0.6
|
||||
# Iniciar servicio OCR con GPU
|
||||
docker compose -f docker-compose.tuning.doctr.yml up -d doctr-gpu
|
||||
|
||||
# Ejecutar optimización (64 trials)
|
||||
docker compose -f docker-compose.tuning.doctr.yml run raytune --service doctr --samples 64
|
||||
|
||||
# Detener servicios
|
||||
docker compose -f docker-compose.tuning.doctr.yml down
|
||||
```
|
||||
|
||||
Salida:
|
||||
Respuesta del servicio OCR:
|
||||
```json
|
||||
{
|
||||
"CER": 0.0125,
|
||||
"WER": 0.1040,
|
||||
"TIME": 331.09,
|
||||
"CER": 0.0149,
|
||||
"WER": 0.0762,
|
||||
"TIME": 15.8,
|
||||
"PAGES": 5,
|
||||
"TIME_PER_PAGE": 66.12
|
||||
"TIME_PER_PAGE": 3.16
|
||||
}
|
||||
```
|
||||
|
||||
@@ -411,54 +329,11 @@ Para la fase de optimización se extendió el dataset:
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
La clase `ImageTextDataset` en `src/dataset_manager.py` gestiona la carga de pares imagen-texto:
|
||||
|
||||
```python
|
||||
class ImageTextDataset:
|
||||
def __init__(self, root):
|
||||
"""
|
||||
Carga pares (imagen, texto) de carpetas pareadas.
|
||||
|
||||
Estructura esperada:
|
||||
root/
|
||||
0/
|
||||
img/
|
||||
page_0001.png
|
||||
txt/
|
||||
page_0001.txt
|
||||
"""
|
||||
self.pairs = []
|
||||
for doc_folder in sorted(os.listdir(root)):
|
||||
img_folder = os.path.join(root, doc_folder, 'img')
|
||||
txt_folder = os.path.join(root, doc_folder, 'txt')
|
||||
# Cargar pares...
|
||||
|
||||
def __getitem__(self, idx):
|
||||
img_path, txt_path = self.pairs[idx]
|
||||
return PIL.Image.open(img_path), open(txt_path).read()
|
||||
```
|
||||
La clase `ImageTextDataset` gestiona la carga de pares imagen-texto desde la estructura de carpetas pareadas. La implementación está disponible en el repositorio (ver Anexo A).
|
||||
|
||||
#### Espacio de Búsqueda
|
||||
|
||||
El espacio de búsqueda se definió considerando los hiperparámetros más relevantes identificados en la documentación de PaddleOCR:
|
||||
|
||||
```python
|
||||
from ray import tune
|
||||
from ray.tune.search.optuna import OptunaSearch
|
||||
|
||||
search_space = {
|
||||
# Parámetros booleanos
|
||||
"use_doc_orientation_classify": tune.choice([True, False]),
|
||||
"use_doc_unwarping": tune.choice([True, False]),
|
||||
"textline_orientation": tune.choice([True, False]),
|
||||
|
||||
# Parámetros continuos (umbrales)
|
||||
"text_det_thresh": tune.uniform(0.0, 0.7),
|
||||
"text_det_box_thresh": tune.uniform(0.0, 0.7),
|
||||
"text_det_unclip_ratio": tune.choice([0.0]), # Fijado
|
||||
"text_rec_score_thresh": tune.uniform(0.0, 0.7),
|
||||
}
|
||||
```
|
||||
El espacio de búsqueda se definió considerando los hiperparámetros más relevantes identificados en la documentación de PaddleOCR, utilizando `tune.choice()` para parámetros booleanos y `tune.uniform()` para umbrales continuos. La implementación está disponible en `src/raytune/raytune_ocr.py` (ver Anexo A).
|
||||
|
||||
**Tabla 17.** *Descripción detallada del espacio de búsqueda.*
|
||||
|
||||
@@ -484,23 +359,7 @@ search_space = {
|
||||
|
||||
#### Configuración de Ray Tune
|
||||
|
||||
```python
|
||||
tuner = tune.Tuner(
|
||||
trainable_paddle_ocr,
|
||||
tune_config=tune.TuneConfig(
|
||||
metric="CER",
|
||||
mode="min",
|
||||
search_alg=OptunaSearch(),
|
||||
num_samples=64,
|
||||
max_concurrent_trials=2
|
||||
),
|
||||
run_config=air.RunConfig(
|
||||
verbose=2,
|
||||
log_to_file=False
|
||||
),
|
||||
param_space=search_space
|
||||
)
|
||||
```
|
||||
Se configuró Ray Tune con OptunaSearch como algoritmo de búsqueda, optimizando CER en 64 trials con 2 ejecuciones concurrentes. La implementación está disponible en `src/raytune/raytune_ocr.py` (ver Anexo A).
|
||||
|
||||
**Tabla 18.** *Parámetros de configuración de Ray Tune.*
|
||||
|
||||
@@ -613,7 +472,7 @@ Configuración óptima:
|
||||
| text_det_unclip_ratio | 0.0 | 1.5 | -1.5 (fijado) |
|
||||
| text_rec_score_thresh | **0.6350** | 0.5 | +0.135 |
|
||||
|
||||
*Fuente: Análisis del notebook.*
|
||||
*Fuente: Análisis de [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results) generados por [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py).*
|
||||
|
||||
#### Análisis de Correlación
|
||||
|
||||
@@ -628,7 +487,7 @@ Se calculó la correlación de Pearson entre los parámetros continuos y las mé
|
||||
| `text_rec_score_thresh` | -0.161 | Correlación débil negativa |
|
||||
| `text_det_unclip_ratio` | NaN | Varianza cero (valor fijo) |
|
||||
|
||||
*Fuente: Análisis del notebook.*
|
||||
*Fuente: Análisis de [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results) generados por [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py).*
|
||||
|
||||
**Tabla 24.** *Correlación de parámetros con WER.*
|
||||
|
||||
@@ -638,7 +497,7 @@ Se calculó la correlación de Pearson entre los parámetros continuos y las mé
|
||||
| `text_det_box_thresh` | +0.227 | Correlación débil positiva |
|
||||
| `text_rec_score_thresh` | -0.173 | Correlación débil negativa |
|
||||
|
||||
*Fuente: Análisis del notebook.*
|
||||
*Fuente: Análisis de [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results) generados por [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py).*
|
||||
|
||||
**Hallazgo clave**: El parámetro `text_det_thresh` muestra la correlación más fuerte (-0.52 con ambas métricas), indicando que valores más altos de este umbral tienden a reducir el error. Este umbral controla qué píxeles se consideran "texto" en el mapa de probabilidad del detector.
|
||||
|
||||
@@ -653,7 +512,7 @@ El parámetro booleano `textline_orientation` demostró tener el mayor impacto e
|
||||
| True | 3.76% | 7.12% | 12.73% | 32 |
|
||||
| False | 12.40% | 14.93% | 21.71% | 32 |
|
||||
|
||||
*Fuente: Análisis del notebook.*
|
||||
*Fuente: Análisis de [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results) generados por [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py).*
|
||||
|
||||
**Interpretación:**
|
||||
|
||||
@@ -706,33 +565,7 @@ Los trials con CER muy alto (>20%) presentaron patrones específicos:
|
||||
|
||||
#### Evaluación sobre Dataset Completo
|
||||
|
||||
La configuración óptima identificada se evaluó sobre el dataset completo de 24 páginas, comparando con la configuración baseline:
|
||||
|
||||
**Configuración Baseline:**
|
||||
```python
|
||||
baseline_config = {
|
||||
"textline_orientation": False, # Valor por defecto
|
||||
"use_doc_orientation_classify": False,
|
||||
"use_doc_unwarping": False,
|
||||
"text_det_thresh": 0.3, # Valor por defecto
|
||||
"text_det_box_thresh": 0.6, # Valor por defecto
|
||||
"text_det_unclip_ratio": 1.5, # Valor por defecto
|
||||
"text_rec_score_thresh": 0.5, # Valor por defecto
|
||||
}
|
||||
```
|
||||
|
||||
**Configuración Optimizada:**
|
||||
```python
|
||||
optimized_config = {
|
||||
"textline_orientation": True,
|
||||
"use_doc_orientation_classify": False,
|
||||
"use_doc_unwarping": False,
|
||||
"text_det_thresh": 0.4690,
|
||||
"text_det_box_thresh": 0.5412,
|
||||
"text_det_unclip_ratio": 0.0,
|
||||
"text_rec_score_thresh": 0.6350,
|
||||
}
|
||||
```
|
||||
La configuración óptima identificada se evaluó sobre el dataset completo de 24 páginas, comparando con la configuración baseline (valores por defecto de PaddleOCR). Los parámetros optimizados más relevantes fueron: `textline_orientation=True`, `text_det_thresh=0.4690`, `text_det_box_thresh=0.5412`, y `text_rec_score_thresh=0.6350`.
|
||||
|
||||
**Tabla 27.** *Comparación baseline vs optimizado (24 páginas).*
|
||||
|
||||
@@ -741,7 +574,7 @@ optimized_config = {
|
||||
| PaddleOCR (Baseline) | 7.78% | 92.22% | 14.94% | 85.06% |
|
||||
| PaddleOCR-HyperAdjust | **1.49%** | **98.51%** | **7.62%** | **92.38%** |
|
||||
|
||||
*Fuente: Ejecución final en notebook `src/paddle_ocr_fine_tune_unir_raytune.ipynb`.*
|
||||
*Fuente: Validación final. Código en [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py), resultados en [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results).*
|
||||
|
||||
#### Métricas de Mejora
|
||||
|
||||
@@ -759,15 +592,16 @@ optimized_config = {
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: "Comparación Baseline vs Optimizado (24 páginas)"
|
||||
title: "Reducción de errores: Baseline vs Optimizado"
|
||||
---
|
||||
xychart-beta
|
||||
x-axis ["CER", "WER"]
|
||||
x-axis ["CER Baseline", "CER Optimizado", "WER Baseline", "WER Optimizado"]
|
||||
y-axis "Tasa de error (%)" 0 --> 16
|
||||
bar "Baseline" [7.78, 14.94]
|
||||
bar "Optimizado" [1.49, 7.62]
|
||||
bar [7.78, 1.49, 14.94, 7.62]
|
||||
```
|
||||
|
||||
*Leyenda: CER = Character Error Rate, WER = Word Error Rate. Baseline = configuración por defecto de PaddleOCR. Optimizado = configuración encontrada por Ray Tune.*
|
||||
|
||||
#### Impacto Práctico
|
||||
|
||||
**En un documento típico de 10,000 caracteres:**
|
||||
@@ -808,7 +642,7 @@ xychart-beta
|
||||
|
||||
Esta sección ha presentado:
|
||||
|
||||
1. **Configuración del experimento**: Arquitectura de subprocesos, dataset extendido, espacio de búsqueda de 7 dimensiones
|
||||
1. **Configuración del experimento**: Arquitectura Docker Compose, dataset extendido, espacio de búsqueda de 7 dimensiones
|
||||
|
||||
2. **Resultados estadísticos**:
|
||||
- CER medio: 5.25% (std: 11.03%)
|
||||
@@ -823,9 +657,9 @@ Esta sección ha presentado:
|
||||
4. **Mejora final**: CER reducido de 7.78% a 1.49% (reducción del 80.9%)
|
||||
|
||||
**Fuentes de datos:**
|
||||
- `src/paddle_ocr_fine_tune_unir_raytune.ipynb`: Código del experimento
|
||||
- `src/raytune_paddle_subproc_results_20251207_192320.csv`: Resultados de 64 trials
|
||||
- `src/paddle_ocr_tuning.py`: Script de evaluación
|
||||
- [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py): Script principal de optimización
|
||||
- [`src/raytune_ocr.py`](https://github.com/seryus/MastersThesis/blob/main/src/raytune_ocr.py): Librería de utilidades Ray Tune
|
||||
- [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results): Resultados CSV de los trials
|
||||
|
||||
## Discusión y análisis de resultados
|
||||
|
||||
@@ -1002,24 +836,18 @@ Para documentos PDF digitales como los evaluados, estos módulos son innecesario
|
||||
|
||||
Para documentos académicos en español similares a los evaluados:
|
||||
|
||||
**Configuración recomendada:**
|
||||
```python
|
||||
config_recomendada = {
|
||||
# OBLIGATORIO
|
||||
"textline_orientation": True,
|
||||
**Tabla 31.** *Configuración recomendada para PaddleOCR.*
|
||||
|
||||
# RECOMENDADO
|
||||
"text_det_thresh": 0.45, # Rango: 0.4-0.5
|
||||
"text_rec_score_thresh": 0.6, # Rango: 0.5-0.7
|
||||
| Parámetro | Valor | Prioridad | Justificación |
|
||||
|-----------|-------|-----------|---------------|
|
||||
| `textline_orientation` | True | Obligatorio | Reduce CER en 69.7% |
|
||||
| `text_det_thresh` | 0.45 (rango: 0.4-0.5) | Recomendado | Correlación fuerte con CER |
|
||||
| `text_rec_score_thresh` | 0.6 (rango: 0.5-0.7) | Recomendado | Filtra reconocimientos poco confiables |
|
||||
| `text_det_box_thresh` | 0.55 (rango: 0.5-0.6) | Opcional | Impacto moderado |
|
||||
| `use_doc_orientation_classify` | False | No recomendado | Innecesario para PDFs digitales |
|
||||
| `use_doc_unwarping` | False | No recomendado | Innecesario para PDFs digitales |
|
||||
|
||||
# OPCIONAL
|
||||
"text_det_box_thresh": 0.55, # Rango: 0.5-0.6
|
||||
|
||||
# NO RECOMENDADO para PDFs digitales
|
||||
"use_doc_orientation_classify": False,
|
||||
"use_doc_unwarping": False,
|
||||
}
|
||||
```
|
||||
*Fuente: Análisis de resultados de optimización.*
|
||||
|
||||
#### Cuándo Aplicar Esta Metodología
|
||||
|
||||
@@ -1066,5 +894,74 @@ Este capítulo ha presentado el desarrollo completo de la contribución:
|
||||
**Resultado principal**: Se logró alcanzar el objetivo de CER < 2% mediante optimización de hiperparámetros, sin requerir fine-tuning ni recursos GPU.
|
||||
|
||||
**Fuentes de datos:**
|
||||
- `src/raytune_paddle_subproc_results_20251207_192320.csv`: Resultados de 64 trials
|
||||
- `src/paddle_ocr_fine_tune_unir_raytune.ipynb`: Notebook principal del experimento
|
||||
- [`src/run_tuning.py`](https://github.com/seryus/MastersThesis/blob/main/src/run_tuning.py): Script principal de optimización
|
||||
- [`src/results/`](https://github.com/seryus/MastersThesis/tree/main/src/results): Resultados CSV de los trials
|
||||
|
||||
**Imágenes Docker:**
|
||||
- `seryus.ddns.net/unir/paddle-ocr-gpu`: PaddleOCR con soporte GPU
|
||||
- `seryus.ddns.net/unir/easyocr-gpu`: EasyOCR con soporte GPU
|
||||
- `seryus.ddns.net/unir/doctr-gpu`: DocTR con soporte GPU
|
||||
|
||||
### Validación con Aceleración GPU
|
||||
|
||||
Para evaluar la viabilidad práctica del enfoque optimizado en escenarios de producción, se realizó una validación adicional utilizando aceleración GPU. Esta fase complementa los experimentos en CPU presentados anteriormente y demuestra la aplicabilidad del método cuando se dispone de hardware con capacidad de procesamiento paralelo.
|
||||
|
||||
#### Configuración del Entorno GPU
|
||||
|
||||
**Tabla 36.** *Especificaciones del entorno de validación GPU.*
|
||||
|
||||
| Componente | Especificación |
|
||||
|------------|----------------|
|
||||
| GPU | NVIDIA GeForce RTX 3060 Laptop |
|
||||
| VRAM | 5.66 GB |
|
||||
| CUDA | 12.4 |
|
||||
| Sistema Operativo | Ubuntu 24.04.3 LTS |
|
||||
| Kernel | 6.14.0-37-generic |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
El entorno de validación representa hardware de consumo típico para desarrollo de aplicaciones de machine learning, permitiendo evaluar el rendimiento en condiciones realistas de despliegue.
|
||||
|
||||
#### Comparación CPU vs GPU
|
||||
|
||||
Se evaluó el tiempo de procesamiento utilizando la configuración optimizada identificada en la fase anterior, comparando el rendimiento entre CPU y GPU.
|
||||
|
||||
**Tabla 37.** *Rendimiento comparativo CPU vs GPU.*
|
||||
|
||||
| Métrica | CPU | GPU (RTX 3060) | Factor de Aceleración |
|
||||
|---------|-----|----------------|----------------------|
|
||||
| Tiempo/Página | 69.4s | 0.55s | **126x** |
|
||||
| Dataset completo (45 páginas) | ~52 min | ~25 seg | **126x** |
|
||||
|
||||
*Fuente: Elaboración propia a partir de experimentos.*
|
||||
|
||||
La aceleración de 126x obtenida con GPU transforma la aplicabilidad práctica del sistema. Mientras que el procesamiento en CPU limita el uso a escenarios de procesamiento por lotes sin restricciones de tiempo, la velocidad con GPU habilita casos de uso interactivos y de tiempo real.
|
||||
|
||||
#### Comparación de Modelos PaddleOCR
|
||||
|
||||
PaddleOCR ofrece dos variantes de modelos: Mobile (optimizados para dispositivos con recursos limitados) y Server (mayor precisión a costa de mayor consumo de memoria). Se evaluó la viabilidad de ambas variantes en el hardware disponible.
|
||||
|
||||
**Tabla 38.** *Comparación de modelos Mobile vs Server en RTX 3060.*
|
||||
|
||||
| Modelo | VRAM Requerida | Resultado | Recomendación |
|
||||
|--------|----------------|-----------|---------------|
|
||||
| PP-OCRv5 Mobile | 0.06 GB | Funciona correctamente | ✓ Recomendado |
|
||||
| PP-OCRv5 Server | 5.3 GB | OOM en página 2 | ✗ Requiere >8 GB VRAM |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
Los modelos Server, a pesar de ofrecer potencialmente mayor precisión, resultan inviables en hardware con VRAM limitada (≤6 GB) debido a errores de memoria (Out of Memory). Los modelos Mobile, con un consumo de memoria 88 veces menor, funcionan de manera estable y ofrecen rendimiento suficiente para el caso de uso evaluado.
|
||||
|
||||
#### Conclusiones de la Validación GPU
|
||||
|
||||
La validación con aceleración GPU permite extraer las siguientes conclusiones:
|
||||
|
||||
1. **Aceleración significativa**: La GPU proporciona una aceleración de 126x sobre CPU, haciendo viable el procesamiento en tiempo real para aplicaciones interactivas.
|
||||
|
||||
2. **Modelos Mobile recomendados**: Para hardware con VRAM limitada (≤6 GB), los modelos Mobile de PP-OCRv5 ofrecen el mejor balance entre precisión y recursos, funcionando de manera estable sin errores de memoria.
|
||||
|
||||
3. **Viabilidad práctica**: Con GPU, el procesamiento de un documento completo (45 páginas) toma menos de 30 segundos, validando la aplicabilidad en entornos de producción donde el tiempo de respuesta es crítico.
|
||||
|
||||
4. **Escalabilidad**: La arquitectura de microservicios dockerizados utilizada para la validación GPU facilita el despliegue horizontal, permitiendo escalar el procesamiento según demanda.
|
||||
|
||||
Esta validación demuestra que la configuración optimizada mediante Ray Tune no solo mejora la precisión (CER: 7.78% → 1.49%) sino que, combinada con aceleración GPU, resulta prácticamente aplicable en escenarios de producción real.
|
||||
|
||||
@@ -10,10 +10,14 @@ Este Trabajo Fin de Máster ha demostrado que es posible mejorar significativame
|
||||
|
||||
El objetivo principal del trabajo era alcanzar un CER inferior al 2% en documentos académicos en español. Los resultados obtenidos confirman el cumplimiento de este objetivo:
|
||||
|
||||
**Tabla 39.** *Cumplimiento del objetivo de CER.*
|
||||
|
||||
| Métrica | Objetivo | Resultado |
|
||||
|---------|----------|-----------|
|
||||
| CER | < 2% | **1.49%** |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
### Conclusiones Específicas
|
||||
|
||||
**Respecto a OE1 (Comparativa de soluciones OCR)**:
|
||||
@@ -34,7 +38,7 @@ El objetivo principal del trabajo era alcanzar un CER inferior al 2% en document
|
||||
**Respecto a OE4 (Optimización con Ray Tune)**:
|
||||
- Se ejecutaron 64 trials con el algoritmo OptunaSearch
|
||||
- El tiempo total del experimento fue aproximadamente 6 horas (en CPU)
|
||||
- La arquitectura basada en subprocesos permitió superar incompatibilidades entre Ray y PaddleOCR
|
||||
- La arquitectura basada en contenedores Docker permitió superar incompatibilidades entre Ray y los motores OCR, facilitando además la portabilidad y reproducibilidad
|
||||
|
||||
**Respecto a OE5 (Validación de la configuración)**:
|
||||
- Se validó la configuración óptima sobre el dataset completo de 24 páginas
|
||||
@@ -69,7 +73,7 @@ El objetivo principal del trabajo era alcanzar un CER inferior al 2% en document
|
||||
|
||||
3. **Ground truth automático**: La extracción automática del texto de referencia puede introducir errores en layouts complejos.
|
||||
|
||||
4. **Ejecución en CPU**: Los tiempos de procesamiento (~69s/página) limitan la aplicabilidad en escenarios de alto volumen.
|
||||
4. **Validación en entorno limitado**: Aunque se validó con GPU (126x más rápido que CPU, 0.55s/página), los experimentos se realizaron en hardware de consumo (RTX 3060). Hardware empresarial podría ofrecer mejor rendimiento.
|
||||
|
||||
5. **Parámetro no explorado**: `text_det_unclip_ratio` permaneció fijo en 0.0 durante todo el experimento.
|
||||
|
||||
@@ -83,8 +87,6 @@ El objetivo principal del trabajo era alcanzar un CER inferior al 2% en document
|
||||
|
||||
3. **Dataset ampliado**: Construir un corpus más amplio y diverso de documentos en español.
|
||||
|
||||
4. **Evaluación con GPU**: Medir tiempos de inferencia con aceleración GPU.
|
||||
|
||||
### Líneas de Investigación
|
||||
|
||||
1. **Transfer learning de hiperparámetros**: Investigar si las configuraciones óptimas para un tipo de documento transfieren a otros dominios.
|
||||
|
||||
@@ -8,61 +8,210 @@ El código fuente completo y los datos utilizados en este trabajo están disponi
|
||||
|
||||
El repositorio incluye:
|
||||
|
||||
- **Notebooks de experimentación**: Código completo de los experimentos realizados
|
||||
- **Scripts de evaluación**: Herramientas para evaluar modelos OCR
|
||||
- **Servicios OCR dockerizados**: PaddleOCR, DocTR, EasyOCR con soporte GPU
|
||||
- **Scripts de evaluación**: Herramientas para evaluar y comparar modelos OCR
|
||||
- **Scripts de ajuste**: Ray Tune con Optuna para optimización de hiperparámetros
|
||||
- **Dataset**: Imágenes y textos de referencia utilizados
|
||||
- **Resultados**: Archivos CSV con los resultados de los 64 trials de Ray Tune
|
||||
- **Resultados**: Archivos CSV con los resultados de los 64 trials por servicio
|
||||
|
||||
## A.2 Estructura del Repositorio
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: "Estructura del repositorio del proyecto"
|
||||
---
|
||||
flowchart LR
|
||||
root["MastersThesis/"] --> docs["docs/"]
|
||||
root --> src["src/"]
|
||||
root --> instructions["instructions/"]
|
||||
root --> scripts["Scripts generación"]
|
||||
|
||||
src --> nb1["paddle_ocr_fine_tune_unir_raytune.ipynb"]
|
||||
src --> py1["paddle_ocr_tuning.py"]
|
||||
src --> csv["raytune_paddle_subproc_results_*.csv"]
|
||||
|
||||
scripts --> gen1["generate_mermaid_figures.py"]
|
||||
scripts --> gen2["apply_content.py"]
|
||||
```
|
||||
|
||||
**Descripción de componentes:**
|
||||
|
||||
- **docs/**: Capítulos de la tesis en Markdown (estructura UNIR)
|
||||
- **src/**: Código fuente de experimentación
|
||||
- `paddle_ocr_fine_tune_unir_raytune.ipynb`: Notebook principal con 64 trials Ray Tune
|
||||
- `paddle_ocr_tuning.py`: Script CLI para evaluación OCR
|
||||
- `raytune_paddle_subproc_results_20251207_192320.csv`: Resultados de optimización
|
||||
- **instructions/**: Plantilla e instrucciones UNIR
|
||||
- **Scripts de generación**: `generate_mermaid_figures.py` y `apply_content.py` para generar el documento TFM
|
||||
MastersThesis/
|
||||
├── docs/ # Documentación de la tesis
|
||||
│ └── metrics/ # Métricas de rendimiento OCR
|
||||
│ ├── metrics.md # Resumen comparativo
|
||||
│ ├── metrics_paddle.md # Resultados PaddleOCR
|
||||
│ ├── metrics_doctr.md # Resultados DocTR
|
||||
│ └── metrics_easyocr.md # Resultados EasyOCR
|
||||
├── src/
|
||||
│ ├── paddle_ocr/ # Servicio PaddleOCR
|
||||
│ │ ├── Dockerfile.gpu # Imagen Docker GPU
|
||||
│ │ ├── Dockerfile.cpu # Imagen Docker CPU
|
||||
│ │ ├── docker-compose.yml # Configuración Docker
|
||||
│ │ └── main.py # API FastAPI
|
||||
│ ├── doctr_service/ # Servicio DocTR
|
||||
│ │ ├── Dockerfile.gpu
|
||||
│ │ ├── docker-compose.yml
|
||||
│ │ └── main.py
|
||||
│ ├── easyocr_service/ # Servicio EasyOCR
|
||||
│ │ ├── Dockerfile.gpu
|
||||
│ │ ├── docker-compose.yml
|
||||
│ │ └── main.py
|
||||
│ ├── dataset/ # Dataset de evaluación
|
||||
│ ├── raytune_ocr.py # Utilidades compartidas Ray Tune
|
||||
│ └── results/ # Resultados de ajuste CSV
|
||||
└── .gitea/workflows/ci.yaml # Pipeline CI/CD
|
||||
```
|
||||
|
||||
## A.3 Requisitos de Software
|
||||
|
||||
Para reproducir los experimentos se requieren las siguientes dependencias:
|
||||
### Sistema de Desarrollo
|
||||
|
||||
**Tabla A1.** *Especificaciones del sistema de desarrollo.*
|
||||
|
||||
| Componente | Especificación |
|
||||
|------------|----------------|
|
||||
| Sistema Operativo | Ubuntu 24.04.3 LTS |
|
||||
| CPU | AMD Ryzen 7 5800H |
|
||||
| RAM | 16 GB DDR4 |
|
||||
| GPU | NVIDIA RTX 3060 Laptop (5.66 GB VRAM) |
|
||||
| CUDA | 12.4 |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
### Dependencias
|
||||
|
||||
**Tabla A2.** *Dependencias del proyecto.*
|
||||
|
||||
| Componente | Versión |
|
||||
|------------|---------|
|
||||
| Python | 3.11.9 |
|
||||
| PaddlePaddle | 3.2.2 |
|
||||
| PaddleOCR | 3.3.2 |
|
||||
| Python | 3.12.3 |
|
||||
| Docker | 29.1.5 |
|
||||
| NVIDIA Container Toolkit | Requerido para GPU |
|
||||
| Ray | 2.52.1 |
|
||||
| Optuna | 4.6.0 |
|
||||
| jiwer | (última versión) |
|
||||
| PyMuPDF | (última versión) |
|
||||
| Optuna | 4.7.0 |
|
||||
|
||||
## A.4 Instrucciones de Ejecución
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
1. Clonar el repositorio
|
||||
2. Instalar dependencias: `pip install -r requirements.txt`
|
||||
3. Ejecutar el notebook `src/paddle_ocr_fine_tune_unir_raytune.ipynb`
|
||||
## A.4 Instrucciones de Ejecución de Servicios OCR
|
||||
|
||||
## A.5 Licencia
|
||||
### PaddleOCR (Puerto 8002)
|
||||
|
||||
**Imágenes Docker:**
|
||||
- GPU: `seryus.ddns.net/unir/paddle-ocr-gpu`
|
||||
- CPU: `seryus.ddns.net/unir/paddle-ocr-cpu`
|
||||
|
||||
```bash
|
||||
cd src/paddle_ocr
|
||||
|
||||
# GPU (recomendado)
|
||||
docker compose up -d
|
||||
|
||||
# CPU (más lento, 126x)
|
||||
docker compose -f docker-compose.cpu-registry.yml up -d
|
||||
```
|
||||
|
||||
### DocTR (Puerto 8003)
|
||||
|
||||
**Imagen Docker:** `seryus.ddns.net/unir/doctr-gpu`
|
||||
|
||||
```bash
|
||||
cd src/doctr_service
|
||||
|
||||
# GPU
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### EasyOCR (Puerto 8002)
|
||||
|
||||
**Imagen Docker:** `seryus.ddns.net/unir/easyocr-gpu`
|
||||
|
||||
```bash
|
||||
cd src/easyocr_service
|
||||
|
||||
# GPU
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Verificar Estado del Servicio
|
||||
|
||||
```bash
|
||||
# Verificar salud del servicio
|
||||
curl http://localhost:8002/health
|
||||
|
||||
# Respuesta esperada:
|
||||
# {"status": "ok", "model_loaded": true, "gpu_name": "NVIDIA GeForce RTX 3060"}
|
||||
```
|
||||
|
||||
## A.5 Uso de la API OCR
|
||||
|
||||
### Evaluar Dataset Completo
|
||||
|
||||
```bash
|
||||
# PaddleOCR - Evaluación completa
|
||||
curl -X POST http://localhost:8002/evaluate_full \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pdf_folder": "/app/dataset",
|
||||
"save_output": true
|
||||
}'
|
||||
```
|
||||
|
||||
### Evaluar con Hiperparámetros Optimizados
|
||||
|
||||
```bash
|
||||
# PaddleOCR con configuración óptima
|
||||
curl -X POST http://localhost:8002/evaluate_full \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pdf_folder": "/app/dataset",
|
||||
"use_doc_orientation_classify": true,
|
||||
"use_doc_unwarping": false,
|
||||
"textline_orientation": true,
|
||||
"text_det_thresh": 0.0462,
|
||||
"text_det_box_thresh": 0.4862,
|
||||
"text_det_unclip_ratio": 0.0,
|
||||
"text_rec_score_thresh": 0.5658,
|
||||
"save_output": true
|
||||
}'
|
||||
```
|
||||
|
||||
## A.6 Ajuste de Hiperparámetros con Ray Tune
|
||||
|
||||
### Ejecutar Ajuste
|
||||
|
||||
```bash
|
||||
cd src
|
||||
|
||||
# Activar entorno virtual
|
||||
source ../.venv/bin/activate
|
||||
|
||||
# PaddleOCR (64 muestras)
|
||||
python -c "
|
||||
from raytune_ocr import *
|
||||
|
||||
ports = [8002]
|
||||
check_workers(ports, 'PaddleOCR')
|
||||
trainable = create_trainable(ports, paddle_ocr_payload)
|
||||
results = run_tuner(trainable, PADDLE_OCR_SEARCH_SPACE, num_samples=64)
|
||||
analyze_results(results, prefix='raytune_paddle', config_keys=PADDLE_OCR_CONFIG_KEYS)
|
||||
"
|
||||
```
|
||||
|
||||
### Servicios y Puertos
|
||||
|
||||
**Tabla A3.** *Servicios Docker y puertos.*
|
||||
|
||||
| Servicio | Puerto | Script de Ajuste |
|
||||
|----------|--------|------------------|
|
||||
| PaddleOCR | 8002 | `paddle_ocr_payload` |
|
||||
| DocTR | 8003 | `doctr_payload` |
|
||||
| EasyOCR | 8002 | `easyocr_payload` |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
## A.7 Métricas de Rendimiento
|
||||
|
||||
Los resultados detallados de las evaluaciones y ajustes de hiperparámetros se encuentran en:
|
||||
|
||||
- [Métricas Generales](metrics/metrics.md) - Comparativa de los tres servicios
|
||||
- [PaddleOCR](metrics/metrics_paddle.md) - Mejor precisión (7.76% CER baseline, **1.49% optimizado**)
|
||||
- [DocTR](metrics/metrics_doctr.md) - Más rápido (0.50s/página)
|
||||
- [EasyOCR](metrics/metrics_easyocr.md) - Balance intermedio
|
||||
|
||||
### Resumen de Resultados
|
||||
|
||||
**Tabla A4.** *Resumen de resultados del benchmark por servicio.*
|
||||
|
||||
| Servicio | CER Base | CER Ajustado | Mejora |
|
||||
|----------|----------|--------------|--------|
|
||||
| **PaddleOCR** | 8.85% | **7.72%** | 12.8% |
|
||||
| DocTR | 12.06% | 12.07% | 0% |
|
||||
| EasyOCR | 11.23% | 11.14% | 0.8% |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
## A.8 Licencia
|
||||
|
||||
El código se distribuye bajo licencia MIT.
|
||||
|
||||
242
docs/metrics/metrics.md
Normal file
242
docs/metrics/metrics.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# Métricas de Rendimiento OCR
|
||||
|
||||
**Fecha de Benchmark:** 2026-01-19
|
||||
**Dataset de Prueba:** 45 páginas (2 PDFs)
|
||||
|
||||
## Especificaciones del Sistema
|
||||
|
||||
| Componente | Especificación |
|
||||
|------------|----------------|
|
||||
| **Sistema Operativo** | Ubuntu 24.04.3 LTS (Noble) |
|
||||
| **Kernel** | 6.14.0-37-generic |
|
||||
| **CPU** | AMD Ryzen 7 5800H with Radeon Graphics |
|
||||
| **RAM** | 16 GB DDR4 |
|
||||
| **GPU** | NVIDIA GeForce RTX 3060 Laptop GPU |
|
||||
| **VRAM** | 5.66 GB |
|
||||
| **CUDA** | 12.4 |
|
||||
|
||||
## Justificación de Ejecución Local vs Cloud
|
||||
|
||||
### Costos de Cloud GPU
|
||||
|
||||
| Plataforma | GPU | Costo/Hora | Costo Mensual |
|
||||
|------------|-----|------------|---------------|
|
||||
| **AWS EC2 g4dn.xlarge** | NVIDIA T4 (16 GB) | $0.526 | ~$384 |
|
||||
| **Google Colab Pro** | T4/P100 | ~$1.30 | $10 + CU extras |
|
||||
| **Google Colab Pro+** | T4/V100/A100 | ~$1.30 | $50 + CU extras |
|
||||
|
||||
### Análisis de Costos para Este Proyecto
|
||||
|
||||
| Tarea | Tiempo GPU | Costo AWS | Costo Colab Pro |
|
||||
|-------|------------|-----------|-----------------|
|
||||
| Ajuste hiperparámetros (64×3 trials) | ~3 horas | ~$1.58 | ~$3.90 |
|
||||
| Evaluación completa (45 páginas) | ~5 min | ~$0.04 | ~$0.11 |
|
||||
| Desarrollo/debug (20 horas/mes) | 20 horas | ~$10.52 | ~$26.00 |
|
||||
|
||||
### Ventajas de Ejecución Local
|
||||
|
||||
1. **Costo cero de GPU**: La RTX 3060 ya está disponible en el equipo de desarrollo
|
||||
2. **Sin límites de tiempo**: AWS y Colab tienen timeouts de sesión
|
||||
3. **Acceso instantáneo**: Sin tiempo de aprovisionamiento de instancias
|
||||
4. **Almacenamiento local**: Dataset y resultados en disco sin costos de transferencia
|
||||
5. **Iteración rápida**: Reinicio inmediato de contenedores Docker
|
||||
|
||||
### Conclusión
|
||||
|
||||
Para un proyecto de investigación con múltiples iteraciones de ajuste de hiperparámetros y desarrollo, **la ejecución local ahorra ~$50-100/mes** comparado con cloud, además de ofrecer mayor flexibilidad y velocidad de iteración
|
||||
|
||||
## Resumen Ejecutivo
|
||||
|
||||
| Servicio | CER | WER | Tiempo/Página | Tiempo Total | VRAM |
|
||||
|----------|-----|-----|---------------|--------------|------|
|
||||
| **PaddleOCR (Mobile)** | **7.76%** | **11.62%** | 0.58s | 32.0s | 0.06 GB |
|
||||
| EasyOCR | 11.23% | 36.36% | 1.88s | 88.5s | ~2 GB |
|
||||
| DocTR | 12.06% | 42.01% | 0.50s | 28.4s | ~1 GB |
|
||||
|
||||
> **Ganador:** PaddleOCR (Mobile) - Mejor precisión (7.76% CER) con velocidad competitiva.
|
||||
|
||||
## Fases Experimentales
|
||||
|
||||
Este documento presenta resultados de dos fases experimentales distintas realizadas durante el desarrollo del TFM. La primera fase corresponde a la optimización de hiperparámetros utilizando Ray Tune, ejecutada en CPU debido a las limitaciones de hardware iniciales. La segunda fase corresponde a la validación práctica con aceleración GPU para evaluar la viabilidad en escenarios de producción.
|
||||
|
||||
**Tabla.** *Fases experimentales y sus características.*
|
||||
|
||||
| Fase | Dataset | Hardware | Resultado Principal |
|
||||
|------|---------|----------|---------------------|
|
||||
| Optimización (CPU) | 24 páginas | CPU | CER: 7.78% → **1.49%** (80.9% mejora) |
|
||||
| Validación (GPU) | 45 páginas | RTX 3060 | CER: 7.76% baseline, 0.55s/página |
|
||||
|
||||
*Fuente: Elaboración propia.*
|
||||
|
||||
La fase de optimización representa el **resultado principal del TFM** (CER 1.49%, precisión 98.51%). La fase de validación GPU confirma la viabilidad práctica del enfoque, demostrando una aceleración de 126x respecto a CPU.
|
||||
|
||||
## Comparación de Servicios OCR
|
||||
|
||||
### Comparación de Precisión (CER - menor es mejor)
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
title "Tasa de Error de Caracteres por Servicio"
|
||||
x-axis ["PaddleOCR", "EasyOCR", "DocTR"]
|
||||
y-axis "CER %" 0 --> 15
|
||||
bar [7.76, 11.23, 12.06]
|
||||
```
|
||||
|
||||
### Comparación de Velocidad (Tiempo por Página)
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
title "Tiempo de Procesamiento por Página (segundos)"
|
||||
x-axis ["DocTR", "PaddleOCR", "EasyOCR"]
|
||||
y-axis "Segundos" 0 --> 2
|
||||
bar [0.50, 0.58, 1.88]
|
||||
```
|
||||
|
||||
### Flujo de Recomendación de Servicio
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A{Prioridad?}
|
||||
A -->|Precisión| B[PaddleOCR]
|
||||
A -->|Velocidad| C[DocTR]
|
||||
A -->|Balance| B
|
||||
B --> D["7.76% CER<br/>0.58s/página"]
|
||||
C --> E["12.06% CER<br/>0.50s/página"]
|
||||
```
|
||||
|
||||
### Hallazgos Clave
|
||||
|
||||
1. **Mejor Precisión**: PaddleOCR logra las tasas de error más bajas (7.76% CER, 11.62% WER)
|
||||
2. **Mejor Velocidad**: DocTR es el más rápido (0.50s/página), pero 55% menos preciso que PaddleOCR
|
||||
3. **EasyOCR**: El más lento (3.8x más lento que PaddleOCR) con precisión intermedia
|
||||
4. **Eficiencia VRAM**: PaddleOCR Mobile usa solo 0.06 GB
|
||||
|
||||
## Configuración de Modelos
|
||||
|
||||
| Servicio | Detección | Reconocimiento | ¿Correcto para Español? |
|
||||
|----------|-----------|----------------|-------------------------|
|
||||
| **PaddleOCR** | PP-OCRv5_mobile_det | PP-OCRv5_mobile_rec | Sí |
|
||||
| **DocTR** | db_resnet50 | crnn_vgg16_bn | No (entrenado en inglés/francés) |
|
||||
| **EasyOCR** | CRAFT | latin_g2.pth | Sí |
|
||||
|
||||
### Notas sobre Modelos
|
||||
|
||||
- **PaddleOCR**: Modelos server más precisos disponibles pero requieren >5.3 GB VRAM (OOM en RTX 3060)
|
||||
- **DocTR**: Se probó modelo `parseq` como alternativa, resultó 2% peor CER y 2x más lento. El problema de diacríticos es de datos de entrenamiento, no de arquitectura
|
||||
- **EasyOCR**: Modelo `latin_g2.pth` es correcto. Los problemas son del detector CRAFT, no del reconocimiento
|
||||
|
||||
> **Conclusión sobre Fine-tuning:** Para documentos en español, **usar PaddleOCR directamente**. El fine-tuning de DocTR/EasyOCR no se justifica dado que PaddleOCR ya ofrece 31-36% mejor precisión sin configuración adicional.
|
||||
|
||||
## Análisis de Errores (del debugset)
|
||||
|
||||
### PaddleOCR (Mejor - 7.76% CER)
|
||||
- **Fortalezas**: Preserva estructura de líneas, maneja bien acentos españoles
|
||||
- **Problemas**: Errores menores de espaciado, diferencias ocasionales de mayúsculas en acentos
|
||||
- **Mejorable**: Sí - el ajuste de hiperparámetros probablemente ayude
|
||||
|
||||
### DocTR (Peor WER - 42.01%)
|
||||
- **Problema Crítico**: Colapsa todo el texto en líneas únicas (pierde estructura)
|
||||
- **Problema de Acentos**: Omite diacríticos ("Indice" vs "Índice")
|
||||
- **Mejorable**: Parcialmente - el problema de estructura puede ser a nivel de modelo
|
||||
|
||||
### EasyOCR (36.36% WER)
|
||||
- **Problema Crítico**: Inserciones espurias de caracteres (";", "g", "0", "1")
|
||||
- **Pérdida de Estructura**: Saltos de línea no preservados
|
||||
- **Mejorable**: Sí - umbrales de detección demasiado sensibles
|
||||
|
||||
## Comparación de Modelos PaddleOCR (RTX 3060)
|
||||
|
||||
| Métrica | Modelos Server | Modelos Mobile | Ganador |
|
||||
|---------|----------------|----------------|---------|
|
||||
| **Tiempo** | 2.47s | 1.08s | Mobile (2.3x más rápido) |
|
||||
| **CER** | 1.82% | 1.42% | Mobile |
|
||||
| **WER** | 16.14% | 12.20% | Mobile |
|
||||
| **VRAM** | 5.3 GB (OOM en página 2) | 0.06 GB | Mobile |
|
||||
| **Multi-página** | No (OOM) | Sí | Mobile |
|
||||
|
||||
> **Conclusión:** Se recomiendan los modelos Mobile - más rápidos, más precisos, caben en VRAM.
|
||||
|
||||
## Rendimiento CPU vs GPU (PaddleOCR)
|
||||
|
||||
Datos de `raytune_paddle_subproc_results_20251207_192320.csv` (CPU) vs RTX 3060 (GPU):
|
||||
|
||||
| Métrica | CPU | GPU (RTX 3060) | Aceleración |
|
||||
|---------|-----|----------------|-------------|
|
||||
| **Tiempo/Página** | 69.4s | 0.55s | **126x más rápido** |
|
||||
| **Mejor CER** | 1.15% | 0.79% | GPU mejor |
|
||||
| **45 páginas** | ~52 min | ~25 seg | **126x más rápido** |
|
||||
|
||||
```mermaid
|
||||
xychart-beta
|
||||
title "Tiempo de Procesamiento por Página: CPU vs GPU"
|
||||
x-axis ["CPU", "GPU (RTX 3060)"]
|
||||
y-axis "Segundos" 0 --> 80
|
||||
bar [69.4, 0.55]
|
||||
```
|
||||
|
||||
> **Conclusión:** GPU es esencial para uso práctico de OCR. El procesamiento en CPU es 126x más lento, haciéndolo impráctico para procesamiento por lotes.
|
||||
|
||||
## Datos Crudos del Benchmark
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-01-19T11:00:00.000000",
|
||||
"platform": {
|
||||
"gpu": "NVIDIA GeForce RTX 3060 Laptop GPU",
|
||||
"vram": "5.66 GB",
|
||||
"cuda": "12.4"
|
||||
},
|
||||
"services": {
|
||||
"PaddleOCR_Mobile": {
|
||||
"port": 8002,
|
||||
"models": {"det": "PP-OCRv5_mobile_det", "rec": "PP-OCRv5_mobile_rec"},
|
||||
"vram_used": "0.06 GB",
|
||||
"results": {
|
||||
"CER": 0.0776,
|
||||
"WER": 0.1162,
|
||||
"PAGES": 45,
|
||||
"TIME_PER_PAGE": 0.58,
|
||||
"TOTAL_TIME": 32.0
|
||||
}
|
||||
},
|
||||
"DocTR": {
|
||||
"port": 8003,
|
||||
"models": {"det": "db_resnet50", "rec": "crnn_vgg16_bn"},
|
||||
"vram_used": "~1 GB",
|
||||
"results": {
|
||||
"CER": 0.1206,
|
||||
"WER": 0.4201,
|
||||
"PAGES": 45,
|
||||
"TIME_PER_PAGE": 0.50,
|
||||
"TOTAL_TIME": 28.4
|
||||
}
|
||||
},
|
||||
"EasyOCR": {
|
||||
"port": 8002,
|
||||
"languages": ["es", "en"],
|
||||
"vram_used": "~2 GB",
|
||||
"results": {
|
||||
"CER": 0.1123,
|
||||
"WER": 0.3636,
|
||||
"PAGES": 45,
|
||||
"TIME_PER_PAGE": 1.88,
|
||||
"TOTAL_TIME": 88.5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Resultados de Ajuste de Hiperparámetros
|
||||
|
||||
Resultados individuales de ajuste por servicio (64 muestras cada uno, páginas 5-10):
|
||||
|
||||
- [Resultados de Ajuste PaddleOCR](metrics_paddle.md)
|
||||
- [Resultados de Ajuste DocTR](metrics_doctr.md)
|
||||
- [Resultados de Ajuste EasyOCR](metrics_easyocr.md)
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
1. ~~Ajuste de Hiperparámetros~~ - Completado (64 muestras por servicio)
|
||||
2. **Evaluación del Dataset Completo** - Ejecutar mejores configuraciones en las 45 páginas
|
||||
3. **Comparar** - Rendimiento base vs ajustado en dataset completo
|
||||
180
docs/metrics/metrics_doctr.md
Normal file
180
docs/metrics/metrics_doctr.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Resultados de Ajuste de Hiperparámetros DocTR
|
||||
|
||||
**Fecha de Ajuste:** 2026-01-19
|
||||
**Plataforma:** NVIDIA RTX 3060 Laptop GPU
|
||||
**Muestras:** 64
|
||||
**Páginas de Prueba:** 5-10 (primer documento)
|
||||
|
||||
### ¿Por Qué Solo 5 Páginas?
|
||||
|
||||
Usamos solo 5 páginas (páginas 5-10) para el ajuste de hiperparámetros porque:
|
||||
|
||||
1. **Velocidad**: 64 pruebas × 5 páginas = 320 evaluaciones de página. Con 45 páginas, serían 2,880 evaluaciones (~9x más tiempo)
|
||||
2. **Eficiencia de recursos**: Cada prueba toma ~2-20 segundos en GPU
|
||||
|
||||
**Riesgo de Sobreajuste**: El ajuste de hiperparámetros en un subconjunto pequeño PUEDE causar sobreajuste. Nuestros resultados confirman esto:
|
||||
- Subconjunto de ajuste: **38% mejora** (7.43% CER)
|
||||
- Dataset completo: **0% mejora** (12.07% CER)
|
||||
|
||||
La falta total de mejora en el dataset completo indica sobreajuste severo a las páginas 5-10, combinado con limitaciones a nivel de modelo (manejo de diacríticos, estructura de líneas) que los hiperparámetros no pueden corregir.
|
||||
|
||||
## Evaluación del Dataset Completo (45 páginas)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 12.06% | 12.07% | **0%** |
|
||||
| **WER** | 42.01% | 42.26% | **0%** |
|
||||
| Tiempo/Página | 0.33s | 0.34s | - |
|
||||
|
||||
> **Nota:** El ajuste no generalizó al dataset completo. Los problemas de DocTR parecen ser a nivel de modelo (diacríticos, estructura de líneas).
|
||||
|
||||
## Resultados del Subconjunto de Ajuste (páginas 5-10)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 12.06% | **7.43%** | **38%** |
|
||||
| **WER** | 42.01% | **35.23%** | **16%** |
|
||||
|
||||
> Nota: Las mejoras en el subconjunto de ajuste no se transfirieron al dataset completo.
|
||||
|
||||
## Mejor Configuración Encontrada
|
||||
|
||||
```json
|
||||
{
|
||||
"assume_straight_pages": true,
|
||||
"straighten_pages": false,
|
||||
"preserve_aspect_ratio": false,
|
||||
"symmetric_pad": false,
|
||||
"disable_page_orientation": true,
|
||||
"disable_crop_orientation": false,
|
||||
"resolve_lines": true,
|
||||
"resolve_blocks": false,
|
||||
"paragraph_break": 0.0977
|
||||
}
|
||||
```
|
||||
|
||||
## Hallazgos Clave
|
||||
|
||||
1. **straighten_pages: false** - ¡Crítico! Configurarlo en true causa ~79% CER (catastrófico)
|
||||
2. **assume_straight_pages: true** - Funciona bien con escaneos de documentos rectos
|
||||
3. **resolve_lines: true** - Ayuda a mantener la estructura de líneas
|
||||
4. **disable_page_orientation: true** - Evita rotación innecesaria
|
||||
|
||||
## Impacto de Parámetros
|
||||
|
||||
Parámetros que mejoraron la precisión:
|
||||
- `straighten_pages=False` absolutamente crítico
|
||||
- `assume_straight_pages=True` en los mejores resultados
|
||||
- `resolve_lines=True` mantiene la estructura del texto
|
||||
|
||||
Parámetros que perjudicaron la precisión:
|
||||
- `straighten_pages=True` catastróficamente malo (~79% CER)
|
||||
- `resolve_blocks=True` ligeramente peor que False
|
||||
|
||||
## Limitaciones Conocidas
|
||||
|
||||
Incluso con ajuste, DocTR todavía tiene problemas:
|
||||
- Omite diacríticos (tildes) - probablemente problema a nivel de modelo
|
||||
- Todavía tiene mayor WER que PaddleOCR debido a problemas de estructura
|
||||
|
||||
## Evaluación del Dataset Completo
|
||||
|
||||
**Estado:** Completado
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8003/evaluate_full \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pdf_folder": "/app/dataset",
|
||||
"assume_straight_pages": true,
|
||||
"straighten_pages": false,
|
||||
"preserve_aspect_ratio": false,
|
||||
"symmetric_pad": false,
|
||||
"disable_page_orientation": true,
|
||||
"disable_crop_orientation": false,
|
||||
"resolve_lines": true,
|
||||
"resolve_blocks": false,
|
||||
"paragraph_break": 0.0977,
|
||||
"save_output": true
|
||||
}'
|
||||
```
|
||||
|
||||
**Resultado:** CER 12.07%, WER 42.26%, 0.34s/página (sin mejora sobre la base)
|
||||
|
||||
**Conclusión:** Los problemas de precisión de DocTR son a nivel de modelo, no ajustables por hiperparámetros.
|
||||
|
||||
## Configuración del Modelo
|
||||
|
||||
### Modelo Actual
|
||||
|
||||
| Componente | Modelo | Estado |
|
||||
|------------|--------|--------|
|
||||
| Detección | `db_resnet50` | Correcto |
|
||||
| Reconocimiento | `crnn_vgg16_bn` | Mejor opción disponible |
|
||||
|
||||
El modelo `crnn_vgg16_bn` fue entrenado principalmente con datasets en inglés y francés, lo que explica la pérdida sistemática de diacríticos españoles (á, é, í, ó, ú, ñ).
|
||||
|
||||
### Prueba con Modelo Alternativo (parseq)
|
||||
|
||||
Se probó el modelo `parseq` (transformer) como alternativa:
|
||||
|
||||
| Métrica | crnn_vgg16_bn | parseq | Resultado |
|
||||
|---------|---------------|--------|-----------|
|
||||
| **CER** | 12.07% | 12.32% | **+2% peor** |
|
||||
| **WER** | 42.26% | 44.0% | **+4% peor** |
|
||||
| Tiempo/Página | 0.34s | 0.70s | 2x más lento |
|
||||
| Diacríticos | No | No | Sin mejora |
|
||||
|
||||
**Conclusión:** El modelo `parseq` no mejora los diacríticos españoles y es más lento. Todos los modelos pre-entrenados de DocTR fueron entrenados principalmente en inglés/francés. Para español se requeriría **fine-tuning con corpus español**.
|
||||
|
||||
### No Se Recomienda Cambio de Modelo
|
||||
|
||||
Mantener `crnn_vgg16_bn` (más rápido, ligeramente mejor precisión). Los problemas de diacríticos son de **datos de entrenamiento**, no de arquitectura del modelo
|
||||
|
||||
## Análisis de Errores del Debugset
|
||||
|
||||
### Errores Observados
|
||||
|
||||
| Ground Truth | DocTR | Tipo de Error |
|
||||
|--------------|-------|---------------|
|
||||
| `bibliográficas` | `bibliograficas` | Diacrítico omitido |
|
||||
| `sección` | `seccion` | Diacrítico omitido |
|
||||
| `Máster` | `Master` | Diacrítico omitido |
|
||||
| `información` | `informacion` | Diacrítico omitido |
|
||||
| `o amplían` | `O amplian` | Mayúscula incorrecta |
|
||||
| Líneas separadas | Todo en una línea | **Estructura perdida** |
|
||||
|
||||
### Problemas Críticos
|
||||
|
||||
1. **Pérdida total de estructura**: Todo el texto de la página se colapsa en una sola línea
|
||||
2. **Omisión sistemática de diacríticos**: TODOS los acentos españoles se pierden
|
||||
3. **Errores de capitalización**: `o` → `O` en medio de oraciones
|
||||
|
||||
### ¿Fine-tuning Recomendado?
|
||||
|
||||
**Sí, para diacríticos.** El modelo CRNN de DocTR fue entrenado principalmente con textos en inglés y francés, lo que explica la omisión sistemática de acentos españoles.
|
||||
|
||||
| Problema | ¿Fine-tuning ayuda? | Explicación |
|
||||
|----------|---------------------|-------------|
|
||||
| Diacríticos | **Sí** | Entrenar con corpus español enseñaría al modelo los acentos |
|
||||
| Estructura de líneas | **No** | Problema arquitectural del modelo, no de entrenamiento |
|
||||
| Capitalización | **Parcial** | Podría mejorar con datos de entrenamiento adecuados |
|
||||
|
||||
### Cómo Fine-Tunear DocTR
|
||||
|
||||
```python
|
||||
from doctr.models import recognition_predictor
|
||||
from doctr.datasets import RecognitionDataset
|
||||
|
||||
# Cargar dataset español
|
||||
train_set = RecognitionDataset(
|
||||
img_folder="path/to/spanish/images",
|
||||
labels_path="path/to/spanish/labels.json"
|
||||
)
|
||||
|
||||
# Fine-tune el modelo de reconocimiento
|
||||
model = recognition_predictor(pretrained=True)
|
||||
# ... configurar entrenamiento
|
||||
```
|
||||
|
||||
Documentación: https://mindee.github.io/doctr/using_doctr/custom_models_training.html
|
||||
182
docs/metrics/metrics_easyocr.md
Normal file
182
docs/metrics/metrics_easyocr.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Resultados de Ajuste de Hiperparámetros EasyOCR
|
||||
|
||||
**Fecha de Ajuste:** 2026-01-19
|
||||
**Plataforma:** NVIDIA RTX 3060 Laptop GPU
|
||||
**Muestras:** 64
|
||||
**Páginas de Prueba:** 5-10 (primer documento)
|
||||
|
||||
### ¿Por Qué Solo 5 Páginas?
|
||||
|
||||
Usamos solo 5 páginas (páginas 5-10) para el ajuste de hiperparámetros porque:
|
||||
|
||||
1. **Velocidad**: 64 pruebas × 5 páginas = 320 evaluaciones de página. Con 45 páginas, serían 2,880 evaluaciones (~9x más tiempo)
|
||||
2. **Eficiencia de recursos**: Cada prueba toma ~10-20 segundos en GPU
|
||||
|
||||
**Riesgo de Sobreajuste**: El ajuste de hiperparámetros en un subconjunto pequeño PUEDE causar sobreajuste. Nuestros resultados confirman esto:
|
||||
- Subconjunto de ajuste: **48% mejora** (5.83% CER)
|
||||
- Dataset completo: **0.8% mejora** (11.14% CER)
|
||||
|
||||
La mejora mínima en el dataset completo indica que los hiperparámetros se sobreajustaron a las páginas 5-10. Los problemas de EasyOCR (detecciones espurias, pérdida de estructura) también pueden ser parcialmente a nivel de modelo.
|
||||
|
||||
## Evaluación del Dataset Completo (45 páginas)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 11.23% | 11.14% | **0.8%** |
|
||||
| **WER** | 36.36% | 36.85% | **-1.3%** |
|
||||
| Tiempo/Página | 1.84s | 1.94s | - |
|
||||
|
||||
> **Nota:** El ajuste mostró mejora mínima en el dataset completo. Los problemas de EasyOCR pueden ser a nivel de modelo.
|
||||
|
||||
## Resultados del Subconjunto de Ajuste (páginas 5-10)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 11.23% | **5.83%** | **48%** |
|
||||
| **WER** | 36.36% | **26.33%** | **28%** |
|
||||
|
||||
> Nota: Las grandes mejoras en el subconjunto de ajuste no se transfirieron al dataset completo.
|
||||
|
||||
## Mejor Configuración Encontrada
|
||||
|
||||
```json
|
||||
{
|
||||
"text_threshold": 0.6647,
|
||||
"low_text": 0.4247,
|
||||
"link_threshold": 0.2184,
|
||||
"slope_ths": 0.1629,
|
||||
"ycenter_ths": 0.7994,
|
||||
"height_ths": 0.6437,
|
||||
"width_ths": 0.6065,
|
||||
"add_margin": 0.1462,
|
||||
"contrast_ths": 0.1671,
|
||||
"adjust_contrast": 0.6416,
|
||||
"decoder": "greedy",
|
||||
"beamWidth": 7,
|
||||
"min_size": 10
|
||||
}
|
||||
```
|
||||
|
||||
## Hallazgos Clave
|
||||
|
||||
1. **decoder: greedy** - Consistentemente mejor que beamsearch para este dataset
|
||||
2. **Mayor text_threshold (0.66)** - Reduce detecciones espurias
|
||||
3. **min_size: 10** - Filtra artefactos de ruido pequeños
|
||||
4. **Umbrales moderados** - Sensibilidad de detección balanceada
|
||||
|
||||
## Impacto de Parámetros
|
||||
|
||||
Parámetros que mejoraron la precisión:
|
||||
- `decoder="greedy"` consistentemente superó a beamsearch
|
||||
- Mayor `text_threshold` (0.6-0.8) redujo el ruido
|
||||
- `min_size >= 5` ayudó a filtrar artefactos
|
||||
|
||||
Parámetros que perjudicaron la precisión:
|
||||
- `decoder="beamsearch"` causó ~35-40% CER en muchas pruebas
|
||||
- `text_threshold` muy bajo (<0.4) detectó demasiado ruido
|
||||
- `min_size` alto (>15) omitió algo de texto
|
||||
|
||||
## Comparación con Problemas de Base
|
||||
|
||||
Problemas originales identificados en el debugset:
|
||||
- Inserciones espurias de caracteres - **Mejorado** con umbrales más altos
|
||||
- Pérdida de estructura - Todavía presente pero menos severa
|
||||
|
||||
## Evaluación del Dataset Completo
|
||||
|
||||
**Estado:** Completado
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8002/evaluate_full \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pdf_folder": "/app/dataset",
|
||||
"text_threshold": 0.6647,
|
||||
"low_text": 0.4247,
|
||||
"link_threshold": 0.2184,
|
||||
"slope_ths": 0.1629,
|
||||
"ycenter_ths": 0.7994,
|
||||
"height_ths": 0.6437,
|
||||
"width_ths": 0.6065,
|
||||
"add_margin": 0.1462,
|
||||
"contrast_ths": 0.1671,
|
||||
"adjust_contrast": 0.6416,
|
||||
"decoder": "greedy",
|
||||
"beamWidth": 7,
|
||||
"min_size": 10,
|
||||
"save_output": true
|
||||
}'
|
||||
```
|
||||
|
||||
**Resultado:** CER 11.14%, WER 36.85%, 1.94s/página (mejora mínima)
|
||||
|
||||
**Conclusión:** El ajuste de EasyOCR proporcionó mejora insignificante en el dataset completo.
|
||||
|
||||
## Configuración del Modelo
|
||||
|
||||
### Modelo Actual (Correcto para Español)
|
||||
|
||||
| Componente | Modelo | Estado |
|
||||
|------------|--------|--------|
|
||||
| Detección | CRAFT | Correcto |
|
||||
| Reconocimiento | `latin_g2.pth` | Correcto para español |
|
||||
| Idiomas | `es,en` | Correcto |
|
||||
|
||||
El modelo `latin_g2.pth` está optimizado para idiomas con escritura latina incluyendo español. **El modelo de reconocimiento es correcto** - los problemas observados (caracteres espurios `0`, `;`, `g`) son del **detector CRAFT**, no del modelo de reconocimiento.
|
||||
|
||||
### No Se Requiere Cambio de Modelo
|
||||
|
||||
A diferencia de DocTR, EasyOCR usa el modelo correcto para español. Los problemas son de detección (umbrales del CRAFT), no de reconocimiento.
|
||||
|
||||
## Análisis de Errores del Debugset
|
||||
|
||||
### Errores Observados
|
||||
|
||||
| Ground Truth | EasyOCR | Tipo de Error |
|
||||
|--------------|---------|---------------|
|
||||
| `o figura` | `0 figura` | Letra `o` → número `0` |
|
||||
| `tabla o figura` | `tabla 0 figura` | Letra `o` → número `0` |
|
||||
| `grupal,` | `grupal;` | Coma → punto y coma |
|
||||
| `páginas,` | `páginas;` | Puntuación incorrecta |
|
||||
| (ninguno) | `g`, `1`, `2` | **Caracteres espurios insertados** |
|
||||
| Líneas separadas | Todo en una línea | **Estructura perdida** |
|
||||
|
||||
### Problemas Críticos
|
||||
|
||||
1. **Caracteres espurios**: El detector CRAFT inserta caracteres falsos (`g`, `1`, `2`, `;`) que no existen en el documento
|
||||
2. **Confusión letra/número**: Consistentemente confunde `o` con `0`
|
||||
3. **Puntuación incorrecta**: Reemplaza comas por punto y coma
|
||||
4. **Pérdida de estructura**: Todo el texto se colapsa en una línea
|
||||
|
||||
### ¿Fine-tuning Recomendado?
|
||||
|
||||
**Sí.** EasyOCR tiene problemas significativos que podrían mejorarse con fine-tuning:
|
||||
|
||||
| Problema | ¿Fine-tuning ayuda? | Explicación |
|
||||
|----------|---------------------|-------------|
|
||||
| Caracteres espurios | **Sí** | El detector CRAFT puede entrenarse para reducir falsos positivos |
|
||||
| Confusión `o`/`0` | **Sí** | El modelo de reconocimiento aprendería del contexto español |
|
||||
| Puntuación | **Sí** | Corpus español enseñaría patrones de puntuación correctos |
|
||||
| Estructura | **Parcial** | Depende de parámetros de agrupación de texto |
|
||||
|
||||
### Cómo Fine-Tunear EasyOCR
|
||||
|
||||
EasyOCR permite fine-tuning del modelo de reconocimiento:
|
||||
|
||||
```bash
|
||||
# 1. Preparar dataset en formato EasyOCR
|
||||
# Estructura: images/ + labels.txt (imagen<tab>texto)
|
||||
|
||||
# 2. Entrenar modelo de reconocimiento
|
||||
python train.py \
|
||||
--train_data ./train_data \
|
||||
--valid_data ./valid_data \
|
||||
--lang_list es en \
|
||||
--saved_model ./custom_model
|
||||
```
|
||||
|
||||
Documentación: https://github.com/JaidedAI/EasyOCR/blob/master/custom_model.md
|
||||
|
||||
### Alternativa Recomendada
|
||||
|
||||
Dado el CER de 11.14% y los problemas fundamentales de EasyOCR, se recomienda **usar PaddleOCR** (7.72% CER) en lugar de invertir esfuerzo en fine-tuning de EasyOCR
|
||||
141
docs/metrics/metrics_paddle.md
Normal file
141
docs/metrics/metrics_paddle.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# Resultados de Ajuste de Hiperparámetros PaddleOCR
|
||||
|
||||
> **Nota:** Los resultados de este documento corresponden a la fase de validación GPU con 45 páginas. El resultado oficial del TFM es **CER 1.49%** obtenido en la validación final de 24 páginas con la configuración optimizada (ver `docs/04_desarrollo_especifico.md`).
|
||||
|
||||
**Fecha de Ajuste:** 2026-01-19
|
||||
**Plataforma:** NVIDIA RTX 3060 Laptop GPU
|
||||
**Muestras:** 64
|
||||
**Páginas de Prueba:** 5-10 (primer documento)
|
||||
|
||||
### ¿Por Qué Solo 5 Páginas?
|
||||
|
||||
Usamos solo 5 páginas (páginas 5-10) para el ajuste de hiperparámetros porque:
|
||||
|
||||
1. **Velocidad**: 64 pruebas × 5 páginas = 320 evaluaciones de página. Con 45 páginas, serían 2,880 evaluaciones (~9x más tiempo)
|
||||
2. **Eficiencia de recursos**: Cada prueba toma ~3-10 segundos en GPU; el dataset completo tomaría ~1 hora por prueba en CPU
|
||||
|
||||
**Riesgo de Sobreajuste**: El ajuste de hiperparámetros en un subconjunto pequeño PUEDE causar sobreajuste. Nuestros resultados confirman esto:
|
||||
- Subconjunto de ajuste: **90% mejora** (0.79% CER)
|
||||
- Dataset completo: **12.8% mejora** (7.72% CER)
|
||||
|
||||
La diferencia dramática muestra que los hiperparámetros se sobreajustaron parcialmente a las páginas 5-10. Un subconjunto de ajuste más grande (ej. 15-20 páginas) podría producir parámetros que generalicen mejor, pero aumentaría el tiempo de ajuste proporcionalmente.
|
||||
|
||||
## Evaluación del Dataset Completo (45 páginas)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 8.85% | **7.72%** | **12.8%** |
|
||||
| **WER** | 13.05% | **11.40%** | **12.6%** |
|
||||
| Tiempo/Página | 0.51s | 0.55s | - |
|
||||
|
||||
## Resultados del Subconjunto de Ajuste (páginas 5-10)
|
||||
|
||||
| Métrica | Base | Ajustado | Mejora |
|
||||
|---------|------|----------|--------|
|
||||
| **CER** | 7.76% | **0.79%** | **90%** |
|
||||
| **WER** | 11.62% | **7.78%** | **33%** |
|
||||
|
||||
> Nota: El subconjunto de ajuste mostró mayores mejoras, sugiriendo que algunos hiperparámetros son específicos de la página.
|
||||
|
||||
## Mejor Configuración Encontrada
|
||||
|
||||
```json
|
||||
{
|
||||
"use_doc_orientation_classify": true,
|
||||
"use_doc_unwarping": false,
|
||||
"textline_orientation": true,
|
||||
"text_det_thresh": 0.0462,
|
||||
"text_det_box_thresh": 0.4862,
|
||||
"text_det_unclip_ratio": 0.0,
|
||||
"text_rec_score_thresh": 0.5658
|
||||
}
|
||||
```
|
||||
|
||||
## Hallazgos Clave
|
||||
|
||||
1. **textline_orientation: true** - Crítico para la precisión
|
||||
2. **use_doc_orientation_classify: true** - Ayuda con la detección de orientación de página
|
||||
3. **use_doc_unwarping: false** - El enderezamiento de documentos perjudica la precisión en este dataset
|
||||
4. **Bajo text_det_thresh (0.0462)** - Detección de texto más sensible ayuda
|
||||
5. **Mayor text_rec_score_thresh (0.5658)** - Filtra reconocimientos de baja confianza
|
||||
|
||||
## Impacto de Parámetros
|
||||
|
||||
Parámetros que mejoraron la precisión:
|
||||
- `textline_orientation=True` consistentemente en los mejores resultados
|
||||
- `use_doc_orientation_classify=True` en las mejores pruebas
|
||||
- Valores más bajos de `text_det_thresh` (0.04-0.10)
|
||||
|
||||
Parámetros que perjudicaron la precisión:
|
||||
- `use_doc_unwarping=True` aumentó el CER significativamente
|
||||
- `text_det_box_thresh` muy bajo (<0.01) causó problemas
|
||||
|
||||
## Evaluación del Dataset Completo
|
||||
|
||||
**Estado:** Completado
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8002/evaluate_full \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"pdf_folder": "/app/dataset",
|
||||
"use_doc_orientation_classify": true,
|
||||
"use_doc_unwarping": false,
|
||||
"textline_orientation": true,
|
||||
"text_det_thresh": 0.0462,
|
||||
"text_det_box_thresh": 0.4862,
|
||||
"text_det_unclip_ratio": 0.0,
|
||||
"text_rec_score_thresh": 0.5658,
|
||||
"save_output": true
|
||||
}'
|
||||
```
|
||||
|
||||
**Resultado:** CER 7.72%, WER 11.40%, 0.55s/página
|
||||
|
||||
## Configuración del Modelo
|
||||
|
||||
### Modelo Actual (Correcto para Español)
|
||||
|
||||
| Componente | Modelo | Estado |
|
||||
|------------|--------|--------|
|
||||
| Detección | `PP-OCRv5_mobile_det` | Correcto |
|
||||
| Reconocimiento | `PP-OCRv5_mobile_rec` | Correcto |
|
||||
|
||||
Los modelos PP-OCRv5 mobile soportan múltiples idiomas incluyendo español con buen manejo de diacríticos.
|
||||
|
||||
### Nota sobre Modelos Server
|
||||
|
||||
PaddleOCR ofrece modelos "server" más precisos:
|
||||
- `PP-OCRv5_server_det` + `PP-OCRv5_server_rec`
|
||||
- Requieren ~5.3 GB VRAM
|
||||
|
||||
**Limitación:** En la RTX 3060 (5.66 GB VRAM) los modelos server causan **OOM (Out of Memory)** en la página 2. Los modelos mobile usados (7.72% CER) son la mejor opción práctica para este hardware.
|
||||
|
||||
Para hardware con más VRAM (8+ GB), los modelos server podrían mejorar la precisión.
|
||||
|
||||
## Análisis de Errores del Debugset
|
||||
|
||||
### Errores Observados
|
||||
|
||||
| Ground Truth | PaddleOCR | Tipo de Error |
|
||||
|--------------|-----------|---------------|
|
||||
| `bibliografía` | `bibliografia` | Acento omitido |
|
||||
| `amplían` | `amplian` | Acento omitido |
|
||||
| `, debes` | `, debes` | Coma Unicode china |
|
||||
| Líneas separadas | Footer fusionado | Estructura menor |
|
||||
|
||||
### Fortalezas
|
||||
|
||||
- **Preserva estructura de líneas**: Mantiene saltos de línea correctamente
|
||||
- **Buen manejo de español**: La mayoría de acentos se reconocen bien
|
||||
- **Bajo ruido**: No inserta caracteres espurios
|
||||
|
||||
### ¿Fine-tuning Recomendado?
|
||||
|
||||
**No.** Con 7.72% CER, PaddleOCR ya tiene excelente precisión para documentos españoles. Los errores observados son menores:
|
||||
|
||||
- Acentos omitidos: ~5% de casos
|
||||
- Puntuación Unicode: Muy ocasional
|
||||
- Impacto en legibilidad: Mínimo
|
||||
|
||||
El esfuerzo de fine-tuning no se justifica para ganancias marginales. Para casos de uso críticos donde se requiera <5% CER, considerar post-procesamiento con corrector ortográfico
|
||||
Reference in New Issue
Block a user