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:
BCEWithLogitsLosspor etiqueta (conpos_weight=sqrt(n_neg/n_pos)); Focal Loss (γ=1.0) adicional en ALC2 por fuerte desbalance. - Oversampling de ALC2 hacia
target_prop=0.15durante 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
patiencebajo. - 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=Truees 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