Downloads · 30 days
8
10% of all-time downloads
PENCR/mrbert-es-gen5a-gen5b-multilabel
mrbert-es-gen5a-gen5b-multilabel is a text classification model from PENCR. Use it when you need a label for a piece of text. It is set up for transformers. The card lists the license as apache-2.0.
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…
Downloads · 30 days
8
10% of all-time downloads
All-time downloads
81
Public
Parameters
150M
602 MB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors601 MB · 99%
From the Hugging Face model README
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.
BSC-LT/MrBERT-es (ModernBERT, contexto de 8192 tokens).Qwen3-30B-A3B-Instruct-2507), con soft labels por subtema (método logit A/B) y pérdida BCE Bernoulli independiente por etiqueta.ModernBertForSequenceClassification estándar — se carga con from_pretrained, sin trust_remote_code.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
...
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
model.configid2label / 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).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.
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.
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).