# Desarrollo específico de la contribución

Este capítulo presenta el desarrollo completo del estudio comparativo y la optimización de hiperparámetros de sistemas OCR. Se estructura según el tipo de trabajo "Comparativa de soluciones" establecido por las instrucciones de UNIR: planteamiento de la comparativa, desarrollo de la comparativa, y discusión y análisis de resultados.

## Planteamiento de la comparativa

### Introducción

Esta sección presenta los resultados del estudio comparativo realizado entre tres soluciones OCR de código abierto: EasyOCR, PaddleOCR y DocTR. Los experimentos fueron documentados en el notebook `ocr_benchmark_notebook.ipynb` del repositorio. El objetivo es identificar el modelo base más prometedor para la posterior fase de optimización de hiperparámetros.

### Identificación del Problema

El reconocimiento óptico de caracteres (OCR) en documentos académicos en español presenta desafíos específicos que no han sido ampliamente abordados en la literatura:

1. **Layouts complejos**: Los documentos académicos combinan texto corrido, tablas, listas numeradas, encabezados multinivel y notas al pie.

2. **Caracteres específicos del español**: Acentos (á, é, í, ó, ú), eñe (ñ), diéresis (ü) y signos de puntuación invertidos (¿, ¡).

3. **Formato formal**: Tipografía profesional con múltiples fuentes, tamaños y estilos (negrita, cursiva).

4. **Calidad variable**: Documentos digitales de alta calidad pero con posibles artefactos de compresión PDF.

### Alternativas Evaluadas

Se seleccionaron tres soluciones OCR de código abierto representativas del estado del arte:

**Tabla 10.** *Soluciones OCR evaluadas en el benchmark comparativo.*

| Solución | Desarrollador | Versión | Justificación de selección |
|----------|---------------|---------|----------------------------|
| EasyOCR | Jaided AI | Última estable | Popularidad, facilidad de uso |
| PaddleOCR | Baidu | PP-OCRv5 | Estado del arte industrial |
| DocTR | Mindee | Última estable | Orientación académica |

*Fuente: Elaboración propia.*

### Criterios de Éxito

Los criterios establecidos para evaluar las soluciones fueron:

1. **Precisión (CER < 5%)**: Error de caracteres aceptable para documentos académicos
2. **Configurabilidad**: Disponibilidad de hiperparámetros ajustables
3. **Soporte para español**: Modelos preentrenados que incluyan el idioma
4. **Documentación**: Calidad de la documentación técnica
5. **Mantenimiento activo**: Actualizaciones recientes y comunidad activa

### Configuración del Experimento

#### Dataset de Evaluación

Se utilizó el documento "Instrucciones para la redacción y elaboración del TFE" del Máster Universitario en Inteligencia Artificial de UNIR, ubicado en la carpeta `instructions/`.

**Tabla 11.** *Características del dataset de evaluación inicial.*

| Característica | Valor |
|----------------|-------|
| Documento fuente | Instrucciones TFE UNIR |
| Número de páginas evaluadas | 5 (benchmark inicial) |
| Formato | PDF digital (no escaneado) |
| Idioma principal | Español |
| Resolución de conversión | 300 DPI |
| Formato de imagen | PNG |

*Fuente: Elaboración propia.*

#### 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.

#### 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).

#### Configuración de los Modelos

Según el código en `ocr_benchmark_notebook.ipynb`:

**EasyOCR**:
```python
import easyocr

easyocr_reader = easyocr.Reader(['es', 'en'])  # Spanish and English
results = easyocr_reader.readtext(image_path)
text = ' '.join([r[1] for r in results])
```

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.

#### 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.

### Resultados del Benchmark

#### Resultados de PaddleOCR (Configuración Baseline)

Durante el benchmark inicial se evaluó PaddleOCR con configuración por defecto en un subconjunto del dataset. Los resultados preliminares mostraron variabilidad significativa entre páginas, con CER entre 1.54% y 6.40% dependiendo de la complejidad del layout.

**Tabla 12.** *Variabilidad del CER por tipo de contenido.*

| Tipo de contenido | CER aproximado | Observaciones |
|-------------------|----------------|---------------|
| Texto corrido | ~1.5-2% | Mejor rendimiento |
| Texto con listas | ~3-4% | Rendimiento medio |
| Tablas | ~5-6% | Mayor dificultad |
| Encabezados + notas | ~4-5% | Layouts mixtos |

*Fuente: Elaboración propia a partir del benchmark.*

**Observaciones del benchmark inicial:**

1. Las páginas con tablas y layouts complejos presentaron mayor error debido a la dificultad de ordenar correctamente las líneas de texto.

2. La página con texto corrido continuo obtuvo el mejor resultado (CER ~1.5%), demostrando la capacidad del modelo para texto estándar.

3. El promedio general se situó en CER ~5-6%, superando el umbral de aceptabilidad para documentos académicos pero con margen de mejora.

4. Los errores más frecuentes fueron: confusión de acentos, caracteres duplicados, y errores en signos de puntuación.

#### Comparativa de Modelos

Los tres modelos evaluados representan diferentes paradigmas de OCR:

**Tabla 13.** *Comparativa de arquitecturas OCR evaluadas.*

| Modelo | Tipo | Componentes | Fortalezas Clave |
|--------|------|-------------|------------------|
| **EasyOCR** | End-to-end (det + rec) | CRAFT + CRNN/Transformer | Ligero, fácil de usar, multilingüe |
| **PaddleOCR** | End-to-end (det + rec + cls) | DB + SVTR/CRNN | Soporte multilingüe robusto, pipeline configurable |
| **DocTR** | End-to-end (det + rec) | DB/LinkNet + CRNN/SAR/ViTSTR | Orientado a investigación, API limpia |

*Fuente: Documentación oficial de cada herramienta (JaidedAI, 2020; PaddlePaddle, 2024; Mindee, 2021).*

#### Análisis Cualitativo de Errores

Un análisis cualitativo de los errores producidos reveló patrones específicos:

**Errores de acentuación:**
- `información` → `informacion` (pérdida de acento)
- `más` → `mas` (cambio de significado)
- `él` → `el` (cambio de significado)

**Errores de caracteres especiales:**
- `año` → `ano` (pérdida de eñe)
- `¿Cómo` → `Como` (pérdida de signos invertidos)

**Errores de duplicación:**
- `titulación` → `titulacióon` (carácter duplicado)
- `documento` → `doccumento` (consonante duplicada)

**Ejemplo de predicción de PaddleOCR para una página:**

> "Escribe siempre al menos un párrafo de introducción en cada capítulo o apartado, explicando de qué vas a tratar en esa sección. Evita que aparezcan dos encabezados de nivel consecutivos sin ningún texto entre medias. [...] En esta titulacióon se cita de acuerdo con la normativa Apa."

**Errores identificados en este ejemplo:**
- `titulacióon` en lugar de `titulación` (carácter duplicado)
- `Apa` en lugar de `APA` (capitalización)

### Justificación de la Selección de PaddleOCR

#### Criterios de Selección

La selección de PaddleOCR para la fase de optimización se basó en los siguientes criterios:

**Tabla 14.** *Evaluación de criterios de selección.*

| Criterio | EasyOCR | PaddleOCR | DocTR |
|----------|---------|-----------|-------|
| CER benchmark | ~6-8% | ~5-6% | ~7-9% |
| Configurabilidad | Baja (3 params) | **Alta (>10 params)** | Media (5 params) |
| Soporte español | Sí | **Sí (dedicado)** | Limitado |
| Documentación | Media | **Alta** | Alta |
| Mantenimiento | Medio | **Alto** | Medio |

*Fuente: Elaboración propia.*

#### Hiperparámetros Disponibles en PaddleOCR

PaddleOCR expone múltiples hiperparámetros ajustables, clasificados por etapa del pipeline:

**Detección:**
- `text_det_thresh`: Umbral de probabilidad para píxeles de texto
- `text_det_box_thresh`: Umbral de confianza para cajas detectadas
- `text_det_unclip_ratio`: Factor de expansión de cajas

**Reconocimiento:**
- `text_rec_score_thresh`: Umbral de confianza para resultados

**Preprocesamiento:**
- `use_textline_orientation`: Clasificación de orientación de línea
- `use_doc_orientation_classify`: Clasificación de orientación de documento
- `use_doc_unwarping`: Corrección de deformación

Esta riqueza de configuración permite explorar sistemáticamente el espacio de hiperparámetros mediante técnicas de optimización automática.

#### Decisión Final

**Se selecciona PaddleOCR (PP-OCRv5)** para la fase de optimización debido a:

1. **Resultados iniciales prometedores**: CER ~5% en configuración por defecto, con potencial de mejora
2. **Alta configurabilidad**: Más de 10 hiperparámetros ajustables en tiempo de inferencia
3. **Pipeline modular**: Permite aislar el impacto de cada componente
4. **Soporte activo para español**: Modelos específicos y actualizaciones frecuentes
5. **Documentación técnica**: Descripción detallada de cada parámetro

### Limitaciones del Benchmark

1. **Tamaño reducido**: Solo 5 páginas evaluadas en el benchmark comparativo inicial. Esto limita la generalización de las conclusiones.

2. **Único tipo de documento**: Documentos académicos de UNIR únicamente. Otros tipos de documentos (facturas, formularios, contratos) podrían presentar resultados diferentes.

3. **Ground truth automático**: El texto de referencia se extrajo programáticamente del PDF, lo cual puede introducir errores en layouts complejos donde el orden de lectura no es evidente.

4. **Ejecución en CPU**: Todos los experimentos se realizaron en CPU, limitando la exploración de configuraciones que podrían beneficiarse de aceleración GPU.

### Resumen de la Sección

Esta sección ha presentado:

1. La identificación del problema y los criterios de éxito establecidos
2. La configuración detallada del benchmark con tres soluciones OCR
3. Los resultados cuantitativos y cualitativos obtenidos
4. La justificación de la selección de PaddleOCR para optimización
5. Las limitaciones reconocidas del benchmark

**Fuentes de datos utilizadas:**
- `ocr_benchmark_notebook.ipynb`: Código del benchmark
- Documentación oficial de PaddleOCR

## Desarrollo de la comparativa: Optimización de hiperparámetros

### 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`.

La optimización de hiperparámetros representa una alternativa al fine-tuning tradicional que no requiere:
- Acceso a GPU dedicada
- Dataset de entrenamiento etiquetado
- Modificación de los pesos del modelo

### Configuración del Experimento

#### Entorno de Ejecución

El experimento se ejecutó en el siguiente entorno:

**Tabla 15.** *Entorno de ejecución del experimento.*

| Componente | Versión/Especificación |
|------------|------------------------|
| Sistema operativo | Windows 10/11 |
| Python | 3.11.9 |
| 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) |

*Fuente: Outputs del notebook `src/paddle_ocr_fine_tune_unir_raytune.ipynb`.*

#### 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:

```mermaid
---
title: "Arquitectura de ejecución con subprocesos"
---
flowchart LR
    A["Ray Tune (proceso principal)"]

    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"]
```

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

```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
```

Salida:
```json
{
    "CER": 0.0125,
    "WER": 0.1040,
    "TIME": 331.09,
    "PAGES": 5,
    "TIME_PER_PAGE": 66.12
}
```

#### Dataset Extendido

Para la fase de optimización se extendió el dataset:

**Tabla 16.** *Características del dataset de optimización.*

| Característica | Valor |
|----------------|-------|
| Páginas totales | 24 |
| Páginas por trial | 5 (páginas 5-10) |
| Estructura | Carpetas `img/` y `txt/` pareadas |
| Resolución | 300 DPI |
| Formato imagen | PNG |

*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()
```

#### 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),
}
```

**Tabla 17.** *Descripción detallada del espacio de búsqueda.*

| Parámetro | Tipo | Rango | Descripción |
|-----------|------|-------|-------------|
| `use_doc_orientation_classify` | Booleano | {True, False} | Clasificación de orientación del documento completo |
| `use_doc_unwarping` | Booleano | {True, False} | Corrección de deformación/curvatura |
| `textline_orientation` | Booleano | {True, False} | Clasificación de orientación por línea de texto |
| `text_det_thresh` | Continuo | [0.0, 0.7] | Umbral de probabilidad para píxeles de texto |
| `text_det_box_thresh` | Continuo | [0.0, 0.7] | Umbral de confianza para cajas detectadas |
| `text_det_unclip_ratio` | Fijo | 0.0 | Coeficiente de expansión (no explorado) |
| `text_rec_score_thresh` | Continuo | [0.0, 0.7] | Umbral de confianza de reconocimiento |

*Fuente: Documentación de PaddleOCR.*

**Justificación del espacio:**

1. **Rango [0.0, 0.7] para umbrales**: Se evitan valores extremos (>0.7) que podrían filtrar demasiado texto válido, y se incluye 0.0 para evaluar el impacto de desactivar el filtrado.

2. **`text_det_unclip_ratio` fijo**: Por decisión de diseño inicial, este parámetro se mantuvo constante para reducir la dimensionalidad del espacio de búsqueda.

3. **Parámetros booleanos completos**: Los tres parámetros de preprocesamiento se exploran completamente para identificar cuáles son necesarios para documentos digitales.

#### 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
)
```

**Tabla 18.** *Parámetros de configuración de Ray Tune.*

| Parámetro | Valor | Justificación |
|-----------|-------|---------------|
| Métrica objetivo | CER | Métrica estándar para OCR |
| Modo | min | Minimizar tasa de error |
| Algoritmo | OptunaSearch (TPE) | Eficiente para espacios mixtos |
| Número de trials | 64 | Balance entre exploración y tiempo |
| Trials concurrentes | 2 | Limitado por memoria disponible |

*Fuente: Elaboración propia.*

**Elección de 64 trials:**

El número de trials se eligió considerando:
- Espacio de búsqueda de 7 dimensiones (3 booleanas + 4 continuas)
- Tiempo estimado por trial: ~6 minutos
- Tiempo total objetivo: <8 horas
- Regla empírica: 10× dimensiones = 70 trials mínimo recomendado

### Resultados de la Optimización

#### Ejecución del Experimento

El experimento se ejecutó exitosamente con los siguientes resultados globales:

**Tabla 19.** *Resumen de la ejecución del experimento.*

| Métrica | Valor |
|---------|-------|
| Trials completados | 64/64 |
| Trials fallidos | 0 |
| Tiempo total | ~6.4 horas |
| Tiempo medio por trial | 367.72 segundos |
| Páginas procesadas | 320 (64 trials × 5 páginas) |

*Fuente: Logs de Ray Tune.*

#### Estadísticas Descriptivas

Del archivo CSV de resultados (`raytune_paddle_subproc_results_20251207_192320.csv`):

**Tabla 20.** *Estadísticas descriptivas de los 64 trials.*

| Estadística | CER | WER | Tiempo (s) | Tiempo/Página (s) |
|-------------|-----|-----|------------|-------------------|
| **count** | 64 | 64 | 64 | 64 |
| **mean** | 5.25% | 14.28% | 347.61 | 69.42 |
| **std** | 11.03% | 10.75% | 7.88 | 1.57 |
| **min** | 1.15% | 9.89% | 320.97 | 64.10 |
| **25%** | 1.20% | 10.04% | 344.24 | 68.76 |
| **50%** (mediana) | 1.23% | 10.20% | 346.42 | 69.19 |
| **75%** | 4.03% | 13.20% | 350.14 | 69.93 |
| **max** | 51.61% | 59.45% | 368.57 | 73.63 |

*Fuente: `src/raytune_paddle_subproc_results_20251207_192320.csv`.*

**Observaciones:**

1. **Alta varianza en CER**: La desviación estándar (11.03%) es mayor que la media (5.25%), indicando una distribución muy dispersa con algunos valores extremos.

2. **Mediana vs Media**: La mediana del CER (1.23%) es mucho menor que la media (5.25%), confirmando una distribución sesgada hacia valores bajos con outliers altos.

3. **Tiempo consistente**: El tiempo de ejecución es muy estable (std = 1.57 s/página), indicando que las configuraciones de hiperparámetros no afectan significativamente el tiempo de inferencia.

#### Distribución de Resultados

**Tabla 21.** *Distribución de trials por rango de CER.*

| Rango CER | Número de trials | Porcentaje |
|-----------|------------------|------------|
| < 2% | 43 | 67.2% |
| 2% - 5% | 7 | 10.9% |
| 5% - 10% | 2 | 3.1% |
| 10% - 20% | 5 | 7.8% |
| > 20% | 7 | 10.9% |

*Fuente: Elaboración propia a partir del CSV de resultados.*

La mayoría de trials (67.2%) alcanzaron CER < 2%, cumpliendo el objetivo establecido. Sin embargo, un 10.9% de trials presentaron fallos catastróficos (CER > 20%).

#### Mejor Configuración Encontrada

La configuración que minimizó el CER fue:

```
Best CER: 0.011535 (1.15%)
Best WER: 0.098902 (9.89%)

Configuración óptima:
  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
```

**Tabla 22.** *Configuración óptima identificada.*

| Parámetro | Valor óptimo | Valor por defecto | Cambio |
|-----------|--------------|-------------------|--------|
| textline_orientation | **True** | False | Activado |
| use_doc_orientation_classify | False | False | Sin cambio |
| use_doc_unwarping | False | False | Sin cambio |
| text_det_thresh | **0.4690** | 0.3 | +0.169 |
| text_det_box_thresh | **0.5412** | 0.6 | -0.059 |
| 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.*

#### Análisis de Correlación

Se calculó la correlación de Pearson entre los parámetros continuos y las métricas de error:

**Tabla 23.** *Correlación de parámetros con CER.*

| Parámetro | Correlación con CER | Interpretación |
|-----------|---------------------|----------------|
| `text_det_thresh` | **-0.523** | Correlación moderada negativa |
| `text_det_box_thresh` | +0.226 | Correlación débil positiva |
| `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.*

**Tabla 24.** *Correlación de parámetros con WER.*

| Parámetro | Correlación con WER | Interpretación |
|-----------|---------------------|----------------|
| `text_det_thresh` | **-0.521** | Correlación moderada negativa |
| `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.*

**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.

#### Impacto del Parámetro textline_orientation

El parámetro booleano `textline_orientation` demostró tener el mayor impacto en el rendimiento:

**Tabla 25.** *Impacto del parámetro textline_orientation.*

| textline_orientation | CER Medio | CER Std | WER Medio | N trials |
|---------------------|-----------|---------|-----------|----------|
| True | 3.76% | 7.12% | 12.73% | 32 |
| False | 12.40% | 14.93% | 21.71% | 32 |

*Fuente: Análisis del notebook.*

**Interpretación:**

1. **Reducción del CER**: Con `textline_orientation=True`, el CER medio es 3.3 veces menor (3.76% vs 12.40%).

2. **Menor varianza**: La desviación estándar también se reduce significativamente (7.12% vs 14.93%), indicando resultados más consistentes.

3. **Reducción del CER**: 69.7% cuando se habilita la clasificación de orientación de línea.

```mermaid
---
title: "Impacto de textline_orientation en CER"
---
xychart-beta
    x-axis ["textline_orientation=False", "textline_orientation=True"]
    y-axis "CER (%)" 0 --> 15
    bar [12.40, 3.76]
```

**Explicación técnica:**

El parámetro `textline_orientation` activa un clasificador que determina la orientación de cada línea de texto detectada. Para documentos con layouts mixtos (tablas, encabezados laterales, direcciones postales), este clasificador asegura que el texto se lea en el orden correcto, evitando la mezcla de líneas de diferentes columnas o secciones.

#### Análisis de Fallos Catastróficos

Los trials con CER muy alto (>20%) presentaron patrones específicos:

**Tabla 26.** *Características de trials con fallos catastróficos.*

| Trial | CER | text_det_thresh | textline_orientation | Diagnóstico |
|-------|-----|-----------------|---------------------|-------------|
| #47 | 51.61% | 0.017 | True | Umbral muy bajo |
| #23 | 43.29% | 0.042 | False | Umbral bajo + sin orientación |
| #12 | 38.76% | 0.089 | False | Umbral bajo + sin orientación |
| #56 | 35.12% | 0.023 | False | Umbral muy bajo + sin orientación |

*Fuente: Análisis del CSV de resultados.*

**Diagnóstico:**

1. **Umbral de detección muy bajo** (`text_det_thresh` < 0.1): Genera exceso de falsos positivos en la detección, incluyendo artefactos, manchas y ruido como "texto".

2. **Desactivación de orientación**: Sin el clasificador de orientación, las líneas de texto pueden mezclarse incorrectamente, especialmente en tablas.

3. **Combinación fatal**: La peor combinación es umbral bajo + sin orientación, que produce textos completamente desordenados y con inserciones de ruido.

**Recomendación**: Evitar `text_det_thresh` < 0.1 en cualquier configuración.

### Comparación Baseline vs Optimizado

#### 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,
}
```

**Tabla 27.** *Comparación baseline vs optimizado (24 páginas).*

| Modelo | CER | Precisión Caracteres | WER | Precisión Palabras |
|--------|-----|---------------------|-----|-------------------|
| 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`.*

#### Métricas de Mejora

**Tabla 28.** *Análisis cuantitativo de la mejora.*

| Forma de Medición | CER | WER |
|-------------------|-----|-----|
| Valor baseline | 7.78% | 14.94% |
| Valor optimizado | 1.49% | 7.62% |
| Mejora absoluta | -6.29 pp | -7.32 pp |
| Reducción relativa del error | **80.9%** | **49.0%** |
| Factor de mejora | 5.2× | 2.0× |

*Fuente: Elaboración propia.*

```mermaid
---
title: "Comparación Baseline vs Optimizado (24 páginas)"
---
xychart-beta
    x-axis ["CER", "WER"]
    y-axis "Tasa de error (%)" 0 --> 16
    bar "Baseline" [7.78, 14.94]
    bar "Optimizado" [1.49, 7.62]
```

#### Impacto Práctico

**En un documento típico de 10,000 caracteres:**

| Configuración | Caracteres con error | Palabras con error* |
|---------------|---------------------|---------------------|
| Baseline | ~778 | ~225 |
| Optimizada | ~149 | ~115 |
| **Reducción** | **629 menos** | **110 menos** |

*Asumiendo longitud media de palabra = 6.6 caracteres en español.

**Interpretación del notebook:**

> "La optimización de hiperparámetros mejoró la precisión de caracteres de 92.2% a 98.5%, una ganancia de 6.3 puntos porcentuales. Aunque el baseline ya ofrecía resultados aceptables, la configuración optimizada reduce los errores residuales en un 80.9%."

### Tiempo de Ejecución

**Tabla 29.** *Métricas de tiempo del experimento.*

| Métrica | Valor |
|---------|-------|
| Tiempo total del experimento | ~6.4 horas |
| Tiempo medio por trial | 347.61 segundos (~5.8 min) |
| Tiempo medio por página | 69.42 segundos |
| Variabilidad (std) | 1.57 segundos/página |
| Páginas procesadas totales | 320 |

*Fuente: CSV de resultados.*

**Observaciones:**

1. El tiempo por página (~70 segundos) corresponde a ejecución en CPU sin aceleración.
2. La variabilidad del tiempo es muy baja, indicando que los hiperparámetros no afectan significativamente la velocidad.
3. Con GPU, los tiempos serían 10-50× menores según benchmarks de PaddleOCR.

### Resumen de la Sección

Esta sección ha presentado:

1. **Configuración del experimento**: Arquitectura de subprocesos, dataset extendido, espacio de búsqueda de 7 dimensiones

2. **Resultados estadísticos**:
   - CER medio: 5.25% (std: 11.03%)
   - CER mínimo: 1.15%
   - 67.2% de trials con CER < 2%

3. **Hallazgos clave**:
   - `textline_orientation=True` reduce CER en 69.7%
   - `text_det_thresh` tiene correlación -0.52 con CER
   - Valores de `text_det_thresh` < 0.1 causan fallos catastróficos

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

## Discusión y análisis de resultados

### Introducción

Esta sección presenta un análisis consolidado de los resultados obtenidos en las fases de benchmark comparativo y optimización de hiperparámetros. Se discuten las implicaciones prácticas, se evalúa el cumplimiento de los objetivos planteados y se identifican las limitaciones del estudio.

### Resumen Consolidado de Resultados

#### Progresión del Rendimiento

**Tabla 30.** *Evolución del rendimiento a través del estudio.*

| Fase | Configuración | CER | Mejora vs anterior |
|------|--------------|-----|-------------------|
| Benchmark inicial | Baseline (5 páginas) | ~5-6% | - |
| Optimización (mejor trial) | Optimizada (5 páginas) | 1.15% | ~80% |
| Validación final | Optimizada (24 páginas) | 1.49% | - |

*Fuente: Elaboración propia.*

El incremento del CER de 1.15% (5 páginas) a 1.49% (24 páginas) es esperado debido a la mayor diversidad de layouts en el dataset completo.

#### Comparación con Objetivo

**Tabla 31.** *Verificación del objetivo general.*

| Aspecto | Objetivo | Resultado | Cumplimiento |
|---------|----------|-----------|--------------|
| Métrica | CER | CER | ✓ |
| Umbral | < 2% | 1.49% | ✓ |
| Método | Sin fine-tuning | Solo hiperparámetros | ✓ |
| Hardware | Sin GPU | CPU only | ✓ |

*Fuente: Elaboración propia.*

### Análisis Detallado de Hiperparámetros

#### Jerarquía de Importancia

Basándose en el análisis de correlación y el impacto observado:

**Tabla 32.** *Ranking de importancia de hiperparámetros.*

| Rank | Parámetro | Impacto | Evidencia |
|------|-----------|---------|-----------|
| 1 | `textline_orientation` | **Crítico** | Reduce CER 69.7% |
| 2 | `text_det_thresh` | **Alto** | Correlación -0.52 |
| 3 | `text_rec_score_thresh` | Medio | Correlación -0.16 |
| 4 | `text_det_box_thresh` | Bajo | Correlación +0.23 |
| 5 | `use_doc_orientation_classify` | Nulo | Sin mejora |
| 6 | `use_doc_unwarping` | Nulo | Sin mejora |

*Fuente: Elaboración propia.*

#### Análisis del Parámetro textline_orientation

**Por qué es tan importante:**

El clasificador de orientación de línea resuelve un problema fundamental en documentos con layouts complejos: determinar el orden correcto de lectura. Sin este clasificador:

1. Las líneas de una tabla pueden mezclarse con texto adyacente
2. Los encabezados laterales pueden insertarse en posiciones incorrectas
3. El texto en columnas puede leerse en orden incorrecto

Para documentos académicos que típicamente incluyen tablas, listas y encabezados multinivel, este clasificador es esencial.

**Recomendación**: Siempre activar `textline_orientation=True` para documentos estructurados.

#### Análisis del Parámetro text_det_thresh

**Comportamiento observado:**

| Rango | CER típico | Comportamiento |
|-------|------------|----------------|
| 0.0 - 0.1 | >20% | Fallos catastróficos |
| 0.1 - 0.3 | 5-15% | Rendimiento pobre |
| 0.3 - 0.5 | 1-5% | Rendimiento óptimo |
| 0.5 - 0.7 | 2-8% | Rendimiento aceptable |

**Interpretación:**

- Valores muy bajos (< 0.1) incluyen ruido y artefactos como "texto"
- Valores muy altos (> 0.6) filtran texto legítimo de bajo contraste
- El rango óptimo (0.3-0.5) balancea precisión y recall de detección

**Valor óptimo encontrado**: 0.4690

#### Parámetros sin Impacto Significativo

**`use_doc_orientation_classify` y `use_doc_unwarping`:**

Estos módulos están diseñados para:
- Documentos escaneados con rotación
- Fotografías de documentos con perspectiva
- Documentos curvados o deformados

Para documentos PDF digitales como los evaluados, estos módulos son innecesarios e incluso pueden introducir artefactos. Su desactivación reduce el tiempo de procesamiento sin pérdida de precisión.

### Análisis de Casos de Fallo

#### Clasificación de Errores

**Tabla 33.** *Tipología de errores observados.*

| Tipo de error | Frecuencia | Ejemplo | Causa probable |
|---------------|------------|---------|----------------|
| Pérdida de acentos | Alta | más → mas | Modelo de reconocimiento |
| Duplicación de caracteres | Media | titulación → titulacióon | Solapamiento de detecciones |
| Confusión de puntuación | Media | ¿ → ? | Caracteres similares |
| Pérdida de eñe | Baja | año → ano | Modelo de reconocimiento |
| Texto desordenado | Variable | Mezcla de líneas | Fallo de orientación |

*Fuente: Análisis cualitativo.*

#### Patrones de Fallo por Tipo de Contenido

**Tabla 34.** *Tasa de error por tipo de contenido.*

| Tipo de contenido | CER estimado | Factor de riesgo |
|-------------------|--------------|------------------|
| Párrafos de texto | ~1% | Bajo |
| Listas numeradas | ~2% | Medio |
| Tablas simples | ~3% | Medio |
| Encabezados + pie de página | ~2% | Medio |
| Tablas complejas | ~5% | Alto |
| Texto en columnas | ~4% | Alto |

*Fuente: Estimación cualitativa.*

### Comparación con Objetivos Específicos

**Tabla 35.** *Cumplimiento de objetivos específicos.*

| Objetivo | Descripción | Resultado | Estado |
|----------|-------------|-----------|--------|
| OE1 | Comparar soluciones OCR | EasyOCR, PaddleOCR, DocTR evaluados; PaddleOCR seleccionado | ✓ Cumplido |
| OE2 | Preparar dataset de evaluación | 24 páginas con ground truth | ✓ Cumplido |
| OE3 | Identificar hiperparámetros críticos | `textline_orientation` y `text_det_thresh` identificados | ✓ Cumplido |
| OE4 | Optimizar con Ray Tune (≥50 trials) | 64 trials ejecutados | ✓ Cumplido |
| OE5 | Validar configuración optimizada | CER: 7.78% → 1.49% documentado | ✓ Cumplido |

*Fuente: Elaboración propia.*

### Limitaciones del Estudio

#### Limitaciones de Generalización

1. **Tipo de documento único**: Solo se evaluaron documentos académicos de UNIR. La configuración óptima puede no ser transferible a otros tipos de documentos (facturas, formularios, contratos).

2. **Idioma único**: El estudio se centró en español. Otros idiomas con diferentes características ortográficas podrían requerir configuraciones diferentes.

3. **Formato único**: Solo se evaluaron PDFs digitales. Documentos escaneados o fotografías de documentos podrían beneficiarse de diferentes configuraciones.

#### Limitaciones Metodológicas

1. **Ground truth automático**: El texto de referencia se extrajo programáticamente del PDF, lo cual puede introducir errores en layouts complejos donde el orden de lectura no es evidente.

2. **Tamaño del dataset**: 24 páginas es un dataset pequeño. Un dataset más amplio proporcionaría estimaciones más robustas.

3. **Parámetro fijo**: `text_det_unclip_ratio` se mantuvo en 0.0 durante todo el experimento. Explorar este parámetro podría revelar mejoras adicionales.

4. **Ejecución en CPU**: Los tiempos reportados corresponden a ejecución en CPU. El comportamiento con GPU podría diferir.

#### Limitaciones de Validación

1. **Sin validación cruzada**: No se realizó validación cruzada sobre diferentes subconjuntos del dataset.

2. **Sin test set independiente**: El dataset de validación final se solapaba parcialmente con el de optimización.

### Implicaciones Prácticas

#### Guía de Configuración Recomendada

Para documentos académicos en español similares a los evaluados:

**Configuración recomendada:**
```python
config_recomendada = {
    # OBLIGATORIO
    "textline_orientation": True,

    # RECOMENDADO
    "text_det_thresh": 0.45,  # Rango: 0.4-0.5
    "text_rec_score_thresh": 0.6,  # Rango: 0.5-0.7

    # 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,
}
```

#### Cuándo Aplicar Esta Metodología

La optimización de hiperparámetros es recomendable cuando:

1. **Sin GPU disponible**: El fine-tuning requiere GPU; la optimización de hiperparámetros no.

2. **Modelo preentrenado adecuado**: El modelo ya soporta el idioma objetivo.

3. **Dominio específico**: Se busca optimizar para un tipo de documento particular.

4. **Mejora incremental**: El rendimiento baseline es aceptable pero mejorable.

#### Cuándo NO Aplicar Esta Metodología

La optimización de hiperparámetros puede ser insuficiente cuando:

1. **Idioma no soportado**: El modelo no incluye el idioma en su vocabulario.

2. **Escritura manuscrita**: Requiere fine-tuning o modelos especializados.

3. **Documentos muy degradados**: Escaneos de baja calidad o documentos históricos.

4. **Requisitos de CER < 0.5%**: Puede requerir fine-tuning para alcanzar precisiones muy altas.

### Resumen del Capítulo

Este capítulo ha presentado el desarrollo completo de la contribución:

**Planteamiento de la comparativa:**
- Evaluación de EasyOCR, PaddleOCR y DocTR
- Selección de PaddleOCR por su configurabilidad

**Desarrollo de la comparativa:**
- 64 trials de Ray Tune con Optuna
- Identificación de `textline_orientation` y `text_det_thresh` como críticos
- CER mínimo alcanzado: 1.15%

**Discusión y análisis:**
- Mejora del CER de 7.78% a 1.49% (reducción del 80.9%)
- Cumplimiento de todos los objetivos específicos
- Identificación de limitaciones y recomendaciones prácticas

**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
