English · Español
Lab 03 — Generar REPORT.md y comparar dos checkpoints lado a lado¶
Objetivo: producir un informe Markdown legible por humanos para un checkpoint, después construir un comparador que difere dos informes y destaque cambios significativos. Termina con una interpretación escrita de un párrafo por checkpoint.
Tiempo estimado: 90-120 minutos.
Prerrequisito: Labs 00-02 hechos;
results.json,per_slice.csv,reliability.png,adversarial_by_category.pngexisten bajoexperiments/20-eval-report/<checkpoint_name>/tanto para el checkpoint final de la Fase 18 como para el best-val de la Fase 19.
Lo que produces¶
Un módulo nuevo:
src/eval/report.py— renderizaresults.json→REPORT.md.src/eval/compare.py— difere dos archivosresults.json; renderizaCOMPARE.md.tests/eval/test_report.py— tests de golden-file sobre un results.json fixture.
Artefactos de salida:
experiments/20-eval-report/<checkpoint_name>/REPORT.md(uno por checkpoint).experiments/20-eval-report/COMPARE.md(uno comparando los dos).learners/borja/phase-20/reflections.md(la interpretación escrita de Borja).
La plantilla REPORT.md¶
Secciones, en orden:
# Eval Report — <checkpoint_name>
**Checkpoint hash:** <sha256>
**Training step:** <step>
**Parent manifest:** <hash>
**Probe set version:** <hash>
**Eval date:** <iso8601>
**Seed:** <int>
## 1. Headline
| Metric | Value | 95% CI |
|---|---|---|
| PPL (test, overall) | 7.42 | — |
| PPL (test, EN) | 6.81 | — |
| PPL (test, ES) | 8.93 | — |
| Aggregate accuracy | 0.78 | [0.66, 0.87] |
| ECE | 0.092 | — |
| Brier | 0.171 | — |
| Adversarial accuracy | 0.55 | [0.32, 0.76] |
## 2. Per-slice accuracy
### By language
<table>
### By regularity
<table>
### By tense
<table>
### By person
<table>
### By verb (counts only — small N per cell)
<table>
## 3. Reliability diagram

## 4. Adversarial slice
| Category | n | Accuracy | 95% CI |
|---|---|---|---|
| Over-regularization | 5 | 0.40 | [0.12, 0.77] |
| Wrong-person agreement | 4 | 0.75 | [0.30, 0.95] |
| ...

## 5. Confusion matrix
| | pred CORRECT | pred INCORRECT | pred AMBIGUOUS |
|---|---|---|---|
| true CORRECT | 28 | 4 | 2 |
| true INCORRECT | 6 | 18 | 0 |
| true AMBIGUOUS | 1 | 0 | 1 |
## 6. Generation sub-eval (pass@k)
| Prompt cell | pass@1 | pass@10 |
|---|---|---|
## 7. Interpretation
<one paragraph; Borja writes>
## 8. Caveats
- Probe set N=60 → per-cell counts are small → wide CIs.
- ES tokenizer was Phase-11 EN-biased; expect inflated ES PPL.
- Adversarial category cells with n<3 are flagged but reported.
TODOs¶
Bloque A — src/eval/report.py¶
def render_report(results_path: Path, out_path: Path) -> None:
"""Read results.json + per_slice.csv; write REPORT.md."""
...
- Carga
results.json,per_slice.csv, incrusta referencias a PNG. - Renderiza cada tabla como Markdown.
- Inserta un bloque marcador para §7 Interpretación con la marca TODO
<!-- INTERPRETATION: Borja writes 1-2 paragraphs here. -->. - Escribe en
out_path(debe estar dentro del directorio por-checkpoint).
Bloque B — src/eval/compare.py¶
def render_compare(results_a: Path, results_b: Path, out_path: Path) -> None:
"""Diff two results.json files; flag significant differences."""
...
- Tablas lado a lado para cada métrica del headline.
- Marca de significancia por fila: calcula CIs de Wilson superpuestos. Si los CIs se solapan, marca
(within noise); si no, marca▲o▼. - Diff por slice: solo se resaltan las filas donde la dirección del cambio es opuesta al cambio agregado, o donde la magnitud excede los 10 puntos porcentuales.
- Diff por categoría adversarial: mismo formato.
- Diagramas de fiabilidad: ambos PNGs incrustados lado a lado vía HTML en Markdown (
<table><tr><td>...</td></tr></table>).
Bloque C — tests/eval/test_report.py¶
test_renders_minimal_report— dado unresults.jsonfixture pequeño,render_reportemite unREPORT.mdque contiene los encabezados de sección requeridos.test_compare_within_noise— dados dosresults.jsonque difieren solo en 1pp de accuracy con N=60, la comparación marca el diff como(within noise).test_compare_significant_drop— dados dosresults.jsondonde la accuracy cae en 20pp, la comparación emite▼.test_interpretation_placeholder_present—REPORT.mdcontiene el marcador TODO.
Bloque D — escribir learners/borja/phase-20/reflections.md¶
Con tus propias palabras (300-500 palabras), responde:
- ¿Qué hace bien este modelo? Cita slices concretos.
- ¿Qué hace mal? Cita slices concretos y categorías adversariales.
- ¿Por qué? Hipotetiza la causa a partir de señales de corpus o dinámica de entrenamiento (estadísticas del corpus de la Fase 12, curvas de pérdida de la Fase 19). Ejemplos:
- "El modelo va al 60% en past-simple irregular vs 92% en past-simple regular. Sospecho que el corpus de la Fase 12 está dominado por formas regulares; las irregulares aparecen ~3× menos según
data/processed/stats.json." - "ECE es 0.18 en el checkpoint best-val de la Fase 19 vs 0.09 en el final de la Fase 18. El best-val se seleccionó solo contra val loss, que no penaliza la sobreconfianza — el entrenamiento más largo de la Fase 18 llevó a salidas mejor calibradas incluso con val loss ligeramente más alta."
- ¿Qué cambiaría? No lo arregles aquí — la Fase 20 mide, no entrena. Lista los puntos como TODOs para fases futuras (Fase 28 LoRA, regeneración de corpus de la Fase 12, etc.).
Bloque E — también rellena la interpretación §7 en cada REPORT.md¶
El marcador debe reemplazarse. La interpretación es el entregable; los números son andamiaje para la frase.
Restricciones¶
- Solo Markdown. Sin trucos HTML salvo la tabla de dos-PNGs-lado-a-lado (aceptable porque mkdocs la renderiza).
- REPORT.md cabe en una pantalla de encabezados. Usa
detailscolapsables si hace falta, pero los headlines deben verse sin hacer scroll. - Borja escribe la prosa. Claude puede borrar un borrador, pero la reflexión en
learners/borja/phase-20/reflections.mdes inconfundiblemente de Borja — primera persona.
Condiciones de parada¶
Hecho cuando:
pytest tests/eval/test_report.py -vpasa.- Ambos checkpoints tienen un
REPORT.mdpoblado (sin marcadores TODO restantes). experiments/20-eval-report/COMPARE.mdexiste y resalta al menos una diferencia significativa (o declara explícitamente "no significant differences detected" con el razonamiento).learners/borja/phase-20/reflections.mdtiene al menos 300 palabras e identifica los tres slices más débiles, con causas hipotetizadas.
Trampas¶
- Reportar medias donde los slices discrepan. Si EN está en 0.85 y ES en 0.55, el agregado (~0.70) es el número menos informativo. Lidera con la tabla por slice, no con el agregado.
- Marcar significancia con demasiada alegría. N=60 y diferencias de 5pp están dentro del ruido. Solo marca diferencias ≥10pp con CIs no solapados. De lo contrario los lectores se acostumbran a ignorar las flechas.
- Rellenar §7 reformulando métricas. "PPL es 7.42 y accuracy es 0.78" — eso es la tabla. La interpretación dice qué implican esos números. Fuérzate a escribir al menos una frase que ate el comportamiento del modelo a una preocupación downstream (agente tutor de la Fase 32, riesgo de deployment, hueco en el corpus).
- Olvidar los caveats. El sesgo del tokenizer ES, el N pequeño por celda, el sesgo de curación manual del probe set — todo esto acota la validez del informe. Lístalos.
Cuándo consultar solutions/¶
Después de que pasen los cuatro tests y ambos REPORTs + COMPARE estén poblados. La solución en solutions/03-report-ref.md (escrita al abrir la fase) muestra un párrafo de interpretación de ejemplo que es específico, hipotetiza causas, y apunta a un arreglo futuro sin intentar arreglarlo en la Fase 20.
Fin de los labs de la Fase 20. Toca escribir PHASE_20_REPORT.md (el informe a nivel de fase, no el REPORT.md de eval) y prepararse para la Fase 21.
Siguiente: Fase 21 — Inference Internals & Sampling.