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:

Etiqueta Dimensión
ALC1 Alcance mayoritario (apunta a la población general)
ALC2 Alcance cuantificado (contiene metas, porcentajes, plazos)
ALC3 Alcance 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

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):

{
  "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

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):

Etiqueta Prevalencia ROC-AUC PR-AUC F1 @0.5 F1 @umbral óptimo Umbral óptimo
ALC1 67.7 % 0.956 0.974 0.927 0.928 0.52
ALC2 2.8 % 0.937 0.487 0.482 0.595 0.30
ALC3 12.5 % 0.871 0.502 0.415 0.520 0.16
Macro 0.921 0.654 0.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:

Etiqueta a b
ALC1 1.0366 -0.0228
ALC2 1.7840 -2.3134
ALC3 0.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

Setup Tiempo 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

@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}
}
Downloads last month
16
Safetensors
Model size
0.1B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support