English · Español
04 — Top-p, a mano, sobre un vocabulario de 10 tokens¶
🇪🇸 Top-p (nucleus sampling) suena exótico. No lo es: es "ordena por probabilidad descendente, suma hasta
p, descarta el resto, renormaliza". Lo derivamos a mano sobre 10 tokens, mostramos el corte exacto, y vemos por quép=0.95es el sweet spot práctico para el tutor de gramática §A13.
Esta página es el complemento numérico de theory/02-top-k-and-top-p.md. Recorremos un ejemplo completo de top-p sobre un vector de logits sintético de 10 tokens para que la aritmética del corte sea totalmente visible.
Setup¶
El mini-GPT en algún paso produce estos logits crudos para 10 candidatos al siguiente token (una distribución sintética pero realista tras un prompt moderado como She has wri___):
| Índice | Token | Logit |
|---|---|---|
| 0 | tten |
4.20 |
| 1 | tes |
1.80 |
| 2 | ting |
1.50 |
| 3 | te |
0.60 |
| 4 | t |
0.30 |
| 5 | tt |
-0.50 |
| 6 | s |
-1.20 |
| 7 | nt |
-2.10 |
| 8 | den |
-3.40 |
| 9 | er |
-4.00 |
(En una ejecución real, el vocabulario es de ~512 tokens; nos centramos en el top 10 por visibilidad.)
Paso 1 — Softmax¶
Resta el máximo por estabilidad numérica (\(4.20\)):
| Índice | Logit − max | exp(·) |
|---|---|---|
| 0 | 0.00 | 1.0000 |
| 1 | -2.40 | 0.0907 |
| 2 | -2.70 | 0.0672 |
| 3 | -3.60 | 0.0273 |
| 4 | -3.90 | 0.0202 |
| 5 | -4.70 | 0.0091 |
| 6 | -5.40 | 0.0045 |
| 7 | -6.30 | 0.0018 |
| 8 | -7.60 | 0.0005 |
| 9 | -8.20 | 0.0003 |
Suma: \(Z = 1.0000 + 0.0907 + 0.0672 + 0.0273 + 0.0202 + 0.0091 + 0.0045 + 0.0018 + 0.0005 + 0.0003 = 1.2216\)
Normaliza \(p_i = \exp(\cdot)_i / Z\):
| Índice | Token | \(p_i\) |
|---|---|---|
| 0 | tten |
0.8186 |
| 1 | tes |
0.0742 |
| 2 | ting |
0.0550 |
| 3 | te |
0.0223 |
| 4 | t |
0.0165 |
| 5 | tt |
0.0075 |
| 6 | s |
0.0037 |
| 7 | nt |
0.0015 |
| 8 | den |
0.0004 |
| 9 | er |
0.0003 |
Verificación de suma: \(\approx 1.0000\) ✓
Paso 2 — Ordenar descendente (ya ordenado en nuestro ejemplo)¶
Paso 3 — Suma cumulativa¶
| Rango | Token | \(p\) | Cumulativa |
|---|---|---|---|
| 1 | tten |
0.8186 | 0.8186 |
| 2 | tes |
0.0742 | 0.8928 |
| 3 | ting |
0.0550 | 0.9478 |
| 4 | te |
0.0223 | 0.9701 |
| 5 | t |
0.0165 | 0.9866 |
| 6 | tt |
0.0075 | 0.9941 |
| 7 | s |
0.0037 | 0.9978 |
| 8 | nt |
0.0015 | 0.9993 |
| 9 | den |
0.0004 | 0.9997 |
| 10 | er |
0.0003 | 1.0000 |
Paso 4 — Aplicar el corte top-p¶
La regla: mantén el conjunto más pequeño de tokens de mayor rango cuya probabilidad cumulativa es al menos \(p\). Luego renormaliza sobre el conjunto mantenido.
Para distintos valores de \(p\):
\(p = 1.0\) (sin truncado)¶
La cumulativa llega a 1.0 solo en el rango 10. Se mantienen los 10 tokens. Sin truncado — equivalente a un muestreo simple sobre la softmax completa. La diversidad es máxima; los tokens de la cola pueden colarse.
\(p = 0.95\) (el default recomendado en §A13)¶
La cumulativa cruza 0.95 entre el rango 3 (0.9478) y el rango 4 (0.9701). El conjunto más pequeño con cumulativa \(\geq 0.95\) es {rango 1, 2, 3} con cumulativa 0.9478 — espera. 0.9478 < 0.95. Así que también necesitamos el rango 4. El conjunto es {rango 1, 2, 3, 4} con cumulativa 0.9701.
Renormaliza sobre los 4 tokens mantenidos:
| Token | \(p\) | \(p / 0.9701\) |
|---|---|---|
tten |
0.8186 | 0.8438 |
tes |
0.0742 | 0.0765 |
ting |
0.0550 | 0.0567 |
te |
0.0223 | 0.0230 |
Los 6 tokens de cola (t, tt, s, nt, den, er) se ponen a cero. La masa de probabilidad que estaba en esos 6 se redistribuye proporcionalmente entre los 4 superiores.
\(p = 0.5\) (truncado agresivo)¶
La cumulativa cruza 0.5 ya en el rango 1 (0.8186). Así que mantenemos solo el token superior único tten. Tras renormalizar, \(p_\text{tten} = 1.0\) — esto es idéntico a greedy decoding para este prompt.
Para prompts donde la distribución es más plana (p. ej., generación abierta), \(p = 0.5\) podría mantener 3-5 tokens; para distribuciones agudamente picudas como esta (el modelo está muy confiado en tten), colapsa a greedy.
Matemática del corte, formal¶
El conjunto mantenido es:
Entonces \(\tilde p_i = p_i / \sum_{j \in S_p} p_j\) para \(i \in S_p\), en caso contrario \(\tilde p_i = 0\). Muestrea de \(\tilde p\).
Por qué importa para el tutor de gramática §A13¶
La capstone de la Fase 32 es un tutor de gramática que propone correcciones. Ajuste de la generación:
p = 1.0es malo. Deja que la cola (conjugaciones de baja probabilidad comoeren esta distribución) se cuele en las salidas. El tutor sugeriría ocasionalmente formas salvajemente erróneas.p = 0.5es malo. Colapsa a greedy en distribuciones confiadas, eliminando la capacidad del tutor de considerar múltiples completados plausibles (útil para frases con conjugaciones realmente ambiguas, p. ej., cuando existen formas regulares e irregulares de pasado para un verbo).p = 0.95es el sweet spot. Corta la basura de cola larga pero preserva los candidatos legítimos del top-\(k\) donde \(k\) varía adaptativamente con la entropía de la distribución. Para pasos confiados, \(k = 1\) o \(2\); para pasos ambiguos, \(k\) puede ser mayor.
El lab de esta fase (02-top-k-and-top-p.md) explora el sweep; el break de esta fase (break/00-...) muestra lo que p = 1.0 y p = 0.5 hacen mal sobre prompts reales.
Comparación con top-k¶
Top-k = "mantén los \(k\) tokens superiores independientemente de la masa de probabilidad". Problema: \(k = 50\) sobre una distribución aguda desperdicia 49 slots; \(k = 5\) sobre una distribución plana descarta demasiada masa. Top-p es adaptativo — ajusta el tamaño del conjunto mantenido en base a la entropía real de la distribución.
Ambos se pueden combinar: "top-50 luego top-p 0.95". Este es el default de OpenAI para modelos antiguos. A la escala de §A13 (vocab 512), combinar es innecesario — top-p solo basta.
Gotcha de implementación numérica¶
Calcular probabilidades cumulativas en fp16 es arriesgado para distribuciones de cola larga: los tokens de cola tienen \(p \sim 10^{-5}\), que está en el borde de la precisión de fp16. Haz siempre top-p en fp32 o superior, aunque el modelo corra en fp16. El overhead de 1-2 ms es irrelevante; la ganancia de corrección es real.
Cita¶
Holtzman, A. et al. (2020). The Curious Case of Neural Text Degeneration. ICLR 2020. https://arxiv.org/abs/1904.09751 — introduce nucleus (top-p) sampling, lo motiva desde el problema de "la cola larga de completados poco naturales". Las secciones 3.1 (la matemática) y 4 (comparación empírica con top-k y temperatura) son la fuente del enfoque aquí.
Recap en un párrafo¶
Muestreo top-p: softmax → ordena descendente → cumula → encuentra el prefijo más pequeño con cumulativa \(\geq p\) → renormaliza sobre ese prefijo → muestrea. Sobre una distribución sintética de 10 tokens de una continuación "She has wri___", \(p = 0.95\) mantiene los 4 tokens superiores (cumulativa 0.9701, el prefijo más pequeño que excede 0.95). \(p = 1.0\) mantiene los 10, incluida la basura. \(p = 0.5\) colapsa a greedy en esta distribución confiada. Para el tutor de gramática §A13, \(p = 0.95\) es el default recomendado — adaptativo a la entropía por paso sin admitir tokens de cola.
Referencias cruzadas: theory/02-top-k-and-top-p.md (fórmulas completas), lab/02-top-k-and-top-p.md (sweep), Fase 32 — el tutor de gramática usa estos ajustes.