Skip to content

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.95 es 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:

\[S_p = \{i_1, i_2, ..., i_k\} \quad \text{donde} \quad \sum_{j=1}^{k-1} p_{i_j} < p \leq \sum_{j=1}^{k} p_{i_j}\]

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.0 es malo. Deja que la cola (conjugaciones de baja probabilidad como er en esta distribución) se cuele en las salidas. El tutor sugeriría ocasionalmente formas salvajemente erróneas.
  • p = 0.5 es 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.95 es 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.