The post Generación de Texto en Español con GPT-2 first appeared on Aprende Machine Learning.
]]>Crearemos nuestra propia IA de generación de texto basada en los diálogos y entrevistas de Ibai Llanos publicados en Youtube. Usaremos un modelo pre-entrenado GPT-2 en castellano disponible desde HuggingFace y haremos el fine-tuning con Pytorch para que aprenda el estilo de escritura deseado.
En este artículo comentaremos brevemente el modelo GPT-2 y crearemos un entorno en Python desde donde poder entrenar y generar texto!
GPT significa “Generative Pre-Training” y es un modelo de Machine Learning creado por OpenAI para la generación de texto. El modelo de Procesamiento del Lenguaje Natural, es un caso particular de Transformers. GPT propone el pre-entrenamiento de un enorme corpus de texto para luego -opcionalmente- realizar el fine-tuning.
El fine-tuning es el proceso de realizar un “ajuste fino” de los parámetros ó capas de la red neuronal, en nuestro caso con un dataset adicional para guiar al modelo a obtener las salidas deseadas.
¿Entonces es aprendizaje no supervisado? Sí; se considera que es aprendizaje no supervisado porque estamos pasando al modelo enormes cantidades de texto, que el modelo organizará automáticamente y le pedimos que “prediga la siguiente palabra” usando como contexto todos los tokens previos (con posicionamiento!). El modelo ajusta sin intervención humana los embeddings y los vectores de Atención. Algunos autores lo consideran aprendizaje “semi-supervisado” porque consideran como “etiqueta de salida” el token a predecir.
Ejemplo: Si tenemos la oración “Buenos días amigos”, el modelo usará “Buenos días” para predecir como etiqueta de salida “amigos”.
Este modelo puede usarse directamente como modelo generativo luego de la etapa de aprendizaje no supervisado (sin hacer fine-tuning).
Al partir de este modelo en crudo y realizar un fine-tuning a nuestro antojo, podemos crear distintos modelos específicos: de tipo Question/Answering, resumen de textos, clasificación, análisis de sentimiento, etc.
Eso es lo que haremos en el ejercicio de hoy: descargar el modelo GPT y realizar el fine-tuning!
GPT es un modelo Transformer. Utiliza sólo la rama “Tansformer-Decoder” a diferencia de modelos como BERT que utilizan la rama Encoder. De esta manera se elimina la Atención cruzada, pues ya no es necesaria y mantiene la “Masked Self-Attention”.
Entre sus características:
Como vemos, la versión pequeña tiene un tamaño aún manejable para entrenar en un ordenador “normal”. Es la versión del modelo que utilizaremos en el ejercicio.
Una ventaja que se consigue al entrenar al modelo con millones de textos de conocimiento general (en contraposición a utilizar textos sobre un sólo tema) es que el modelo consigue habilidades “zero shot”, es decir, logra realizar satisfactoriamente algunas tareas para las que no ha sido entrenado específicamente. Por ejemplo, GPT-2 puede traducir textos de inglés a francés sin haber sido entrenado para ello. También consigue responder a preguntas ó generar código en Java.
Puede que sepas de la existencia de GPT-3 y hasta puede que hayas escuchado hablar sobre el recientemente lanzado “ChatGPT” que algunos denominan como GPT-3.5 ó GPT-4. Entonces, ¿porqué vamos a usar al viejo GPT-2 en este ejercicio?
La respuesta rápida es porque GPT-2 es libre!, su código fue liberado y tenemos acceso al repositorio y a su implementación desde HuggingFace. Existen muchos modelos libres tuneado de GPT-2 y publicados que podemos usar. Si bien cuenta con un tamaño de parámetros bastante grande, GPT-2 puede ser reentrenado en nuestro propio ordenador.
En cuanto a resultados, GPT-2 fue unos de los mejores de su época (Feb 2019), batiendo records y con valores -en algunos casos- similares a los del humano:
En cambio GPT-3 aún no ha sido liberado, ni su código ni su red pre-entrenada, además de que tiene un tamaño inmensamente mayor a su hermano pequeño, haciendo casi imposible que lo podamos instalar ó usar en nuestra computadora de casa ó trabajo.
Es cierto que puedes utilizar GPT-3 mediante la API de pago de OpenAI y también se puede utilizar ChatGPT de modo experimental desde su web. Te animo a que lo hagas, pero no dejes de aprender a utilizar GPT-2 que será de gran ayuda para comprender como ajustar uno de estos modelos de lenguaje para tus propios fines.
HuggingFace se ha convertido en el gran repositorio de referencia de modelos pre-entrenados. Es un sitio web en donde cualquier persona ó insitutición pueden subir sus modelos entrenados para compartirlos.
HuggingFace ofrece una librería python llamada transformers que permite descargar modelos preentrenados de NLP (GPT, BERT, BART,ELECTRA, …), utilizarlos, hacer el fine tuning, reentrenar.
En el ejercicio que haremos instalaremos la librería de HuggingFace para acceder a los modelos de GPT.
Dentro de HuggingFace podemos buscar modelos para NLP y también para Visión Artificial, cómo el de Stable Diffusion, para crear imágenes, como se explica en un anterior post del blog!).
Y podemos encontrar Modelos con distintos fines. En nuestro caso, estamos interesados en utilizar un modelo en Español.
Usaremos el modelo llamado “flax-community/gpt-2-spanish“, puedes ver su ficha aquí, y desde ya, agradecemos enormemente al equipo que lo ha creado y compartido gratuitamente. Ocupa unos 500MB.
Un detalle, que verás en el código: realmente cargaremos una red pre-entrenada con los pesos y el embeddings PERO también usaremos el tokenizador! (es decir, cargaremos 2 elementos del repositorio de HuggingFace, no sólo el modelo).
En otros artículos de NLP de este tipo, utilizan textos de Shakespeare porque es un escritor reconocido, respetado y porque no tiene derechos de autor. Nosotros utilizaremos textos de Ibai Llanos generados a partir de transcripciones generadas automáticamente por Whisper de sus videos de Youtube. Ibai es un reconocido Streamer español de Twitch. ¿Porqué Ibai? Para hacer divertido el ejercicio! Para que sea en castellano, con jerga actual
El proyecto consiste en tomar un modelo GPT-2 pre-entrenado en castellano y realizar el fine-tuning con nuestro propio dataset de texto. Como resultado obtendremos un modelo que será capaz de crear textos “con la manera de hablar” de Ibai.
Aquí puedes encontrar la Jupyter notebook completa en mi repo de Github con el ejercicio que realizaremos. En total son unas 100 líneas de código.
El dataset es una selección totalmente arbitraría de videos de Youtube de Ibai con entrevistas y charlas de sus streams en Twitch. En algunos videos juega videojuegos en vivo, entrevista cantantes, futbolistas ó realiza compras de productos usados que le llaman la atención.
Utilicé un notebook de Google Colab con Whisper que es un modelo de machine learning lanzado hace pocos meses (en 2022) que realiza la transcripción automática de Audio a Texto. Usaremos como entradas esos textos. Disclaimer: Pueden contener errores de mala transcripción y también es posible que hubiera palabras que el modelo no comprenda del español.
El archivo de texto que utilizaremos como Dataset con fines educativos, lo puedes encontrar aquí.
Si tienes instalado Anaconda, puedes crear un nuevo Environment python para este proyecto. Si no, instala anaconda siguiendo esta guía, ó utiliza cualquier manejador de ambientes python de tu agrado.
También puedes ejecutar el código una notebook en la nube con Google Colab y aprovechar el uso de GPU gratuito. En este artículo te cuento sobre cómo usar Colab.
En este ejercicio utilizaremos la librería Pytorch para entrenar la red neuronal. Te recomiendo ir a la web oficial de Pytorch para obtener la versión que necesitas en tu ordenador, porque puede variar la instalación si usas Windows, Linux ó Mac y si tienes o no GPU.
Ejecuta las siguientes líneas en tu terminal:
conda create -n gpt2 python=3.9 -y # Activa el nuevo ambiente con: 'conda activate gpt2' conda install numpy tqdm transformers -y # si tienes GPU instala Pytorch con: conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia # si no tienes GPU, instala con: conda install pytorch torchvision torchaudio cpuonly -c pytorch
Ahora pasamos a un notebook o una IDE Python y empezamos importando las librerías python que utilizaremos, incluyendo transformers de HuggingFace:
import os import time import datetime import numpy as np import random from tqdm import tqdm import torch from torch.utils.data import Dataset, DataLoader, random_split, RandomSampler from transformers import AutoTokenizer, AutoModelForCausalLM from transformers import AdamW, get_linear_schedule_with_warmup
Haremos una distinción; si vamos a utilizar GPU para entrenar ó CPU, definiendo una variable llamada device. Nótese que también alteramos el tamaño que usaremos de batch. En el caso de GPU, podemos utilizar valores 2 ó 3 según el tamaño de memoria RAM que tenga la tarjeta gráfica.
if torch.cuda.is_available(): print("Usar GPU") device = torch.device("cuda") batch_size = 3 else: print("usar CPU") device = torch.device("cpu") batch_size = 1
La primera vez que ejecutemos esta celda, tomará unos minutos en descargar los 500MB del modelo y el tokenizador en Español desde HuggingFace, pero luego ya se utilizará esa copia desde el disco, siendo una ejecución inmediata.
Para este ejercicio estamos creando un “token especial” (de control) que llamaremos “ibai” con el que luego indicaremos al modelo que queremos obtener una salida de este tipo.
# Load the GPT tokenizer. tokenizer = AutoTokenizer.from_pretrained("flax-community/gpt-2-spanish", bos_token='<|startoftext|>', eos_token='<|endoftext|>', pad_token='<|pad|>') model = AutoModelForCausalLM.from_pretrained("flax-community/gpt-2-spanish") control_code = "ibai" special_tokens_dict = { "additional_special_tokens": ['f"<|{control_code}|>"'], } num_added_toks = tokenizer.add_special_tokens(special_tokens_dict) model.resize_token_embeddings(len(tokenizer)) unk_tok_emb = model.transformer.wte.weight.data[tokenizer.unk_token_id, :] for i in range(num_added_toks): model.transformer.wte.weight.data[-(i+1), :] = unk_tok_emb
Creamos una clase python que hereda de Dataset que recibe el archivo txt que contiene los textos para fine-tuning.
class GPT2Dataset(Dataset): def __init__(self, control_code, tokenizer, archivo_texto, max_length=768): self.tokenizer = tokenizer self.input_ids = [] self.attn_masks = [] print('loading text...') sentences = open(archivo_texto, 'r', encoding="utf-8").read().lower().split('n') print('qty:',len(sentences)) for row in tqdm(sentences): encodings_dict = tokenizer('<|startoftext|>'+ f"<|{control_code}|>" + row + '<|endoftext|>', truncation=True, max_length=max_length, padding="max_length") self.input_ids.append(torch.tensor(encodings_dict['input_ids'])) self.attn_masks.append(torch.tensor(encodings_dict['attention_mask'])) def __len__(self): return len(self.input_ids) def __getitem__(self, idx): return self.input_ids[idx], self.attn_masks[idx]
Instanciamos la clase, pasando el nombre de archivo “ibai_textos.txt” a utilizar
dataset = GPT2Dataset(control_code, tokenizer, archivo_texto="ibai_textos.txt", max_length=768) # Split into training and validation sets train_size = int(0.99 * len(dataset)) val_size = len(dataset) - train_size train_dataset, val_dataset = random_split(dataset, [train_size, val_size]) print('{:>5,} training samples'.format(train_size)) print('{:>5,} validation samples'.format(val_size)) train_dataloader = DataLoader( train_dataset, # The training samples. sampler = RandomSampler(train_dataset), # Select batches randomly batch_size = batch_size # Trains with this batch size. )
Realizando entre 1 y 3 epochs debería ser suficiente para que el modelo quede tuneado.
epochs = 1 learning_rate = 5e-4 warmup_steps = 1e2 epsilon = 1e-8 optimizer = AdamW(model.parameters(), lr = learning_rate, eps = epsilon) total_steps = len(train_dataloader) * epochs scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps = warmup_steps, num_training_steps = total_steps) def format_time(elapsed): return str(datetime.timedelta(seconds=int(round((elapsed)))))
Ahora si, a entrenar el modelo durante cerca de 2 horas si tenemos GPU ó durante un día entero en CPU.
El código es bastante estándar en PyTorch para entreno de redes neuronales profundas; un loop principal por epoch donde procesamos por batches las líneas de texto del dataset y hacemos backpropagation.
total_t0 = time.time() model = model.to(device) for epoch_i in range(0, epochs): print('======== Epoch {:} / {:} ========'.format(epoch_i + 1, epochs)) print('Training...') t0 = time.time() total_train_loss = 0 model.train() for step, batch in enumerate(train_dataloader): b_input_ids = batch[0].to(device) b_labels = batch[0].to(device) b_masks = batch[1].to(device) model.zero_grad() outputs = model( b_input_ids, labels=b_labels, attention_mask = b_masks, token_type_ids=None ) loss = outputs[0] batch_loss = loss.item() total_train_loss += batch_loss # Get sample every x batches. if step % sample_every == 0 and not step == 0: elapsed = format_time(time.time() - t0) print(' Batch {:>5,} of {:>5,}. Loss: {:>5,}. Elapsed: {:}.'.format(step, len(train_dataloader), batch_loss, elapsed)) loss.backward() optimizer.step() scheduler.step() # Calculate the average loss over all of the batches. avg_train_loss = total_train_loss / len(train_dataloader) # Measure how long this epoch took. training_time = format_time(time.time() - t0) print("") print(" Average training loss: {0:.2f}".format(avg_train_loss)) print(" Training epoch took: {:}".format(training_time)) t0 = time.time() total_eval_loss = 0 nb_eval_steps = 0 print("Training complete!") print("Total training took {:} (h:mm:ss)".format(format_time(time.time()-total_t0)))
El tiempo de entreno varía según tu ordenador, memoria RAM y si tienes o no placa de video con GPU.
Luego de varias horas de entreno, mejor guardar el modelo para no tener que reentrenar cada vez y reutilizar el modelo que hicimos. Para guardar hacemos:
output_dir = './model_gpt_ibai/' if not os.path.exists(output_dir): os.makedirs(output_dir) model_to_save = model.module if hasattr(model, 'module') else model model_to_save.save_pretrained(output_dir) tokenizer.save_pretrained(output_dir)
En la notebook con el ejercicio verás también una celda con el código de ejemplo para cargar tu modelo ya entrenado.
Generamos 3 salidas preguntando ¿Qué es el fútbol? con máximo de 300 caracteres. Puedes variar estos parámetros para obtener más párrafos y con un máximo de 764 letras.
Fijate que agregamos al prompt el token de control de inicio (startoftext) pero también nuestro token de control que llamamos “ibai”.
model.eval() prompt = "<|startoftext|>" + "<|ibai|>" + "¿ qué es el fútbol ?" generated = torch.tensor(tokenizer.encode(prompt)).unsqueeze(0) generated = generated.to(device) sample_outputs = model.generate( generated, num_return_sequences=3, max_length = 300, do_sample=True, top_k=50, top_p=0.95 ) for i, sample_output in enumerate(sample_outputs): print("{}: {}nn".format(i, tokenizer.decode(sample_output, skip_special_tokens=True)))
Y obtenemos como salidas:
Ahora ya puedes jugar y probar tú mismo con distintas salidas!
Aquí te dejo algunos ejemplos divertidos que conseguí (pinto en negrita el comienzo del prompt enviado al modelo):
En estos días estamos viendo cómo ChatGPT está siendo trending topic por ser el modelo GPT más poderoso y versátil de OpenAI, con capacidad de responder a cualquier pregunta, traducir idiomas, dar definiciones, crear poesía, historias y realizar snippets de código python.
En este artículo te acercamos un poco más a conocer qué son los modelos GPT que están revolucionando el campo del NLP mediante un ejercicio práctico.
Ya conoces un poco más sobre la librería transformers de HuggingFace, sobre los distintos modelos que puedes descargar en tu ordenador y personalizar. Como siempre, esto es sólo la punta del iceberg, te invito a que sigas investigando y aprendiendo más sobre todo ello y me dejes tus comentarios al respecto.
Nos vemos en el próximo post!
Puedes descargar la notebook con el ejercicio completo y el archivo con los textos de Ibai.
Recibe los próximos artículos sobre Machine Learning, estrategias, teoría y código Python en tu casilla de correo!
NOTA: algunos usuarios reportaron que el email de confirmación y/o posteriores a la suscripción entraron en su carpeta de SPAM. Te sugiero que revises y recomiendo que agregues nuestro remitente info @ aprendemachinelearning.com a tus contactos para evitar problemas. Gracias!
Si te gustan los contenidos del blog y quieres darme tu apoyo, puedes comprar el libro en papel, ó en digital (también lo puede descargar gratis!).
The post Generación de Texto en Español con GPT-2 first appeared on Aprende Machine Learning.
]]>