Paddle ocr gpu support. #4
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,3 +10,5 @@ src/paddle_ocr/wheels
|
|||||||
src/*.log
|
src/*.log
|
||||||
src/output_*.ipynb
|
src/output_*.ipynb
|
||||||
debugset/
|
debugset/
|
||||||
|
|
||||||
|
src/dataset_hf/
|
||||||
|
|||||||
77
README.md
77
README.md
@@ -183,7 +183,7 @@ python src/paddle_ocr_tuning.py \
|
|||||||
|
|
||||||
## Fuentes de Datos
|
## Fuentes de Datos
|
||||||
|
|
||||||
- **Dataset**: Instrucciones para la elaboración del TFE (UNIR), 24 páginas
|
- **Dataset**: 2 documentos UNIR (45 páginas total): Instrucciones TFE (24 pág.) + Plantilla TFE (21 pág.)
|
||||||
- **Resultados Ray Tune (PRINCIPAL)**: `src/raytune_paddle_subproc_results_20251207_192320.csv` - 64 trials de optimización con todas las métricas y configuraciones
|
- **Resultados Ray Tune (PRINCIPAL)**: `src/raytune_paddle_subproc_results_20251207_192320.csv` - 64 trials de optimización con todas las métricas y configuraciones
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -290,39 +290,60 @@ Este trabajo adoptó la estrategia de **optimización de hiperparámetros** en l
|
|||||||
|
|
||||||
La optimización de hiperparámetros demostró ser una **alternativa efectiva** al fine-tuning, logrando una reducción del 80.9% en el CER sin reentrenar el modelo.
|
La optimización de hiperparámetros demostró ser una **alternativa efectiva** al fine-tuning, logrando una reducción del 80.9% en el CER sin reentrenar el modelo.
|
||||||
|
|
||||||
### Tareas Completadas
|
|
||||||
|
|
||||||
- [x] **Estructura docs/ según plantilla UNIR**: Todos los capítulos siguen numeración exacta (1.1, 1.2, etc.)
|
|
||||||
- [x] **Añadir diagramas Mermaid**: 7 diagramas añadidos (pipeline OCR, arquitectura Ray Tune, gráficos de comparación)
|
|
||||||
- [x] **Generar documento TFM unificado**: Script `apply_content.py` genera documento completo desde docs/
|
|
||||||
- [x] **Convertir Mermaid a PNG**: Script `generate_mermaid_figures.py` genera figuras automáticamente
|
|
||||||
|
|
||||||
### Tareas Pendientes
|
### Tareas Pendientes
|
||||||
|
|
||||||
#### 1. Validación del Enfoque (Prioridad Alta)
|
#### Obligatorias para Entrega
|
||||||
- [ ] **Validación cruzada en otros documentos**: Evaluar la configuración óptima en otros tipos de documentos en español (facturas, formularios, contratos) para verificar generalización
|
- [ ] **Revisión final del documento**: Abrir en Word, actualizar índices (Ctrl+A → F9), ajustar figuras, guardar como .docx
|
||||||
- [ ] **Ampliar el dataset**: El dataset actual tiene solo 24 páginas. Construir un corpus más amplio y diverso (mínimo 100 páginas)
|
|
||||||
- [ ] **Validación del ground truth**: Revisar manualmente el texto de referencia extraído automáticamente para asegurar su exactitud
|
|
||||||
|
|
||||||
#### 2. Experimentación Adicional (Prioridad Media)
|
|
||||||
- [ ] **Explorar `text_det_unclip_ratio`**: Este parámetro quedó fijado en 0.0. Incluirlo en el espacio de búsqueda podría mejorar resultados
|
|
||||||
- [ ] **Comparativa con fine-tuning** (si se obtiene acceso a GPU): Cuantificar la brecha de rendimiento entre optimización de hiperparámetros y fine-tuning real
|
|
||||||
- [x] **Evaluación con GPU**: Validado con RTX 3060 - 126x más rápido que CPU (0.55s/página vs 69.4s/página)
|
|
||||||
|
|
||||||
#### 3. Documentación y Presentación (Prioridad Alta)
|
|
||||||
- [ ] **Crear presentación**: Preparar slides para la defensa del TFM
|
- [ ] **Crear presentación**: Preparar slides para la defensa del TFM
|
||||||
- [ ] **Revisión final del documento**: Verificar formato, índices y contenido en Word
|
|
||||||
|
|
||||||
#### 4. Extensiones Futuras (Opcional)
|
#### Opcionales (Mejoras Futuras)
|
||||||
- [ ] **Herramienta de configuración automática**: Desarrollar una herramienta que determine automáticamente la configuración óptima para un nuevo tipo de documento
|
- [ ] **Validación cruzada**: Evaluar configuración en otros documentos (facturas, formularios)
|
||||||
- [ ] **Benchmark público para español**: Publicar un benchmark de OCR para documentos en español que facilite comparación de soluciones
|
- [ ] **Explorar `text_det_unclip_ratio`**: Parámetro fijado en 0.0, podría mejorar resultados
|
||||||
- [ ] **Optimización multi-objetivo**: Considerar CER, WER y tiempo de inferencia simultáneamente
|
- [ ] **Comparativa con fine-tuning**: Cuantificar brecha vs fine-tuning real
|
||||||
|
- [ ] **Herramienta de configuración automática**: Auto-detectar configuración óptima por documento
|
||||||
|
- [ ] **Benchmark público para español**: Facilitar comparación de soluciones OCR
|
||||||
|
|
||||||
### Recomendación de Próximos Pasos
|
#### Completadas
|
||||||
|
- [x] **Estructura docs/ según plantilla UNIR**
|
||||||
|
- [x] **Diagramas Mermaid**: 8 figuras generadas
|
||||||
|
- [x] **Documento TFM unificado**: Script `apply_content.py`
|
||||||
|
- [x] **Evaluación con GPU**: RTX 3060 - 126x más rápido (0.55s/página)
|
||||||
|
|
||||||
1. **Inmediato**: Abrir documento generado en Word, actualizar índices (Ctrl+A, F9), guardar como .docx
|
### Dataset
|
||||||
2. **Corto plazo**: Validar en 2-3 tipos de documentos adicionales para demostrar generalización
|
|
||||||
3. **Para la defensa**: Crear presentación con visualizaciones de resultados
|
El dataset contiene **45 páginas** de 2 documentos UNIR:
|
||||||
|
- `src/dataset/0/`: Instrucciones TFE (24 páginas)
|
||||||
|
- `src/dataset/1/`: Plantilla TFE (21 páginas)
|
||||||
|
|
||||||
|
#### Formato Hugging Face
|
||||||
|
|
||||||
|
El dataset está disponible en formato Hugging Face en `src/dataset_hf/`:
|
||||||
|
|
||||||
|
```
|
||||||
|
src/dataset_hf/
|
||||||
|
├── README.md # Dataset card
|
||||||
|
├── metadata.jsonl # Metadata (image_path, text, doc_id, page_num)
|
||||||
|
└── data/ # 45 imágenes PNG
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Generar/Regenerar Dataset
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Convertir de formato original a HF
|
||||||
|
source .venv/bin/activate
|
||||||
|
python src/dataset_formatting/convert_to_hf_dataset.py
|
||||||
|
|
||||||
|
# Upload a Gitea packages (requiere GITEA_TOKEN)
|
||||||
|
./src/dataset_formatting/upload-dataset.sh $GITEA_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Descargar Dataset
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Desde Gitea packages
|
||||||
|
curl -O https://seryus.ddns.net/api/packages/unir/generic/ocr-dataset-spanish/1.0.0/dataset-1.0.0.tar.gz
|
||||||
|
tar -xzf dataset-1.0.0.tar.gz -C src/dataset_hf/
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
138
src/dataset_formatting/convert_to_hf_dataset.py
Executable file
138
src/dataset_formatting/convert_to_hf_dataset.py
Executable file
@@ -0,0 +1,138 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Convert custom OCR dataset to Hugging Face format."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def convert_dataset(source_dir: str, output_dir: str):
|
||||||
|
"""Convert folder-based dataset to HF ImageFolder format."""
|
||||||
|
|
||||||
|
source = Path(source_dir)
|
||||||
|
output = Path(output_dir)
|
||||||
|
data_dir = output / "data"
|
||||||
|
data_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
metadata = []
|
||||||
|
|
||||||
|
for doc_folder in sorted(source.iterdir()):
|
||||||
|
if not doc_folder.is_dir():
|
||||||
|
continue
|
||||||
|
|
||||||
|
doc_id = doc_folder.name
|
||||||
|
img_dir = doc_folder / "img"
|
||||||
|
txt_dir = doc_folder / "txt"
|
||||||
|
|
||||||
|
if not img_dir.exists() or not txt_dir.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
for img_file in sorted(img_dir.glob("*.png")):
|
||||||
|
txt_file = txt_dir / f"{img_file.stem}.txt"
|
||||||
|
if not txt_file.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Extract page number
|
||||||
|
page_num = int(img_file.stem.split("_")[-1])
|
||||||
|
|
||||||
|
# New filename: page_{doc_id}_{page_num:04d}.png
|
||||||
|
new_name = f"page_{doc_id}_{page_num:04d}.png"
|
||||||
|
|
||||||
|
# Copy image
|
||||||
|
shutil.copy(img_file, data_dir / new_name)
|
||||||
|
|
||||||
|
# Read text
|
||||||
|
text = txt_file.read_text(encoding="utf-8").strip()
|
||||||
|
|
||||||
|
# Add metadata entry
|
||||||
|
metadata.append({
|
||||||
|
"file_name": f"data/{new_name}",
|
||||||
|
"text": text,
|
||||||
|
"document_id": doc_id,
|
||||||
|
"page_number": page_num
|
||||||
|
})
|
||||||
|
|
||||||
|
# Write metadata.jsonl
|
||||||
|
with open(output / "metadata.jsonl", "w", encoding="utf-8") as f:
|
||||||
|
for entry in metadata:
|
||||||
|
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
||||||
|
|
||||||
|
# Write dataset card
|
||||||
|
write_dataset_card(output, len(metadata))
|
||||||
|
|
||||||
|
print(f"Converted {len(metadata)} samples to {output}")
|
||||||
|
|
||||||
|
|
||||||
|
def write_dataset_card(output_dir: Path, num_samples: int):
|
||||||
|
"""Write HF dataset card."""
|
||||||
|
card = f'''---
|
||||||
|
dataset_info:
|
||||||
|
features:
|
||||||
|
- name: image
|
||||||
|
dtype: image
|
||||||
|
- name: text
|
||||||
|
dtype: string
|
||||||
|
- name: document_id
|
||||||
|
dtype: string
|
||||||
|
- name: page_number
|
||||||
|
dtype: int32
|
||||||
|
splits:
|
||||||
|
- name: train
|
||||||
|
num_examples: {num_samples}
|
||||||
|
license: cc-by-4.0
|
||||||
|
language:
|
||||||
|
- es
|
||||||
|
task_categories:
|
||||||
|
- image-to-text
|
||||||
|
tags:
|
||||||
|
- ocr
|
||||||
|
- spanish
|
||||||
|
- academic-documents
|
||||||
|
- unir
|
||||||
|
---
|
||||||
|
|
||||||
|
# UNIR OCR Dataset
|
||||||
|
|
||||||
|
Dataset de documentos académicos en español para evaluación de sistemas OCR.
|
||||||
|
|
||||||
|
## Descripción
|
||||||
|
|
||||||
|
- **Idioma**: Español
|
||||||
|
- **Dominio**: Documentos académicos (instrucciones TFE de UNIR)
|
||||||
|
- **Formato**: Imágenes PNG (300 DPI) + texto ground truth
|
||||||
|
- **Total**: {num_samples} pares imagen-texto
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
|
||||||
|
```python
|
||||||
|
from datasets import load_dataset
|
||||||
|
|
||||||
|
dataset = load_dataset("path/to/dataset")
|
||||||
|
|
||||||
|
for sample in dataset["train"]:
|
||||||
|
image = sample["image"]
|
||||||
|
text = sample["text"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Estructura
|
||||||
|
|
||||||
|
Cada muestra contiene:
|
||||||
|
- `image`: Imagen de la página (PIL.Image)
|
||||||
|
- `text`: Texto ground truth extraído del PDF
|
||||||
|
- `document_id`: ID del documento fuente
|
||||||
|
- `page_number`: Número de página
|
||||||
|
|
||||||
|
## Citación
|
||||||
|
|
||||||
|
Parte del TFM "Optimización de Hiperparámetros OCR con Ray Tune" - UNIR 2025
|
||||||
|
'''
|
||||||
|
(output_dir / "README.md").write_text(card, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
|
||||||
|
source = sys.argv[1] if len(sys.argv) > 1 else "src/dataset"
|
||||||
|
output = sys.argv[2] if len(sys.argv) > 2 else "src/dataset_hf"
|
||||||
|
|
||||||
|
convert_dataset(source, output)
|
||||||
63
src/dataset_formatting/upload-dataset.sh
Executable file
63
src/dataset_formatting/upload-dataset.sh
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Upload OCR dataset to Gitea generic packages
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./src/dataset_formatting/upload-dataset.sh [token]
|
||||||
|
#
|
||||||
|
# Environment variables:
|
||||||
|
# GITEA_TOKEN - Gitea API token
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
GITEA_URL="https://seryus.ddns.net"
|
||||||
|
GITEA_ORG="unir"
|
||||||
|
PACKAGE_NAME="ocr-dataset-spanish"
|
||||||
|
VERSION="1.0.0"
|
||||||
|
DATASET_DIR="src/dataset_hf"
|
||||||
|
TARBALL="dataset-${VERSION}.tar.gz"
|
||||||
|
|
||||||
|
# Get token
|
||||||
|
TOKEN="${1:-${GITEA_TOKEN}}"
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
echo "Error: No token provided"
|
||||||
|
echo "Usage: $0 [token]"
|
||||||
|
echo " or set GITEA_TOKEN environment variable"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check dataset exists
|
||||||
|
if [ ! -d "$DATASET_DIR" ]; then
|
||||||
|
echo "Error: Dataset not found at $DATASET_DIR"
|
||||||
|
echo "Run: python src/convert_to_hf_dataset.py first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create tarball
|
||||||
|
echo "Creating tarball..."
|
||||||
|
tar -czvf "$TARBALL" -C "$DATASET_DIR" .
|
||||||
|
echo "Created: $TARBALL ($(du -h $TARBALL | cut -f1))"
|
||||||
|
|
||||||
|
# Upload
|
||||||
|
echo "Uploading to Gitea packages..."
|
||||||
|
echo " URL: $GITEA_URL/api/packages/$GITEA_ORG/generic/$PACKAGE_NAME/$VERSION/$TARBALL"
|
||||||
|
|
||||||
|
HTTP_CODE=$(curl -sS -w "%{http_code}" -o /tmp/upload_response.txt \
|
||||||
|
-X PUT \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary "@$TARBALL" \
|
||||||
|
"$GITEA_URL/api/packages/$GITEA_ORG/generic/$PACKAGE_NAME/$VERSION/$TARBALL")
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
echo "Success! Dataset uploaded."
|
||||||
|
echo "Download URL: $GITEA_URL/api/packages/$GITEA_ORG/generic/$PACKAGE_NAME/$VERSION/$TARBALL"
|
||||||
|
rm "$TARBALL"
|
||||||
|
elif [ "$HTTP_CODE" = "409" ]; then
|
||||||
|
echo "Package version already exists (HTTP 409)"
|
||||||
|
rm "$TARBALL"
|
||||||
|
else
|
||||||
|
echo "Error: Upload failed with HTTP $HTTP_CODE"
|
||||||
|
cat /tmp/upload_response.txt
|
||||||
|
rm "$TARBALL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user