Fine-tuning en la práctica
18 min read
La lección anterior, sobre BERT (Bidirectional Encoder Representations from Transformers) y GPT (Generative Pre-trained Transformer), dejó dos pilas entrenadas contra texto crudo y todavía sin oficio: representan bien el español y no sirven para nada concreto. Al despedirse hizo además una afirmación sin números —que mover esos pesos no cabe donde han cabido las celdas de este curso—. Una afirmación sin números es de las pocas cosas que este curso no se ha permitido.
¿Cuántos números hay que mover, entonces? La pregunta tiene respuesta exacta, y de ella salen las otras dos: cuánta memoria ocupan mientras se mueven y cuánto tarda una vuelta. De las tres sale la misma conclusión, y por eso esta lección no tiene celdas. Lo que tiene es un cuaderno, y hay que ir a ejecutarlo fuera.
Antes de las cuentas, mira qué es exactamente lo que se reaprovecha. La lección del proyecto de sentimiento ajustó un clasificador de reseñas de cine desde el generador de números aleatorios: 180 reseñas para entrenar, 60 guardadas, un 88.3 % de acierto sobre esas 60 y siete fallos, cuatro de ellos con un no que la bolsa de palabras no sabía dónde colocar. No lo sabía porque a la bolsa de palabras nunca le llegó el orden.
El fine-tuning hace esa misma tarea y cambia una sola cosa de sitio: debajo del clasificador ya no hay una bolsa de palabras, sino doce bloques que alguien ha entrenado durante semanas contra miles de millones de palabras en español. Lo que esa pila devuelve en cada posición depende de la frase entera, así que el no llega. Y lo que tú pones encima es diminuto, que es la parte que conviene contar despacio.
Ciento diez millones de números
El modelo del cuaderno es BETO, el BERT que la Universidad de Chile entrenó en español. Por dentro es el encoder del artículo con sus cinco números puestos: bloques, , cabezas, y un vocabulario de entradas. Con eso, la cuenta de parámetros es la de la lección sobre las quince cajas del artículo, evaluada:
que son las cuatro proyecciones de cada atención y las dos capas de cada perceptrón por posiciones, doce veces. Falta la tabla de embeddings, que en un vocabulario de este tamaño no es un detalle:
Sumadas dan , y con los sesgos, las dos normalizaciones de cada bloque y la tabla de posiciones se queda en unos millones. Guardado cada número en cuatro bytes, eso es
unos 440 MB sólo para los pesos. Entrenar pide dos cosas más al lado. Backpropagation —su lección— produce un gradiente por parámetro, que es otra copia entera; y el optimizador que usan estas bibliotecas guarda además dos números por parámetro, un promedio del gradiente y otro de su cuadrado, que es una mejora del descenso de gradiente de su lección y queda fuera de este curso. Cuatro copias de MB pasan de GB, y todavía no se ha guardado ni una activación.
Son tres cosas las que dejan esto fuera del navegador, y cada una por su cuenta ya sobraría. La primera es la más seca: no existe PyTorch compilado para el intérprete que corre en la pestaña, así que no hay manera de cargar unos pesos preentrenados aunque cupieran. La segunda es ese GB dentro de una pestaña. Y la tercera es el reloj. Una reseña truncada a posiciones cuesta, sólo hacia delante, del orden de multiplicaciones, y la pasada hacia atrás cuesta aproximadamente el doble, así que tres vueltas sobre reseñas son
Una GPU (graphics processing unit) de las gratuitas hace del orden de de esas operaciones por segundo, y por eso el cuaderno tarda minutos. Un hilo de WebAssembly sin GPU hace del orden de : la misma cuenta se mide en semanas. Las celdas de este curso se cortan a los diez segundos.
Lo único que cambia es de dónde parte el descenso
Con las cuentas hechas, lo que queda es notablemente pequeño. El bucle que corre en el cuaderno es el de la lección sobre el descenso de gradiente, letra por letra:
Lo que cambia es . En todo el curso ha salido del generador de números aleatorios; aquí sale del preentrenamiento, y esa sustitución es el fine-tuning entero. Nada más de esa línea se toca.
Encima de la pila hace falta algo que diga si una reseña habla bien o mal, porque lo que sale por arriba son filas de números y ninguna de ellas es una respuesta. El clasificador toma la fila de la primera posición —la que BERT reserva para eso— y le pone una capa de salida de dos unidades, entrenada con la entropía cruzada de la lección sobre las funciones de pérdida:
números nuevos, contra los millones que ya estaban puestos. Esos sí salen del generador, y son los únicos.
Queda la tasa de aprendizaje, y es la decisión con más consecuencias del cuaderno. El bloque 2 entrenaba con del orden de ; aquí se usa , unas cincuenta veces menos. El motivo no es la divergencia que esa lección derivó para grande, sino algo que ocurre mucho antes: está ya en un sitio que costó semanas de máquina, y un paso del tamaño que hace falta cuando se parte del ruido saca a de ese sitio en las primeras actualizaciones. Con la pérdida bajando, además, porque ajustar millones de parámetros a unos miles de reseñas es facilísimo si se permite mover los parámetros lo suficiente. Lo que se pierde por el camino no aparece en esa pérdida. El paso pequeño es lo que convierte el preentrenamiento en un punto de partida en vez de en un recuerdo.
El cuaderno, y qué mirar mientras corre
Abrir el cuaderno en Colab
Lo primero, antes de ejecutar nada: en el menú de Colab, entorno de ejecución con GPU. La primera
celda dice cuál te ha tocado, y si no hay ninguna lo dice también —el cuaderno corre igual sobre
CPU, con la última cuenta de arriba de por medio—. Las versiones de las bibliotecas están fijadas a
propósito: unos pesos preentrenados y una versión concreta de transformers son las dos mitades de
un resultado reproducible, y dejar la segunda al aire es la manera más silenciosa de que el cuaderno
deje de funcionar dentro de un año.
Después, cinco cosas, en este orden. El tokenizador viene con el modelo y no lo eliges tú: es un tokenizador de subpalabras como los de la lección sobre la tokenización, y sus entradas son exactamente las filas de la tabla de embeddings preentrenada, así que cambiarlo dejaría esas filas sin dueño. Las reseñas se parten en y , como en el proyecto del bloque 2, y se truncan a posiciones. Se dan tres vueltas. Se imprime después de cada una, y al final. Y la última celda te deja escribir tus propias frases y ver qué contesta.
Los dos números que importan son ésos, y lo que hay que mirar no es cuánto valen sino cuánto ha hecho falta para conseguirlos: tres vueltas, unos miles de ejemplos y unos minutos de GPU. Compáralo con lo que costó el 88.3 % del bloque 2 y con lo que costaron las semanas de preentrenamiento que hay debajo.
Y una concesión, dicha en voz alta porque es la primera del curso de este tamaño. En el cuaderno,
loss.backward() calcula el gradiente de todo el modelo en una línea. Eso es exactamente la
recurrencia que derivaste en la lección sobre backpropagation y programaste en la de implementar el MLP, corriendo sobre un
grafo que la biblioteca ha construido sola mientras hacía el forward pass. Es la única pieza de este
cuaderno que hace algo que tú no has escrito, y ahora sabes qué es lo que hace.
Comprueba tu intuición
Tres preguntas: por qué esto no cabe en el navegador, qué pasa si no bajas la tasa de aprendizaje y qué es exactamente lo que aporta haber preentrenado.
Todas las celdas de este curso han corrido en el navegador y ésta no. Marca lo que de verdad lo impide.
Select every correct option. This is graded all-or-nothing: there is no partial credit.
El cuaderno usa , unas cincuenta veces menos que el con el que entrenaste el MLP (multilayer perceptron) del bloque 2. ¿Qué pasa si lo dejas en ?
La lección del proyecto de sentimiento ajustó un clasificador de reseñas desde el generador de números aleatorios y acertó el 88.3 % de las 60 que no había leído. Marca lo que el preentrenamiento pone hoy sobre la mesa y aquel proyecto no tenía.
Select every correct option. This is graded all-or-nothing: there is no partial credit.
Con eso se cierra el curso. La entrada del vocabulario que en el bloque 1 tenía una fila y una sola tiene ahora un vector por frase, y entre aquella tabla y este cuaderno no hay más que lo que has escrito tú: una neurona, una pila de capas, una recurrencia, dos compuertas, una atención y quince cajas. El modelo que acabas de ajustar no lleva dentro ni una operación que no hayas derivado antes en una lección y ejecutado después en una celda.
Lo que queda es leer. Attention is All You Need es un artículo corto y ahora se lee caja por caja —la lección sobre las quince cajas las puso todas sobre su figura 1—, y detrás de él hay una literatura que se dedica a cambiarle piezas: otras maneras de codificar la posición, atenciones que calculan lo mismo moviendo menos memoria, bloques donde cada token activa sólo una parte del perceptrón, variantes para contextos de cientos de miles de posiciones. Ninguna de ellas es una arquitectura nueva. Todas son ediciones sobre la aritmética que montaste en el proyecto del Transformer, y ése es el sitio donde este curso te deja: no delante de un modelo que funciona, sino delante de un artículo que puedes discutir.
Further reading2 sources · 2 papers
Where this lesson comes from, and where to go next. None of it is needed to carry on with the course.
- Spanish Pre-trained BERT Model and Evaluation Data
El modelo que afinas en el cuaderno: un BERT de 12 bloques y 768 de ancho entrenado sobre unos 3.000 millones de palabras en español, con su batería de tareas. De aquí salen los 110 millones de parámetros que no caben en el navegador.
- Universal Language Model Fine-tuning for Text Classification
El porqué de la tasa minúscula del cuaderno: un paso grande sobre pesos preentrenados los borra. Trae recetas —descongelar por capas, una tasa por capa— que el cuaderno no usa; el principio de no perder lo que costó semanas, sí.