{ "cells": [ { "cell_type": "markdown", "id": "be3c1872", "metadata": {}, "source": [ "# AI-based OCR Benchmark Notebook\n", "\n", "This notebook benchmarks **AI-based OCR models** on scanned PDF documents/images in Spanish.\n", "It excludes traditional OCR engines like Tesseract that require external installations." ] }, { "cell_type": "code", "execution_count": null, "id": "6a1e98fe", "metadata": {}, "outputs": [], "source": [ "%pip install --upgrade pip\n", "%pip install --upgrade jupyter\n", "%pip install --upgrade ipywidgets\n", "%pip install --upgrade ipykernel\n", "\n", "# Install necessary packages\n", "%pip install transformers torch pdf2image pillow jiwer paddleocr hf_xet paddlepaddle\n", "# pdf reading\n", "%pip install PyMuPDF\n", "\n", "# Data analysis and visualization\n", "%pip install pandas\n", "%pip install matplotlib\n", "%pip install seaborn" ] }, { "cell_type": "code", "execution_count": 1, "id": "ae33632a", "metadata": {}, "outputs": [], "source": [ "# Imports\n", "import os, json\n", "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "from pdf2image import convert_from_path\n", "from PIL import Image, ImageOps\n", "import torch\n", "from jiwer import wer, cer\n", "from paddleocr import PaddleOCR\n", "import fitz # PyMuPDF\n", "import re\n", "from datetime import datetime" ] }, { "cell_type": "markdown", "id": "0e00f1b0", "metadata": {}, "source": [ "## 1 Configuration" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "PDF_FOLDER = './instructions' # Folder containing PDF files\n", "OUTPUT_FOLDER = 'results'\n", "os.makedirs(OUTPUT_FOLDER, exist_ok=True)" ] }, { "cell_type": "code", "execution_count": 3, "id": "8bd4ca23", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "c:\\Users\\sji\\Desktop\\MastersThesis\\instructions\n", "c:\\Users\\sji\\Desktop\\MastersThesis\\paddle_ocr_tuning.py\n", "c:\\Users\\sji\\Desktop\\MastersThesis\n" ] } ], "source": [ "PDF_FOLDER_ABS = os.path.abspath(PDF_FOLDER) # ./instructions -> C:\\...\\instructions\n", "SCRIPT_ABS = os.path.abspath(\"paddle_ocr_tuning.py\") # paddle_ocr_tuning.py -> C:\\...\\paddle_ocr_tuning.py\n", "SCRIPT_DIR = os.path.dirname(SCRIPT_ABS)\n", "\n", "print(PDF_FOLDER_ABS)\n", "print(SCRIPT_ABS)\n", "print(SCRIPT_DIR)" ] }, { "cell_type": "code", "execution_count": null, "id": "243849b9", "metadata": {}, "outputs": [], "source": [ "# 3. PaddleOCR \n", "# https://www.paddleocr.ai/v3.0.0/en/version3.x/pipeline_usage/OCR.html?utm_source=chatgpt.com#21-command-line\n", "from paddleocr import PaddleOCR\n", "\n", "# Initialize with better settings for Spanish/Latin text\n", "# https://www.paddleocr.ai/main/en/version3.x/algorithm/PP-OCRv5/PP-OCRv5_multi_languages.html?utm_source=chatgpt.com#5-models-and-their-supported-languages\n", "paddleocr_model = PaddleOCR(\n", " text_detection_model_name=\"PP-OCRv5_server_det\",\n", " text_recognition_model_name=\"PP-OCRv5_server_rec\"\n", ")" ] }, { "cell_type": "code", "execution_count": 9, "id": "329da34a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
3.3.1\n",
       "
\n" ], "text/plain": [ "\u001b[1;36m3.3\u001b[0m.\u001b[1;36m1\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import paddleocr\n", "\n", "print(paddleocr.__version__)" ] }, { "cell_type": "code", "execution_count": 10, "id": "b1541bb6", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
c:\\Users\\sji\\Desktop\\MastersThesis\\.venv\\Lib\\site-packages\\paddleocr\n",
       "
\n" ], "text/plain": [ "c:\\Users\\sji\\Desktop\\MastersThesis\\.venv\\Lib\\site-packages\\paddleocr\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# 1) Locate the installed PaddleOCR package\n", "pkg_dir = os.path.dirname(paddleocr.__file__)\n", "print(pkg_dir)" ] }, { "cell_type": "markdown", "id": "84c999e2", "metadata": {}, "source": [ "## 2 Helper Functions" ] }, { "cell_type": "code", "execution_count": null, "id": "9596c7df", "metadata": {}, "outputs": [], "source": [ "from typing import List, Optional\n", "from paddle_ocr_tuning import pdf_to_images, pdf_extract_text, evaluate_text, assemble_from_paddle_result\n", "\n", "def show_page(img: Image.Image, text: str, scale: float = 1):\n", " \"\"\"\n", " Displays a smaller version of the image with text as a footer.\n", " \"\"\"\n", " # Compute plot size based on image dimensions (but without resizing the image)\n", " w, h = img.size\n", " figsize = (w * scale / 100, h * scale / 100) # convert pixels to inches approx\n", "\n", " fig, ax = plt.subplots(figsize=figsize)\n", " ax.imshow(img)\n", " ax.axis(\"off\")\n", "\n", "\n", " # Add OCR text below the image (footer)\n", " # plt.figtext(0.5, 0.02, text.strip(), wrap=True, ha='center', va='bottom', fontsize=10)\n", " plt.tight_layout()\n", " plt.show()" ] }, { "cell_type": "markdown", "id": "e42cae29", "metadata": {}, "source": [ "## Run AI OCR Benchmark" ] }, { "cell_type": "code", "execution_count": null, "id": "9b55c154", "metadata": {}, "outputs": [], "source": [ "results = []\n", "\n", "for pdf_file in os.listdir(PDF_FOLDER):\n", " if not pdf_file.lower().endswith('.pdf'):\n", " continue\n", " pdf_path = os.path.join(PDF_FOLDER, pdf_file)\n", " page_range = range(5, 10)\n", " \n", " images = pdf_to_images(pdf_path, 300, page_range)\n", " \n", " for i, img in enumerate(images):\n", " # img = preprocess_for_ocr(img)\n", " page_num = page_range[i]\n", " ref = pdf_extract_text(pdf_path, page_num=page_num)\n", " show_page(img, f\"page: {page_num}\", 0.15)\n", " print(f\"ref: \\n{ref}\")\n", " \n", " # Convert PIL image to numpy array\n", " image_array = np.array(img)\n", " out = paddleocr_model.predict(\n", " image_array,\n", " use_doc_orientation_classify=False,\n", " use_doc_unwarping=False,\n", " use_textline_orientation=True\n", " )\n", " # PaddleOCR\n", " paddle_text = assemble_from_paddle_result(out)\n", " print(f\"paddle_text: \\n{paddle_text}\")\n", " results.append({'PDF': pdf_file, 'Page': page_num, 'Model': 'PaddleOCR', 'Prediction': paddle_text, **evaluate_text(ref, paddle_text)})\n", " " ] }, { "cell_type": "markdown", "id": "0db6dc74", "metadata": {}, "source": [ "## 5 Save and Analyze Results" ] }, { "cell_type": "code", "execution_count": null, "id": "da3155e3", "metadata": {}, "outputs": [], "source": [ "df_results = pd.DataFrame(results)\n", "\n", "# Generate a unique filename with timestamp\n", "timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n", "filename = f\"ai_ocr_benchmark_finetune_results_{timestamp}.csv\"\n", "filepath = os.path.join(OUTPUT_FOLDER, filename)\n", "\n", "df_results.to_csv(filepath, index=False)\n", "print(f\"Benchmark results saved as {filename}\")\n", "\n", "# Summary by model\n", "summary = df_results.groupby('Model')[['WER', 'CER']].mean()\n", "print(summary)\n", "\n", "# Plot\n", "summary.plot(kind='bar', figsize=(8,5), title='AI OCR Benchmark (WER & CER)')\n", "plt.ylabel('Error Rate')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "3e0f00c0", "metadata": {}, "source": [ "### How to read this chart:\n", "- CER (Character Error Rate) focus on raw transcription quality\n", "- WER (Word Error Rate) penalizes incorrect tokenization or missing spaces\n", "- CER and WER are error metrics, which means:\n", " - Higher values = worse performance\n", " - Lower values = better accuracy" ] }, { "cell_type": "markdown", "id": "830b0e25", "metadata": {}, "source": [ "# Busqueda de hyperparametros\n", "https://docs.ray.io/en/latest/tune/index.html" ] }, { "cell_type": "code", "execution_count": null, "id": "3a4bd700", "metadata": {}, "outputs": [], "source": [ "!python --version\n", "!pip --version" ] }, { "cell_type": "code", "execution_count": 18, "id": "b0cf4bcf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Looking in indexes: https://pypi.org/simple, https://pypi.ngc.nvidia.com\n", "Collecting rich\n", " Downloading rich-14.2.0-py3-none-any.whl.metadata (18 kB)\n", "Requirement already satisfied: ray[tune] in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (2.51.1)\n", "Requirement already satisfied: click!=8.3.0,>=7.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (8.2.1)\n", "Requirement already satisfied: filelock in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (3.20.0)\n", "Requirement already satisfied: jsonschema in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (4.25.1)\n", "Requirement already satisfied: msgpack<2.0.0,>=1.0.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (1.1.2)\n", "Requirement already satisfied: packaging in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (25.0)\n", "Requirement already satisfied: protobuf>=3.20.3 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (6.33.0)\n", "Requirement already satisfied: pyyaml in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (6.0.2)\n", "Requirement already satisfied: requests in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (2.32.5)\n", "Requirement already satisfied: pandas in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (2.3.3)\n", "Requirement already satisfied: tensorboardX>=1.9 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (2.6.4)\n", "Requirement already satisfied: pyarrow>=9.0.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (22.0.0)\n", "Requirement already satisfied: fsspec in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from ray[tune]) (2025.10.0)\n", "Collecting markdown-it-py>=2.2.0 (from rich)\n", " Downloading markdown_it_py-4.0.0-py3-none-any.whl.metadata (7.3 kB)\n", "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from rich) (2.19.2)\n", "Requirement already satisfied: colorama in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from click!=8.3.0,>=7.0->ray[tune]) (0.4.6)\n", "Collecting mdurl~=0.1 (from markdown-it-py>=2.2.0->rich)\n", " Downloading mdurl-0.1.2-py3-none-any.whl.metadata (1.6 kB)\n", "Requirement already satisfied: numpy in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from tensorboardX>=1.9->ray[tune]) (2.3.4)\n", "Requirement already satisfied: attrs>=22.2.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from jsonschema->ray[tune]) (25.4.0)\n", "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from jsonschema->ray[tune]) (2025.9.1)\n", "Requirement already satisfied: referencing>=0.28.4 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from jsonschema->ray[tune]) (0.37.0)\n", "Requirement already satisfied: rpds-py>=0.7.1 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from jsonschema->ray[tune]) (0.28.0)\n", "Requirement already satisfied: typing-extensions>=4.4.0 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from referencing>=0.28.4->jsonschema->ray[tune]) (4.15.0)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from pandas->ray[tune]) (2.9.0.post0)\n", "Requirement already satisfied: pytz>=2020.1 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from pandas->ray[tune]) (2025.2)\n", "Requirement already satisfied: tzdata>=2022.7 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from pandas->ray[tune]) (2025.2)\n", "Requirement already satisfied: six>=1.5 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from python-dateutil>=2.8.2->pandas->ray[tune]) (1.17.0)\n", "Requirement already satisfied: charset_normalizer<4,>=2 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from requests->ray[tune]) (3.4.4)\n", "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from requests->ray[tune]) (3.11)\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from requests->ray[tune]) (2.5.0)\n", "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\sji\\desktop\\mastersthesis\\.venv\\lib\\site-packages (from requests->ray[tune]) (2025.10.5)\n", "Downloading rich-14.2.0-py3-none-any.whl (243 kB)\n", "Downloading markdown_it_py-4.0.0-py3-none-any.whl (87 kB)\n", "Downloading mdurl-0.1.2-py3-none-any.whl (10.0 kB)\n", "Installing collected packages: mdurl, markdown-it-py, rich\n", "\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ---------------------------------------- 0/3 [mdurl]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " ------------- -------------------------- 1/3 [markdown-it-py]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " -------------------------- ------------- 2/3 [rich]\n", " ---------------------------------------- 3/3 [rich]\n", "\n", "Successfully installed markdown-it-py-4.0.0 mdurl-0.1.2 rich-14.2.0\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "# Instalaci贸n de Ray y Ray Tune\n", "%pip install -U \"ray[tune]\" rich" ] }, { "cell_type": "code", "execution_count": 6, "id": "f3ca0b9b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2025-11-12 22:30:42,267\tINFO worker.py:1850 -- Calling ray.init() again after it has already been called.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Ray Tune listo (versi贸n: 2.51.1 )\n" ] } ], "source": [ "import ray\n", "from ray import tune\n", "from ray.tune.schedulers import ASHAScheduler\n", "\n", "ray.init(ignore_reinit_error=True)\n", "print(\"Ray Tune listo (versi贸n:\", ray.__version__, \")\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "ae5a10c4", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2025-11-12 22:30:48,318\tINFO worker.py:1850 -- Calling ray.init() again after it has already been called.\n" ] } ], "source": [ "# ===============================================================\n", "# 馃攳 RAY TUNE: OPTIMIZACI脫N AUTOM脕TICA DE HIPERPAR脕METROS OCR\n", "# ===============================================================\n", "\n", "from ray import tune, air\n", "from ray.tune.schedulers import ASHAScheduler\n", "import pandas as pd\n", "import time\n", "import colorama\n", "from rich import print\n", "import sys, subprocess \n", "from rich.console import Console\n", "\n", "colorama.just_fix_windows_console()\n", "ray.init(ignore_reinit_error=True)\n", "\n", "# Tell Ray Tune to use a Jupyter-compatible console\n", "console = Console(force_jupyter=True)" ] }, { "cell_type": "code", "execution_count": 8, "id": "96c320e8", "metadata": {}, "outputs": [], "source": [ "\n", "\n", "# --- Configuraci贸n base del experimento ---\n", "search_space = {\n", " \"dpi\": tune.choice([240, 300, 360]),\n", " \"textline_orientation\": tune.choice([True, False]),\n", " \"text_det_box_thresh\": tune.uniform(0.4, 0.7),\n", " \"text_det_unclip_ratio\": tune.uniform(1.2, 2.0),\n", " \"text_rec_score_thresh\": tune.choice([0.0, 0.2, 0.4]),\n", " \"line_tolerance\": tune.choice([0.5, 0.6, 0.7]),\n", " \"min_box_score\": tune.choice([0, 0.5, 0.6])\n", "}\n", "KEYMAP = {\n", " \"dpi\": \"dpi\",\n", " \"textline_orientation\": \"textline-orientation\",\n", " \"text_det_box_thresh\": \"text-det-box-thresh\",\n", " \"text_det_unclip_ratio\": \"text-det-unclip-ratio\",\n", " \"text_rec_score_thresh\": \"text-rec-score-thresh\",\n", " \"line_tolerance\": \"line-tolerance\",\n", " \"pages_per_pdf\": \"pages-per-pdf\",\n", " \"min_box_score\": \"min-box-score\",\n", "}" ] }, { "cell_type": "code", "execution_count": 7, "id": "accb4e9d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Notebook Python: c:\\Users\\sji\\Desktop\\MastersThesis\\.venv\\Scripts\\python.exe\n",
       "
\n" ], "text/plain": [ "Notebook Python: c:\\Users\\sji\\Desktop\\MastersThesis\\.venv\\Scripts\\python.exe\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
{'CER': 0.019801980198019802, 'WER': 0.09090909090909091, 'TIME': 38.859522104263306, 'PAGES': 1}\n",
       "
\n" ], "text/plain": [ "\u001b[1m{\u001b[0m\u001b[32m'CER'\u001b[0m: \u001b[1;36m0.019801980198019802\u001b[0m, \u001b[32m'WER'\u001b[0m: \u001b[1;36m0.09090909090909091\u001b[0m, \u001b[32m'TIME'\u001b[0m: \u001b[1;36m38.859522104263306\u001b[0m, \u001b[32m'PAGES'\u001b[0m: \u001b[1;36m1\u001b[0m\u001b[1m}\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
return code: 0\n",
       "
\n" ], "text/plain": [ "return code: \u001b[1;36m0\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
args: ['c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\.venv\\\\Scripts\\\\python.exe', \n",
       "'c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\paddle_ocr_tuning.py', '--pdf-folder', \n",
       "'c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\instructions', '--pages-per-pdf', '1', '--dpi', '360', \n",
       "'--textline-orientation', 'True', '--text-det-box-thresh', '0.46611732611383844', '--text-det-unclip-ratio', \n",
       "'1.3598680409827462', '--text-rec-score-thresh', '0.0', '--line-tolerance', '0.5', '--min-box-score', '0.6']\n",
       "
\n" ], "text/plain": [ "args: \u001b[1m[\u001b[0m\u001b[32m'c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\.venv\\\\Scripts\\\\python.exe'\u001b[0m, \n", "\u001b[32m'c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\paddle_ocr_tuning.py'\u001b[0m, \u001b[32m'--pdf-folder'\u001b[0m, \n", "\u001b[32m'c:\\\\Users\\\\sji\\\\Desktop\\\\MastersThesis\\\\instructions'\u001b[0m, \u001b[32m'--pages-per-pdf'\u001b[0m, \u001b[32m'1'\u001b[0m, \u001b[32m'--dpi'\u001b[0m, \u001b[32m'360'\u001b[0m, \n", "\u001b[32m'--textline-orientation'\u001b[0m, \u001b[32m'True'\u001b[0m, \u001b[32m'--text-det-box-thresh'\u001b[0m, \u001b[32m'0.46611732611383844'\u001b[0m, \u001b[32m'--text-det-unclip-ratio'\u001b[0m, \n", "\u001b[32m'1.3598680409827462'\u001b[0m, \u001b[32m'--text-rec-score-thresh'\u001b[0m, \u001b[32m'0.0'\u001b[0m, \u001b[32m'--line-tolerance'\u001b[0m, \u001b[32m'0.5'\u001b[0m, \u001b[32m'--min-box-score'\u001b[0m, \u001b[32m'0.6'\u001b[0m\u001b[1m]\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import sys, subprocess\n", "print(\"Notebook Python:\", sys.executable)\n", "# test paddle ocr run with params\n", "args = [sys.executable, \n", " SCRIPT_ABS, \n", " \"--pdf-folder\", PDF_FOLDER_ABS, \n", " \"--pages-per-pdf\", \"1\",\n", " \"--dpi\",\"360\" ,\n", " \"--textline-orientation\",\"True\",\n", " \"--text-det-box-thresh\",\"0.46611732611383844\",\n", " \"--text-det-unclip-ratio\",\"1.3598680409827462\",\n", " \"--text-rec-score-thresh\",\"0.0\",\n", " \"--line-tolerance\", \"0.5\",\n", " \"--min-box-score\",\"0.6\"]\n", "test_proc = subprocess.run(args, capture_output=True, text=True, cwd=SCRIPT_DIR)\n", "if test_proc.returncode != 0:\n", " print(test_proc.stderr)\n", "last = test_proc.stdout.strip().splitlines()[-1]\n", "\n", "metrics = json.loads(last)\n", "print(metrics)\n", "\n", "print(f\"return code: {test_proc.returncode}\")\n", "print(f\"args: {args}\")" ] }, { "cell_type": "code", "execution_count": 9, "id": "8df28468", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "c:\\Users\\sji\\Desktop\\MastersThesis\\.venv\\Lib\\site-packages\\ray\\tune\\impl\\tuner_internal.py:144: RayDeprecationWarning: The `RunConfig` class should be imported from `ray.tune` when passing it to the Tuner. Please update your imports. See this issue for more context and migration options: https://github.com/ray-project/ray/issues/49454. Disable these warnings by setting the environment variable: RAY_TRAIN_ENABLE_V2_MIGRATION_WARNINGS=0\n", " _log_deprecation_warning(\n", "2025-11-12 22:31:01,166\tINFO tune.py:616 -- [output] This uses the legacy output and progress reporter, as Jupyter notebooks are not supported by the new engine, yet. For more information, please see https://github.com/ray-project/ray/issues/36949\n" ] }, { "data": { "text/html": [ "
\n", "
\n", "
\n", "

Tune Status

\n", " \n", "\n", "\n", "\n", "\n", "\n", "
Current time:2025-11-12 22:39:26
Running for: 00:08:25.78
Memory: 9.9/31.8 GiB
\n", "
\n", "
\n", "
\n", "

System Info

\n", " Using AsyncHyperBand: num_stopped=1
Bracket: Iter 64.000: None | Iter 32.000: None | Iter 16.000: None | Iter 8.000: None | Iter 4.000: None | Iter 2.000: None | Iter 1.000: -0.062382927481937384
Logical resource usage: 1.0/12 CPUs, 0/1 GPUs (0.0/1.0 accelerator_type:G)\n", "
\n", " \n", "
\n", "
\n", "
\n", "

Trial Status

\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Trial name status loc dpi line_tolerance min_box_score text_det_box_thresh text_det_unclip_rati\n", "o text_rec_score_thres\n", "htextline_orientation iter total time (s) CER WER TIME
trainable_paddle_ocr_3632f_00000TERMINATED127.0.0.1:22388 360 0.6 0.6 0.5981391.595 0.2True 1 500.4 0.06845950.414935473.74
trainable_paddle_ocr_3632f_00001TERMINATED127.0.0.1:10796 300 0.6 0.5 0.4180691.618570.2True 1 465.4740.05630630.285714438.892
\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "2025-11-12 22:31:01,216\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00000_0_dpi=360,line_tolerance=0.6000,min_box_score=0.6000,text_det_box_thresh=0.5981,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:01,216\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00000_0_dpi=360,line_tolerance=0.6000,min_box_score=0.6000,text_det_box_thresh=0.5981,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:01,265\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00001_1_dpi=300,line_tolerance=0.6000,min_box_score=0.5000,text_det_box_thresh=0.4181,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:01,265\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00001_1_dpi=300,line_tolerance=0.6000,min_box_score=0.5000,text_det_box_thresh=0.4181,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:06,561\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00000_0_dpi=360,line_tolerance=0.6000,min_box_score=0.6000,text_det_box_thresh=0.5981,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:06,563\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00000_0_dpi=360,line_tolerance=0.6000,min_box_score=0.6000,text_det_box_thresh=0.5981,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:06,605\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00001_1_dpi=300,line_tolerance=0.6000,min_box_score=0.5000,text_det_box_thresh=0.4181,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:31:06,605\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00001_1_dpi=300,line_tolerance=0.6000,min_box_score=0.5000,text_det_box_thresh=0.4181,text_det_unclip_r_2025-11-12_22-31-01\n" ] }, { "data": { "text/html": [ "
\n", "

Trial Progress

\n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Trial name CER PAGES TIME TIME_PER_PAGE WER
trainable_paddle_ocr_3632f_000000.0684595 2473.74 236.7680.414935
trainable_paddle_ocr_3632f_000010.0563063 2438.892 219.3720.285714
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "2025-11-12 22:38:52,093\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00001_1_dpi=300,line_tolerance=0.6000,min_box_score=0.5000,text_det_box_thresh=0.4181,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:39:26,972\tWARNING trial.py:647 -- The path to the trial log directory is too long (max length: 260. Consider using `trial_dirname_creator` to shorten the path. Path: C:\\Users\\sji\\AppData\\Local\\Temp\\ray\\session_2025-11-12_22-29-00_496141_15712\\artifacts\\2025-11-12_22-31-01\\trainable_paddle_ocr_2025-11-12_22-31-01\\driver_artifacts\\trainable_paddle_ocr_3632f_00000_0_dpi=360,line_tolerance=0.6000,min_box_score=0.6000,text_det_box_thresh=0.5981,text_det_unclip_r_2025-11-12_22-31-01\n", "2025-11-12 22:39:26,988\tINFO tune.py:1009 -- Wrote the latest version of all result files and experiment state to 'C:/Users/sji/ray_results/trainable_paddle_ocr_2025-11-12_22-31-01' in 0.0087s.\n", "2025-11-12 22:39:26,994\tINFO tune.py:1041 -- Total run time: 505.83 seconds (505.77 seconds for the tuning loop).\n" ] } ], "source": [ "def trainable_paddle_ocr(config):\n", " args = [sys.executable, SCRIPT_ABS, \"--pdf-folder\", PDF_FOLDER_ABS, \"--pages-per-pdf\", \"2\"]\n", " for k, v in config.items():\n", " args += [f\"--{KEYMAP[k]}\", str(v)]\n", " proc = subprocess.run(args, capture_output=True, text=True, cwd=SCRIPT_DIR)\n", "\n", " if proc.returncode != 0:\n", " tune.report(CER=1.0, WER=1.0, TIME=0.0, ERROR=proc.stderr[:500])\n", " return\n", " # 煤ltima l铆nea = JSON con m茅tricas\n", " last = proc.stdout.strip().splitlines()[-1]\n", " \n", " metrics = json.loads(last)\n", " tune.report(metrics=metrics)\n", "\n", "scheduler = ASHAScheduler(grace_period=1, reduction_factor=2)\n", "\n", "tuner = tune.Tuner(\n", " trainable_paddle_ocr,\n", " tune_config=tune.TuneConfig(metric=\"CER\", \n", " mode=\"min\", \n", " scheduler=scheduler, \n", " num_samples=2, \n", " max_concurrent_trials=4),\n", " run_config=air.RunConfig(verbose=2, log_to_file=False),\n", " param_space=search_space\n", ")\n", "\n", "results = tuner.fit()\n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "710a67ce", "metadata": {}, "outputs": [], "source": [ "df = results.get_dataframe().sort_values(\"CER\", ascending=True)" ] }, { "cell_type": "code", "execution_count": 11, "id": "1ab345a3", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Guardado: raytune_paddle_subproc_results_20251112_223927.csv\n",
       "
\n" ], "text/plain": [ "Guardado: raytune_paddle_subproc_results_20251112_223927.csv\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Generate a unique filename with timestamp\n", "timestamp = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n", "filename = f\"raytune_paddle_subproc_results_{timestamp}.csv\"\n", "filepath = os.path.join(OUTPUT_FOLDER, filename)\n", "\n", "\n", "df.to_csv(filename, index=False)\n", "print(f\"Guardado: {filename}\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "3e3a34e4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CERWERTIMEPAGESTIME_PER_PAGEtimestamptraining_iterationtime_this_iter_stime_total_spidtime_since_restoreiterations_since_restoreconfig/dpiconfig/text_det_box_threshconfig/text_det_unclip_ratioconfig/text_rec_score_threshconfig/line_toleranceconfig/min_box_score
count2.0000002.0000002.0000002.02.0000002.000000e+002.02.0000002.0000002.0000002.0000002.02.0000002.0000002.0000002.02.02.000000
mean0.0623830.350325456.3158702.0228.0702881.762958e+091.0482.937319482.93731916592.000000482.9373191.0330.0000000.5081041.6067870.20.60.550000
std0.0085940.09137324.6417090.012.3005732.404163e+010.024.69645124.6964518196.78180824.6964510.042.4264070.1273290.0166660.00.00.070711
min0.0563060.285714438.8915502.0219.3724691.762958e+091.0465.474291465.47429110796.000000465.4742911.0300.0000000.4180691.5950030.20.60.500000
25%0.0593450.318019447.6037102.0223.7213781.762958e+091.0474.205805474.20580513694.000000474.2058051.0315.0000000.4630861.6008950.20.60.525000
50%0.0623830.350325456.3158702.0228.0702881.762958e+091.0482.937319482.93731916592.000000482.9373191.0330.0000000.5081041.6067870.20.60.550000
75%0.0654210.382630465.0280302.0232.4191971.762958e+091.0491.668833491.66883319490.000000491.6688331.0345.0000000.5531211.6126800.20.60.575000
max0.0684600.414935473.7401902.0236.7681071.762958e+091.0500.400347500.40034722388.000000500.4003471.0360.0000000.5981391.6185720.20.60.600000
\n", "
" ], "text/plain": [ " CER WER TIME PAGES TIME_PER_PAGE timestamp \\\n", "count 2.000000 2.000000 2.000000 2.0 2.000000 2.000000e+00 \n", "mean 0.062383 0.350325 456.315870 2.0 228.070288 1.762958e+09 \n", "std 0.008594 0.091373 24.641709 0.0 12.300573 2.404163e+01 \n", "min 0.056306 0.285714 438.891550 2.0 219.372469 1.762958e+09 \n", "25% 0.059345 0.318019 447.603710 2.0 223.721378 1.762958e+09 \n", "50% 0.062383 0.350325 456.315870 2.0 228.070288 1.762958e+09 \n", "75% 0.065421 0.382630 465.028030 2.0 232.419197 1.762958e+09 \n", "max 0.068460 0.414935 473.740190 2.0 236.768107 1.762958e+09 \n", "\n", " training_iteration time_this_iter_s time_total_s pid \\\n", "count 2.0 2.000000 2.000000 2.000000 \n", "mean 1.0 482.937319 482.937319 16592.000000 \n", "std 0.0 24.696451 24.696451 8196.781808 \n", "min 1.0 465.474291 465.474291 10796.000000 \n", "25% 1.0 474.205805 474.205805 13694.000000 \n", "50% 1.0 482.937319 482.937319 16592.000000 \n", "75% 1.0 491.668833 491.668833 19490.000000 \n", "max 1.0 500.400347 500.400347 22388.000000 \n", "\n", " time_since_restore iterations_since_restore config/dpi \\\n", "count 2.000000 2.0 2.000000 \n", "mean 482.937319 1.0 330.000000 \n", "std 24.696451 0.0 42.426407 \n", "min 465.474291 1.0 300.000000 \n", "25% 474.205805 1.0 315.000000 \n", "50% 482.937319 1.0 330.000000 \n", "75% 491.668833 1.0 345.000000 \n", "max 500.400347 1.0 360.000000 \n", "\n", " config/text_det_box_thresh config/text_det_unclip_ratio \\\n", "count 2.000000 2.000000 \n", "mean 0.508104 1.606787 \n", "std 0.127329 0.016666 \n", "min 0.418069 1.595003 \n", "25% 0.463086 1.600895 \n", "50% 0.508104 1.606787 \n", "75% 0.553121 1.612680 \n", "max 0.598139 1.618572 \n", "\n", " config/text_rec_score_thresh config/line_tolerance \\\n", "count 2.0 2.0 \n", "mean 0.2 0.6 \n", "std 0.0 0.0 \n", "min 0.2 0.6 \n", "25% 0.2 0.6 \n", "50% 0.2 0.6 \n", "75% 0.2 0.6 \n", "max 0.2 0.6 \n", "\n", " config/min_box_score \n", "count 2.000000 \n", "mean 0.550000 \n", "std 0.070711 \n", "min 0.500000 \n", "25% 0.525000 \n", "50% 0.550000 \n", "75% 0.575000 \n", "max 0.600000 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.describe()" ] }, { "cell_type": "code", "execution_count": 16, "id": "4ce5eb6a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Correlaci贸n con CER:\n",
       " config/min_box_score            1.0\n",
       "CER                             1.0\n",
       "config/text_det_box_thresh      1.0\n",
       "config/dpi                      1.0\n",
       "config/text_det_unclip_ratio   -1.0\n",
       "config/text_rec_score_thresh    NaN\n",
       "config/line_tolerance           NaN\n",
       "Name: CER, dtype: float64\n",
       "
\n" ], "text/plain": [ "Correlaci贸n con CER:\n", " config/min_box_score \u001b[1;36m1.0\u001b[0m\n", "CER \u001b[1;36m1.0\u001b[0m\n", "config/text_det_box_thresh \u001b[1;36m1.0\u001b[0m\n", "config/dpi \u001b[1;36m1.0\u001b[0m\n", "config/text_det_unclip_ratio \u001b[1;36m-1.0\u001b[0m\n", "config/text_rec_score_thresh NaN\n", "config/line_tolerance NaN\n", "Name: CER, dtype: float64\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Correlaci贸n con WER:\n",
       " config/min_box_score            1.0\n",
       "config/dpi                      1.0\n",
       "config/text_det_box_thresh      1.0\n",
       "WER                             1.0\n",
       "config/text_det_unclip_ratio   -1.0\n",
       "config/text_rec_score_thresh    NaN\n",
       "config/line_tolerance           NaN\n",
       "Name: WER, dtype: float64\n",
       "
\n" ], "text/plain": [ "Correlaci贸n con WER:\n", " config/min_box_score \u001b[1;36m1.0\u001b[0m\n", "config/dpi \u001b[1;36m1.0\u001b[0m\n", "config/text_det_box_thresh \u001b[1;36m1.0\u001b[0m\n", "WER \u001b[1;36m1.0\u001b[0m\n", "config/text_det_unclip_ratio \u001b[1;36m-1.0\u001b[0m\n", "config/text_rec_score_thresh NaN\n", "config/line_tolerance NaN\n", "Name: WER, dtype: float64\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "param_cols = [\n", " \"config/dpi\",\n", " \"config/text_det_box_thresh\",\n", " \"config/text_det_unclip_ratio\",\n", " \"config/text_rec_score_thresh\",\n", " \"config/line_tolerance\",\n", " \"config/min_box_score\",\n", "]\n", "# Correlaci贸n de Pearson con CER y WER\n", "corr_cer = df[param_cols + [\"CER\"]].corr()[\"CER\"].sort_values(ascending=False)\n", "corr_wer = df[param_cols + [\"WER\"]].corr()[\"WER\"].sort_values(ascending=False)\n", "\n", "print(\"Correlaci贸n con CER:\\n\", corr_cer)\n", "print(\"Correlaci贸n con WER:\\n\", corr_wer)" ] }, { "cell_type": "code", "execution_count": 13, "id": "02fc0a87", "metadata": {}, "outputs": [ { "data": { "image/png": "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fXc81KWC/n7yySfTvd2pPR+jbf+KFSvc+aPp1OWBmngrTWpvs7NmzXLN/LWtF198sXfjjTd63377bZJ11nYmlpblyGuvveaahGs5uXPn9kqXLu317t3bW758eSiNf66tW7cuYlr/uOl/3/vvv+81b97cna9lypRx180777yTJF3QsUjLPGTVqlWumwj/uNerV8974oknIq6xwYMHu2tL94DE+yY113pa7jkpdQ8Qfs0G7deU9k9qzk2/ewDdX1Irue184YUXIp4v6vJC3UWoSwKth+6pH3/8cZJnUEbs/6wkh/6JdbAGAACQFVFHCQAAIACBEgAAQAACJQAAgAAESgAAAAEIlAAAAAIQKAEAAASgw8l0UieBemO5OvpKz1vfAQBA5lOvSOqwVp35Jn7RcDQESumkIEnvCwMAAPHnm2++cb37p4RAKZ38LuO1o9WVOwAAyPqOHDniMjpS++oXAqV08ovbFCQRKAEAEF9SW22GytwAAAABCJQAAAACECgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAAeiZGwAAZBlnznq2dtdB23f0pJUolGBNK11suXLG7uXzBEoAACBLWLTlB7t/3mf2w+GToWGliyTYuGtrWcc6pWOyThS9AQCALBEk3f7KxoggSfYcPumGa3wsECgBAICYF7fdP+8z86KM84dpvNJlNgIlAAAQU2t3HUySkxRO4ZHGK11mI1ACAAAxte/oyQxNl5EIlAAAQEyVKJSQoekyEoESAACIqaaVLnat24I6AdBwjVe6zEagBAAAYipXzhyuCwBJHCz53zU+Fv0pESgBAICY61intD31h8usVJHI4jV91/BY9aNEh5MAACBL6FintF1dqxQ9cwMAAESj4rUWlxa1rIKiNwAAgKwaKE2dOtUqVqxoCQkJ1qxZM1u7dm2y6WfPnm01atRw6evWrWsLFy5Mkmbr1q3WtWtXK1KkiBUoUMCaNGliu3fvDo3fs2eP3XTTTVaqVCk3/rLLLrM5c+ack+0DAADxK6aB0qxZs2z48OE2btw427hxo9WvX986dOhg+/bti5p+9erV1rdvXxs4cKBt2rTJunfv7j5btmwJpdm5c6e1atXKBVPLly+3zZs327333usCK1+/fv1s+/bt9tZbb9knn3xiPXv2tBtuuMHNEwAAwJfD87zMf3HK/6ccJOX2TJkyxX0/e/aslStXzgYPHmwjR45Mkr537952/Phxmz9/fmhY8+bNrUGDBjZt2jT3vU+fPpYnTx57+eWXA5dbsGBBe+qpp1yukq9o0aL20EMP2R//+MdUrfuRI0dcjtXhw4etcOHCadpuAAAQG2l9fscsR+n06dO2YcMGa9eu3X9XJmdO933NmjVRp9Hw8PSiHCg/vQKtBQsWWLVq1dzwEiVKuGBs7ty5EdO0bNnS5WYdPHjQTTNz5kw7efKkXXHFFedkWwEAQHyKWaB04MABO3PmjJUsWTJiuL6rDlE0Gp5cehXZHTt2zCZOnGgdO3a0xYsXW48ePVzR2ooVK0LT/Pvf/7ZffvnF5SLly5fPbr31VnvjjTesSpUqget76tQpF4WGfwAAQPaWrfpRUu6QdOvWzYYNG+b+VrGc6japaK5NmzZumOosHTp0yN59910rVqyYy3FSHaWVK1e6CuLRTJgwwe6///5M3BoAAHDe5igpQMmVK5ft3bs3Yri+qzVaNBqeXHrNM3fu3Far1v91g+6rWbNmqNWbKnurTtTzzz9vV111latArsrkjRs3di3wgowaNcqVZ/qfb775Jt3bDgAA4kPMAqW8efNao0aNbOnSpRE5QvreokWLqNNoeHh6WbJkSSi95qnK4WrRFm7Hjh1WoUIF9/eJEydC9aHCKWjzc6SiURGdKn2FfwAAQPYW06I3dQ3Qv39/l5vTtGlTmzx5smvVNmDAgFAz/rJly7piLxk6dKgrPps0aZJ17tzZVcJev369TZ8+PTTPESNGuNZxrVu3trZt29qiRYts3rx5rqsAUbcBqoukekmPPvqoq6ekojcFXOGt6QAAAMyLsSeeeMIrX768lzdvXq9p06beBx98EBrXpk0br3///hHp//3vf3vVqlVz6WvXru0tWLAgyTyfe+45r0qVKl5CQoJXv359b+7cuRHjd+zY4fXs2dMrUaKEd8EFF3j16tXzXnrppTSt9+HDh9WtgvsfAADEh7Q+v2Paj1I8ox8lAADiT9z0owQAAJDVESgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAAQiUAAAAAhAoAQAABCBQAgAACECgBAAAEIBACQAAIACBEgAAQAACJQAAgAAESgAAAAEIlAAAAAIQKAEAAAQgUAIAAAhAoAQAABCAQAkAACAAgRIAAEAAAiUAAIAABEoAAAABCJQAAAACECgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAAQiUAAAAAhAoAQAABCBQAgAACECgBAAAEIBACQAAIACBEgAAQAACJQAAgAAESgAAAAEIlAAAAAIQKAEAAAQgUAIAAAhAoAQAABCAQAkAACCrBkpTp061ihUrWkJCgjVr1szWrl2bbPrZs2dbjRo1XPq6devawoULk6TZunWrde3a1YoUKWIFChSwJk2a2O7duyPSrFmzxq688ko3vnDhwta6dWv7+eefM3z7AABA/IppoDRr1iwbPny4jRs3zjZu3Gj169e3Dh062L59+6KmX716tfXt29cGDhxomzZtsu7du7vPli1bQml27txprVq1csHU8uXLbfPmzXbvvfe6wCo8SOrYsaO1b9/eBWbr1q2zO++803LmjHncCAAAspAcnud5sVq4cpCU2zNlyhT3/ezZs1auXDkbPHiwjRw5Mkn63r172/Hjx23+/PmhYc2bN7cGDRrYtGnT3Pc+ffpYnjx57OWXXw5crqa5+uqrbfz48ele9yNHjrgcq8OHD7scKQAAkPWl9fkdsyyU06dP24YNG6xdu3b/XZmcOd135fhEo+Hh6UU5UH56BVoLFiywatWqueElSpRwwdjcuXND6ZVb9eGHH7pxLVu2tJIlS1qbNm1s1apVya7vqVOn3M4N/wAAgOwtZoHSgQMH7MyZMy5QCafve/bsiTqNhieXXkHQsWPHbOLEia5obfHixdajRw/r2bOnrVixwqX58ssv3f/33Xef3XLLLbZo0SK77LLL7KqrrrLPP/88cH0nTJjgIlD/o5wvAACQvWWrSjnKUZJu3brZsGHDXJGcivC6dOkSKprz09x66602YMAAa9iwoT3++ONWvXp1e/755wPnPWrUKJdN53+++eabTNoqAAAQK7ljteBixYpZrly5bO/evRHD9b1UqVJRp9Hw5NJrnrlz57ZatWpFpKlZs2aoaK106dLu/2hpEreMC5cvXz73AQAA54+Y5SjlzZvXGjVqZEuXLg0NU26Pvrdo0SLqNBoenl6WLFkSSq95qnL49u3bI9Ls2LHDKlSo4P5WVwRlypRJNg0AAEBMc5REXQP079/fGjdubE2bNrXJkye7Vm0qEpN+/fpZ2bJl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UaNc8Zz/+eabb1K9nQAA4DwIlFTEpVZnderUcYGDirT0GT16tBu2atWqJMViycmbN681atTIli5dGpEjpO8tWrSIOo2Gh6eXJUuWhNJrnqocvn379og0O3bscJXRw3OSVPFc6d96661Qi7gg+fLlc3WYwj8AACB7S3PNZQUb6rfop59+si+++MLUaK5q1ap20UUXpWsF1DVA//79rXHjxta0aVPXBYFang0YMMCN79evn6sbpaIvGTp0qLVp08YmTZrkisxmzpxp69evt+nTp4fmOWLECNc6rnXr1ta2bVvXUm/evHmuq4DwIOnEiRP2yiuvRNQ5Kl68uMvlAgAAUKATc0888YRXvnx5L2/evF7Tpk29Dz74IDSuTZs2Xv/+/SPS//vf//aqVavm0teuXdtbsGBBknk+99xzXpUqVbyEhASvfv363ty5c0Pj3nvvPXWJEPWza9euVK3z4cOHXXr9DwAA4kNan99p6kcJ/0U/SgAAxJ9z2o8SAADA+YRACQAAIACBEgAAQAACJQAAgAAESgAAAAEIlAAAAAIQKAEAAAQgUAIAAAhAoAQAABCAQAkAACAAgRIAAEAAAiUAAIAABEoAAAABCJQAAAACECgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAAQiUAAAAAhAoAQAABCBQAgAACECgBAAAEIBACQAAIACBEgAAQAACJQAAgAAESgAAAAEIlAAAAAIQKAEAAAQgUAIAAAhAoAQAABCAQAkAACAAgRIAAEAAAiUAAIAABEoAAAABCJQAAAACECgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAWTlQmjp1qlWsWNESEhKsWbNmtnbt2mTTz54922rUqOHS161b1xYuXJgkzdatW61r165WpEgRK1CggDVp0sR2794dGn/y5EkbNGiQFS1a1AoWLGi9evWyvXv3npPtAwAA8SnmgdKsWbNs+PDhNm7cONu4caPVr1/fOnToYPv27YuafvXq1da3b18bOHCgbdq0ybp37+4+W7ZsCaXZuXOntWrVygVTy5cvt82bN9u9997rAivfsGHDbN68eS7oWrFihX3//ffWs2fPTNlmAAAQH3J4nufFcgWUg6TcnilTprjvZ8+etXLlytngwYNt5MiRSdL37t3bjh8/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sKGVLl3aOnXqlGyO0qlTp9zODf8AAIDsLaaB0oEDB+zMmTNWsmTJiOH6vmfPnqjTaHhK6VXs9tJLL9nSpUvtoYceshUrVrhASMuSL7/80v1/33332ZgxY1zulOooXXHFFXbwYPSOHVXUpwjU/yjXCwAAZG9ZojJ3RuvTp4917drVVfRW/SUFQuvWrXO5TH7xntxzzz3Wq1cva9SokavPpErfqigezahRo1w2nf/55ptvMnWbAADAeRYoFStWzHLlymV79+6NGK7vpUqVijqNhqclvVSuXNkt64svvnDfVdQmtWr9X7N8v7K30u3evTvqPDReZZnhHwAAkL3FNFDKmzevy81REZlPuT363qJFi6jTaHh4elmyZElgevn2229dHSU/QNIyFfioZZ3vl19+sa+++soqVKiQAVsGAACyg5h3D6CuAfr372+NGze2pk2buu4B1KptwIABbny/fv2sbNmyro6QDB061Nq0aWOTJk2yzp0728yZM239+vU2ffp0N/7YsWOuNZuK1JTLtHPnTrvrrrusSpUqrtK3KDfotttus3Hjxrm6RgqOHnnkETfu+uuvj9m+AAAAWUvMAyU199+/f7+NHTvWVchWM/9FixaFKmyrKEyt03wtW7Z0fSepEvbo0aOtatWqrhsAvw8lFeVt3rzZXnzxRddFQJkyZax9+/Y2fvz4iL6UFBjlzp3bbrrpJvv5559dNwXLli1zlboBAACyRD9K8Yp+lAAAiD9x1Y8SAABAVhbzord45WfE0fEkAADxw39up7ZAjUApnY4ePer+p+NJAADi8zmuIriUUEcpndSNwffff2+FChVyHVVmxYhZQZw6xjyf+nw6X7db2Pbz77hzzDnm55MjGXR/V06SgiQ19gpvLBaEHKV00s695JJLLKs7XzvHPF+3W9j28++4c8w55ueTwhlwf09NTpKPytwAAAABCJQAAAACEChlU+pcUz2Ph3eyeT44X7db2Pbz77hzzDnm55N8Mbq/U5kbAAAgADlKAAAAAQiUAAAAAhAoAQAABCBQAgAACECglEVNnTrVKlasaAkJCdasWTNbu3ZtqqabOXOm6ym8e/fuoWG//PKL3X333Va3bl0rUKCA6420X79+rmfxcFqepg3/TJw40eJ52+Xmm29Osl0dO3aMSHPw4EG78cYbXSdmF154oQ0cONCOHTtm8bzdibfZ/zzyyCNxfcxfeOGFJOus6RL3vDt27FgrXbq05c+f39q1a2eff/55XB/zlLY7O1/nqTnm8XKdn4ttj5drfWoa73GHDh2yQYMGuetYLd2qVatmCxcuTNM8T5486eZRtGhRK1iwoPXq1cv27t2bthX3kOXMnDnTy5s3r/f88897n376qXfLLbd4F154obd3795kp9u1a5dXtmxZ73e/+53XrVu30PBDhw557dq182bNmuVt27bNW7Nmjde0aVOvUaNGEdNXqFDBe+CBB7wffvgh9Dl27JgXz9su/fv39zp27BixXQcPHoxIo/H169f3PvjgA2/lypVelSpVvL59+3rxvN3h26uP5p0jRw5v586dcX3MZ8yY4RUuXDhinffs2RORZuLEiV6RIkW8uXPneh9//LHXtWtXr1KlSt7PP/8ct8c8pe3Oztd5ao55PFzn52rb4+Fan5nG7T516pTXuHFj75prrvFWrVrl7nXLly/3PvroozTN87bbbvPKlSvnLV261Fu/fr3XvHlzr2XLlmladwKlLEg3t0GDBoW+nzlzxitTpow3YcKEwGl+/fVXd/CfffZZd8NI/NBMbO3atXptsvf1119HXEiPP/64l922PaX98dlnn7l9sW7dutCwt99+291ovvvuOy+7HHONv/LKKyOGxeMx14NDQVCQs2fPeqVKlfIeeeSRiCAiX7583r/+9a+4PeYpbXd2vs5Ts+3xcJ1n1nHPitd60zRu91NPPeVVrlzZO336dLrnqes+T5483uzZs0Nptm7d6s4D/ZBILYrespjTp0/bhg0bXFFB+Hvl9H3NmjWB0z3wwANWokQJl5WcGocPH3ZZr8p+DqesWGVRNmzY0GXb/vrrr5Ydtn358uUuTfXq1e3222+3H3/8MTRO89Z+aNy4cWiYlqllf/jhh5YdjrmymhcsWBA1bTwecxWXVKhQwb0gs1u3bvbpp5+Gxu3atcv27NkTMU+910nZ8v484/WYJ7fd2f06T822Z+XrPLOOe1a81k+nY7vfeusta9GihSs2K1mypNWpU8cefPBBO3PmTKrnqfEqkg5PU6NGDStfvnyy+zsxXoqbxRw4cMCdCDoxwun7tm3bok6zatUqe+655+yjjz5K1TJUZqu6DH379o14seCQIUPssssus4svvthWr15to0aNsh9++MEee+wxi+dtVz2Fnj17WqVK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lSSQnZGjBGRzy5Yts08++cR69erlvquS9549eyx37twuWAj/qPK1qBJ14hyD1Eyn3ImlS5cGrku0+SZWs2ZNe//99yOG6bsqBmc0BTvy888/h5atysz/Vxr232UrELrkkkvcd+XKPPTQQ67SunJwVCE8FrQ/FBDt3r07yfFQro5PFbn79+9vr7zyiuuaYfr06aleRtCxqFatWmjfJU6vloQKIH0ffPBBurcRyArIUQKykVOnTrlgRsHI3r17bdGiRa5VlLoH6Nevn0vTrl07VxzSvXt3e/jhh91DT83llTOhVlcq3lHrJhWpqZhKAYIChdRMN27cOJdroSKpPn36uNZiys24++673bI1X+XGaJwe8n6AFW7EiBF2ww03WMOGDd0yFZCoGb2a1f9WKqrS/hHtn/Hjx7vWWSp+81uwKZgYPHiwC4C2b9/utmn48OGWM2dOV0R300032ZAhQ1xujfaNWvhde+21dt1111lm0jH561//6loRKgeoVatWdvjwYRfIqNhOwdHYsWNdKzm1WtO5MX/+fBfMpNZf/vIXt33aT+rvSkHklClT7Mknn4yaXsdL54WW/cgjj9iRI0fsnnvuycCtBmIg1pWkAGRcZW5d0vqoQm3x4sVdK7Xnn38+VBHZd+TIEW/w4MFemTJlXAXncuXKuUrYu3fvDlUU7tWrl3fhhRe6+fmtnFKaTubMmeNaWuXNm9e1GOvZs2do3Jo1a1zLLbXM8m8/iStzy5NPPulVrlzZLUMVrl966aWI8dEqB2se4a2xolXm9vePPhdddJEbFt6aTtRiTK3atP6lSpXy7r777lArMFWMrlu3bkSFdrXKu/jii12Lud9SmTu57fErc//0008RaVTpfPLkya4CuvaVjnmHDh1cazMZP368q8SvlmpaR1X2//LLLwPXR/PXMC3P99prr7nK25p/+fLlvUceeSTZCvpqHdeqVSu3/3Ts1CKPytyIZzn0TywCNAAAgKyOOkoAAAABCJQAAAACECgBAAAEIFACAAAIQKAEAAAQgEAJAAAgAIESAABAAAIlAACAAARKAAAAAQiUAAAAAhAoAQAABCBQAgAAsOj+H/J0DCCfyHwoAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAHHCAYAAABXx+fLAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAQJZJREFUeJzt3Ql4VOXd/vFfCEvYEZBVdlREFGQVF0ALokUELRX9W4m4oEWwFjcQAREsdSlFWRWLVGlf6IugFBGsgBQURKEIIgSKKIsCocoqm3D+1/2810xnQhImIckkeb6f6xplzpw5c84zJzP3PNtJCIIgMAAAAI8UifcOAAAA5DUCEAAA8A4BCAAAeIcABAAAvEMAAgAA3iEAAQAA7xCAAACAdwhAAADAOwQgAADgHQIQctWhQ4fs3nvvtWrVqllCQoI9/PDDbvnu3butR48eVqlSJbd8zJgxBf6Ysuuuu+6yunXrWkH19NNPu3IAOBdQkBCAkGVTp051X3gZ3VasWBFe93e/+51b/9e//rW9+eabduedd7rlv/3tb23BggU2aNAgt/z666/P8XdCr/3222/nynbTO6b0KNjceOONlt8odGX2HoZuWg/5S9++fa1IkSL2/fffRy3XfS0vUaKEHT16NOqxr776yr2fTz75pOX38y8pKcnyK/09R+5r6dKlrXXr1vbGG29ke5vz5s1zwRF5r2gcXhOFxDPPPGP16tU7bXnDhg3D/160aJFdfvnlNmzYsKh1tLxbt2726KOP5tr+Kaiolql79+45ut2Mjim7Jk+ebKdOnbK8dP/991vHjh3D97du3WpDhw61Pn362NVXXx1e3qBBgzzdL5zZVVddZRMnTrSPPvrIunbtGl7+8ccfuwB04sQJ++yzz9x6IVo39Nz8QkHttddeO215YmKi5WfNmjWzRx55xP37u+++c8eQnJxsx44ds/vuuy9bAWj8+PGEoDggACHbbrjhBmvZsmWm6+zZs8caN26c7vIKFSoUyNLP6Jiyq1ixYpbX2rZt624h+sJUANKyX/3qVxZPP/74o5UqVSqu+5CfhULMsmXLogKQQs6ll15qR44ccY9Fhh3dVzi64oorzuq1f/rpJxfWixcvbmeraNGi2TrXDh8+7GpecuPcieX4atasGbXfqs2qX7++/fGPf8xWAEL80ASGXPHhhx+6KmLVLLz77rvhKuNQ81kQBO5XT2h5yL59+1yfmlq1arlfiKpNeu65506rIdH9l156yS655BJXZX7uuee6ZjR9kYu2qQ/KP//5zzE35yjY3HPPPVa1alW3zaZNm7rnn+mYvv766xztA6Ttabsvvviivfrqq64WRmXRqlUr+/TTT097/saNG11NV8WKFd1+K5TOmTPHcsL//u//WosWLaxkyZJWuXJl98G/c+fOmJ47bdq08HO1b7fddptt3749ap0OHTpYkyZNbNWqVdauXTv35RVqpnnnnXesS5cuVqNGDXf8KocRI0bYyZMn093Gl19+addcc43bhr6knn/++dP2SU1Dam644IILXFlVr17dbrnlFtuyZUvUuaU+aRdffLFbR+eDasx++OGHmGsIVYumL2mFfNV0btiwId2+Mv/+97/d+6/1ypcvb71793Zf4pmpXbu2+/sI1eqE6P6VV17pQk56j+l4Qj86znSupz0PVR6h81DlHApVOif1fD32yiuvWE4LfV4sWbLENf1VqVLFzjvvvDOeOzlxfLHSZ0+jRo2iziFZunSp/fKXv3Tvl7ar90xN/wqoIXrv9TkokU1rOXUuInPUACHb9u/fb3v37o1apj9edWy+6KKLXP8Y/cHrAytUZXzZZZeF+8106tTJevXqFX6uPvjbt2/vvmD1R64PDlXrq5+QqpojO0rrw00fjqqFUodk/XLTB476HykA6DW0XO3zatY5U3OOPpT0gaovpH79+rmmPX356wNKoew3v/lNhsekD8Dc8Ne//tUOHjzoykLlqi90fVmrP0eo1mj9+vXuS09f+AMHDnRfun/7299cs99bb71lN998c7ZfX+WrL2R9yY0aNcp1XFfo1Jfpv/71r0xr8J599lkbMmSI3Xrrre59SE1NtbFjx7ovqrTP/c9//uPeRwUkBSx9yIdev0yZMjZgwAD3fwUL1VIdOHDAXnjhhajX0xeCArDKR685c+ZMe+KJJ1xA1rZFwUn9sRYuXOheS++pyvcf//iHffHFF+HzQ+UdOvaHHnrIBd5x48a5/daxZ1Zj98EHH7jXU42AQo7OKx233qPVq1ef1tld+6pzTeWrx9Wcoi95hf7MqHZn1qxZrtlFX67Hjx934Vj90vR39Pjjj7sfGTpvVDb6Un/ggQdiPtcjvf766y446u9Ir6Uwu27dOrvuuuvcua/j1N+fmoRD712s0n5+iGpfypUrF7VM4UevpfdfP2wyO3dy4viyQse+Y8cOO+ecc6KW6zX1Xug90WfiypUr3bmgdfVY6Fz79ttv3Tmoz5a0zuZcRAwCIItef/31QKdOercSJUpErVunTp2gS5cup21D6z744INRy0aMGBGULl062LRpU9TygQMHBomJicG2bdvc/UWLFrnnP/TQQ6dt99SpU+F/a1vJyckxHdOYMWPcNqdNmxZedvz48aBt27ZBmTJlggMHDpzxmNITy7raR60XsnXrVrcvlSpVCr7//vvw8nfeecct//vf/x5e9rOf/Sy45JJLgqNHj0aVwRVXXBGcf/75Qaw+/fRTt229t6Fjr1KlStCkSZPgyJEj4fXmzp3r1hs6dGh42bBhw9yykK+//tq9X88++2zUa6xbty4oWrRo1PL27du7506aNOm0ffrxxx9PW3b//fcHpUqVijre0DbeeOON8LJjx44F1apVC37xi1+El02ZMsWtN3r06AzPm6VLl7p1/vKXv0Q9Pn/+/HSXp9WsWTNXbv/5z3/Cyz7//POgSJEiQa9evU4rs7vvvjvq+TfffLN7389k/Pjx7vnaX1m+fLm7/8033wRffvml+/f69euj3rPQvsd6rofOw3LlygV79uyJev3u3bsHSUlJ7vVC9Lp632P5WtE5n9FnSOfOnU/7rLnqqquCn376KWobGZ07OXF8GdHf6XXXXRekpqa6m87pO++8M93Ps/TO31GjRgUJCQlR5abnpVdmZ3su4sxoAkO2qepWv1wib++99162t6dfRWo60C8p/TIM3dRZV7/e//nPf7r1VLOhX7bpdULO7nBsdUTUsPbbb789vEy/rvSrS8PeVQWf13r27Bn1qzLUOVk1QKFRP6oVUS2CajJC5aVfxZ07d7bNmzfH3FyVlpoS1YygX96Ro3LUJKXqfjUBZkQ1E6q6135Fvo8q3/PPP98WL14ctb5+desXblpqOgsJHZ/KQL+q1ewXSTVEkf0yVIug2r9QWYXOGzXj9e/fP8PzRuegmqJUOxm572rK02uk3fdIqqVcs2aNq2mIrEVQvxxtT+dYWqFamRAdn94/1XLF2g9IVBugWkDVmur90euHmsHSdoDO6rn+i1/8IqqWU3+LGsGpWka9XohqSHXexUrnVdrPD91+//vfn7au+tak1zk6vXPnbI/vTN5//323vm6qYVTN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16+3go4+QAAAFO7v72wFoBDVAumSGO+995698sordujQIWaCBgAAhacTdCjwrFixwnWIVs3PJ598YrVq1bJ27drZuHHjrH379me77wAAALku5gCkvj4KPOoIraBz//3321//+lerXr167u4hAABAvALQ0qVLXdhREOrQoYMLQZUqVcrp/QEAAMg/w+D37dtnr776qpUqVcqee+45d+X3Sy65xPr162czZ8601NTU3N1TAACAHJLtTtC69MWyZcvC/YE+//xzO//88+2LL76wgo5RYAAAFO7v72xfDLV06dJWsWJFdzvnnHOsaNGitmHDhuxuDgAAIP/1ATp16pR99tlnrrZHtT4a/n748GGrWbOmmwRx/Pjx7v8AAACFJgBVqFDBBZ5q1aq5oPPHP/7RdYbWJTIAAAAKZQB64YUXXPC54IILcnePAAAA8ksA0rw/AAAAhUG2O0EDAAAUVAQgAADgHQIQAADwDgEIAAB4J18EIM0hVLduXUtKSrI2bdrYypUrM1x31qxZ1rJlSzcsX5MxNmvWzN58880M13/ggQcsISHBxowZk0t7DwAACpq4B6AZM2bYgAEDbNiwYbZ69Wpr2rSpde7c2fbs2ZPu+pp5evDgwbZ8+XJbu3at9e7d290WLFhw2rqzZ8+2FStWuOuWAQAA5JsANHr0aLvvvvtciGncuLFNmjTJXXB1ypQp6a6vyRdvvvlmu+iii9wkjL/5zW/s0ksvddcli7Rz507r37+//eUvf7FixYrl0dEAAICCIK4B6Pjx47Zq1Srr2LHjf3eoSBF3XzU8Z6LruC5cuNBSUlKsXbt2UZftuPPOO+2xxx6ziy++ONf2HwAAFPKJEHPD3r177eTJk1a1atWo5bq/cePGDJ+nq7zqGmTHjh2zxMREmzBhgnXq1Cn8+HPPPecuzvrQQw/FtB/ajm6RV5MFAACFV1wDUHaVLVvW1qxZY4cOHXI1QOpDVL9+fdc8phqll156yfUnUufnWIwaNcqGDx+e6/sNAADyh7g2gVWuXNnV4OzevTtque7roqsZUTNZw4YN3QiwRx55xHr06OFCjCxdutR1oK5du7arBdLtm2++cetppFl6Bg0a5GqVQrft27fn8JECAID8JK4BqHjx4taiRQtXixPZf0f327ZtG/N29JxQE5b6/mh0mGqIQjeNAlN/oPRGikmJEiWsXLly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C1kZ3fQ4AJwJV4MHkKNy+4rps2bNcleMlu3bt1vr1q3tgw8+sIsvvtgty+2LdBbmq6ADPqEGCECuNYF9/fXX7r5CyzXXXGOlSpWypk2b2vLly6Oes2zZMrv66qutZMmSVqtWLXvooYfs8OHD6W6/YsWKLmTppivbS6VKlcLLFi9e7MJQiRIlXHPXH/7wh0z3d9++fXbvvfe6bZUrV86uvfZa+/zzz8OPP/3009asWTN77bXX3NW7k5KS3PL58+fbVVddZRUqVHCvf+ONN9qWLVvCz4v12D/66CNXa6XHzznnHOvcubP98MMP4atfjxo1yr2uykbPnzlzZhbfEQDpIQAByHWDBw+2Rx991NasWWMXXHCB3X777fbTTz+5xxQarr/+evvFL35ha9eutRkzZrhA1K9fvyy/zqpVq+zWW2+12267zdatW+fCy5AhQ2zq1KkZPueXv/yl7dmzx9577z33/ObNm9vPfvYz+/7778Pr/Pvf/7a33nrLhRkdgyigDRgwwD777DNbuHChFSlSxG6++WYXWmI9di3TazVu3NgFIx13165d7eTJk+5xhZ833njDJk2aZOvXr7ff/va39qtf/cqWLFmS5bIBkEaOXloVQKGnqzp369Ytw8f1sTJ79mz3761bt7r7r732Wvjx9evXu2UbNmxw9++5556gT58+UdtYunRpUKRIkeDIkSOZ7kto+//617/c/f/3//5f0KlTp6h1HnvssaBx48bh+7rC9B//+Mfw65QrVy44evRo1HMaNGgQvPLKK+7fw4YNC4oVKxbs2bMn031JTU11+7Ju3bqYj/32228PrrzyynS3p30qVaqUu2p2JJWXngfg7FADBCDXXXrppeF/V69e3f1ftS6i5ibV0JQpUyZ8UzOQalK2bt2apdfZsGGDXXnllVHLdH/z5s3hWpVIeu1Dhw65JqzI19frRjZn1alTJ9zcFqJtqjanfv36rulMzW2ybdu2mI89VAOUHtU6/fjjj9apU6eofVONUOS+AcgeOkEDyHXFihUL/1v9YiTUVKQAcv/997t+P2nVrl07V/dLr61Q8uGHH572mPr2hJQuXfq0x9VUpWA0efJkq1GjhjueJk2ahDtox3Ls6teT2b7Ju+++azVr1ox6TP2bAJwdAhCAuFKfmy+//NIaNmx41tu66KKLXKfiSLqvvjeJiYnpvvauXbusaNGi4RqcWPznP/+xlJQUF37UeVvUfyerVDuk/kPDhw8/7TH1C1LQUY1S+/bts7xtAJkjAAHIsv3794c7A4eoGUkjuLLqiSeesMsvv9x1etZoLNW2KBD94x//sHHjxmVpW4888oi1atXKRowYYT179nQdi7WNCRMmpLt+x44drW3btm5eo+eff94FpW+//dbVuqhDc8uWLdN9nkZr6XhfffVVV4OkkDJw4MAsH/ugQYPskksusb59+9oDDzzghtdrFJs6ZleuXNl1nlbHZ9UYacSZyl2BTk1uycnJWX49AP9FAAKQZWoyuuyyy6KW3XPPPW6oeHZqQTSqSaOlVJuiftQNGjRwASarVKPzt7/9zYYOHepCkMLJM8884yZvTI+apObNm+deu3fv3paamuqG0rdr186qVq2a4etoxNf06dNds52avS688EJ7+eWXszwJowLX+++/b08++aSbz0hNYm3atHF9i0THoL5HGg321VdfuWY5HaPWB3B2EtQT+iy3AQAAUKAwCgwAAHiHAAQAALxDAAIAAN4hAAEAAO8QgAAAgHcIQAAAwDsEIAAA4B0CEAAA8A4BCAAAeIcABAAAvEMAAgAA3iEAAQAA7/x/AMWQdXKJnMMAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "\n", "plt.scatter(df[\"config/text_det_box_thresh\"], df[\"CER\"])\n", "plt.xlabel(\"Detection Box Threshold\")\n", "plt.ylabel(\"CER\")\n", "plt.title(\"Effect of Detection Threshold on Character Error Rate\")\n", "plt.show()\n", "\n", "plt.scatter(df[\"config/line_tolerance\"], df[\"WER\"])\n", "plt.xlabel(\"Line Tolerance\")\n", "plt.ylabel(\"WER\")\n", "plt.title(\"Effect of Line Tolerance on Word Error Rate\")\n", "plt.show()\n" ] } ], "metadata": { "kernelspec": { "display_name": ".venv (3.11.9)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }