{ "cells": [ { "cell_type": "markdown", "id": "65c9fdf3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Hugging Face: IA Colaborativa\n", "=========================" ] }, { "cell_type": "markdown", "id": "32a802c2", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "¿Quién soy?\n", "------------------\n", "\n", "
\n", "

Cristian Cardellino

\n", "
Postdoc en Université Côte d'Azur (Niza, Francia)
\n", "
\n", " \n", "
\n", "
\n", " @crscardellino -\n", " @crscardellino@mastodon.social -\n", " https://crscardellino.ar\n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "bb685a55", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Esquema de la charla\n", "\n", "1. [¿Qué hay detrás de ChatGPT?](#¿Qué-hay-detrás-de-ChatGPT?)\n", "2. [Hugging Face](#Hugging-Face)\n", "3. [Utilizando un modelo de Hugging Face](#Utilizando-un-modelo-de-Hugging-Face)\n", "4. [Personalizando un modelo de Hugging Face](#Personalizando-un-modelo-de-Hugging-Face)" ] }, { "cell_type": "markdown", "id": "eb7f3997", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# ¿Qué hay detrás de ChatGPT?" ] }, { "cell_type": "markdown", "id": "87d1ca59", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Cómo continúa esta frase?\n", "\n", "

You ...

" ] }, { "cell_type": "markdown", "id": "1e5a5c6b", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "

You shall ...

" ] }, { "cell_type": "markdown", "id": "f71da59e", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "

You shall not ...

" ] }, { "cell_type": "markdown", "id": "2910e985", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "
\n", "

You shall not pass!

\n", "
\n", " \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "283ca08c", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Qué son los \"modelos de lenguaje\"? (Language Models)\n", "\n", "- Modelos de aprendizaje automático.\n", "- Dado un contexto (e.g. una lista de palabras previas), predicen la palabra siguiente.\n", "- Se entrenan con texto libre." ] }, { "cell_type": "markdown", "id": "778b5e91", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### ¿Qué son los \"LLMs\"? (Large Language Models)\n", "\n", "- Modelos de lenguajes entrenados con una gran cantidad de datos y de parámetros:\n", " - Suelen entrenarse con corpus del orden de $10^{10}$ palabras.\n", " - Suelen tener de $10^8$ o $10^9$ parámetros en adelante.\n", "- El término se asocia generalmente a aquellos modelos basados en la arquitectura neuronal del **Transformer**." ] }, { "cell_type": "markdown", "id": "cfc710ea", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Qué es un \"Transformer\"?\n", "\n", "- Es una arquitectura de red neuronal que se presentó en el paper [\"Attention is All You Need\"](https://arxiv.org/abs/1706.03762).\n", "- Existen variantes, de acuerdo a que parte de la arquitectura usan:\n", " - Los modelos de traducción de secuencia a secuencia (e.g. el [Transformer](https://arxiv.org/abs/1706.03762) o el [T5](https://arxiv.org/abs/1910.10683)). Tienen codificador y decodificador. Sirven para tareas de transformación (e.g. traducción).\n", " - Los modelos basados en el codificador (e.g. [BERT](https://arxiv.org/abs/1810.04805)). Sirven para buscar representaciones vectoriales (embeddings) del texto.\n", " - Los modelos basados en el decodificador (e.g. [GPT](https://arxiv.org/abs/2005.14165)). Sirven para generación de texto.\n", "- La idea del transformer es \"definir\" una palabra de acuerdo a la relación que tiene con las palabras de su vecindario, en una operación de multiplicación matricial con pesos.\n", " - Para una explicación más sencilla pero más detallada sugiero los posts de la serie \"The Illustrated...\" de [Jay Alammar](http://jalammar.github.io/):\n", " - [The Illustrated Transformer](http://jalammar.github.io/illustrated-transformer/)\n", " - [The Illustrated BERT](http://jalammar.github.io/illustrated-bert/)\n", " - [The Illustrated GPT-2](http://jalammar.github.io/illustrated-gpt2/) / [How GPT-3 Works](http://jalammar.github.io/how-gpt3-works-visualizations-animations/)" ] }, { "cell_type": "markdown", "id": "8958cf42", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Hugging Face" ] }, { "cell_type": "markdown", "id": "6038bd78", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Qué es Hugging Face?\n", "\n", "- Una [comunidad colaborativa](https://huggingface.co/) para hacer Inteligencia Artificial (IA).\n", "- Cuenta con repositorios para subir [modelos](https://huggingface.co/models), [datasets](https://huggingface.co/datasets) y [demos](https://huggingface.co/spaces).\n", "- Además, ofrecen varias librerías orientadas a la IA, particularmente al Aprendizaje Profundo (Deep Learning), entre las que destacan:\n", " - [`transformers`](https://huggingface.co/docs/transformers): La que veremos en esta charla, para todo lo relacionado a NLP con LLMs.\n", " - [`datasets`](https://huggingface.co/docs/datasets): Una librería especializada en el tratamiento de los conjuntos de datos a utilizar para entrenar/ajustar los LLMs.\n", " - [`tokenizers`](https://huggingface.co/docs/tokenizers): Para el proceso de \"tokenización\", i.e. la división de texto de manera discreta en palabras o subpalabras.\n", "- Hugging Face no sólo ofrece soluciones sobre NLP, sino que también lo hace con imágenes, con librerías como [`diffusers`](https://huggingface.co/docs/diffusers), para la generación de imágenes:\n", " - Lectura recomendada: [The Illustrated Stable Diffusion](http://jalammar.github.io/illustrated-stable-diffusion/)" ] }, { "cell_type": "markdown", "id": "25ad7d45", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Cómo empezar con Hugging Face?\n", "\n", "- Primero se [crea una cuenta en la página](https://huggingface.co/join).\n", "- Luego podemos [crear modelos](https://huggingface.co/new) a través del menú que se despliega de nuestro avatar.\n", "- Una vez creado el modelo, este es un repositorio de git que puede accederse clonándolo localmente.\n", " - Requiere de [`git-lfs`](https://git-lfs.com/)." ] }, { "cell_type": "markdown", "id": "3c6f89c3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Utilizando un modelo de Hugging Face" ] }, { "cell_type": "markdown", "id": "d06c7318", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Cargando los modelos\n", "\n", "- Hugging Face ofrece muchísimos modelos en su [repositorio](https://huggingface.co/models), para este caso elegimos el modelo [`bigscience/bloom-3b`](https://huggingface.co/bigscience/bloom-3b) de la organización [Big Science](https://bigscience.huggingface.co/blog/bloom).\n", " - Esta organización ha estado [creando modelos](https://huggingface.co/bigscience) bajo una [licencia abierta](https://bigscience.huggingface.co/blog/the-bigscience-rail-license) (con ciertas limitaciones de uso para evitar abuso).\n", " - Son responsables del [LLM abierto más grande actualmente disponible](https://huggingface.co/bigscience/bloom).\n", "- El modelo elegido es un modelo de 3 mil millones (3 billion) de parámetros." ] }, { "cell_type": "code", "execution_count": 1, "id": "0e0d53be", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "import torch\n", "\n", "from IPython.display import display, HTML\n", "from transformers import AutoModelForCausalLM, AutoTokenizer\n", "\n", "BASE_MODEL = 'bigscience/bloom-3b' # More models at https://huggingface.co/models\n", "\n", "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)\n", "model = AutoModelForCausalLM.from_pretrained(\n", " BASE_MODEL,\n", " low_cpu_mem_usage=True,\n", " torch_dtype='auto'\n", ")" ] }, { "cell_type": "markdown", "id": "022de9b5", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Generando Texto a Partir de un PROMPT\n", "\n", "- Los modelos de lenguaje necesitan una semilla, denominada comúnmente **prompt**, para iniciar su conversación.\n", "- A partir de dicha semilla, los modelos pueden empezar a predecir las palabras siguiente.\n", "- La coherencia de la frase depende de varios aspectos:\n", " - El tamaño y [entrenamiento](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling_from_scratch.ipynb) o [ajuste](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) (fine-tuning) del modelo.\n", " - Modelos más grandes suelen ser mejor en escenarios \"open end\", aunque pueden desvariar (o \"alucinar\").\n", " - El tipo de datos con el que se entrenó/ajustó el modelo.\n", " - La [estrategia](https://github.com/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb) a la hora de generar texto.\n", " - La [documentación de Hugging Face](https://huggingface.co/docs/transformers/notebooks) tiene más ejemplos que pueden reproducirse." ] }, { "cell_type": "markdown", "id": "e89d104b", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Estableciendo un PROMPT\n", "\n", "- El **prompt** inicial es el que \"ayudará\" al modelo a devolver resultados más o menos coherentes.\n", "- Actualmente es más un arte que una ciencia.\n", " - **No existe el \"prompt engineering\" porque los modelos no son determinísticos.**\n", "- Depende muchísimo del modelo, la inicialización aleatoria (i.e. la suerte), la tarea que se busca resolver, entre otros factores.\n", "- Algo bastante común es que se le den ejemplos concretos de cómo se espera que genere texto.\n", " - A esta práctica se le conoce como [\"Few Shot Learning\"](https://arxiv.org/abs/2005.14165), si bien el modelo no \"aprende\" sino que busca contextos similares a los vistos en los ejemplos." ] }, { "cell_type": "markdown", "id": "6e6b4464", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Ejemplo de PROMPT\n", "\n", "- Siguiendo los ejemplos de [esta publicación](https://medium.com/@fractal.ai/create-conversational-agents-using-bloom-part-1-63a66e6321c0), y en vistas de armar un chatbot, buscaré definir 4 cosas:\n", " - La \"identidad\", i.e. ¿Qué es?\n", " - La \"intención\", i.e. ¿Qué hace?\n", " - El \"comportamiento\", i.e. ¿Cómo lo hace?\n", " - Además le daré pie a que continué una conversación (\"Few Shot Learning\")." ] }, { "cell_type": "code", "execution_count": 2, "id": "c1227c49", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "PROMPT = \"\"\"\n", "La siguiente es una conversación entre un HUMANO y un bot EXPERTO en software libre.\n", "El EXPERTO le ayuda al HUMANO con preguntas acerca de software libre.\n", "El EXPERTO es conversacional, optimista, flexible, creativo y genera respuestas parecidas a un humano.\n", "\n", "HUMANO: Hola, ¿Cómo estás?\n", "EXPERTO: Hola, muy bien. Estoy acá para ayudarte con preguntas respecto al software libre.\n", "\n", "HUMANO: ¿Qué es el software libre?\n", "EXPERTO:\"\"\".strip()" ] }, { "cell_type": "markdown", "id": "82988db2", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Generando texto de manera \"Greedy\"\n", "\n", "- La estrategia para generar texto puede variar. La opción más directa es **greedy**, i.e. devolver la palabra que es más probable después de la secuencia.\n", " - La principal ventaja de esta alternativa, es que es determinística, i.e. ante la misma entrada debería devolver la misma salida.\n", " - La principal desventaja es que tiende a repetir y quedar limitada a ciertas frases o palabras." ] }, { "cell_type": "code", "execution_count": 3, "id": "11bec6de", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "La siguiente es una conversación entre un HUMANO y un bot EXPERTO en software libre.\n", "El EXPERTO le ayuda al HUMANO con preguntas acerca de software libre.\n", "El EXPERTO es conversacional, optimista, flexible, creativo y genera respuestas parecidas a un humano.\n", "\n", "HUMANO: Hola, ¿Cómo estás?\n", "EXPERTO: Hola, pmuy bien. Estoy acá para ayudarte con preguntas respecto al software libre.\n", "\n", "HUMANO: ¿Qué es el software libre?\n", "EXPERTO: El software libre es un software que se puede modificar, redistribuir y distribuir libremente.\n", "HUMANO: ¿En qué consiste la licencia GPL?\n", "EXPERTO: La licencia GPL es una licencia de software libre que permite a los usuarios modificar, redistribuir\n" ] } ], "source": [ "MAX_TOKENS = 50\n", "input_ids = tokenizer.encode(PROMPT, return_tensors='pt')\n", "greedy_output = model.generate(input_ids, max_length=input_ids.shape[1] + MAX_TOKENS)\n", "output = tokenizer.decode(greedy_output[0], skip_special_tokens=True)\n", "\n", "print(output)" ] }, { "cell_type": "markdown", "id": "ba05a269", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Generando texto usando aleatoriedad\n", "\n", "- Si bien hay [varias estrategias para generar texto libre](https://github.com/huggingface/blog/blob/main/notebooks/02_how_to_generate.ipynb) una que resulta muy interesante es mediante el sampleo estadístico.\n", "- La idea es que la manera de seleccionar la siguiente palabra es con cierta probabilidad estadística (i.e. no siempre la más probable).\n", " - La principal ventaja es que hace el texto más \"creativo\" y más \"humano\".\n", " - La principal desventaja es que no es determinístico y es suceptible de \"alucinar\".\n", " - En este caso se samplea de las `top_k` palabras más probable que a su vez son la menor cantidad de palabras cuya probabilidad conjunta es mayor que `top_p`." ] }, { "cell_type": "code", "execution_count": 4, "id": "dc66f288", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "La siguiente es una conversación entre un HUMANO y un bot EXPERTO en software libre.\n", "El EXPERTO le ayuda al HUMANO con preguntas acerca de software libre.\n", "El EXPERTO es conversacional, optimista, flexible, creativo y genera respuestas parecidas a un humano.\n", "\n", "HUMANO: Hola, ¿Cómo estás?\n", "EXPERTO: Hola, pmuy bien. Estoy acá para ayudarte con preguntas respecto al software libre.\n", "\n", "HUMANO: ¿Qué es el software libre?\n", "EXPERTO: El software libre, es aquel software que esta escrito en un lenguaje de programación que puede ser modificado y copiado por cualquier persona o entidad.\n", "\n", "HUMANO: ¿En general cuáles son los usos que se pueden dar a un software libre?\n", "EXPERTO\n" ] } ], "source": [ "torch.manual_seed(42) # To ensure determinism\n", "\n", "sampling_output = model.generate(\n", " input_ids,\n", " do_sample=True,\n", " max_length=input_ids.shape[1] + MAX_TOKENS,\n", " top_k=50,\n", " top_p=0.95,\n", ")\n", "output = tokenizer.decode(sampling_output[0], skip_special_tokens=True)\n", "\n", "print(output)" ] }, { "cell_type": "markdown", "id": "98bdd38e", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Un Chatbot Sencillo\n", "\n", "- El modelo de lenguaje no tiene noción de cuando parar, porque está entrenado para continuar el mensaje dado en el **prompt**.\n", " - Seguirá generando texto hasta alcanzar el valor del parámetro `max_length`.\n", " - El texto generado inluirá las palabras que marcan la conversación (i.e. \"HUMANO\" y \"EXPERTO\").\n", "- Para poder utilizar un modelo para hacer un **chatbot** requerimos de un poco de ingeniería de software clásica.\n", " - Una opción es utilizar precisamente las palabras que definen la conversación como puntos de inicio y final, y descartar el resto.\n", "- En [`chatbot.py`](./chatbot.py) hay un ejemplo sencillo de cómo puede realizarse esto.\n", " - Consiste de una clase `ChatBot` que sirve como *wrapper* de los modelos de Hugging Face.\n", " - Posee un CLI sencillo que mantiene un loop continuo para chatear." ] }, { "cell_type": "code", "execution_count": null, "id": "a3e12232", "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "import torch\n", "from chatbot import ChatBot # local module in the repository\n", "\n", "torch.manual_seed(42) # to be more deterministic\n", "\n", "PROMPT = \"\"\"\n", "La siguiente es una conversación entre un HUMANO y un bot EXPERTO en software libre.\n", "El EXPERTO le ayuda al HUMANO con preguntas acerca de software libre.\n", "El EXPERTO es conversacional, optimista, flexible, creativo y genera respuestas parecidas a un humano.\n", "\n", "HUMANO: Hola, ¿Cómo estás?\n", "EXPERTO: Hola, muy bien. Estoy acá para ayudarte con preguntas respecto al software libre.\n", "\"\"\".strip()\n", "\n", "chatbot = ChatBot(\n", " base_model='bigscience/bloom-3b',\n", " initial_prompt=PROMPT,\n", " keep_context=True,\n", " creative=True,\n", " human_identifier='HUMANO',\n", " bot_identifier='EXPERTO'\n", ")\n", "\n", "while True:\n", " input_text = input('> ')\n", " if input_text == 'exit':\n", " break\n", " print(chatbot.chat(input_text))" ] }, { "cell_type": "markdown", "id": "6e570fc3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Personalizando un modelo de Hugging Face" ] }, { "cell_type": "markdown", "id": "adb09645", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Cómo se entrenan los LLMs?\n", "\n", "- Para entrenar LLMs se requiere de muchos datos y mucho cómputo.\n", "- El modelo de GPT-3 se estima que tuvo un costo de entrenamiento cercano a los U$D4.6 Millones\n", " - Requirió de varias semanas de entrenamiento\n", " - El corpus reportado es de aproximadamente 500 mil millones (billions) de palabras.\n", " - Varios GPUS para entrenarlo y hardware especializado\n", " - No son modelos que entren en la memoria de una sola GPU." ] }, { "cell_type": "markdown", "id": "16a26206", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "### ¿Y entonces qué puedo hacer?\n", "\n", "- Una ventaja de los LLMs es que el entrenamiento es sobre texto libre, pero se puede **especializar**.\n", "- Uno puede entrenar modelos para diversas tareas especializados en corpus más chico.\n", "- El hecho de que no sea \"desde cero\" ayuda a evitar sobreajuste (overfit) y tiene buen desempeño.\n", "- El procedimiento de **especialización** se conoce como **fine-tuning**." ] }, { "cell_type": "markdown", "id": "649e2ef4", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Cómo personalizar un modelo de Hugging Face?\n", "\n", "- Se inicia por algún modelo pre-entrenado para la tarea específica que uno busca (e.g. clasificación, generación, etc).\n", "- Se toma un corpus especializado (anotado, revisado, etc.) y se entrena utilizando dicho corpus.\n", "- Intentaremos [entrenar que un modelo genere texto](https://github.com/huggingface/notebooks/blob/main/examples/language_modeling.ipynb) con el estilo del **Martín Fierro**.\n", "- Para hacerlo menos pesado, utilizaremos un modelo más chico `DeepESP/gpt2-spanish` como base.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "17f2884d", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "import torch\n", "from transformers import AutoModelForCausalLM, AutoTokenizer\n", "\n", "BASE_MODEL = 'DeepESP/gpt2-spanish' # We play with a smaller model\n", "tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)\n", "model = AutoModelForCausalLM.from_pretrained(BASE_MODEL)" ] }, { "cell_type": "markdown", "id": "16690597", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Probando el Modelo Base\n", "\n", "- Antes de ajustar el modelo vemos cómo se desenvuelve si le damos como entrada el primer verso del \"Martín Fierro\"." ] }, { "cell_type": "code", "execution_count": 2, "id": "322a4a9b", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Aquí me pongo a cantar y a llorar. \n", "\n", "Los sollozos de Meggie se desvanecen por la noche en el salón. Al parecer no se ve nada. \n", "\n", "—¿Y si no fuera el final del mundo, el fin de un mundo?\n" ] } ], "source": [ "torch.manual_seed(42) # To ensure determinism\n", "\n", "input_ids = tokenizer.encode(\"Aquí me pongo a cantar\", return_tensors='pt')\n", "sampling_output = model.generate(input_ids, do_sample=True, max_length=50, top_k=50, top_p=0.95)\n", "output = tokenizer.decode(sampling_output[0], skip_special_tokens=True)\n", "\n", "print(output)" ] }, { "cell_type": "markdown", "id": "ec722e81", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Cargando el Dataset\n", "\n", "- Utilizamos la librería [datasets](https://huggingface.co/docs/datasets/index) de Hugging Face para cargar el corpus.\n", "- En el directorio [`./data`] tenemos dos archivos: [`martin-fierro_train.txt`](./data/martin-fierro_train.txt) y [`martin-fierro_validation.txt`](./data/martin-fierro_validation.txt).\n", " - El archivo de entrenamiento es sobre las 12 primeras partes.\n", " - El archivo de validación es sobre la última parte." ] }, { "cell_type": "code", "execution_count": 3, "id": "5a27197e", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I - Cantor y Gaucho.\n", "\n", "1\n", "Aquí me pongo a cantar\n", "Al compás de la vigüela,\n", "Que el hombre que lo desvela\n", "Una pena estraordinaria\n", "Como la ave solitaria\n", "Con el cantar se consuela.\n" ] } ], "source": [ "from datasets import load_dataset\n", "\n", "datasets = load_dataset('text', data_files={'train': './data/martin-fierro_train.txt',\n", " 'validation': './data/martin-fierro_validation.txt'})\n", "print('\\n'.join(datasets['train'][:9]['text']))" ] }, { "cell_type": "markdown", "id": "9504707f", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Tokenizando los datos\n", "\n", "- La función auxiliar `tokenize` del módulo [`utils`](./utils.py) sirve para tokenizar y codificar el conjunto de datos de manera eficiente mediante el [método `map`](https://huggingface.co/docs/datasets/about_map_batch).\n", "- Lo que devuelve es un nuevo dataset cuyos tokens están convertidos en índices del vocabulario y [máscaras de atención](https://huggingface.co/docs/transformers/glossary#attention-mask)" ] }, { "cell_type": "code", "execution_count": 4, "id": "33059c5f", "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from utils import tokenize # local module in the repository\n", "\n", "tokenized_datasets = datasets.map(tokenize(tokenizer), batched=True, num_proc=4, remove_columns=['text'])" ] }, { "cell_type": "markdown", "id": "81d67b22", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Agrupando los textos\n", "\n", "- Para entrenar de manera más eficiente es común utilizar lo que se conoce como **mini-batch gradient descent**.\n", "- La idea es tomar los textos de a bloques de un valor máximo.\n", " - El valor máximo estará limitado por la memoria de la unidad de procesamiento (e.g. GPU).\n", "- Utilizamos la función auxiliar `group_texts` del módulo [`utils`](./utils.py).\n", " - La función además establece las etiquetas que utilizará Hugging Face para entrenar.\n", " - En este caso las etiquetas son las mismas palabras, porque busca predecir la palabra siguiente." ] }, { "cell_type": "code", "execution_count": 5, "id": "3100e195", "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from functools import partial\n", "from utils import group_texts # local module in the repository\n", "\n", "lm_datasets = tokenized_datasets.map(\n", " partial(group_texts, block_size=128),\n", " batched=True,\n", " batch_size=1024,\n", " num_proc=4,\n", ")" ] }, { "cell_type": "markdown", "id": "d64a23ec", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Decodificando\n", "\n", "- Podemos ver que los textos pasan a estar agrupados en bloques de 128 tokens.\n", "- Además, vemos que el texto fue reemplazado por números (índices en el vocabulario).\n", "- Por último, si decodificamos estos números, obtenemos el texto original." ] }, { "cell_type": "code", "execution_count": 6, "id": "b9d33b7b", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "128\n", "[50, 1368, 6505, 282, 324, 24275, 526, 23, 208, 208]\n" ] } ], "source": [ "print(len(lm_datasets['train'][0]['input_ids']))\n", "print(lm_datasets['train'][0]['input_ids'][:10])" ] }, { "cell_type": "code", "execution_count": 7, "id": "7dfb316d", "metadata": { "scrolled": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I - Cantor y Gaucho.\n", "\n", "1\n", "Aquí me pongo a cantar\n", "Al compás de la vigüela,\n", "Que el hombre que lo desvela\n", "Una pena estraordinaria\n", "Como la ave solitaria\n", "Con el cantar se consuela.\n", "\n", "2\n", "Pido a los Santos del Cielo\n", "Que ayuden mi pensamiento;\n", "Les pido en este momento\n", "Que voy a cantar mi historia\n", "Me refresquen la memoria\n", "Y aclaren mi entendimiento.\n", "\n", "3\n", "Vengan Santos milagrosos,\n", "Vengan todos en mi ayuda,\n", "Que la lengua se me añuda\n", "Y se me turba\n" ] } ], "source": [ "print(tokenizer.decode(lm_datasets['train'][0]['input_ids']))" ] }, { "cell_type": "markdown", "id": "d7e2032f", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Compartir Modelo en Hugging Face\n", "\n", "- Una opción a la hora de entrenar un modelo es subirlo a Hugging Face para compartirlo con la comunidad.\n", "- Para eso, una vez que tengan la cuenta de Hugging Face, y creado el modelo, hay que hacer login mediante un [token](https://huggingface.co/settings/tokens)." ] }, { "cell_type": "code", "execution_count": 8, "id": "a8b90ba2", "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from huggingface_hub import notebook_login\n", "\n", "notebook_login()" ] }, { "cell_type": "markdown", "id": "a6b775d3", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Entrenamiento\n", "\n", "- Una vez definido el conjunto de datos, pasamos a la parte más intensa computacionalmente, el entrenamiento.\n", "- Podemos decidir guardar el modelo localmente o hacer un backup de cada época del modelo en Hugging Face.\n", "- Definimos las propiedades del entrenamiento mediante [`TrainingArguments`](https://huggingface.co/docs/transformers/v4.28.1/en/main_classes/trainer#transformers.TrainingArguments).\n", "- Definimos el entrenamiento del modelo mediante [`Trainer`](https://huggingface.co/docs/transformers/v4.28.1/en/main_classes/trainer#transformers.Trainer).\n", " - El entrenamiento tardará desde unos segundos hasta varios minutos dependiendo el poder de cómputo." ] }, { "cell_type": "code", "execution_count": 9, "id": "3b121d21", "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " \n", " [180/180 11:44, Epoch 10/10]\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
EpochTraining LossValidation Loss
14.3864004.202457
23.9480004.043974
33.7962003.980350
43.6105003.945783
53.4444003.927984
63.3855003.919229
73.3142003.909090
83.2192003.907399
93.1615003.906959
103.1637003.906726

" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from transformers import Trainer, TrainingArguments\n", "\n", "training_args = TrainingArguments(\n", " 'flisol-cba-martin-fierro',\n", " evaluation_strategy='epoch',\n", " num_train_epochs=10,\n", " learning_rate=2e-5,\n", " weight_decay=0.01,\n", " logging_steps=5\n", ")\n", "\n", "trainer = Trainer(\n", " model=model,\n", " args=training_args,\n", " train_dataset=lm_datasets['train'],\n", " eval_dataset=lm_datasets['validation']\n", ")\n", "\n", "trainer.train()\n", "trainer.push_to_hub() # This pushes the trained model to Hugging Face model repository\n", "tokenizer.push_to_hub('flisol-cba-martin-fierro')" ] }, { "cell_type": "markdown", "id": "db2099f4", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Probando el Nuevo Modelo\n", "\n", "- Ahora que tenemos el modelo entrenado, la pregunta es, ¿Cómo se comportará?\n", "- Para ello volvemos a hacer la prueba anterior, quizás esta vez con mejores resultados.\n", " - Para evitar tener que entrenar el modelo nuevamente directamente tomo el [modelo compartido en Hugging Face](https://huggingface.co/crscardellino/flisol-cba-martin-fierro)." ] }, { "cell_type": "code", "execution_count": 1, "id": "6a35e80f", "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Aquí me pongo a cantar;\n", "y si tengo el sueño:\n", "de pronto se me ha quedado la sangre:\n", "como te asombre se me\n", "lo oí decir muchas veces,\n", "pero el tiempo me ha borrado.\n", "\n", "2\n", "Soy\n" ] } ], "source": [ "import torch\n", "from transformers import AutoModelForCausalLM, AutoTokenizer\n", "\n", "MODEL = 'flisol-cba-martin-fierro'\n", "tokenizer = AutoTokenizer.from_pretrained(MODEL)\n", "model = AutoModelForCausalLM.from_pretrained(MODEL)\n", "\n", "torch.manual_seed(42) # To ensure determinism\n", "\n", "input_ids = tokenizer.encode(\"Aquí me pongo a cantar\", return_tensors='pt')\n", "sampling_output = model.generate(input_ids, do_sample=True, max_length=50, top_k=50, top_p=0.95)\n", "output = tokenizer.decode(sampling_output[0], skip_special_tokens=True)\n", "\n", "print(output)" ] }, { "cell_type": "markdown", "id": "f4e33157", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# ¡Muchas Gracias!" ] }, { "cell_type": "markdown", "id": "f04a4e4a", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ¿Preguntas?\n", "\n", "* Twitter: https://twitter.com/crscardellino\n", "* Mastodon: https://mastodon.social/@crscardellino\n", "* LinkedIn: https://www.linkedin.com/in/crscardellino\n", "* Página Personal: https://crscardellino.ar / https://crscardellino.github.io\n", "* GitHub: https://github.com/crscardellino/\n", "* Código y modelo de la presentación: https://huggingface.co/crscardellino/flisol-cba-martin-fierro/" ] }, { "cell_type": "raw", "id": "ad5d7870", "metadata": { "slideshow": { "slide_type": "skip" } }, "source": [ "License\n", "-------\n", "\n", "flisol-cba-martin-fierro\n", "Copyright (C) 2023 Cristian Cardellino\n", "\n", "This program is free software: you can redistribute it and/or modify\n", "it under the terms of the GNU General Public License as published by\n", "the Free Software Foundation, either version 3 of the License, or\n", "(at your option) any later version.\n", "\n", "This program is distributed in the hope that it will be useful,\n", "but WITHOUT ANY WARRANTY; without even the implied warranty of\n", "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n", "GNU General Public License for more details.\n", "\n", "You should have received a copy of the GNU General Public License\n", "along with this program. If not, see ." ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.8" }, "rise": { "scroll": true } }, "nbformat": 4, "nbformat_minor": 5 }