Skip to content

English · Español

Break 00 — Barajar las codificaciones posicionales entre posiciones

Tomamos las codificaciones posicionales (positional encodings) sinusoidales y barajamos las filas. PE[t] ya no corresponde a la posición t, sino a una posición aleatoria. La attention sigue funcionando, pero el modelo recibe información posicional permutada. Predicción: la pérdida se queda en log(V) (no aprende nada), porque la posición ahora es ruido. Comparar contra "sin PE" muestra que alguna información posicional, incluso inconsistente, es estructuralmente distinta de ninguna.

Anclas: LYNX_CORTEX.md §4 / PHASE 16; theory §00 equivariancia bajo permutación; theory §01 sinusoidal; .claude/commands/break.md.


El break

En src/minimodel/nn/positional.py:

class SinusoidalPositionalEncoding(Module):
    def __init__(self, max_len: int, d_model: int, seed: int = 0) -> None:
        super().__init__()
        pe = self._build_pe(max_len, d_model)  # shape (max_len, d_model)

        # BUG: shuffle the rows of pe.
        rng = np.random.default_rng(seed)
        perm = rng.permutation(max_len)
        pe = pe[perm]                                   # permute rows
        self.pe = Tensor(pe, requires_grad=False)

Los valores de PE siguen siendo vectores sinusoidales válidos; simplemente están asociados a las posiciones equivocadas. El patrón en t = 3 podría ser el patrón que debería estar en t = 17.

Predice, luego ejecuta

El modelo depende de PE para romper la equivariancia bajo permutación de la attention (theory §00). El PE sinusoidal codifica la posición mediante una relación de fase específica — PE[t] y PE[t+1] están "cerca" en similitud coseno. Barajar destruye esta relación de vecindad.

La attention dispone entonces de información posicional que es:

  • Consistente por posición (dentro de un único forward pass, PE[3] es siempre el mismo vector).
  • Globalmente sin sentido (el vector de la posición 3 puede parecerse al de la posición 17, no al de la 2 o la 4).

Esto implica:

  1. Frases idénticas obtienen embeddings idénticos (así que el modelo puede técnicamente memorizarlas).
  2. Pero el modelo no puede aprender que "la siguiente palabra depende de la posición inmediatamente anterior" — porque "inmediatamente anterior" ya no es detectable desde el PE.

Predicciones

  1. La pérdida de entrenamiento baja despacio a medida que el modelo memoriza el train set.
  2. La pérdida de validación se queda cerca de log(V) porque el PE barajado no generaliza — los ejemplos de entrenamiento tienen una baraja, los de validación tienen la misma baraja, pero el modelo ha aprendido f(token_3, pe_17) en lugar de f(token_3, position_3).
  3. Si se vuelve a barajar el PE entre entrenamiento y evaluación (otro bug aparte), todo empeora — distintos valores de PE para las mismas posiciones.
  4. Comparado con "sin PE en absoluto": el modelo roto es al menos igual de malo. A veces, peor.

Escribe las predicciones en learners/borja/phase-16/notes/breaks.md antes de ejecutar.

Observa

just exp 16-train --tag broken-shuffled-pe

Diagnósticos:

  1. Dibuja la pérdida de train y val. Train debería memorizar despacio; val debería estancarse.
  2. Calcula las matrices de attention del modelo entrenado sobre una frase reservada. Compáralas con el modelo sin modificar — las filas de attention del modelo roto parecen aleatorias.
  3. Calcula la similitud coseno cos(PE[t], PE[t+1]) — para el PE sinusoidal está cerca de 1 (los vecinos son similares). Para el PE barajado, es ~0.

Síntoma que Borja verá

  • La pérdida de train decrece (memorización).
  • La pérdida de val se queda en log(V) ≈ log(512) = 6.24 o cerca.
  • El gap entre train/val es enorme.
  • cos(PE[t], PE[t+1]) es ~0 (era ~0.99 en el caso sin romper).

Causa oculta (una frase)

pe = pe[perm] barajó las filas del positional encoding, destruyendo la relación de fase suave que permite al PE sinusoidal codificar la posición relativa.

Cascada de pistas

  1. ¿Qué propiedad codifica el PE sinusoidal que hace que las posiciones cercanas tengan vectores similares? Imprime cos(PE[t], PE[t+k]) para k = 1, 2, 5, 10.
  2. El modelo puede memorizar el train set pero no generalizar. ¿Qué te dice eso sobre la estructura globalmente significativa del PE?
  3. Mira SinusoidalPositionalEncoding.__init__. ¿Hay algún procesamiento extra después de _build_pe que no esperarías?

Diff de arreglo

# Remove the shuffling.
self.pe = Tensor(pe, requires_grad=False)

Por qué esto enseña el concepto

El PE sinusoidal funciona gracias a la relación de fase suave entre posiciones adyacentes — Vaswani et al. 2017 §3.5 lo motiva precisamente para que "para cualquier offset fijo k, PE[t+k] se pueda representar como una función lineal de PE[t]". Barajar rompe la propiedad de offset-como-función-lineal. El modelo todavía puede aprender hechos específicos por posición, pero no puede aprender la estructura relacional que hace que "la palabra antes de was" sea una consulta significativa. RoPE (theory §03) tiene la misma propiedad por construcción — y por eso theory §04 predice que RoPE gana en extrapolación. Este /break hace que la propiedad sea concreta.


Siguiente: el /break de la Fase 17 sobre la máscara causal ausente.