diff --git a/thesis_output/figures/figures b/thesis_output/figures/figures
new file mode 120000
index 0000000..7edfd1a
--- /dev/null
+++ b/thesis_output/figures/figures
@@ -0,0 +1 @@
+../figures
\ No newline at end of file
diff --git a/thesis_output/figures/unir_logo.png b/thesis_output/figures/unir_logo.png
new file mode 100644
index 0000000..8d8942b
Binary files /dev/null and b/thesis_output/figures/unir_logo.png differ
diff --git a/thesis_output/presentation.html b/thesis_output/presentation.html
new file mode 100644
index 0000000..a3797cb
--- /dev/null
+++ b/thesis_output/presentation.html
@@ -0,0 +1,1319 @@
+
+
+
+
+
+ TFM - Optimización de Hiperparámetros OCR con Ray Tune
+
+
+
+
+
+
+
+
+
+
+
+
+ Trabajo Fin de Máster
+ Optimización de Hiperparámetros OCR con Ray Tune para Documentos Académicos en Español
+
+
+ Sergio Jiménez Jiménez
+ Director: Javier Rodrigo Villazón Terrazas
+ Máster Universitario en Inteligencia Artificial
+ 2025
+
+
+
+
+
+ Agenda
+ 1
Motivación y planteamiento del problema
+ 2
Objetivos y estado del arte
+ 3
Metodología y arquitectura
+ 4
Resultados experimentales
+ 5
Conclusiones y trabajo futuro
+
+
+
+
+ Motivación
+
+
+
+ La digitalización documental es una necesidad estratégica para organizaciones
+ OCR como puente entre el mundo físico y digital
+ Documentos en español: caracteres especiales ausentes en conjuntos de entrenamiento internacionales
+ Modelos preentrenados: rendimiento subóptimo fuera de benchmarks estándar
+ Fine-tuning requiere infraestructura costosa y datos etiquetados
+
+
+
+
Errores típicos en español
+
+ Original OCR Error
+
+ más mas Pérdida de acento
+ año ano Pérdida de eñe
+ ¿Cómo Como Signos especiales
+ titulación titulacióon Duplicación
+
+
+
+
+
+
+
+
+ Planteamiento del Problema
+
+ ¿Es posible mejorar significativamente el rendimiento de modelos OCR preentrenados para documentos en español mediante la optimización sistemática de hiperparámetros, sin requerir fine-tuning?
+
+
+
+
+
Datos
Miles de imágenes etiquetadas
Subconjunto de validación
+
+
+
Hardware
GPU alta memoria (>16 GB)
CPU / GPU consumo
+
+
+
Tiempo
Días / semanas
Minutos / horas
+
+
+
Expertise
Alto (ML avanzado)
Bajo-medio
+
+
+
Riesgo
Sobreajuste, catastrófico
Limitado, reversible
+
+
+
+
+
+
+ Objetivos
+
+ Objetivo general: Optimizar PaddleOCR para documentos académicos en español alcanzando un CER < 2% sin fine-tuning del modelo base.
+
+
+ OE1: Comparar tres motores OCR open-source (EasyOCR, PaddleOCR, DocTR)
+ OE2: Preparar dataset de evaluación de 45 páginas con ground truth
+ OE3: Identificar hiperparámetros críticos mediante análisis de correlación
+ OE4: Ejecutar 64 trials de optimización con Ray Tune + Optuna
+ OE5: Validar la configuración optimizada frente al baseline
+
+
+
+
+
+ Estado del Arte: Motores OCR
+
+
+
EasyOCR
+
JaidedAI
+
CRAFT + CRNN
+
+ 80+ idiomas
+ Fácil de usar
+ Baja configurabilidad
+
+
+
+
PaddleOCR
+
Baidu / PaddlePaddle
+
DB + SVTR (PP-OCRv5)
+
+ Alta configurabilidad
+ Pipeline modular
+ Soporte español dedicado
+
+
+
+
DocTR
+
Mindee
+
DB/LinkNet + CRNN/SAR
+
+ TF y PyTorch
+ Soporte español limitado
+ Rápido en inferencia
+
+
+
+
+ Pipeline de un sistema OCR moderno
+
+
+
+
+ Metodología: 5 Fases
+
+ Fases de la metodología experimental
+
+
1
Preparación del dataset
PDF → 300 DPI + GT
+
2
Benchmark comparativo
3 motores, CER/WER
+
3
Espacio de búsqueda
7 hiperparámetros
+
4
Optimización
64 trials, TPE
+
5
Validación
45 páginas completas
+
+
+
+
+
+ Arquitectura: Microservicios Docker
+
+
+
+
Arquitectura de microservicios para optimización OCR
+
+
+
+ Contenedor Ray Tune: Orquestador de trials (Optuna TPE)
+ Contenedor OCR: PaddleOCR con acceso GPU
+ Comunicación: REST API (HTTP POST /evaluate)
+ Respuesta: JSON {CER, WER, TIME}
+ Docker Compose: Despliegue reproducible
+
+
+ Hardware:
+ RTX 3060 Laptop (5.66 GB VRAM)
+ AMD Ryzen 7 5800H
+ 16 GB DDR4 | Ubuntu 24.04
+
+
+
+
+
+
+
+ Espacio de Búsqueda: 7 Hiperparámetros
+
+
+
+ Parámetro Tipo Rango
+
+ textline_orientationBooleano True / False
+ use_doc_orientation_classifyBooleano True / False
+ use_doc_unwarpingBooleano True / False
+ text_det_threshContinuo [0.01, 0.50]
+ text_det_box_threshContinuo [0.01, 0.90]
+ text_rec_score_threshContinuo [0.01, 0.99]
+ text_det_unclip_ratioFijo 0.0
+
+
+
+
+
+
Ciclo de optimización con Ray Tune y Optuna
+
+ Algoritmo: TPE (Tree-structured Parzen Estimator)
+ Trials: 64 | Concurrencia: 2 workers
+ Métrica: Minimizar CER
+
+
+
+
+
+
+
+ Resultados: Benchmark Comparativo
+
+
+
+
+
+
+ Motor CER WER s/pág VRAM
+
+ EasyOCR 11.23% 36.36% 1.88 ~2 GB
+ PaddleOCR 7.76% 11.62% 0.58 0.06 GB
+ DocTR 12.06% 42.01% 0.50 ~1 GB
+
+
+
+ PaddleOCR seleccionado: Mejor CER (7.76%) con el menor consumo de VRAM (0.06 GB) y alta configurabilidad.
+
+
+
+
+
+
+
+ Resultados: 64 Trials de Optimización
+
+
+
+
+
+
+
+
0.79%
+
Mejor CER (Trial #1)
+
+
+
+
+
67.2%
+
Trials con CER < 2%
+
+
+
+ 0 fallos en 64 trials
+ Tiempo total: ~5 minutos (GPU)
+
+
+
+
+
+
+
+ Hallazgo Clave: textline_orientation
+
+
+
+
+
+
+
-63.2%
+
Reducción en CER
+
+
+ Un único parámetro booleano tiene mayor impacto que todos los umbrales numéricos combinados
+ Decisiones arquitecturales > ajustes numéricos finos
+ Crítico para documentos con layouts complejos (índices, listas, encabezados)
+ 52 de 64 trials (81%) lo activaron automáticamente (Optuna aprendió rápido)
+
+
+
+
+
+
+
+ Análisis de Hiperparámetros
+
+
+
Correlación Pearson con CER
+
+
+
+
+
+
Importancia de Hiperparámetros
+
+
+
+
+
+
+ Insight: use_doc_unwarping (+0.88) es perjudicial en PDFs digitales (añade procesamiento innecesario). Los parámetros booleanos (arquitecturales) dominan sobre los umbrales numéricos.
+
+
+
+
+
+ Validación: Baseline vs Optimizado
+
+
+
+
+
+
+ Métrica Baseline Optimizado Mejora
+
+ CER (45 pág) 8.85% 7.72% -12.8%
+ WER (45 pág) 13.05% 11.40% -12.6%
+ CER (mejor trial, 5 pág) 7.76% 0.79% -89.8%
+
+
+
+ Nota: La diferencia entre el mejor trial (0.79%) y la validación completa (7.72%) evidencia sobreajuste al subconjunto de 5 páginas usado en la optimización. Un subconjunto más amplio (15-20 páginas) mejoraría la generalización.
+
+
+
+
+
+
+
+ Aceleración GPU
+
+
+
+
+
+
+
+
82x
+
Factor de aceleración
+
+
+
0.84 s
+
GPU: segundos por página
+
+
+
69.4 s
+
CPU: segundos por página
+
+
+
+ 64 trials × 5 páginas:
+ CPU: ~6.2 horas
+ GPU: ~5 minutos
+
+
+
+
+
+
+
+ Configuración Óptima
+
+
+
+ config_optimizada = {
+ "textline_orientation" : True , # CRÍTICO
+ "use_doc_orientation_classify" : True ,
+ "use_doc_unwarping" : False , # Innecesario
+ "text_det_thresh" : 0.0462 ,
+ "text_det_box_thresh" : 0.4862 ,
+ "text_det_unclip_ratio" : 0.0 ,
+ "text_rec_score_thresh" : 0.5658 ,
+ }
+
+
+
+
Insights clave
+
+ textline_orientation = True : Parámetro más impactante (-63.2% CER)
+ use_doc_unwarping = False : Procesamiento innecesario para PDFs digitales
+ text_det_thresh bajo : Captura más regiones de texto, reduce omisiones
+ Parámetros booleanos dominan sobre umbrales numéricos
+
+
+ Esta configuración es directamente aplicable a otros documentos académicos en español con layouts similares.
+
+
+
+
+
+
+
+ Conclusiones
+
+
+
Contribuciones
+
+
1
+
Metodología reproducible para optimización de hiperparámetros OCR con código abierto
+
+
+
2
+
Análisis sistemático de hiperparámetros PaddleOCR con correlaciones Pearson
+
+
+
3
+
Configuración validada para documentos académicos en español (CER 0.79%)
+
+
+
4
+
Infraestructura dockerizada reproducible con imágenes públicas
+
+
+
+
Limitaciones
+
+
!
+
Un único tipo de documento (académico UNIR)
+
+
+
!
+
Corpus modesto (45 páginas)
+
+
+
!
+
Sobreajuste al subconjunto de optimización (5 páginas)
+
+
+
!
+
text_det_unclip_ratio no explorado
+
+
+
+
+
+
+
+ Líneas de Trabajo Futuro
+
+
+
Extensiones inmediatas
+
+ Validación cruzada en otros tipos de documentos (facturas, formularios, manuscritos)
+ Subconjunto de optimización más amplio (15-20 páginas)
+ Exploración de text_det_unclip_ratio
+
+
+
+
Líneas de investigación
+
+ Transfer learning de hiperparámetros entre dominios
+ Optimización multi-objetivo (CER + WER + velocidad)
+ Comparación rigurosa HPO vs fine-tuning
+
+
+
+
Aplicaciones prácticas
+
+ Herramienta de configuración automática por tipo de documento
+ Integración en pipelines de producción
+ Benchmark público de OCR en español
+
+
+
+
+
+
+
+
+ Gracias
+ Preguntas?
+
+
+ Sergio Jiménez Jiménez
+ Máster Universitario en Inteligencia Artificial
+ Universidad Internacional de La Rioja (UNIR) | 2025
+
+
+
+
+
+
+
+
+
+
diff --git a/thesis_output/presentation/charts.js b/thesis_output/presentation/charts.js
new file mode 100644
index 0000000..2ea7bce
--- /dev/null
+++ b/thesis_output/presentation/charts.js
@@ -0,0 +1,328 @@
+// Chart instances
+const charts = {};
+
+// UNIR Colors
+const BLUE = '#0098CD';
+const BLUE_DARK = '#007AA3';
+const LIGHT = '#E6F4F9';
+const RED = '#E8654A';
+const ORANGE = '#F0A030';
+const GREEN = '#2EAD4B';
+const GRAY = '#CCCCCC';
+
+// Common chart options
+const commonOptions = {
+ responsive: true,
+ maintainAspectRatio: true,
+ animation: { duration: 1200, easing: 'easeOutQuart' },
+ plugins: { legend: { display: false } }
+};
+
+function createBenchmarkChart() {
+ const ctx = document.getElementById('chartBenchmark');
+ if (!ctx || charts.benchmark) return;
+ charts.benchmark = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: ['EasyOCR', 'PaddleOCR', 'DocTR'],
+ datasets: [
+ {
+ label: 'CER (%)',
+ data: [11.23, 7.76, 12.06],
+ backgroundColor: [GRAY, BLUE, GRAY],
+ borderColor: [GRAY, BLUE_DARK, GRAY],
+ borderWidth: 2,
+ borderRadius: 6,
+ barPercentage: 0.6
+ },
+ {
+ label: 'WER (%)',
+ data: [36.36, 11.62, 42.01],
+ backgroundColor: ['rgba(204,204,204,0.4)', 'rgba(0,152,205,0.4)', 'rgba(204,204,204,0.4)'],
+ borderColor: [GRAY, BLUE, GRAY],
+ borderWidth: 2,
+ borderRadius: 6,
+ barPercentage: 0.6
+ }
+ ]
+ },
+ options: {
+ ...commonOptions,
+ indexAxis: 'y',
+ plugins: {
+ legend: { display: true, position: 'top', labels: { font: { family: 'Calibri', size: 12 } } }
+ },
+ scales: {
+ x: { title: { display: true, text: 'Error Rate (%)', font: { family: 'Calibri' } }, grid: { color: '#f0f0f0' } },
+ y: { grid: { display: false }, ticks: { font: { family: 'Calibri', size: 14, weight: 'bold' } } }
+ }
+ }
+ });
+}
+
+function createTrialsChart() {
+ const ctx = document.getElementById('chartTrials');
+ if (!ctx || charts.trials) return;
+ charts.trials = new Chart(ctx, {
+ type: 'doughnut',
+ data: {
+ labels: ['CER < 1%', 'CER 1-2%', 'CER 2-5%', 'CER 5-10%'],
+ datasets: [{
+ data: [15, 28, 10, 11],
+ backgroundColor: [BLUE_DARK, BLUE, '#7EC8E3', GRAY],
+ borderColor: 'white',
+ borderWidth: 3,
+ hoverOffset: 8
+ }]
+ },
+ options: {
+ ...commonOptions,
+ cutout: '55%',
+ plugins: {
+ legend: {
+ display: true,
+ position: 'bottom',
+ labels: { font: { family: 'Calibri', size: 12 }, padding: 15, usePointStyle: true, pointStyle: 'rectRounded' }
+ }
+ }
+ }
+ });
+}
+
+function createTextlineChart() {
+ const ctx = document.getElementById('chartTextline');
+ if (!ctx || charts.textline) return;
+ charts.textline = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: ['False', 'True'],
+ datasets: [{
+ label: 'CER medio (%)',
+ data: [4.73, 1.74],
+ backgroundColor: [GRAY, BLUE],
+ borderColor: ['#aaa', BLUE_DARK],
+ borderWidth: 2,
+ borderRadius: 8,
+ barPercentage: 0.5
+ }]
+ },
+ options: {
+ ...commonOptions,
+ scales: {
+ y: {
+ beginAtZero: true,
+ max: 6,
+ title: { display: true, text: 'CER (%)', font: { family: 'Calibri', size: 13 } },
+ grid: { color: '#f0f0f0' }
+ },
+ x: {
+ title: { display: true, text: 'textline_orientation', font: { family: 'Calibri', size: 13, weight: 'bold' } },
+ grid: { display: false },
+ ticks: { font: { family: 'Calibri', size: 16, weight: 'bold' } }
+ }
+ },
+ plugins: {
+ legend: { display: false },
+ tooltip: {
+ callbacks: {
+ label: (ctx) => `CER: ${ctx.parsed.y}%`
+ }
+ }
+ }
+ }
+ });
+}
+
+function createCorrelationChart() {
+ const ctx = document.getElementById('chartCorrelation');
+ if (!ctx || charts.correlation) return;
+ const params = [
+ 'use_doc_unwarping',
+ 'text_det_thresh',
+ 'text_det_box_thresh',
+ 'text_rec_score_thresh',
+ 'textline_orientation',
+ 'use_doc_orient_classify'
+ ];
+ const values = [0.879, 0.428, 0.311, -0.268, -0.535, -0.712];
+ const colors = values.map(v => v > 0 ? RED : BLUE);
+
+ charts.correlation = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: params,
+ datasets: [{
+ data: values,
+ backgroundColor: colors,
+ borderColor: colors.map(c => c === RED ? '#C04030' : BLUE_DARK),
+ borderWidth: 1.5,
+ borderRadius: 4,
+ barPercentage: 0.65
+ }]
+ },
+ options: {
+ ...commonOptions,
+ indexAxis: 'y',
+ scales: {
+ x: {
+ min: -1, max: 1,
+ title: { display: true, text: 'Correlación Pearson', font: { family: 'Calibri', size: 11 } },
+ grid: { color: (ctx) => ctx.tick.value === 0 ? '#666' : '#f0f0f0' }
+ },
+ y: {
+ grid: { display: false },
+ ticks: { font: { family: 'Consolas, monospace', size: 10 } }
+ }
+ }
+ }
+ });
+}
+
+function createImportanceChart() {
+ const ctx = document.getElementById('chartImportance');
+ if (!ctx || charts.importance) return;
+ const params = [
+ 'use_doc_unwarping',
+ 'use_doc_orient_classify',
+ 'textline_orientation',
+ 'text_det_thresh',
+ 'text_det_box_thresh',
+ 'text_rec_score_thresh'
+ ];
+ const values = [0.879, 0.712, 0.535, 0.428, 0.311, 0.268];
+ const colors = values.map((_, i) => {
+ const alpha = 1 - (i * 0.12);
+ return `rgba(0, 152, 205, ${alpha})`;
+ });
+
+ charts.importance = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: params,
+ datasets: [{
+ data: values,
+ backgroundColor: colors,
+ borderColor: BLUE_DARK,
+ borderWidth: 1,
+ borderRadius: 4,
+ barPercentage: 0.65
+ }]
+ },
+ options: {
+ ...commonOptions,
+ indexAxis: 'y',
+ scales: {
+ x: {
+ beginAtZero: true, max: 1,
+ title: { display: true, text: '|Correlación|', font: { family: 'Calibri', size: 11 } },
+ grid: { color: '#f0f0f0' }
+ },
+ y: {
+ grid: { display: false },
+ ticks: { font: { family: 'Consolas, monospace', size: 10 } }
+ }
+ }
+ }
+ });
+}
+
+function createValidationChart() {
+ const ctx = document.getElementById('chartValidation');
+ if (!ctx || charts.validation) return;
+ charts.validation = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: ['CER (45 pág)', 'WER (45 pág)', 'CER (mejor trial)'],
+ datasets: [
+ {
+ label: 'Baseline',
+ data: [8.85, 13.05, 7.76],
+ backgroundColor: 'rgba(204,204,204,0.7)',
+ borderColor: '#aaa',
+ borderWidth: 2,
+ borderRadius: 6,
+ barPercentage: 0.7
+ },
+ {
+ label: 'Optimizado',
+ data: [7.72, 11.40, 0.79],
+ backgroundColor: BLUE,
+ borderColor: BLUE_DARK,
+ borderWidth: 2,
+ borderRadius: 6,
+ barPercentage: 0.7
+ }
+ ]
+ },
+ options: {
+ ...commonOptions,
+ plugins: {
+ legend: { display: true, position: 'top', labels: { font: { family: 'Calibri', size: 13 } } }
+ },
+ scales: {
+ y: {
+ beginAtZero: true,
+ title: { display: true, text: 'Error Rate (%)', font: { family: 'Calibri' } },
+ grid: { color: '#f0f0f0' }
+ },
+ x: {
+ grid: { display: false },
+ ticks: { font: { family: 'Calibri', size: 12 } }
+ }
+ }
+ }
+ });
+}
+
+function createGPUChart() {
+ const ctx = document.getElementById('chartGPU');
+ if (!ctx || charts.gpu) return;
+ charts.gpu = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: ['CPU (Ryzen 7 5800H)', 'GPU (RTX 3060)'],
+ datasets: [{
+ label: 'Segundos por página',
+ data: [69.4, 0.84],
+ backgroundColor: [ORANGE, BLUE],
+ borderColor: ['#CC8020', BLUE_DARK],
+ borderWidth: 2,
+ borderRadius: 8,
+ barPercentage: 0.5
+ }]
+ },
+ options: {
+ ...commonOptions,
+ indexAxis: 'y',
+ scales: {
+ x: {
+ beginAtZero: true,
+ title: { display: true, text: 'Segundos por página', font: { family: 'Calibri', size: 13 } },
+ grid: { color: '#f0f0f0' }
+ },
+ y: {
+ grid: { display: false },
+ ticks: { font: { family: 'Calibri', size: 14, weight: 'bold' } }
+ }
+ },
+ plugins: {
+ legend: { display: false },
+ tooltip: {
+ callbacks: {
+ label: (ctx) => `${ctx.parsed.x} s/página`
+ }
+ }
+ }
+ }
+ });
+}
+
+// Chart creation map
+const chartCreators = {
+ benchmark: createBenchmarkChart,
+ trials: createTrialsChart,
+ textline: createTextlineChart,
+ correlations: () => { createCorrelationChart(); createImportanceChart(); },
+ validation: createValidationChart,
+ gpu: createGPUChart
+};
diff --git a/thesis_output/presentation/figures b/thesis_output/presentation/figures
new file mode 120000
index 0000000..7edfd1a
--- /dev/null
+++ b/thesis_output/presentation/figures
@@ -0,0 +1 @@
+../figures
\ No newline at end of file
diff --git a/thesis_output/presentation/index.html b/thesis_output/presentation/index.html
new file mode 100644
index 0000000..d2dc930
--- /dev/null
+++ b/thesis_output/presentation/index.html
@@ -0,0 +1,98 @@
+
+
+
+
+
+ TFM - Optimización de Hiperparámetros OCR con Ray Tune
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/thesis_output/presentation/slides/01_title.html b/thesis_output/presentation/slides/01_title.html
new file mode 100644
index 0000000..6d3573c
--- /dev/null
+++ b/thesis_output/presentation/slides/01_title.html
@@ -0,0 +1,12 @@
+
+
+ Trabajo Fin de Máster
+ Optimización de Hiperparámetros OCR con Ray Tune para Documentos Académicos en Español
+
+
+ Sergio Jiménez Jiménez
+ Director: Javier Rodrigo Villazón Terrazas
+ Máster Universitario en Inteligencia Artificial
+ 2025
+
+
diff --git a/thesis_output/presentation/slides/02_agenda.html b/thesis_output/presentation/slides/02_agenda.html
new file mode 100644
index 0000000..96b9584
--- /dev/null
+++ b/thesis_output/presentation/slides/02_agenda.html
@@ -0,0 +1,8 @@
+
+ Agenda
+ 1
Motivación y planteamiento del problema
+ 2
Objetivos y estado del arte
+ 3
Metodología y arquitectura
+ 4
Resultados experimentales
+ 5
Conclusiones y trabajo futuro
+
diff --git a/thesis_output/presentation/slides/03_motivation.html b/thesis_output/presentation/slides/03_motivation.html
new file mode 100644
index 0000000..709bb12
--- /dev/null
+++ b/thesis_output/presentation/slides/03_motivation.html
@@ -0,0 +1,26 @@
+
+ Motivación
+
+
+
+ La digitalización documental es una necesidad estratégica para organizaciones
+ OCR como puente entre el mundo físico y digital
+ Documentos en español: caracteres especiales ausentes en conjuntos de entrenamiento internacionales
+ Modelos preentrenados: rendimiento subóptimo fuera de benchmarks estándar
+ Fine-tuning requiere infraestructura costosa y datos etiquetados
+
+
+
+
Errores típicos en español
+
+ Original OCR Error
+
+ más mas Pérdida de acento
+ año ano Pérdida de eñe
+ ¿Cómo Como Signos especiales
+ titulación titulacióon Duplicación
+
+
+
+
+
diff --git a/thesis_output/presentation/slides/04_problem.html b/thesis_output/presentation/slides/04_problem.html
new file mode 100644
index 0000000..12ff260
--- /dev/null
+++ b/thesis_output/presentation/slides/04_problem.html
@@ -0,0 +1,26 @@
+
+ Planteamiento del Problema
+
+ ¿Es posible mejorar significativamente el rendimiento de modelos OCR preentrenados para documentos en español mediante la optimización sistemática de hiperparámetros, sin requerir fine-tuning?
+
+
+
+
+
Datos
Miles de imágenes etiquetadas
Subconjunto de validación
+
+
+
Hardware
GPU alta memoria (>16 GB)
CPU / GPU consumo
+
+
+
Tiempo
Días / semanas
Minutos / horas
+
+
+
Expertise
Alto (ML avanzado)
Bajo-medio
+
+
+
Riesgo
Sobreajuste, catastrófico
Limitado, reversible
+
+
+
diff --git a/thesis_output/presentation/slides/05_objectives.html b/thesis_output/presentation/slides/05_objectives.html
new file mode 100644
index 0000000..75b2934
--- /dev/null
+++ b/thesis_output/presentation/slides/05_objectives.html
@@ -0,0 +1,13 @@
+
+ Objetivos
+
+ Objetivo general: Optimizar PaddleOCR para documentos académicos en español alcanzando un CER < 2% sin fine-tuning del modelo base.
+
+
+ OE1: Comparar tres motores OCR open-source (EasyOCR, PaddleOCR, DocTR)
+ OE2: Preparar dataset de evaluación de 45 páginas con ground truth
+ OE3: Identificar hiperparámetros críticos mediante análisis de correlación
+ OE4: Ejecutar 64 trials de optimización con Ray Tune + Optuna
+ OE5: Validar la configuración optimizada frente al baseline
+
+
diff --git a/thesis_output/presentation/slides/06_state_of_art.html b/thesis_output/presentation/slides/06_state_of_art.html
new file mode 100644
index 0000000..da2e6c3
--- /dev/null
+++ b/thesis_output/presentation/slides/06_state_of_art.html
@@ -0,0 +1,37 @@
+
+ Estado del Arte: Motores OCR
+
+
+
EasyOCR
+
JaidedAI
+
CRAFT + CRNN
+
+ 80+ idiomas
+ Fácil de usar
+ Baja configurabilidad
+
+
+
+
PaddleOCR
+
Baidu / PaddlePaddle
+
DB + SVTR (PP-OCRv5)
+
+ Alta configurabilidad
+ Pipeline modular
+ Soporte español dedicado
+
+
+
+
DocTR
+
Mindee
+
DB/LinkNet + CRNN/SAR
+
+ TF y PyTorch
+ Soporte español limitado
+ Rápido en inferencia
+
+
+
+
+ Pipeline de un sistema OCR moderno
+
diff --git a/thesis_output/presentation/slides/07_methodology.html b/thesis_output/presentation/slides/07_methodology.html
new file mode 100644
index 0000000..3b779fa
--- /dev/null
+++ b/thesis_output/presentation/slides/07_methodology.html
@@ -0,0 +1,12 @@
+
+ Metodología: 5 Fases
+
+ Fases de la metodología experimental
+
+
1
Preparación del dataset
PDF → 300 DPI + GT
+
2
Benchmark comparativo
3 motores, CER/WER
+
3
Espacio de búsqueda
7 hiperparámetros
+
4
Optimización
64 trials, TPE
+
5
Validación
45 páginas completas
+
+
diff --git a/thesis_output/presentation/slides/08_architecture.html b/thesis_output/presentation/slides/08_architecture.html
new file mode 100644
index 0000000..72f1e2e
--- /dev/null
+++ b/thesis_output/presentation/slides/08_architecture.html
@@ -0,0 +1,24 @@
+
+ Arquitectura: Microservicios Docker
+
+
+
+
Arquitectura de microservicios para optimización OCR
+
+
+
+ Contenedor Ray Tune: Orquestador de trials (Optuna TPE)
+ Contenedor OCR: PaddleOCR con acceso GPU
+ Comunicación: REST API (HTTP POST /evaluate)
+ Respuesta: JSON {CER, WER, TIME}
+ Docker Compose: Despliegue reproducible
+
+
+ Hardware:
+ RTX 3060 Laptop (5.66 GB VRAM)
+ AMD Ryzen 7 5800H
+ 16 GB DDR4 | Ubuntu 24.04
+
+
+
+
diff --git a/thesis_output/presentation/slides/09_search_space.html b/thesis_output/presentation/slides/09_search_space.html
new file mode 100644
index 0000000..ca1a3df
--- /dev/null
+++ b/thesis_output/presentation/slides/09_search_space.html
@@ -0,0 +1,43 @@
+
+ Espacio de Búsqueda: 7 Hiperparámetros
+
+
+
+ Parámetro Tipo Rango Descripción
+
+ textline_orientationBooleano True / False Orientación de líneas de texto
+ use_doc_orientation_classifyBooleano True / False Clasificación de orientación
+ use_doc_unwarpingBooleano True / False Corrección de deformaciones
+ text_det_threshContinuo [0.01, 0.50] Umbral binarización probabilidad
+ text_det_box_threshContinuo [0.01, 0.90] Confianza caja de texto
+ text_rec_score_threshContinuo [0.01, 0.99] Confianza del reconocedor
+ text_det_unclip_ratioFijo 0.0 Expansión de cajas (no explorado)
+
+
+
+
+ Discretos / Booleanos (3) — True | False
+ Solo 2 valores por parámetro (8 combinaciones). Interruptores on/off de módulos del pipeline. Decisiones arquitecturales : cambian qué se ejecuta.
+
+
+ Continuos / Float (3) — 0.01 ← → 0.99
+ Valores reales muestreados uniformemente. Infinitos valores , grid search inviable. Ajustan sensibilidad de detección y reconocimiento.
+
+
+ Fijo (1) — 0.0
+ Constante en todos los trials. Trabajo futuro.
+
+
+
+
+
+
Ciclo de optimización con Ray Tune y Optuna
+
+ Algoritmo: TPE (Tree-structured Parzen Estimator)
+ Trials: 64 | Concurrencia: 2 workers
+ Métrica: Minimizar CER
+ Combinaciones: 2³ × ∞³ = espacio mixto discreto-continuo
+
+
+
+
diff --git a/thesis_output/presentation/slides/10_benchmark.html b/thesis_output/presentation/slides/10_benchmark.html
new file mode 100644
index 0000000..b939248
--- /dev/null
+++ b/thesis_output/presentation/slides/10_benchmark.html
@@ -0,0 +1,21 @@
+
+ Resultados: Benchmark Comparativo
+
+
+
+
+
+
+ Motor CER WER s/pág VRAM
+
+ EasyOCR 11.23% 36.36% 1.88 ~2 GB
+ PaddleOCR 7.76% 11.62% 0.58 0.06 GB
+ DocTR 12.06% 42.01% 0.50 ~1 GB
+
+
+
+ PaddleOCR seleccionado: Mejor CER (7.76%) con el menor consumo de VRAM (0.06 GB) y alta configurabilidad.
+
+
+
+
diff --git a/thesis_output/presentation/slides/11_trials.html b/thesis_output/presentation/slides/11_trials.html
new file mode 100644
index 0000000..4908874
--- /dev/null
+++ b/thesis_output/presentation/slides/11_trials.html
@@ -0,0 +1,32 @@
+
+ Resultados: 64 Trials de Optimización
+
+
+
+
+
+
+
+
0.79%
+
Mejor CER (Trial #1)
+
+
+
+
+
67.2%
+
Trials con CER < 2%
+
+
+
+ 0 fallos en 64 trials
+ Tiempo total: ~5 minutos (GPU)
+
+
+
+
diff --git a/thesis_output/presentation/slides/12_key_finding.html b/thesis_output/presentation/slides/12_key_finding.html
new file mode 100644
index 0000000..d400fe4
--- /dev/null
+++ b/thesis_output/presentation/slides/12_key_finding.html
@@ -0,0 +1,20 @@
+
+ Hallazgo Clave: textline_orientation
+
+
+
+
+
+
+
-63.2%
+
Reducción en CER
+
+
+ Un único parámetro booleano tiene mayor impacto que todos los umbrales numéricos combinados
+ Decisiones arquitecturales > ajustes numéricos finos
+ Crítico para documentos con layouts complejos (índices, listas, encabezados)
+ 52 de 64 trials (81%) lo activaron automáticamente (Optuna aprendió rápido)
+
+
+
+
diff --git a/thesis_output/presentation/slides/13_correlations.html b/thesis_output/presentation/slides/13_correlations.html
new file mode 100644
index 0000000..dc23166
--- /dev/null
+++ b/thesis_output/presentation/slides/13_correlations.html
@@ -0,0 +1,20 @@
+
+ Análisis de Hiperparámetros
+
+
+
Correlación Pearson con CER
+
+
+
+
+
+
Importancia de Hiperparámetros
+
+
+
+
+
+
+ Insight: use_doc_unwarping (+0.88) es perjudicial en PDFs digitales (añade procesamiento innecesario). Los parámetros booleanos (arquitecturales) dominan sobre los umbrales numéricos.
+
+
diff --git a/thesis_output/presentation/slides/14_validation.html b/thesis_output/presentation/slides/14_validation.html
new file mode 100644
index 0000000..937c675
--- /dev/null
+++ b/thesis_output/presentation/slides/14_validation.html
@@ -0,0 +1,21 @@
+
+ Validación: Baseline vs Optimizado
+
+
+
+
+
+
+ Métrica Baseline Optimizado Mejora
+
+ CER (45 pág) 8.85% 7.72% -12.8%
+ WER (45 pág) 13.05% 11.40% -12.6%
+ CER (mejor trial, 5 pág) 7.76% 0.79% -89.8%
+
+
+
+ Nota: La diferencia entre el mejor trial (0.79%) y la validación completa (7.72%) evidencia sobreajuste al subconjunto de 5 páginas usado en la optimización. Un subconjunto más amplio (15-20 páginas) mejoraría la generalización.
+
+
+
+
diff --git a/thesis_output/presentation/slides/15_gpu.html b/thesis_output/presentation/slides/15_gpu.html
new file mode 100644
index 0000000..c2dcb54
--- /dev/null
+++ b/thesis_output/presentation/slides/15_gpu.html
@@ -0,0 +1,29 @@
+
+ Aceleración GPU
+
+
+
+
+
+
+
+
82x
+
Factor de aceleración
+
+
+
0.84 s
+
GPU: segundos por página
+
+
+
69.4 s
+
CPU: segundos por página
+
+
+
+ 64 trials × 5 páginas:
+ CPU: ~6.2 horas
+ GPU: ~5 minutos
+
+
+
+
diff --git a/thesis_output/presentation/slides/16_optimal_config.html b/thesis_output/presentation/slides/16_optimal_config.html
new file mode 100644
index 0000000..89ffcaa
--- /dev/null
+++ b/thesis_output/presentation/slides/16_optimal_config.html
@@ -0,0 +1,30 @@
+
+ Configuración Óptima
+
+
+
+ config_optimizada = {
+ "textline_orientation" : True , # CRÍTICO
+ "use_doc_orientation_classify" : True ,
+ "use_doc_unwarping" : False , # Innecesario
+ "text_det_thresh" : 0.0462 ,
+ "text_det_box_thresh" : 0.4862 ,
+ "text_det_unclip_ratio" : 0.0 ,
+ "text_rec_score_thresh" : 0.5658 ,
+ }
+
+
+
+
Insights clave
+
+ textline_orientation = True : Parámetro más impactante (-63.2% CER)
+ use_doc_unwarping = False : Procesamiento innecesario para PDFs digitales
+ text_det_thresh bajo : Captura más regiones de texto, reduce omisiones
+ Parámetros booleanos dominan sobre umbrales numéricos
+
+
+ Esta configuración es directamente aplicable a otros documentos académicos en español con layouts similares.
+
+
+
+
diff --git a/thesis_output/presentation/slides/17_conclusions.html b/thesis_output/presentation/slides/17_conclusions.html
new file mode 100644
index 0000000..489ef4b
--- /dev/null
+++ b/thesis_output/presentation/slides/17_conclusions.html
@@ -0,0 +1,43 @@
+
+ Conclusiones
+
+
+
Contribuciones
+
+
1
+
Metodología reproducible para optimización de hiperparámetros OCR con código abierto
+
+
+
2
+
Análisis sistemático de hiperparámetros PaddleOCR con correlaciones Pearson
+
+
+
3
+
Configuración validada para documentos académicos en español (CER 0.79%)
+
+
+
4
+
Infraestructura dockerizada reproducible con imágenes públicas
+
+
+
+
Limitaciones
+
+
!
+
Un único tipo de documento (académico UNIR)
+
+
+
!
+
Corpus modesto (45 páginas)
+
+
+
!
+
Sobreajuste al subconjunto de optimización (5 páginas)
+
+
+
!
+
text_det_unclip_ratio no explorado
+
+
+
+
diff --git a/thesis_output/presentation/slides/18_future_work.html b/thesis_output/presentation/slides/18_future_work.html
new file mode 100644
index 0000000..dc41156
--- /dev/null
+++ b/thesis_output/presentation/slides/18_future_work.html
@@ -0,0 +1,29 @@
+
+ Líneas de Trabajo Futuro
+
+
+
Extensiones inmediatas
+
+ Validación cruzada en otros tipos de documentos (facturas, formularios, manuscritos)
+ Subconjunto de optimización más amplio (15-20 páginas)
+ Exploración de text_det_unclip_ratio
+
+
+
+
Líneas de investigación
+
+ Transfer learning de hiperparámetros entre dominios
+ Optimización multi-objetivo (CER + WER + velocidad)
+ Comparación rigurosa HPO vs fine-tuning
+
+
+
+
Aplicaciones prácticas
+
+ Herramienta de configuración automática por tipo de documento
+ Integración en pipelines de producción
+ Benchmark público de OCR en español
+
+
+
+
diff --git a/thesis_output/presentation/slides/19_thanks.html b/thesis_output/presentation/slides/19_thanks.html
new file mode 100644
index 0000000..4638ce8
--- /dev/null
+++ b/thesis_output/presentation/slides/19_thanks.html
@@ -0,0 +1,11 @@
+
+
+ Gracias
+ Preguntas?
+
+
+ Sergio Jiménez Jiménez
+ Máster Universitario en Inteligencia Artificial
+ Universidad Internacional de La Rioja (UNIR) | 2025
+
+
diff --git a/thesis_output/presentation/styles.css b/thesis_output/presentation/styles.css
new file mode 100644
index 0000000..ece9e6b
--- /dev/null
+++ b/thesis_output/presentation/styles.css
@@ -0,0 +1,458 @@
+:root {
+ --unir-blue: #0098CD;
+ --unir-blue-dark: #007AA3;
+ --unir-light: #E6F4F9;
+ --unir-text: #404040;
+ --unir-gray: #E7E6E6;
+ --unir-red: #E8654A;
+ --unir-orange: #F0A030;
+}
+
+.reveal {
+ font-family: 'Calibri', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
+ font-size: 28px;
+ color: var(--unir-text);
+}
+
+.reveal h1, .reveal h2, .reveal h3 {
+ font-family: 'Calibri Light', 'Calibri', 'Segoe UI', Arial, sans-serif;
+ color: var(--unir-blue);
+ text-transform: none;
+ letter-spacing: -0.02em;
+ font-weight: 600;
+}
+
+.reveal h1 { font-size: 1.8em; }
+.reveal h2 { font-size: 1.4em; margin-bottom: 0.6em; }
+.reveal h3 { font-size: 1.1em; }
+
+.reveal .slides section {
+ text-align: left;
+ padding: 20px 40px;
+}
+
+/* Corner logo on all slides except title */
+.reveal .slides section:not(.title-slide)::after {
+ content: '';
+ position: absolute;
+ top: 15px;
+ right: 20px;
+ width: 110px;
+ height: 30px;
+ background: url('figures/unir_logo.png') no-repeat center;
+ background-size: contain;
+ opacity: 0.8;
+}
+
+/* Bottom accent line - fixed to viewport bottom */
+#bottom-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, var(--unir-blue), var(--unir-light));
+ z-index: 50;
+ pointer-events: none;
+}
+
+/* Title slide */
+.title-slide {
+ text-align: center !important;
+}
+.title-slide h1 {
+ font-size: 1.5em !important;
+ line-height: 1.3;
+ margin-top: 0.2em;
+}
+.title-slide .subtitle {
+ color: var(--unir-blue);
+ font-size: 0.75em;
+ font-weight: 600;
+ margin-bottom: 0.5em;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
+}
+.title-slide .meta {
+ font-size: 0.65em;
+ color: #666;
+ line-height: 1.8;
+}
+.title-slide .meta strong {
+ color: var(--unir-text);
+}
+.title-slide .logo-large {
+ width: 220px;
+ margin-bottom: 10px;
+}
+.title-slide .divider {
+ width: 120px;
+ height: 3px;
+ background: var(--unir-blue);
+ margin: 15px auto;
+}
+
+/* Thank you slide */
+.thanks-slide {
+ text-align: center !important;
+}
+.thanks-slide h1 {
+ font-size: 2.5em !important;
+ margin-bottom: 0.3em;
+}
+.thanks-slide .questions {
+ font-size: 1.2em;
+ color: #666;
+ margin-bottom: 1em;
+}
+
+/* Two column layout */
+.two-columns {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 30px;
+ align-items: start;
+}
+.two-columns-60-40 {
+ display: grid;
+ grid-template-columns: 3fr 2fr;
+ gap: 30px;
+ align-items: start;
+}
+.two-columns-40-60 {
+ display: grid;
+ grid-template-columns: 2fr 3fr;
+ gap: 30px;
+ align-items: start;
+}
+.three-columns {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ gap: 20px;
+ align-items: start;
+}
+
+/* Highlight box */
+.highlight-box {
+ background: var(--unir-light);
+ border-left: 5px solid var(--unir-blue);
+ padding: 15px 20px;
+ border-radius: 0 8px 8px 0;
+ margin: 15px 0;
+ font-size: 0.85em;
+}
+.highlight-box.center-box {
+ border-left: none;
+ border-top: 3px solid var(--unir-blue);
+ border-radius: 0 0 8px 8px;
+ text-align: center;
+}
+
+/* Metric cards */
+.metric-cards {
+ display: flex;
+ gap: 15px;
+ flex-wrap: wrap;
+ justify-content: center;
+}
+.metric-card {
+ background: white;
+ border: 2px solid var(--unir-light);
+ border-radius: 12px;
+ padding: 15px 20px;
+ text-align: center;
+ min-width: 130px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.06);
+ transition: transform 0.2s;
+}
+.metric-card:hover {
+ transform: translateY(-2px);
+}
+.metric-card .number {
+ font-size: 1.6em;
+ font-weight: 700;
+ color: var(--unir-blue);
+ line-height: 1.2;
+}
+.metric-card .number.success { color: #2EAD4B; }
+.metric-card .number.warning { color: var(--unir-orange); }
+.metric-card .number.danger { color: var(--unir-red); }
+.metric-card .label {
+ font-size: 0.6em;
+ color: #888;
+ margin-top: 4px;
+}
+
+/* Data table */
+.data-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 0.75em;
+ margin: 10px 0;
+}
+.data-table thead th {
+ background: var(--unir-blue);
+ color: white;
+ padding: 10px 14px;
+ text-align: left;
+ font-weight: 600;
+}
+.data-table thead th:first-child {
+ border-radius: 8px 0 0 0;
+}
+.data-table thead th:last-child {
+ border-radius: 0 8px 0 0;
+}
+.data-table tbody td {
+ padding: 8px 14px;
+ border-bottom: 1px solid var(--unir-gray);
+}
+.data-table tbody tr:nth-child(even) {
+ background: #FAFCFE;
+}
+.data-table tbody tr.highlight {
+ background: var(--unir-light);
+ font-weight: 600;
+}
+.data-table tbody tr:last-child td:first-child {
+ border-radius: 0 0 0 8px;
+}
+.data-table tbody tr:last-child td:last-child {
+ border-radius: 0 0 8px 0;
+}
+
+/* Engine cards */
+.engine-card {
+ background: white;
+ border: 2px solid var(--unir-gray);
+ border-radius: 12px;
+ padding: 18px;
+ text-align: center;
+ transition: all 0.3s;
+}
+.engine-card.selected {
+ border-color: var(--unir-blue);
+ background: var(--unir-light);
+ box-shadow: 0 4px 16px rgba(0,152,205,0.2);
+}
+.engine-card h3 {
+ margin: 0 0 5px 0;
+ font-size: 0.9em;
+}
+.engine-card .developer {
+ font-size: 0.55em;
+ color: #999;
+ margin-bottom: 10px;
+}
+.engine-card .arch {
+ font-size: 0.6em;
+ color: var(--unir-text);
+ background: var(--unir-light);
+ border-radius: 6px;
+ padding: 4px 8px;
+ display: inline-block;
+ margin-bottom: 8px;
+}
+.engine-card.selected .arch {
+ background: white;
+}
+.engine-card ul {
+ text-align: left;
+ font-size: 0.6em;
+ margin: 0;
+ padding-left: 16px;
+}
+
+/* Agenda items */
+.agenda-item {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin: 12px 0;
+ font-size: 0.85em;
+}
+.agenda-number {
+ width: 36px;
+ height: 36px;
+ background: var(--unir-blue);
+ color: white;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 700;
+ font-size: 0.9em;
+ flex-shrink: 0;
+}
+
+/* Tags */
+.tag {
+ display: inline-block;
+ background: var(--unir-light);
+ color: var(--unir-blue-dark);
+ border-radius: 20px;
+ padding: 3px 12px;
+ font-size: 0.6em;
+ font-weight: 600;
+ margin: 2px;
+}
+.tag.bool { background: #FFF3E0; color: #E65100; }
+.tag.cont { background: #E8F5E9; color: #2E7D32; }
+.tag.fixed { background: var(--unir-gray); color: #888; }
+
+/* Chart containers */
+.chart-container {
+ position: relative;
+ width: 100%;
+ max-height: 420px;
+}
+.chart-container canvas {
+ max-height: 420px;
+}
+
+/* Bullet lists */
+.reveal ul, .reveal ol {
+ font-size: 0.8em;
+ line-height: 1.6;
+}
+.reveal li {
+ margin-bottom: 6px;
+}
+
+/* Compact list */
+.compact-list { font-size: 0.7em; }
+.compact-list li { margin-bottom: 3px; }
+
+/* Objective check */
+.obj-list {
+ list-style: none;
+ padding: 0;
+ font-size: 0.72em;
+}
+.obj-list li {
+ padding: 6px 0 6px 30px;
+ position: relative;
+}
+.obj-list li::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 8px;
+ width: 18px;
+ height: 18px;
+ border: 2px solid var(--unir-blue);
+ border-radius: 50%;
+}
+.obj-list li.done::before {
+ background: var(--unir-blue);
+ box-shadow: inset 0 0 0 3px white;
+}
+
+/* Conclusion items */
+.contribution-item {
+ display: flex;
+ align-items: start;
+ gap: 10px;
+ margin: 8px 0;
+ font-size: 0.72em;
+}
+.contribution-icon {
+ width: 28px;
+ height: 28px;
+ background: var(--unir-blue);
+ color: white;
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ flex-shrink: 0;
+}
+.limitation-icon {
+ width: 28px;
+ height: 28px;
+ background: var(--unir-orange);
+ color: white;
+ border-radius: 6px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 14px;
+ flex-shrink: 0;
+}
+
+/* Figure caption */
+.fig-caption {
+ text-align: center;
+ font-size: 0.55em;
+ color: #999;
+ font-style: italic;
+ margin-top: 5px;
+}
+
+/* Comparison table for fine-tuning vs HPO */
+.compare-row {
+ display: grid;
+ grid-template-columns: 140px 1fr 1fr;
+ gap: 0;
+ font-size: 0.65em;
+}
+.compare-row.header > div {
+ background: var(--unir-blue);
+ color: white;
+ padding: 8px 12px;
+ font-weight: 600;
+}
+.compare-row > div {
+ padding: 6px 12px;
+ border-bottom: 1px solid var(--unir-gray);
+}
+.compare-row .label-col {
+ font-weight: 600;
+ background: #FAFCFE;
+}
+.compare-row .highlight-col {
+ background: var(--unir-light);
+}
+
+/* Slide number */
+.reveal .slide-number {
+ color: var(--unir-blue);
+ font-size: 14px;
+ font-family: 'Calibri', sans-serif;
+}
+
+/* Progress bar */
+.reveal .progress span {
+ background: var(--unir-blue);
+}
+
+/* Improvements arrow */
+.improvement {
+ color: #2EAD4B;
+ font-weight: 700;
+ font-size: 0.8em;
+}
+
+/* Code/param names */
+code, .param {
+ font-family: 'Consolas', 'Courier New', monospace;
+ background: var(--unir-light);
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-size: 0.85em;
+}
+
+/* Section divider */
+.section-divider {
+ text-align: center !important;
+}
+.section-divider h2 {
+ font-size: 1.8em !important;
+}
+.section-divider .section-number {
+ font-size: 3em;
+ color: var(--unir-blue);
+ opacity: 0.2;
+ font-weight: 700;
+}