Proyecto: ajustar un modelo pequeño en Colab
20 min de lectura
De la cadena que el bloque ha montado sobre el mini-GPT, el primer eslabón dejó una predicción por comprobar. El ajuste supervisado (supervised fine-tuning, SFT) le enseñó a un modelo preentrenado con tokens de Galdós la forma de diez respuestas y ningún contenido, y la lección anticipó lo que pasaría en el otro extremo: con miles de pares variados y un modelo que lo ha leído casi todo, respuestas útiles. De ese otro extremo salen los modelos abiertos, y la referencia de la que parte todo lo que el bloque ha puesto después.
¿Qué cuesta comprobarlo? Esa cuenta es lo primero que hace esta lección, porque decide dónde corre el proyecto. El modelo es Qwen2.5-0.5B, uno de los modelos abiertos más pequeños que se publican, y ajustarlo entero pide casi el doble de la memoria que el Python del navegador puede llegar a usar: su implementación es un cuaderno de Colab, con una GPU (graphics processing unit) prestada. Lo segundo es mirar dentro del modelo antes de ajustarlo, y lo que aparece es un problema que el bloque ya conoce.
El cuaderno repite, línea por línea, el ajuste supervisado del mini-GPT: una plantilla con otros nombres, la misma máscara, la misma pérdida y el bucle de la lección sobre entrenar el mini-GPT. Cambian los números:
| el mini-GPT | Qwen2.5-0.5B | |
|---|---|---|
| parámetros | ||
| entradas del vocabulario | ||
| texto del preentrenamiento | tokens de una novela | tokens |
| pares del ajuste | , escritos por mí | , escritos por voluntarios |
| tokens especiales de la plantilla | , sin entrenar | , sin entrenar |
| dónde se ajusta | una celda del navegador | un cuaderno de Colab, con GPU |
La fila que decide el resultado es la tercera. La pérdida del ajuste sólo habla de los pares del conjunto, y lo que el modelo haga con cualquier otra instrucción lo deciden los pesos que comparten todas y el sitio del que partieron: es lo que la pérdida no dice. Para el mini-GPT, ese sitio era una novela, y diez pares de colores no tenían ningún contenido que sacar de ella. Qwen leyó en su preentrenamiento unos ciento cuarenta millones de veces más texto, en más de 29 idiomas, el español entre ellos. El contenido ya está en sus pesos, y lo que los pares tienen que enseñarle es a sacarlo en forma de respuesta.
Lo que cuesta ajustar 494 millones de parámetros
Contemos primero lo que hay que mover. Qwen2.5-0.5B tiene bloques de y un vocabulario de entradas, y el fichero de sus pesos trae parámetros. Más de la cuarta parte son la tabla de embeddings, atada a la salida como la del mini-GPT:
El total sale del fichero y no de la cuenta por bloque de la lección sobre la caché, que aquí no da exacta: el perceptrón de Qwen tiene tres matrices y no dos, y sus cabezas comparten las claves y los valores por grupos.
Entrenar pide más que los pesos. Cada parámetro lleva al lado su gradiente, y AdamW guarda por cada
uno las dos medias móviles del Adam del mini-GPT, y . Son cuatro
números por parámetro, de cuatro bytes cada uno en coma flotante de 32 bits:
y todavía no se ha guardado ni una activación. Las de la ida, que la vuelta necesita, crecen con la longitud de la conversación, y sólo los logits de una posición son ya números: con 512 posiciones, GB.
Una pestaña del navegador no llega. Pyodide, el Python que ejecuta las celdas del curso, está compilado a WebAssembly de 32 bits: una dirección de memoria tiene 32 bits, y con ellas se numeran como mucho bytes, unos GB. Los pesos y sus gradientes ya ocupan de ellos. A Pyodide le falta también PyTorch, pero eso tendría arreglo, porque el mini-GPT se entrenó en NumPy sin él. La memoria, no.
Ni el tiempo. La lección sobre entrenar el mini-GPT midió en el navegador algo menos de un milisegundo por token de ida y vuelta para sus parámetros, y lo que cuesta un token es proporcional a : es el de la lección sobre las leyes de escala. Qwen tiene veces más parámetros, unos segundos por token. Los pares del cuaderno suman tokens, y una sola época tardaría
más de un mes con la pestaña abierta. Las celdas del curso se cortan a los diez segundos.
En una GPU, las cuentas cambian de escala. El cálculo de esa época, en operaciones de coma flotante (floating-point operations, FLOPs), es el de aquella lección con :
La T4 que Colab presta gratis hace hasta de esas operaciones por segundo en coma flotante de 32 bits. A pleno rendimiento son cinco minutos; en la práctica, más. Tiene 16 GB de memoria, y el ajuste cabe entero: los GB, y al lado las activaciones de una conversación cada vez.
Si no cupiera, la salida habitual sería no mover los parámetros. LoRA (low-rank adaptation) los congela y entrena, al lado de cada matriz, dos matrices estrechas cuyo producto se le suma, y los gradientes y las medias móviles se quedan en una fracción mínima de los GB. Aquí no hace falta, y queda fuera del curso.
La misma pérdida, con la plantilla de Qwen
Qwen usa ChatML (Chat Markup Language), la plantilla que la lección sobre la plantilla de chat nombró como la más extendida entre los modelos abiertos. Tiene dos tokens especiales y una diferencia con la del mini-GPT: el rol no tiene token propio. Cada mensaje abre con <|im_start|>, sigue con el nombre del rol escrito en tokens corrientes, user o assistant, y un salto de línea, y cierra con <|im_end|>, el token de fin de mensaje, y otro salto.
La máscara es la de aquella lección: 1 en el contenido de la respuesta y en su <|im_end|>, 0 en todo lo demás, el rol del asistente y su salto incluidos, porque los escribe la plantilla antes de que el modelo tome la palabra. En la respuesta de la nieve se cobran ocho tokens, los siete de La nieve es blanca. y el <|im_end|>. La pérdida es la de la lección sobre el ajuste supervisado sin cambiar un símbolo: en cada paso, la suma de sobre los tokens cobrados de un batch, dividida entre cuántos son.
Dos filas que el preentrenamiento no distinguió
Ahí está el problema conocido. En el modelo preentrenado, la fila de <|im_end|> en la tabla de embeddings es, hasta el redondeo, la de <|im_start|>, y la de las 290 entradas que van detrás hasta el final de la tabla: otros especiales que Qwen reserva para otros usos y filas de relleno que no corresponden a ningún token. El cuaderno lo comprueba: las 292 filas miden entre y , y el coseno entre dos cualesquiera es 1 hasta la cuarta cifra. El preentrenamiento no distinguió nunca entre ellas.
Con la tabla atada, el logit de una entrada es , y filas iguales dan logits iguales en cualquier posición. Las 292 entradas empatan, y el softmax les da a todas la misma probabilidad. Entre todas no pasan de 1, así que cada una, y <|im_end|> con ellas, se queda en
en cada posición de cualquier respuesta. Es la cota de la lección sobre la plantilla, para un especial del mini-GPT, con otra razón detrás: allí, las filas nuevas empezaban en la media de la tabla; aquí, el preentrenamiento las ha dejado iguales.
La consecuencia se ve en cuanto el modelo escribe. Si cada posición cierra con probabilidad como mucho, una respuesta muestreada tiene de media 292 tokens o más, y la generación voraz, que sólo elegiría <|im_end|> si ninguna otra entrada pasara de , no la cierra. El modelo preentrenado no sabe terminar. De todo lo que el ajuste le enseña, lo más nuevo es el token que cierra cada respuesta, y ningún texto se lo enseñó antes.
El cuaderno, y qué mirar mientras corre
El proyecto no corre sobre tu mini-GPT ni sobre ningún modelo del navegador. Corre sobre Qwen2.5-0.5B en su versión preentrenada, la que Qwen publica como base, frente a la instruct, ya ajustada. Su licencia es Apache 2.0, y el cuaderno lo carga fijado a un commit, igual que fija las versiones de las bibliotecas.
Abrir el cuaderno en Colab
Antes de ejecutar nada, elige en el menú de Colab un entorno con GPU; la segunda celda dice cuál te ha tocado. Después, el cuaderno recorre esta lección en orden. Imprime las cuentas de la primera sección, escribe la plantilla a mano y la compara con la que trae la biblioteca (que, si no le das un mensaje de sistema, añade uno en inglés que nadie ha escrito), y mide las 292 filas. Le hace al modelo preentrenado cinco instrucciones que he escrito yo, y ninguna de las cinco respuestas llega a su <|im_end|>: cuatro repiten la instrucción una y otra vez, y la quinta da vueltas a una frase.
Los pares salen de OpenAssistant Conversations, un conjunto que escribieron y puntuaron más de voluntarios en 2023, en 35 idiomas, con licencia Apache 2.0. De cada conversación en español, el cuaderno toma el primer mensaje y la respuesta que los voluntarios pusieron primera al compararla con las demás: un par de ajuste supervisado escogido con una comparación, como las de la lección sobre de dónde salen las preferencias. Descarta las conversaciones de más de 512 tokens en vez de cortarlas, porque una respuesta cortada no llega a su <|im_end|>. Quedan pares con tokens, de los que se cobra el 86 %, y los 169 de la parte de validación quedan reservados para medir.
El ajuste es una época, 203 pasos de 16 conversaciones, con el bucle de la lección sobre entrenar el mini-GPT: AdamW, recorte del gradiente a norma 1 y su calendario, calentamiento y coseno hasta la décima parte. La tasa máxima es , 250 veces menos que la del ajuste del mini-GPT, que tenía que verse en doce pasos y se llevó la novela por delante; ésta tiene que dejar en su sitio lo que Qwen sabe. Las conversaciones pasan de una en una y cada una suma su gradiente al del batch, así que ninguna se rellena. Al final, la celda imprime cuánto ha tardado y la memoria que llegó a ocupar la GPU: compárala con los GB.
El cuaderno mide tres números antes del ajuste y después. La pérdida en las respuestas reservadas, en nats por token cobrado: antes, , cuando repartir por igual costaría . El texto de las respuestas ya lo predice bien, aunque no sepa escribirlo en su turno. La probabilidad media que da a <|im_end|> justo donde una respuesta reservada acaba: antes, , más de sesenta mil veces por debajo de la cota. Y la pérdida en el final de Marianela, de donde salió el trozo con que la lección sobre el ajuste supervisado midió el olvido: antes, nats por token de Qwen, un número que sólo se compara con el suyo de después. Mira cuánto se mueve cada uno, y vuelve a darle las cinco instrucciones. La última es la pregunta de la Gran Muralla de la lección anterior: fíjate en qué contesta, y pregúntate de dónde lo saca.
Comprueba tu intuición
Tres preguntas: por qué esto no cabe en el navegador, qué tokens cobra el ajuste y qué asegura la cota.
Ajustar entero Qwen2.5-0.5B no cabe en una celda del curso. Marca lo que, por sí solo, ya lo impediría.
Marca todas las opciones correctas. Se corrige todo o nada: no hay puntuación parcial.
Con la plantilla de Qwen, un par del cuaderno termina en estos tokens: <|im_start|>, assistant, un salto de línea, los siete de La nieve es blanca., <|im_end|> y otro salto de línea. Marca los que entran en la pérdida del ajuste.
Marca todas las opciones correctas. Se corrige todo o nada: no hay puntuación parcial.
En el modelo preentrenado, la fila de <|im_end|> es la de otros 291 tokens. Muestreas respuestas con el modelo tal cual, con y sin ningún corte, hasta que sale <|im_end|>. ¿Qué puedes asegurar de su longitud?
El ajuste supervisado hace obedecer a un modelo en la forma de sus pares. Lo que el modelo dice, en cambio, sale de dos sitios y de ninguno más: de lo que sus pesos guardaron del preentrenamiento y de cómo escribían quienes redactaron las respuestas. Nada en el ajuste comprueba que sea verdad. Si los pesos no saben si la Muralla se ve desde la Luna, la respuesta tendrá igual forma de respuesta.
Queda una palanca que no toca los pesos: lo que va en el prompt. Un prompt puede darle al modelo lo que sus pesos no saben, pedirle una respuesta que se pueda comprobar y decirle con exactitud qué se espera de ella. La lección siguiente abre el bloque 3 por ahí, con el prompt como especificación.
Para profundizar3 fuentes · 3 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.
- Qwen2.5 Technical Report
El informe del modelo del cuaderno. Su preentrenamiento leyó 18 billones de tokens, y la versión instruct añade encima lo que este bloque ha contado: un ajuste supervisado con más de un millón de ejemplos y varias etapas de refuerzo.
- OpenAssistant Conversations: Democratizing Large Language Model Alignment
Los datos del cuaderno: 161 443 mensajes en 35 idiomas, escritos y puntuados por más de 13 500 voluntarios. Cuenta cómo se clasificaron las respuestas, de donde sale la preferida que el cuaderno toma de cada conversación.
- LoRA: Low-Rank Adaptation of Large Language Models
La salida cuando el ajuste entero no cabe, que esta lección enuncia sin derivar: congelar los pesos y entrenar dos matrices estrechas al lado de cada uno. En GPT-3, la memoria del ajuste baja de 1.2 TB a 350 GB.