---
name: gliner_glirel_tuning
lang: py
domain: datascience
description: "Estudio empirico de GLiNER y GLiREL: distribucion de scores, sensibilidad a threshold/top_k/labels/idioma, calibracion de thresholds para extract_graph_hybrid"
tags: [nlp, gliner, glirel, thresholds]
uses_functions: []
uses_types: []
framework: "jupyterlab"
entry_point: "notebooks/main.ipynb"
dir_path: "projects/osint_graph/analysis/gliner_glirel_tuning"
repo_url: ""
---

## Notas

Estudio empirico de GLiNER y GLiREL: distribucion de scores, sensibilidad a threshold/top_k/labels/idioma, calibracion de thresholds para extract_graph_hybrid.

Tras varias jornadas el alcance se amplio: ahora cubre **6 modelos** (GLiNER, GLiREL, mREBEL, REBEL, GLiNER2, NuExtract 2.0-2B) + **OpenIE schema-less ES** con spaCy + reglas de dependencia. La conclusion ganadora vive en el vault `osint_nlp_models`.

## Notebooks (orden cronologico — ejecutados con outputs guardados)

| # | Notebook | Hallazgo clave |
|---|---|---|
| 01 | `notebooks/01_gliner_glirel_tuning.ipynb` | Calibracion thresholds GLiNER+GLiREL. Multilingue: labels EN funcionan sobre texto ES. snake_case verbal labels >> natural_long en GLiREL. |
| 02 | `notebooks/02_e2e_spanish_graph.ipynb` | E2E ES + grafo. Descubrimiento: GLiREL emite 51 falsos positivos en es_corporate_short a t=0.15; a t=0.30 solo 1 relacion (tambien falsa). **No hay sweet spot** en castellano. |
| 03 | `notebooks/03_mrebel_vs_glirel.ipynb` | mREBEL frase-a-frase: 8 tripletas crudas, 5 alineables, 4 inequivocamente correctas. Cero falsos absurdos. **PERO** licencia CC BY-NC-SA 4.0 (no comercial). |
| 04 | `notebooks/04_gliner2_winner.ipynb` ⭐ | GLiNER2 `fastino/gliner2-large-v1` (Apache 2.0, 340M, NER+RE joint). 6/8 correctas vs 4/5 mREBEL, 20× mas rapido. Funciona en OSINT castellano. **Modelo elegido**. |
| 05 | `notebooks/05_long_text_and_pdf.ipynb` | Pipeline PDF E2E sobre `politica_proteccion_datos.pdf` (BBVA, 89.882 chars). 67 chunks, 378 entidades, 54 relaciones, 97.9s total. |
| 06 | `notebooks/06_improvements.ipynb` | Mejoras GLiNER2: threshold 0.3 (vs 0.5 default) → +187% relaciones (71→204). Coref normalize+substring → −18% aislados (389→318). Descripciones por relacion **sin efecto**. `batch_extract` 25% **mas lento** en CPU. |
| 07 | `notebooks/07_nuextract_vs_gliner2.ipynb` | NuExtract 2.0-2B GPU sobre RTX 3070: load 7.1s, T1 2.88s vs CPU 25s (8.7×). PDF entero extrapolado 5.2 min vs GLiNER2 CPU 2.2 min — **2.6× mas lento incluso con GPU**. Calidad similar. **Descartado por velocidad**. |
| 08 | `notebooks/08_improving_gliner2.ipynb` | Label naming: snake_case verbal >> camelCase >> espacios. `include_confidence=True` permite threshold por relacion. Post-filter typed gratis y decisivo. GLiREL+allowed_head/tail post-hoc revive el modelo como complemento. |
| 09 | `notebooks/09_spacy_es_openie.ipynb` | spaCy ES `es_core_news_md` + reglas de dependencia: OpenIE schema-less en castellano. `(Enmanuel, querer, Ashlly)` con verbo del texto, 5ms/frase. Reglas pendientes V2: pasiva refleja, copulares, coref pronombres. |

## Hallazgos operativos consolidados

### Stack final recomendado para `graph_explorer`

```
Capa 1 (NER + RE schema-driven):
  GLiNER2 (Apache 2.0)
    + threshold=0.3 (vs default 0.5)
    + snake_case verbal labels
    + include_confidence=True (para tuning fino)

Capa 2 (post-procesado puro, gratis):
  filter_relations_by_entity_types  ← descarta absurdos (Madrid president_of Persona)
  merge_entity_aliases              ← BBVA ⊂ Banco Bilbao Vizcaya...
  aggregate_extraction_results       ← dedupe + counter sobre N chunks

Capa 3 (chunking para texto largo):
  chunk_with_overlap (max_chars=1500, overlap_sentences=2)

Capa 4 opcional (OpenIE schema-less complementaria):
  spaCy es_core_news_md + extract_triples_spacy_es
```

Todo el stack esta como **funciones del registry** tras esta sesion (10 funciones en core/datascience/pipelines).

### Decisiones registradas en el vault

`vaults/osint_nlp_models/decisions/`:
- `2026-05-04-mrebel-over-glirel.md` — primera decision (mañana): mREBEL gana a GLiREL pero caveat licencia.
- `2026-05-04-gliner2-over-mrebel.md` ⭐ — decision final (tarde): GLiNER2 reemplaza a todos por velocidad + Apache 2.0 + multilingue ES nativo.
- `2026-05-04-license-constraint.md` — plan de contingencia si en algun momento se necesita comercial sin Apache 2.0.

### Modelos descartados y por que

| Modelo | Razon |
|---|---|
| **GLiREL** `jackboyla/glirel-large-v0` | 51 falsos positivos en ES corporate, sin sweet spot. Util quiza en EN tecnico (no probado). |
| **mREBEL large/base** | CC BY-NC-SA 4.0 (bloqueante comercial) + 25× mas lento que GLiNER2. Queda como fallback. |
| **REBEL EN-only** | Apache 2.0 pero requiere traducir ES→EN, +500ms-1s + riesgo nombres propios. |
| **NuExtract 2.0-2B** | 2.6× mas lento que GLiNER2 incluso con GPU. Mejor para "ficha rica" por entidad pero excesivo para grafo. |
| **triplet-extract EN-only** | Pierdes verbos del texto castellano al traducir; `(quiere, loves)` no es lo mismo. |

## Pendientes (tracked en issues)

- `dev/issues/0050-jupyter-exec-collab-client-failure.md` — bug `jupyter_exec` con cliente colaborativo.
- `projects/osint_graph/apps/graph_explorer/issues/0041-split-confidence-thresholds.md` — split `confidence_threshold` en `entity_threshold` + `relation_threshold`.
- `projects/osint_graph/apps/graph_explorer/issues/0042-gliner2-unified-extractor.md` ⭐ — sustituir GLiREL por GLiNER2 en `extract_graph_hybrid` del panel `paste_extract`.
- `dev/issues/0051-extraction-pipeline-followups.md` — funciones aun por construir (NuExtract loader, extract_graph_from_pdf, spaCy ES V2 rules, kernel startup fix). Ver issue.

## Como reproducir cualquier experimento

Cada notebook tiene su `build_notebook_*.py` y, cuando es pesado, su `run_*.py` que vuelca a JSON:

```bash
cd projects/osint_graph/analysis/gliner_glirel_tuning
./.venv/bin/python3 -u run_benchmark_v2.py            # genera benchmark_v2.json
./.venv/bin/python3 build_notebook_gliner2.py         # genera notebooks/04_gliner2_winner.ipynb
IPYTHONDIR=$(pwd)/.ipython ./.venv/bin/jupyter nbconvert \
    --to notebook --execute notebooks/04_gliner2_winner.ipynb \
    --output 04_gliner2_winner.ipynb --ExecutePreprocessor.timeout=600
```

JSONs de resultados (todos en la raiz del analysis):
- `benchmark_v2.json` — GLiNER2 sobre 4 corpora.
- `improvements.json` — 5 configs A-E sobre el PDF + coref.
- `nuextract_results.json` — NuExtract CPU baseline + GPU.
- `nuextract_full.json` — NuExtract GPU sobre PDF entero (179 chunks parsed OK).
- `mrebel_results.json` — mREBEL sobre es_corporate_short.
- `openie_results.json` — comparativa 3 paradigmas (triplet-extract EN, spaCy ES, GLiNER2).

## Playground

`projects/osint_graph/analysis/gliner_glirel_tuning/playground/` — server FastAPI + frontend Sigma.js sirviendo en `localhost:7878`. Aplica todo el stack de capas 1-3 sobre cualquier texto que pegues. Ver `playground/server.py` y `playground/index.html`.
