Files

714 lines
63 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "6b64ed95-f2d5-440e-b90b-bfd083d63716",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"id": "9b488857",
"metadata": {},
"source": [
"# Guardar multilingual-e5-small en local y benchmark de carga\n",
"\n",
"Guardamos el modelo en `.local/models/` (gitignored) y comparamos:\n",
"- Carga desde HuggingFace cache vs carga desde path local\n",
"- Tiempo de primer encoding tras carga\n",
"- Verificación de que los embeddings son idénticos"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "22b75c11",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"FN_REGISTRY_ROOT: /home/lucas/fn_registry\n",
"Destino local: /home/lucas/fn_registry/.local/models/multilingual-e5-small\n",
"RAM actual: 833 MB\n"
]
}
],
"source": [
"import os, time, gc\n",
"import numpy as np\n",
"from sentence_transformers import SentenceTransformer\n",
"import psutil\n",
"\n",
"FN_ROOT = os.environ.get('FN_REGISTRY_ROOT', '/home/lucas/fn_registry')\n",
"MODEL_ID = 'intfloat/multilingual-e5-small'\n",
"LOCAL_PATH = os.path.join(FN_ROOT, '.local', 'models', 'multilingual-e5-small')\n",
"\n",
"def ram_mb():\n",
" return psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024)\n",
"\n",
"print(f'FN_REGISTRY_ROOT: {FN_ROOT}')\n",
"print(f'Destino local: {LOCAL_PATH}')\n",
"print(f'RAM actual: {ram_mb():.0f} MB')"
]
},
{
"cell_type": "markdown",
"id": "00e8cb16",
"metadata": {},
"source": [
"## 1. Guardar modelo en .local/models/"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "90df0aac",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cargando modelo desde HuggingFace cache...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c21758811d8c41f28cec7ecf11df90ed",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" Cargado en 6.43s\n",
"Guardando en /home/lucas/fn_registry/.local/models/multilingual-e5-small...\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cb775051d2b64cfcad0f9f0a4302a2c4",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Writing model shards: 0%| | 0/1 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" Guardado en 2.33s\n",
" Tamaño en disco: 465.6 MB\n",
" multilingual-e5-small/\n",
" README.md (0.5 MB)\n",
" config.json (0.0 MB)\n",
" config_sentence_transformers.json (0.0 MB)\n",
" model.safetensors (448.8 MB)\n",
" modules.json (0.0 MB)\n",
" sentence_bert_config.json (0.0 MB)\n",
" tokenizer.json (16.3 MB)\n",
" tokenizer_config.json (0.0 MB)\n",
" 1_Pooling/\n",
" config.json (0.0 MB)\n",
" 2_Normalize/\n"
]
},
{
"data": {
"text/plain": [
"4063"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Cargar desde HF cache y guardar localmente\n",
"print('Cargando modelo desde HuggingFace cache...')\n",
"t0 = time.perf_counter()\n",
"model = SentenceTransformer(MODEL_ID)\n",
"hf_load_time = time.perf_counter() - t0\n",
"print(f' Cargado en {hf_load_time:.2f}s')\n",
"\n",
"# Guardar en .local/models/\n",
"print(f'Guardando en {LOCAL_PATH}...')\n",
"t0 = time.perf_counter()\n",
"model.save(LOCAL_PATH)\n",
"save_time = time.perf_counter() - t0\n",
"print(f' Guardado en {save_time:.2f}s')\n",
"\n",
"# Verificar tamaño en disco\n",
"total_size = 0\n",
"for dirpath, dirnames, filenames in os.walk(LOCAL_PATH):\n",
" for f in filenames:\n",
" fp = os.path.join(dirpath, f)\n",
" total_size += os.path.getsize(fp)\n",
"print(f' Tamaño en disco: {total_size / (1024*1024):.1f} MB')\n",
"\n",
"# Listar archivos guardados\n",
"for dirpath, dirnames, filenames in os.walk(LOCAL_PATH):\n",
" level = dirpath.replace(LOCAL_PATH, '').count(os.sep)\n",
" indent = ' ' * level\n",
" subdir = os.path.basename(dirpath)\n",
" print(f' {indent}{subdir}/')\n",
" for f in sorted(filenames):\n",
" size = os.path.getsize(os.path.join(dirpath, f))\n",
" print(f' {indent} {f} ({size/(1024*1024):.1f} MB)')\n",
"\n",
"del model\n",
"gc.collect()"
]
},
{
"cell_type": "markdown",
"id": "876b8c22",
"metadata": {},
"source": [
"## 2. Benchmark: carga local vs HF cache\n",
"\n",
"Cargamos 5 veces de cada fuente para tener estadísticas estables."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "42346646",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Benchmark de carga (5 iteraciones cada uno)...\n",
"\n",
"→ Cargando desde HuggingFace cache...\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0859bcd797a94dca8afdc0341ed73044",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "39c9cc105c904dd39fcf08889b33ba98",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "6c777e538f764bc99cca408f6242eeda",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "16d63aeb9fcb4d5f8e8d330931ff7d4b",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "6b7b24c69e87464ea2efd25156b77170",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" Media: 4.134s ± 0.211s (min: 3.797s)\n",
"→ Cargando desde .local/models/...\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c12421a330124488ad628e6175f3229a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a36175de726e4c13ba1cadb89186af2c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e0507871bb0648a7910f9521856ece72",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9f5aa78b20d34492a2e924445d4ed769",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cb904177545448d5b83aea15f8f15b40",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" Media: 1.821s ± 0.138s (min: 1.563s)\n",
"\n",
"Speedup local vs HF cache: 2.27x\n"
]
}
],
"source": [
"N_RUNS = 5\n",
"\n",
"def bench_load(source, path, runs=N_RUNS):\n",
" \"\"\"Carga modelo N veces, retorna tiempos y RAM.\"\"\"\n",
" times = []\n",
" rams = []\n",
" for i in range(runs):\n",
" gc.collect()\n",
" ram_before = ram_mb()\n",
" t0 = time.perf_counter()\n",
" m = SentenceTransformer(path)\n",
" elapsed = time.perf_counter() - t0\n",
" ram_after = ram_mb()\n",
" times.append(elapsed)\n",
" rams.append(ram_after - ram_before)\n",
" del m\n",
" gc.collect()\n",
" return {\n",
" 'source': source,\n",
" 'times': times,\n",
" 'mean_time': np.mean(times),\n",
" 'std_time': np.std(times),\n",
" 'min_time': np.min(times),\n",
" 'mean_ram_delta': np.mean(rams),\n",
" }\n",
"\n",
"print(f'Benchmark de carga ({N_RUNS} iteraciones cada uno)...')\n",
"print()\n",
"\n",
"# Carga desde HF cache\n",
"print('→ Cargando desde HuggingFace cache...')\n",
"hf_bench = bench_load('HF cache', MODEL_ID)\n",
"print(f' Media: {hf_bench[\"mean_time\"]:.3f}s ± {hf_bench[\"std_time\"]:.3f}s (min: {hf_bench[\"min_time\"]:.3f}s)')\n",
"\n",
"# Carga desde path local\n",
"print('→ Cargando desde .local/models/...')\n",
"local_bench = bench_load('Local path', LOCAL_PATH)\n",
"print(f' Media: {local_bench[\"mean_time\"]:.3f}s ± {local_bench[\"std_time\"]:.3f}s (min: {local_bench[\"min_time\"]:.3f}s)')\n",
"\n",
"speedup = hf_bench['mean_time'] / local_bench['mean_time']\n",
"print(f'\\nSpeedup local vs HF cache: {speedup:.2f}x')"
]
},
{
"cell_type": "markdown",
"id": "06291006",
"metadata": {},
"source": [
"## 3. Verificación: embeddings idénticos\n",
"\n",
"Confirmamos que el modelo local produce exactamente los mismos embeddings que el de HF cache."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8e6eaa4a",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a469b638479a45deb836f54d1edaa056",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\u001b[1mBertModel LOAD REPORT\u001b[0m from: intfloat/multilingual-e5-small\n",
"Key | Status | | \n",
"------------------------+------------+--+-\n",
"embeddings.position_ids | UNEXPECTED | | \n",
"\n",
"Notes:\n",
"- UNEXPECTED:\tcan be ignored when loading from different task/architecture; not ok if you expect identical arch.\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2da4a0a304ba40a0a4748941dbe4ea9a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Loading weights: 0%| | 0/199 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Max diferencia absoluta: 0.00e+00\n",
"Mean diferencia absoluta: 0.00e+00\n",
"¿Son idénticos (atol=1e-6)? ✓ SÍ\n",
" [0] cosine=1.0000000000 | passage: La inteligencia artificial transforma la industria \n",
" [1] cosine=1.0000000000 | passage: Los mercados financieros reaccionan a las decisione\n",
" [2] cosine=1.0000000000 | passage: El aprendizaje profundo requiere grandes cantidades\n",
" [3] cosine=1.0000000000 | query: ¿Cómo funciona el machine learning?\n",
" [4] cosine=1.0000000000 | query: ¿Qué afecta los precios de las acciones?\n"
]
},
{
"data": {
"text/plain": [
"6961"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"test_texts = [\n",
" 'passage: La inteligencia artificial transforma la industria tecnológica',\n",
" 'passage: Los mercados financieros reaccionan a las decisiones de política monetaria',\n",
" 'passage: El aprendizaje profundo requiere grandes cantidades de datos etiquetados',\n",
" 'query: ¿Cómo funciona el machine learning?',\n",
" 'query: ¿Qué afecta los precios de las acciones?',\n",
"]\n",
"\n",
"# Cargar ambos modelos\n",
"model_hf = SentenceTransformer(MODEL_ID)\n",
"model_local = SentenceTransformer(LOCAL_PATH)\n",
"\n",
"# Generar embeddings\n",
"emb_hf = model_hf.encode(test_texts, normalize_embeddings=True)\n",
"emb_local = model_local.encode(test_texts, normalize_embeddings=True)\n",
"\n",
"# Comparar\n",
"max_diff = np.max(np.abs(emb_hf - emb_local))\n",
"mean_diff = np.mean(np.abs(emb_hf - emb_local))\n",
"are_equal = np.allclose(emb_hf, emb_local, atol=1e-6)\n",
"\n",
"print(f'Max diferencia absoluta: {max_diff:.2e}')\n",
"print(f'Mean diferencia absoluta: {mean_diff:.2e}')\n",
"print(f'¿Son idénticos (atol=1e-6)? {\"✓ SÍ\" if are_equal else \"✗ NO\"}')\n",
"\n",
"# Cosine similarity entre pares correspondientes\n",
"for i, text in enumerate(test_texts):\n",
" sim = np.dot(emb_hf[i], emb_local[i])\n",
" print(f' [{i}] cosine={sim:.10f} | {text[:60]}')\n",
"\n",
"del model_hf, model_local\n",
"gc.collect()"
]
},
{
"cell_type": "markdown",
"id": "c139a193",
"metadata": {},
"source": [
"## 4. Visualización de tiempos de carga"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "53664d2a",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_18429/1763775165.py:10: MatplotlibDeprecationWarning: The 'labels' parameter of boxplot() has been renamed 'tick_labels' since Matplotlib 3.9; support for the old name will be dropped in 3.11.\n",
" bp = axes[0].boxplot(data, labels=labels, patch_artist=True)\n"
]
},
{
"data": {
"image/png": "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KlasmFxdXVWoUCEFBwfrypUrkqTbt29r5MiRqlatmnx8fOTp6am6detq/fr1Fsc5deqUTCaTPv74Y3366acqWbKkXF1ddfjwYUn/fX2qV68uNzc3lSxZUjNmzEj253vOnDl6+umn5efnJ1dXV5UrV07Tpk2z6loAAJnTxIkTFR0dra+//tqiYJsoICBAgwYNMj+39m9JsWLF1KpVK/3666+qXr263N3dNWPGDEnS6dOn1bp1a3l6esrPz0+vv/66fv311yTrbm7evFkdO3ZUkSJF5OrqqsKFC+v111+3armGxHHbli1bNHDgQPn6+ipnzpzq27evbt++rRs3big4OFi5cuVSrly59MYbb8gwDItjWDseMwxD48aNU6FCheTh4aGGDRsmO1ZIbm3RR7nGW7duac2aNeYCVXLu3r1r81q3iTkXLlyod999VwULFpSHh4ciIyNTvCdGcvcGSPwe2LJli5566im5ubmpRIkS+vbbby32tXZMl3idy5cvt+l60lJqr5Wk/33ufvjhhwe+xpGkHTt2qHnz5vLx8ZGHh4fq16+vrVu3JulnzXhdkv7991+1bdvW4mfr/jG5ZP3rK1uu5+bNmzp69Kh5nJua5F4XPvfcc5KkI0eOpLqvi4uLRcHW1v1//vlnRUVFqXPnzua2xIlNwcHBFn23bNkiZ2dnvfnmm6keE0hvzLQFMrmXX35Zb7/9ttauXavevXsn2+evv/5Sq1atVLFiRY0dO1aurq46ceKEeeBQtmxZjR07ViNHjlSfPn1Ut25dSbL4o3n16lW1aNFCL774orp06aJ8+fKlmuuDDz6QyWTSm2++qUuXLunTTz9V48aNtW/fPptnYsTHx6tVq1b6/fff9eKLL2rQoEGKiorSunXrdOjQIZUsWTLF665bt668vb31xhtvKHv27JoxY4YaNGigjRs3JrnpwYABA5QrVy6NGjVKp06d0qeffqr+/fvrhx9+SDXf2rVr1b59e5UrV04hISG6evWqunfvrkKFCiXp27dvX82dO1fdu3fXwIEDdfLkSU2dOlV79+7V1q1blT179mTP0bdvX507d07r1q1L9q1A97t48aJq1qxpLqj6+vpq9erV6tmzpyIjIzV48GCL/iEhIXJ3d9dbb72lEydO6PPPP1f27Nnl5OSk69eva/To0dq+fbvmzp2r4sWLa+TIkRb7b9y4UT/88IMGDhwoV1dXffnll2revLn+/PNPBQYGSrL+6zF69GiFhISoV69eeuqppxQZGaldu3Zpz549atKkSYrXfOHCBTVs2FB3797VW2+9JU9PT82cOTPZ77d58+apa9euatasmT788EPdvHlT06ZNU506dbR3795UbyAXHR2tunXr6siRI+rRo4eqVq2qK1euaMWKFfr333+VN29eRUZGatasWerUqZN69+6tqKgoff3112rWrJn+/PPPJEuQzJkzR7du3VKfPn3k6uqq3Llza+/evWrevLn8/f01ZswYxcfHa+zYsfL19U2Sadq0aSpfvrxat26tbNmy6eeff9Zrr72mhIQE9evXL8VrAQBkXj///LNKlCiRbBEkObb8LTl27Jg6deqkvn37qnfv3ipdurRiYmL09NNP6/z58xo0aJDy58+vBQsWJPmHpSQtWrRIN2/e1Kuvvqo8efLozz//1Oeff65///1XixYtsirvgAEDlD9/fo0ZM0bbt2/XzJkzlTNnTm3btk1FihTR+PHjtWrVKn300UcKDAy0KNpYOx4bOXKkxo0bp2eeeUbPPPOM9uzZo6ZNm+r27dsPzPco17h7927dvn1bVatWTXb733//LU9PT92+fVv58uVT7969NXLkyBTHkfd7//335eLiomHDhikuLu6h3t1z4sQJdejQQT179lTXrl01e/ZsdevWTdWqVVP58uUlWT+m8/HxUcmSJbV161a9/vrrNmd5VA96rXQva17j/PHHH2rRooWqVaumUaNGycnJyfxPkc2bN+upp56SZP14PTY2Vo0aNVJ4eLgGDhyoAgUKaN68efrjjz8e+dqtuZ4///xTDRs21KhRox7q/hoXLlyQJOXNm/ehMlq7//z58+Xu7q527dqZ28qWLav3339fw4cPV4cOHdS6dWvFxMSoW7duKlOmjMaOHftQmYA0YwB4rM2ZM8eQZOzcuTPFPj4+PkaVKlXMz0eNGmXc++M/efJkQ5Jx+fLlFI+xc+dOQ5IxZ86cJNvq169vSDKmT5+e7Lb69eubn69fv96QZBQsWNCIjIw0t//444+GJGPKlCnmtqJFixpdu3Z94DFnz55tSDI++eSTJH0TEhLMH0syRo0aZX7etm1bw8XFxQgLCzO3nTt3zvDy8jLq1atnbkv8HDdu3NjieK+//rrh7Oxs3LhxI8l571W5cmXD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+6XFNRr3rcWbkqFDh+qrr77Sb7/9ppo1az6wf3JfP1vd//mX/hs733uttozpDMNIcTJGooiICKvWBE6Oj49PioVqW14rPeg1TuI4s2vXrqlex507d6wer58+fVoBAQFJPj/JjattlZav2e63efNm9ezZU82aNdMHH3xg8/4//PCD3n33XfXs2VOvvvpqqn3nz5+v3LlzJzu5QZJKliyp0aNHa/jw4QoMDNR7771ncx4gPVC0BTK5f//9VxEREckOiBO5u7tr06ZNWr9+vX755RetWbNGP/zwg55++mmtXbtWzs7ODzxPetwROLVZstZkSmspndPaAfODJCQkyM/PT/Pnz092e3JrlT7seSSpS5cuKQ4Y7x8sp3Tt6f05SU69evUUFham5cuXa+3atZo1a5YmT56s6dOnp3rHWWslfn7mzZuX7J1lbfnnQEq+++47devWTW3bttXw4cPl5+cnZ2dnhYSEWNw8L9Gj/HyFhYWpUaNGKlOmjD755BMVLlxYLi4uWrVqlSZPnvzQs+sBAI8vb29vFShQQIcOHbKqv61/Sx7l71Z8fLyaNGmia9eu6c0331SZMmXk6emps2fPqlu3blb/3bJl7HLvuCUjxmOPeo2J/xi/fv16svdIuF9iofratWtW5Uvu65fauDw51owRbRnTXb9+/YFrlg4aNEjffPNNqn1SMmfOnGRv0CWlzWulRIlf248++ijJPQwS5ciRwzyb2pbxujUc5fXV/v371bp1awUGBmrx4sU2j6/XrVun4OBgtWzZUtOnT0+1b3h4uDZv3qw+ffqkuq7z2rVrJUnnzp3T1atXk30dAGQ0irZAJpd4U6r736J2PycnJzVq1EiNGjXSJ598ovHjx+udd97R+vXr1bhx4wf+Z9tW978NyjAMnThxwmLwkStXLt24cSPJvqdPn7Z4C33JkiW1Y8cO3blzx+obLPj6+srDw0PHjh1Lsu3o0aNycnJKMhPjYRQtWlRS0uuVlOTcJUuW1G+//abatWs/1Isda79Gvr6+8vLyUnx8fKp3HU5LyV3/33//LQ8PD/OLH1u+Hrlz51b37t3VvXt3RUdHq169eho9enSqRduiRYta/XWQJD8/v4f6/JQsWfKBL4IXL16sEiVKaOnSpRZft1GjRll1Dj8/P7m5uenEiRNJtt3f9vPPPysuLk4rVqywmPWSVsttAAAeT61atdLMmTMVGhqqoKCgVPumxd+SokWL6vDhw0lmTN7/d+vgwYP6+++/9c0331jcHGzdunVWn+tRWDseu3eMd++49PLly6m+C0t69GssU6aMJOnkyZOqUKHCA/snLknwKAXnxNnDN27csHgbemrLhFnD2jHdyZMnValSpVSP9cYbb6hLly4PlePed9cl50GvlRI96DVO4jjT29s71XGmLeP1okWL6tChQ0l+tpIbV1v7+sra63kYYWFhat68ufz8/LRq1SrlyJHDpv137Nih5557TtWrV9ePP/74wILv999/L8Mwkl0aIdH06dO1bt06ffDBBwoJCVHfvn21fPlym3IB6YE1bYFM7I8//tD777+v4sWLp/pHKrn/uif+5zcuLk6S5OnpKUnJ/pF/GN9++63FW/IWL16s8+fPW7xlpWTJktq+fbvFHXhXrlypM2fOWByrffv2unLliqZOnZrkPCnN+HR2dlbTpk21fPlyi7f3XLx4UQsWLFCdOnUe+DZ4a/j7+6ty5cr65ptvLN7qtm7dOh0+fNii7/PPP6/4+Hi9//77SY5z9+7dB37urf0aOTs7q3379lqyZEmyxcXE5QrSUmhoqMVSEGfOnNHy5cvVtGlTOTs72/T1SJx5kChHjhwKCAgwf6+m5JlnntH27dv1559/mtsuX76cZCZNs2bN5O3trfHjx1ssW3DvPqlp37699u/fr59++inJtsTvx8SZDPd+f+7YsUOhoaGpHjuRs7OzGjdurGXLluncuXPm9hMnTmj16tVJ+t5/roiICM2ZM8eqcwEAMqc33nhDnp6e6tWrly5evJhke1hYmKZMmSIpbf6WNGvWTGfPntWKFSvMbbdu3dJXX31l0S+5cxmGYc6S3qwdjzVu3FjZs2fX559/bpH1008/feA5HvUaq1WrJhcXF+3atcuiPTIyMsl4yDAMjRs3TtKDJ3GkJrHYuGnTJnNbTEzMQ89slawf00VERCgsLEy1atVK9XjlypVT48aNH+rh7++f4nGtea2U6EGvcapVq6aSJUvq448/VnR0dJLjJo4zbRmvP/PMMzp37pwWL15sbrt582ayyypY+/rK2utJPNfRo0etWnP4woULatq0qZycnPTrr7+m+o+EsLCwJO9AO3LkiFq2bKlixYpp5cqVVk10WbBggYoUKaI6deoku/3kyZMaPny42rdvr7ffflsff/yxVqxYoW+//faBxwbSGzNtgUxi9erVOnr0qO7evauLFy/qjz/+0Lp161S0aFGtWLFCbm5uKe47duxYbdq0SS1btlTRokV16dIlffnllypUqJD5j1vJkiWVM2dOTZ8+XV5eXvL09FSNGjUees2r3Llzq06dOurevbsuXryoTz/9VAEBARY3o+jVq5cWL16s5s2b6/nnn1dYWJi+++4786AxUXBwsL799lsNGTJEf/75p+rWrauYmBj99ttveu2119SmTZtkM4wbN07r1q1TnTp19NprrylbtmyaMWOG4uLiNHHixIe6ruSEhISoZcuWqlOnjnr06KFr167p888/V/ny5S0Ga/Xr11ffvn0VEhKiffv2qWnTpsqePbuOHz+uRYsWacqUKRY3GLhf4o2+Bg4cqGbNmsnZ2Vkvvvhisn0nTJig9evXq0aNGurdu7fKlSuna9euac+ePfrtt9+sfvuctQIDA9WsWTMNHDhQrq6u+vLLLyVJY8aMMfex9utRrlw5NWjQQNWqVVPu3Lm1a9cuLV68WP379081wxtvvKF58+apefPmGjRokDw9PTVz5kwVLVpUBw4cMPfz9vbWtGnT9PLLL6tq1ap68cUX5evrq/DwcP3yyy+qXbt2sv8gSDR8+HAtXrxYHTt2VI8ePVStWjVdu3ZNK1as0PTp01WpUiW1atVKS5cu1XPPPaeWLVvq5MmTmj59usqVK5fsAD45o0eP1tq1a1W7dm29+uqrio+P19SpUxUYGKh9+/aZ+zVt2lQuLi569tln1bdvX0VHR+urr76Sn5+fzp8/b9W5AACZT8mSJbVgwQK98MILKlu2rIKDgxUYGKjbt29r27ZtWrRokfnt4mnxt6Rv376aOnWqOnXqpEGDBsnf31/z5883j1ETZwiWKVNGJUuW1LBhw3T27Fl5e3tryZIlD5y9mlasHY/5+vpq2LBhCgkJUatWrfTMM89o7969Wr169QPfxv+o1+jm5qamTZvqt99+09ixY83te/bsUadOndSpUycFBAQoNjZWP/30k7Zu3ao+ffqoatWqD/15adq0qYoUKaKePXtq+PDhcnZ21uzZs81jpIdh7Zjut99+k2EYKY7p05s1r5USPeg1jpOTk2bNmqUWLVqofPny6t69uwoWLKizZ89q/fr18vb21s8//yzJ+vF67969NXXqVAUHB2v3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",
"text/plain": [
"<Figure size 1400x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data",
"transient": {}
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
"\n",
"# Box plot de tiempos\n",
"data = [hf_bench['times'], local_bench['times']]\n",
"labels = ['HF cache', 'Local (.local/)']\n",
"colors = ['#e74c3c', '#2ecc71']\n",
"\n",
"bp = axes[0].boxplot(data, labels=labels, patch_artist=True)\n",
"for patch, color in zip(bp['boxes'], colors):\n",
" patch.set_facecolor(color)\n",
" patch.set_alpha(0.7)\n",
"axes[0].set_ylabel('Tiempo de carga (s)')\n",
"axes[0].set_title('Distribución de tiempos de carga')\n",
"\n",
"# Bar chart comparativo\n",
"means = [hf_bench['mean_time'], local_bench['mean_time']]\n",
"stds = [hf_bench['std_time'], local_bench['std_time']]\n",
"bars = axes[1].bar(labels, means, yerr=stds, color=colors, alpha=0.8, capsize=10)\n",
"for bar, mean in zip(bars, means):\n",
" axes[1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.05,\n",
" f'{mean:.3f}s', ha='center', fontsize=12, fontweight='bold')\n",
"axes[1].set_ylabel('Tiempo medio (s)')\n",
"axes[1].set_title(f'Carga media ({N_RUNS} runs) — speedup: {speedup:.2f}x')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}