MrBERT-es GEN5a/GEN5b — Clasificador multi-etiqueta de política pública (Costa Rica)

Modelo de clasificación multi-etiqueta de textos de política pública costarricense en 48 subtemas (GEN5b) organizados jerárquicamente en 6 temas (GEN5a). A diferencia de un clasificador de etiqueta única, este modelo captura la multi-etiquetación: un mismo texto puede pertenecer a varios subtemas a la vez.

  • Encoder base: BSC-LT/MrBERT-es (ModernBERT, contexto de 8192 tokens).
  • Método: destilación de conocimiento a partir de un teacher LLM (Qwen3-30B-A3B-Instruct-2507), con soft labels por subtema (método logit A/B) y pérdida BCE Bernoulli independiente por etiqueta.
  • Corpus de destilación: 38 812 textos de tres dominios — propuestas de programa de gobierno, actas legislativas de control político y noticias de medios.
  • Formato: ModernBertForSequenceClassification estándar — se carga con from_pretrained, sin trust_remote_code.

Uso rápido

El modelo emite una probabilidad por cada uno de los 48 subtemas (GEN5b). La probabilidad de cada uno de los 6 temas (GEN5a) se deriva por el módulo de máxima restricción (MCM): la probabilidad de un tema es el máximo de las probabilidades de sus subtemas hijos. La función clasificar de abajo devuelve ambos niveles en una salida estructurada y ordenada.

import torch, numpy as np
from transformers import AutoModelForSequenceClassification, AutoTokenizer

repo = "PENCR/mrbert-es-gen5a-gen5b-multilabel"
tok = AutoTokenizer.from_pretrained(repo)
model = AutoModelForSequenceClassification.from_pretrained(repo).eval()

def clasificar(texto, max_length=512):
    enc = tok(texto, truncation=True, max_length=max_length, return_tensors="pt")
    with torch.no_grad():
        p = torch.sigmoid(model(**enc).logits)[0].numpy()      # (48,) prob por subtema
    cfg = model.config
    parent = {int(k): int(v) for k, v in cfg.spml_parent_of.items()}   # subtema_idx -> tema_idx
    umbral = np.array(cfg.spml_umbrales_por_categoria)                  # (48,)
    tema_nom = {int(k): v for k, v in cfg.spml_tema_idx_names.items()}  # tema_idx -> nombre
    salida = []
    for t in range(len(tema_nom)):
        hijos = [s for s in range(48) if parent[s] == t]
        subs = sorted(
            [{"subtema": cfg.id2label[s], "prob": round(float(p[s]), 3),
              "activo": bool(p[s] >= umbral[s])} for s in hijos],
            key=lambda d: -d["prob"])
        salida.append({"tema": tema_nom[t], "prob_tema": round(float(p[hijos].max()), 3),
                       "subtemas": subs})
    return sorted(salida, key=lambda d: -d["prob_tema"])   # temas ordenados por probabilidad

# ---- ejemplo ----
texto = ("Fortalecimiento de la Contraloria General de la Republica y del control "
         "del gasto publico y la contratacion administrativa.")
for t in clasificar(texto):
    print(f"{t['prob_tema']:.3f}  TEMA: {t['tema']}")
    for s in t["subtemas"]:
        if s["activo"]:
            print(f"         · {s['prob']:.3f}  {s['subtema']}")

Salida (subtemas que superan su umbral por categoría):

0.998  TEMA: GESTION_POLITICA
         · 0.998  S26_CONTROLES_POLITICOS_JURIDICOS_ADMIN
         · 0.993  S27_CORRUPCION_TRANSPARENCIA_GOB_ABIERTO
         · 0.951  S34_REFORMA_ESTADO_Y_POLITICA
         · 0.541  S33_PROCESO_LEGISLATIVO
0.992  TEMA: SOLVENCIA_DEL_ESTADO
         · 0.992  S43_GASTO_Y_FINANZAS_PUBLICAS
...

Como DataFrame

Para una tabla plana (una fila por subtema), legible y filtrable:

import pandas as pd
def clasificar_df(texto, max_length=512):
    filas = [{"tema": t["tema"], "prob_tema": t["prob_tema"], **s}
             for t in clasificar(texto, max_length) for s in t["subtemas"]]
    return pd.DataFrame(filas)

df = clasificar_df(texto)
print(df[df.activo].to_string(index=False))     # solo los activos

Campos disponibles en model.config

  • id2label / label2id — nombre de cada uno de los 48 subtemas (índice 0–47).
  • spml_tema_idx_names — nombre de cada uno de los 6 temas (índice 0–5).
  • spml_parent_of — mapa subtema_idx → tema_idx (para el MCM).
  • spml_umbrales_por_categoria — umbral de decisión calibrado por subtema (48 valores).

Umbral por categoría

Cada subtema tiene un umbral propio calibrado (rango 0.25–0.69), en model.config.spml_umbrales_por_categoria (48 valores indexados por subtema). Usar el umbral por categoría en lugar de un 0.5 uniforme mejora el F1 frente al teacher. También se puede usar 0.5 para un corte simple.

Rendimiento

Evaluado sobre un conjunto held-out de propuestas de gobierno 2026 (n=583, etiqueta humana única out-of-sample, nunca vista en entrenamiento). El modelo recupera la etiqueta humana con:

Métrica Valor
top-1 (predicción #1 = etiqueta humana) 0.569
top-3 0.811
top-5 0.889
tema top-1 (vía MCM) 0.748
recall etiqueta humana (umbral por categoría) 0.882
cardinalidad media @0.5 4.64 subtemas

Captura ~4-5 subtemas por texto (multi-etiquetación real, frente a la etiqueta única del dato histórico) sin perder la recuperación de la etiqueta principal. La fidelidad al teacher en el held-out de destilación (n=3877) es de top-1 0.748, correlación de probabilidades 0.891 y MAE 0.047.

Detalles del modelo

  • Arquitectura: MrBERT-es (ModernBERT) + cabeza de clasificación de secuencia estándar, 48 salidas, activación sigmoidal por etiqueta, pooling sobre el token CLS.
  • Longitud recomendada: 512 tokens para textos cortos (propuestas/noticias); el encoder soporta hasta 8192 para textos largos (actas legislativas).
  • Idioma: español.

Citación

Encoder: Tamayo, D. et al. (2026). MrBERT: Modern Multilingual Encoders via Vocabulary, Domain, and Dimensional Adaptation. arXiv:2602.21379. Barcelona Supercomputing Center — Language Technologies Lab. · Arquitectura base ModernBERT: Warner, B. et al. (2024). arXiv:2412.13663. · Teacher: Yang, A. et al. (2025). Qwen3 Technical Report. arXiv:2505.09388.

Infraestructura: entrenado en la supercomputadora Kabré del Centro Nacional de Alta Tecnología de Costa Rica (CeNAT/CNCA).


Modelo desarrollado para el Programa Estado de la Nación (PEN) — clasificación de las variables GEN5a (tema) y GEN5b (subtema).

Downloads last month
55
Safetensors
Model size
0.2B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for PENCR/mrbert-es-gen5a-gen5b-multilabel

Base model

BSC-LT/MrBERT
Finetuned
BSC-LT/MrBERT-es
Finetuned
(14)
this model

Papers for PENCR/mrbert-es-gen5a-gen5b-multilabel