Una sola columna: el modelo de lenguaje causal

Una sola columna: el modelo de lenguaje causal

20 min de lectura

El curso anterior se despidió, con sus propias palabras, dejándote «delante de un artículo que puedes discutir» y no delante de un modelo que funcione: un Transformer entero en NumPy, y unos pesos ajenos afinados una vez en un cuaderno fuera del navegador. Una lección antes había tomado la decisión de la que vive todo lo que sigue: de las dos columnas del artículo, GPT se queda con la derecha y pone la máscara en todas sus auto-atenciones, y se le pide el token siguiente. Ese objeto se llama modelo de lenguaje, y aquel curso lo definió dos veces como una pérdida por posición: sobre una RNN de caracteres, y sobre el Transformer.

Hay una pregunta que ninguna de esas dos veces hizo, y esta lección existe para hacerla: ¿qué probabilidad le da el modelo a un texto entero? No a la posición siete de un texto: al texto. Resulta ser la pregunta que ordena todo lo demás. De su respuesta sale por qué la máscara causal no es una restricción que se paga sino la razón de que entrenar quepa en una pasada, qué número exacto mide un modelo de lenguaje y, al final del bloque, cómo un modelo entrenado sólo para continuar texto acaba haciendo tareas que nadie le enseñó. Hoy toca lo primero.

Tapa con la mano lo que sigue a En un lugar de la y di qué viene. Lo has dicho antes de terminar de leer: tras En un lugar de cabían cien cosas; tras En un lugar de la, casi sólo Mancha. Un modelo de lenguaje es ese jugador. Lee lo que hay a la izquierda y reparte su «apuesta» entre las entradas del vocabulario para la posición siguiente, y el texto, sin que nadie lo etiquete, trae escrita la respuesta correcta de cada posición.

Lo que el curso anterior no dijo es que ese juego, jugado posición a posición, es una probabilidad para el texto entero. La probabilidad de que salga En y luego un es la de En por la de un sabiendo que vino En; añade lugar y multiplicas otra vez. Multiplica las apuestas en orden y tienes la apuesta del modelo por el texto.

Y la máscara es lo que permite hacer las TT apuestas de un texto a la vez. La posición tt sólo ve lo que hay a su izquierda, así que su apuesta es la misma con el resto del texto a su derecha que sin él: puedes poner el texto entero sobre la mesa, con las respuestas a la vista, y leer las TT apuestas de una sola pasada.

Una distribución sobre textos, y la cadena que la factoriza

Fijemos el vocabulario VV y llamemos xt∈Vx_t \in V al token que ocupa la posición tt de un texto: x1:Tx_{1:T} es el texto entero, x<tx_{<t} lo que hay antes de la posición tt y x≤tx_{\le t} lo mismo con esa posición incluida. (El curso anterior escribía wtw_t; aquí es xtx_t, la letra que allí era la fuente de un traductor.) Un modelo de lenguaje asigna a cada texto de TT tokens un número pθ(x1:T)p_\theta(x_{1:T}), no negativo y tal que, sumado sobre todos los textos de esa longitud, da 11: una distribución sobre las secuencias de TT tokens, para cada TT. El subíndice dice de quién es la distribución: de los pesos θ\theta, no del español. Lo que el modelo cree, no lo que es.

No hace falta guardar un número por texto. Con dos tokens, p(x1,x2)=p(x1) p(x2∣x1)p(x_1, x_2) = p(x_1)\,p(x_2 \mid x_1): la probabilidad de que pasen dos cosas es la de la primera por la de la segunda sabida la primera, que es la definición de probabilidad condicionada leída al revés. Aplicada T−1T - 1 veces,

pθ(x1:T)=∏t=1Tpθ(xt∣x<t),p_\theta(x_{1:T}) = \prod_{t=1}^{T} p_\theta(x_t \mid x_{<t}),

con x<1x_{<1} la secuencia vacía, de modo que el primer factor es pθ(x1)p_\theta(x_1) a secas. Es la regla de la cadena de la probabilidad (comparte nombre con la de las derivadas, y nada más), y es una identidad: toda distribución sobre textos se escribe así, sea la que sea. Elegir la forma causal no aproxima nada; lo único que hay que aproximar es cada factor, y para eso está la red.

Ver por qué la factorización es exacta, y por qué su recíproco también

Para dos posiciones, la probabilidad condicionada se define como p(x2∣x1)=p(x1,x2)/p(x1)p(x_2 \mid x_1) = p(x_1, x_2) / p(x_1) cuando p(x1)>0p(x_1) > 0, así que p(x1,x2)=p(x1) p(x2∣x1)p(x_1, x_2) = p(x_1)\,p(x_2 \mid x_1) es esa definición con el denominador pasado al otro lado. Para TT posiciones, toma como «primera cosa» el prefijo x1:T−1x_{1:T-1} y como «segunda» el token xTx_T: p(x1:T)=p(x1:T−1) p(xT∣x<T)p(x_{1:T}) = p(x_{1:T-1})\,p(x_T \mid x_{<T}), y el primer factor es el mismo problema con una posición menos. Repetido hasta p(x1)p(x_1), sale el producto.

El recíproco es lo que hace que la red sea un modelo de lenguaje. Si cada factor es una distribución sobre VV, el producto lo es sobre las secuencias de TT tokens: al sumar sobre xTx_T sólo el último factor depende de él, y suma 11; repite con xT−1x_{T-1}, y así hasta que no queda ningún factor y la suma vale 11. Con TT softmax cualesquiera, el producto es una distribución legítima sobre los textos.

Y ahí entra la red. Entre los tokens y los números está la columna derecha del Transformer tal como la montaste en el proyecto del Transformer, sin la subcapa que miraba a la otra columna: la tabla, los bloques con su máscara, y la tabla leída al revés. Lo que sale por arriba en la posición tt es un vector zt∈R∣V∣\mathbf{z}_t \in \mathbb{R}^{\lvert V \rvert}, los logits de esa posición: la preactivación de la capa de salida del curso anterior. Apilados por filas dan Z∈RT×∣V∣\mathbf{Z} \in \mathbb{R}^{T \times \lvert V \rvert}, una fila por posición leída y una columna por entrada. El softmax de la lección sobre las funciones de pérdida convierte cada fila en la distribución que el producto necesita:

pθ(xt+1∣x≤t)=softmax(zt)xt+1=ezt, xt+1∑v∈Vezt, v.p_\theta(x_{t+1} \mid x_{\le t}) = \text{softmax}(\mathbf{z}_t)_{x_{t+1}} = \frac{e^{z_{t,\,x_{t+1}}}}{\sum_{v \in V} e^{z_{t,\,v}}}.

Fíjate en el desplazamiento: la fila tt se calcula con x≤tx_{\le t} y apuesta por xt+1x_{t+1}, así que el factor de la posición tt del producto, pθ(xt∣x<t)p_\theta(x_t \mid x_{<t}), sale de la fila t−1t - 1.

Todas las condicionales en una sola pasada

Cada factor del producto pide, en principio, una pasada por la red con su propio prefijo: x≤1x_{\le 1}, luego x≤2x_{\le 2}, y así. Serían TT pasadas por texto. Lo que las convierte en una es la máscara, y el argumento es el que el proyecto del Transformer dejó demostrado y aquí sólo se cita: con la máscara en cada bloque, la fila tt de lo que sale depende únicamente de las filas 11 a tt de lo que entró, y eso sobrevive a apilar. Con lo que el zt\mathbf{z}_t calculado sobre el texto entero es, número a número, el que saldría de pasar sólo el prefijo:

zt(x1:T)=zt(x≤t)para todo t,\mathbf{z}_t(x_{1:T}) = \mathbf{z}_t(x_{\le t}) \quad \text{para todo } t,

donde el argumento indica qué se le dio a la red. Una sola pasada sobre x1:Tx_{1:T} devuelve las TT filas de Z\mathbf{Z}, con los TT factores del producto dentro.

Qué texto se le pasa y contra qué se compara es el desplazamiento de la lección sobre las máscaras sin ningún cambio: de una ventana de T+1T + 1 tokens del corpus, la red lee los TT primeros, y la fila tt se compara con el token t+1t + 1, que es la misma ventana corrida una posición. Eso era el teacher forcing (el token verdadero en cada posición, no el que el modelo habría escrito), y aquí es lo que hace que cada fila sea la condicional que el producto pide y no otra.

Dos cosas más, dichas en voz alta. El primer factor, pθ(x1)p_\theta(x_1), no lo calcula ninguna fila, porque no hay fila con nada delante. El curso anterior ponía ahí <GO>; el mini-GPT de este bloque prescinde de él: el primer token de cada ventana se da y no se predice, y lo que la red modela de una ventana es pθ(x2:T+1∣x1)p_\theta(x_{2:T+1} \mid x_1), con TT factores y no T+1T + 1. Y sin la máscara pasa lo que la lección sobre BERT y GPT usó para descartar un encoder entrenado contra el token siguiente: la fila tt contendría ya xt+1x_{t+1}, y la manera más barata de bajar la pérdida sería copiar. La máscara no es una restricción que el modelo paga: es lo que hace que la barra vertical diga la verdad.

La pérdida: menos el logaritmo del producto, por token

Entrenar es hacer que el modelo apueste fuerte por los textos del corpus: subir pθ(x2:T+1∣x1)p_\theta(x_{2:T+1} \mid x_1) sobre sus ventanas. Un producto de TT números entre 00 y 11 es minúsculo e incómodo de derivar; su logaritmo es una suma, y con el signo cambiado, un coste. Repartido entre las TT apuestas,

L(θ)=−1T∑t=1Tlog⁡pθ(xt+1∣x≤t)=−1Tlog⁡pθ(x2:T+1∣x1),\mathcal{L}(\theta) = -\frac{1}{T}\sum_{t=1}^{T}\log p_\theta(x_{t+1} \mid x_{\le t}) = -\frac{1}{T}\log p_\theta(x_{2:T+1} \mid x_1),

que es la entropía cruzada del curso anterior con la etiqueta puesta en el token que de verdad vino, una por fila, promediada. Cada fila le cobra al modelo −log⁡-\log de lo que apostó por la verdad: nada si lo apostó todo, ln⁡∣V∣\ln \lvert V \rvert si repartió por igual, y sin techo si apostó casi nada. Es el número que el modelo de lenguaje de caracteres imprimía en cada vuelta; lo nuevo es saber que exp⁡(−T L)\exp(-T\,\mathcal{L}) es la probabilidad que el modelo le da a la ventana, y que entrenar es subirla.

La cuenta a mano, con cuatro tokens

Esta lección no lleva celda a propósito: el modelo que cumple todo lo de arriba, el mini-GPT de este bloque, lo cargas y lo entrenas más adelante, en la lección sobre entrenar un mini-GPT. Aquí el modelo es una hoja de papel: los logits me los he inventado yo, elegidos para que eze^{z} salga entero. Los tokens son palabras, para que quepan en una hoja; el vocabulario del mini-GPT no está hecho de palabras, y de eso trata la lección siguiente, sobre BPE.

Toma la ventana la casa es blanca y el vocabulario de sus cuatro palabras, en orden alfabético: V={blanca,casa,es,la}V = \{\textit{blanca}, \textit{casa}, \textit{es}, \textit{la}\}. El primer token se da, así que hay tres apuestas, y en cada fila la red ve el prefijo y nada más:

ttlo que ve la fila, x≤tx_{\le t}lo que viene, xt+1x_{t+1}zt\mathbf{z}_t, en el orden de VV
11lacasa(ln⁡2,  ln⁡4,  0,  0)(\ln 2,\; \ln 4,\; 0,\; 0)
22la casaes(ln⁡4,  0,  ln⁡2,  0)(\ln 4,\; 0,\; \ln 2,\; 0)
33la casa esblanca(ln⁡4,  ln⁡2,  0,  0)(\ln 4,\; \ln 2,\; 0,\; 0)

Haz tres cosas con cada fila, mirando sólo sus números:

  1. Exponencia los cuatro logits y súmalos. En la fila 11 sale (2,4,1,1)(2, 4, 1, 1), que suma 88; comprueba que las otras dos también suman 88 (elección mía, no casualidad).
  2. Divide la casilla del token que de verdad vino entre esa suma: es pθ(xt+1∣x≤t)p_\theta(x_{t+1} \mid x_{\le t}). En la fila 11, casa es la segunda casilla: 4/8=1/24/8 = 1/2.
  3. Toma −ln⁡-\ln de ese número: −ln⁡(1/2)=ln⁡2≈0.693-\ln(1/2) = \ln 2 \approx 0.693.

Te tienen que salir 1/21/2, 1/41/4 y 1/21/2, que cuestan ln⁡2\ln 2, 2ln⁡22\ln 2 y ln⁡2\ln 2, y la media es

L=ln⁡2+2ln⁡2+ln⁡23=43ln⁡2≈0.924,\mathcal{L} = \frac{\ln 2 + 2\ln 2 + \ln 2}{3} = \frac{4}{3}\ln 2 \approx 0.924,

frente al ln⁡4≈1.386\ln 4 \approx 1.386 de un modelo que repartiera por igual y al 00 de uno que lo apostara todo a la verdad, siempre. Y ahora por el otro lado: multiplica las tres apuestas. 12⋅14⋅12=116\frac{1}{2} \cdot \frac{1}{4} \cdot \frac{1}{2} = \frac{1}{16} es pθ(casa,es,blanca∣la)p_\theta(\textit{casa}, \textit{es}, \textit{blanca} \mid \textit{la}), la probabilidad de la ventana dado su primer token, y exp⁡(−3⋅43ln⁡2)=2−4\exp\left(-3 \cdot \frac{4}{3}\ln 2\right) = 2^{-4} es el mismo dieciseisavo. La media de los −log⁡-\log y el producto de las probabilidades son un solo número visto desde dos lados.

Mira la fila 22. El modelo apostó más por blanca que por es: la casa blanca es un principio razonable, y su favorita habría fallado. La pérdida no le pregunta eso. Le pregunta cuánto apostó por lo que de verdad vino, y como a es le dio 1/41/4, le cobra 2ln⁡22\ln 2: el doble que donde acertó con 1/21/2, y no un salto de «mal» a «bien». Con 1/81/8, el triple. Acertar la favorita no aparece en la fórmula, y por eso un modelo puede mejorar mucho sin cambiar ninguna de sus favoritas. Y la fila 22 tendría los mismos logits sin blanca al final de la ventana: nunca lo vio. Ésa es la máscara en una frase, y lo que permite escribir tres filas en una tabla en lugar de tres pasadas.

Comprueba tu intuición

Cuatro preguntas sobre la máscara, la fila tt, la cadena y la ventana de arriba por el otro lado.

Una columna con la máscara causal en todos sus bloques lee una ventana de T+1T + 1 tokens. Marca lo que la máscara compra al entrenar.

Marca todas las opciones correctas. Se corrige todo o nada: no hay puntuación parcial.

La red lee x1:Tx_{1:T} y devuelve Z∈RT×∣V∣\mathbf{Z} \in \mathbb{R}^{T \times \lvert V \rvert}. ¿Qué hay en su fila tt?

Escribir pθ(x1:T)p_\theta(x_{1:T}) como el producto de las condicionales pθ(xt∣x<t)p_\theta(x_t \mid x_{<t}) es una aproximación: la probabilidad exacta de un texto necesitaría, además del producto, un término que recoja lo que las condicionales no capturan.

El modelo de la tabla de arriba le dio 1/21/2, 1/41/4 y 1/21/2 a los tres tokens que de verdad venían. ¿Qué probabilidad le da a la ventana entera, pθ(casa,es,blanca∣la)p_\theta(\textit{casa}, \textit{es}, \textit{blanca} \mid \textit{la})? Escríbela como decimal.

Se acepta un margen de ±0.001.


Todo lo de esta lección se ha contado con cuatro palabras como tokens. El vocabulario del mini-GPT que este bloque entrena tiene 512512 entradas y ninguna elegida a mano: las eligió un procedimiento. El curso anterior dijo por qué tenía que ser así, un vocabulario de palabras no es total, y las subpalabras lo arreglan partiendo lo que no conocen en trozos que sí. Lo que aquel curso no hizo, y lo dijo, fue construir uno: su explorable mostraba el resultado de BPE, y de dónde salía cada corte quedó fuera.

Ese procedimiento es la lección siguiente, sobre BPE de verdad: no partir una palabra en trozos que ya existen, sino fusionar, sobre un corpus en español, los pares más frecuentes hasta el tamaño que se quiera, y ver qué le hace eso a la ñ, a qu y a ción. Con el vocabulario en la mano, lo que queda del bloque es cargar el modelo, seguir entrenándolo, muestrear de él y medirlo, y todo eso es aritmética sobre la fórmula de hoy.

¿Te ha sido útil?
Para profundizar2 fuentes · 2 papers

De dónde sale lo de esta lección, y dónde seguir si quieres más. Nada de aquí hace falta para continuar el curso.

  • A Neural Probabilistic Language Model
    paperBengio, Ducharme, Vincent y Jauvin, 2003Journal of Machine Learning Research 3EN

    La primera red entrenada contra la regla de la cadena: su introducción abre con el producto de esta lección y explica por qué una red y no una tabla de recuentos. Con un MLP de ventana fija donde aquí hay un Transformer.

  • Prediction and Entropy of Printed English
    paperClaude E. Shannon, 1951Bell System Technical Journal 30(1)EN

    El juego de tapar con la mano, jugado por personas sobre inglés en 1951, y lo que sale de medirlo: cuánto se puede apostar por la letra siguiente. La idea de esta lección, décadas antes de la primera red que la usó.