CoolFace
Modelpublic

PENCR/bertin-alc-multilabel

sourceHugging Facemitupdated 5mo agoView on Hugging Face
0likes5downloads
Model Card

BERTIN multi-label ALC — clasificación de alcance de propuestas (es)

Modelo multi-label que, dado el texto de una propuesta de política pública en español, predice tres dimensiones de alcance de forma independiente:

EtiquetaDimensión
ALC1Alcance mayoritario (apunta a la población general)
ALC2Alcance cuantificado (contiene metas, porcentajes, plazos)
ALC3Alcance institucional (referencia legal / marco normativo)

Las tres salidas son sigmoids independientes (no suman 1): una propuesta puede cumplir varias dimensiones a la vez.

Construido sobre `bertin-project/bertin-roberta-base-spanish`, con una rama auxiliar de Bag-of-Words (HashingVectorizer, 1024 features) y una cabeza multi-label de 3 salidas.

Uso rápido

python
from transformers import pipeline

clf = pipeline(
    "bertin-alc",
    model="PENCR/bertin-alc-multilabel",
    trust_remote_code=True,
)

clf("Reducir en un 30% la pobreza infantil al año 2030.")

Salida (formato dict, el default):

python
{
  "ALC1": {"prob": 0.91, "prob_raw": 0.90, "threshold": 0.52, "pred": True},
  "ALC2": {"prob": 0.73, "prob_raw": 0.45, "threshold": 0.30, "pred": True},
  "ALC3": {"prob": 0.08, "prob_raw": 0.20, "threshold": 0.16, "pred": False}
}
  • prob: probabilidad calibrada con Platt scaling.
  • prob_raw: probabilidad cruda (sigmoid del logit).
  • threshold: umbral óptimo por etiqueta (maximiza F1 en validación).
  • pred: prob >= threshold.

Parámetros opcionales

python
clf(texto, raw=True)                     # devolver probas crudas (sin Platt)
clf(texto, return_format="list")         # lista de dicts (uno por etiqueta)
clf(texto, return_format="raw")          # {"ALC1": 0.91, "ALC2": ..., "ALC3": ...}

Métricas

Evaluación sobre el hold-out de test (muestra estratificada, best epoch = 2):

EtiquetaPrevalenciaROC-AUCPR-AUCF1 @0.5F1 @umbral óptimoUmbral óptimo
ALC167.7 %0.9560.9740.9270.9280.52
ALC22.8 %0.9370.4870.4820.5950.30
ALC312.5 %0.8710.5020.4150.5200.16
Macro0.9210.6540.681

Los umbrales óptimos ya vienen cargados en config.thresholds y se usan por defecto en el pipeline.

Calibración

Para cada etiqueta se entrenó una regresión Platt (a·logit(p) + b) sobre un hold-out del 30 % del train:

Etiquetaab
ALC11.0366-0.0228
ALC21.7840-2.3134
ALC30.8169-1.4047

Nota honesta sobre la calibración: Platt mejoró ECE en ALC1 pero lo empeoró en ALC2 (0.848 → 0.955) y ALC3 (0.748 → 0.776) por pocos positivos en el hold-out (ALC2 tiene prevalencia de 2.8 %). Las probabilidades post-Platt siguen sirviendo para ordenar propuestas y para decidir con los umbrales aquí publicados, pero no deben interpretarse como frecuencias reales. Para quien prefiera las probas crudas: clf(texto, raw=True).

Arquitectura

texto ─┬─► BERTIN tokenizer ─► BERTIN encoder (RoBERTa base) ─► mean-pool (768)
       │                                                               │
       └─► HashingVectorizer (1024) ─► Linear+BN+ReLU+Drop(0.3) ──► (512)
                                                                       │
                                                        concat ────────┤
                                                                       ▼
                                               Linear(1280→256) ─► ReLU ─► Drop(0.4)
                                                                       │
                                                              Linear(256→3) → logits
                                                                       │
                                                                    sigmoid
  • Backbone: bertin-project/bertin-roberta-base-spanish (~125 M params).
  • Longitud máxima: 256 tokens.
  • Loss: BCEWithLogitsLoss por etiqueta (con pos_weight=sqrt(n_neg/n_pos)); Focal Loss (γ=1.0) adicional en ALC2 por fuerte desbalance.
  • Oversampling de ALC2 hacia target_prop=0.15 durante el train.
  • Tamaño en disco: ~498 MB (model.safetensors).

Entrenamiento

  • Dataset: ~29 k propuestas anotadas por expertos (no se publica por acuerdos con la fuente).
  • Split: 70 % train / 15 % val / 15 % test, estratificado multi-label.
  • Optimizador: AdamW, lr=1e-5, weight_decay=0.1, 10 % warmup lineal.
  • Epochs: 20 con patience=6; el mejor checkpoint es el del epoch 2 (val_loss = 0.274). A partir del epoch 3 el modelo empieza a sobreajustar.
  • Batch size: 32.
  • Hardware de entrenamiento: 1× GPU NVIDIA (CUDA).

Hardware sugerido para inferencia

SetupTiempo por predicción
GPU NVIDIA~40 ms
Apple Silicon (MPS+FP16)~150–300 ms
CPU (x86)~1–2 s

El pipeline detecta MPS y castea a FP16 automáticamente (requerido por BatchNorm en el backend Metal).

Limitaciones

  • ALC2 tiene poca prevalencia (2.8 %): F1 = 0.60 al umbral óptimo y calibración imperfecta. Úselo como señal de "probable cuantificación" más que como una decisión dura.
  • Sobreajuste desde epoch 3: el modelo entregado es el del epoch 2. Si reentrena con más datos, mantenga patience bajo.
  • Lenguaje: funciona con texto en español de registro formal / político. No se garantiza buen desempeño en textos coloquiales, otros dialectos o traducciones automáticas.
  • Sesgos: el dataset proviene de propuestas de política pública de Costa Rica; las etiquetas reflejan criterios de analistas humanos y pueden contener sesgos sistemáticos de ese proceso.
  • `trust_remote_code=True` es necesario porque el pipeline es custom; revise el código antes de usarlo en producción.

Cita

bibtex
@misc{bertin_alc_multilabel,
  title  = {BERTIN multi-label ALC: clasificación de alcance de propuestas de política pública (es)},
  author = {Equipo del proyecto},
  year   = {2026},
  url    = {https://huggingface.co/PENCR/bertin-alc-multilabel}
}