15. Introducción a la generación de texto.#
NOTA1: Este documento es una traducción del documento que se puede ver en este enlace .
NOTA2: Se aconseja ejecutar los códigos que aquí se presentan en google colab si no se dispone de un ordenador potente y con GPU para agilizar la ejecución del código
Generar texto sin sentido es un ejercicio de programación sencillo para principiantes, pero completar una oración de forma significativa requeriría mucho trabajo. El panorama de la tecnología de autocompletado se ha transformado drásticamente con la introducción de enfoques neuronales. Con la biblioteca de transformers de Hugging Face, implementar el autocompletado de texto requiere solo unas pocas líneas de código. En este tutorial completo, implementará varios ejemplos y explorará cómo los sistemas modernos se diferencian de los tradicionales y por qué estas diferencias son importantes.
15.1. Descripción general.#
Este apartado consta de cuatro bloques:
Enfoques tradicionales y enfoques neuronales
Arquitectura de autocompletado
Implementación básica de autocompletar
Almacenamiento en caché y entrada por lotes
15.2. Enfoques tradicionales y enfoques neuronales#
Cuando escribes una palabra en la barra de búsqueda de Google, como “máquina”, es posible que aparezcan otras palabras adicionales, como “aprendizaje”, para formar “aprendizaje automático”. Se trata de una tecnología de autocompletado . La sugerencia puede no ser la que esperas, pero siempre es coherente.
Los sistemas tradicionales de autocompletado se han basado en métodos relativamente estadísticos. Los modelos de N-gram predicen la siguiente palabra observando una ventana fija de palabras anteriores y comparándolas con muestras recopiladas. Este método tiene dificultades con contextos más largos y combinaciones novedosas. Los enfoques basados en diccionarios solo pueden sugerir palabras que ya han visto antes, lo que limita su capacidad para manejar terminología nueva. El análisis de frecuencia proporciona sugerencias basadas en patrones comunes, pero a menudo pasa por alto el contexto matizado del texto actual.
Los sistemas de autocompletado neuronal, en particular los basados en GPT-2, representan un cambio fundamental en la capacidad. Estos sistemas entienden el contexto en lugar de buscar coincidencias de palabras. Consideran todo el alcance del texto anterior en lugar de solo unas pocas palabras. Captan relaciones semánticas, lo que les permite sugerir opciones de finalización que coinciden no solo con la gramática sino también con el significado del texto. La capacidad generativa les permite producir frases u oraciones completas que mantienen la coherencia con el contenido existente.
15.3. Arquitectura de autocompletado.#
Un moderno sistema de autocompletado neuronal integra varios componentes sofisticados que funcionan juntos sin problemas.
El modelo de lenguaje funciona como motor cognitivo. Procesa el texto de entrada y mantiene un estado interno para capturar los matices del proceso de generación de texto en curso. El componente de tokenización actúa como un puente entre el texto legible por humanos y las representaciones numéricas del modelo. El controlador de generación organiza el proceso, empleando estrategias avanzadas para filtrar y clasificar las posibles finalizaciones. Equilibra cuidadosamente el tiempo de respuesta y la calidad de las sugerencias, lo que garantiza que los usuarios reciban finalizaciones útiles sin demoras notables.
El desarrollo de un sistema de autocompletado neuronal eficaz implica superar varios desafíos críticos. La latencia es una preocupación principal, ya que los usuarios esperan un tiempo de respuesta en milisegundos mientras manejan la complejidad computacional de las operaciones de redes neuronales.
El control de calidad es otro desafío. Se espera que el sistema genere sugerencias relevantes, por lo que se requieren mecanismos de filtrado avanzados para evitar que se completen los campos de forma inapropiada y garantizar que las sugerencias se ajusten al dominio y al estilo de escritura del usuario.
La gestión de recursos es crucial a la hora de escalar el sistema para que admita a varios usuarios. Las importantes demandas de memoria de los modelos neuronales y la intensidad computacional de la generación de texto deben equilibrarse cuidadosamente con los recursos del sistema y los requisitos de tiempo de respuesta.
15.4. Implementación básica de autocompletar#
Dejemos de lado las consideraciones de un sistema más grande y centrémonos en una función de autocompletado simple para texto parcial. Es fácil de implementar utilizando los modelos entrenados previamente de la biblioteca de transformers:
(El modelo que utilizamos aquí lo podemos ver en HugginFace en este enlace )
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
class AutoComplete:
def __init__(self, model_name='gpt2'):
"""Initialize the auto-complete system."""
self.tokenizer = GPT2Tokenizer.from_pretrained(model_name)
self.model = GPT2LMHeadModel.from_pretrained(model_name)
self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
self.model.to(self.device)
self.model.eval() # Set to evaluation mode
def get_completion(self, text, max_length=50):
"""Generate completion for the input text."""
# Encode the input text
inputs = self.tokenizer(text, add_special_tokens=False, return_tensors="pt")
input_ids = inputs["input_ids"].to(self.device)
attn_masks = inputs["attention_mask"].to(self.device)
# Generate completion
with torch.no_grad():
outputs = self.model.generate(
input_ids,
attention_mask=attn_masks,
max_length=max_length,
num_return_sequences=1,
pad_token_id=self.tokenizer.eos_token_id,
do_sample=True,
temperature=0.7
)
# Decode and extract completion
full_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
completion = full_text[len(text):]
return completion
# using autocomplete to see what we get
auto_complete = AutoComplete()
text = "The future of artificial"
completion = auto_complete.get_completion(text)
print(f"Input: {text}")
print(f"Completion: {completion}")
D:\MisTrabajos\IA_generativa\venv\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
Input: The future of artificial
Completion: intelligence is uncertain, but it is becoming increasingly likely that someday, when we become self-aware, we'll be able to "know" it.
In a recent article, Richard Schmalz and I discussed why self
Veamos qué hace el código anterior. Definió la clase AutoComplete, que se carga GPT2Tokenizercomo tokenizador de texto y GPT2LMHeadModelcomo un modelo GPT-2 entrenado previamente capaz de generar texto. El modelo está configurado en modo de evaluación ya que está utilizando el modelo, no para entrenarlo.
La generación de texto está en la función get_completion(). El texto de entrada se convierte en tokens antes de pasarlo al modelo. Invoca el modelo con torch.no_grad() contexto para omitir el cálculo del gradiente y ahorrar tiempo y memoria. Se llama al modelo con temperature=0.7 para lograr una creatividad equilibrada. La salida del modelo debe convertirse nuevamente en texto mediante el tokenizador. Los otros parámetros en self.model.generate() son:
num_return_sequences=1 para generar solo una finalización. El modelo puede generar múltiples salidas para la misma entrada.
pad_token_id=self.tokenizer.eos_token_id para evitar el relleno innecesario
do_sample=True para permitir el muestreo en lugar de la generación de texto determinista. Es necesario para la generación creativa.
15.5. Almacenamiento en caché y entrada por lotes.#
El código anterior funciona como un programa simple, pero necesita algo de pulido para ejecutarlo como un servicio.
Primero, implementemos un sistema de almacenamiento en caché para mejorar el rendimiento de las aplicaciones en tiempo real:
from functools import lru_cache
class CachedAutoComplete(AutoComplete):
def __init__(self, cache_size=1000, **kwargs):
"""Initialize with caching support."""
super().__init__(**kwargs)
self.get_completion = lru_cache(maxsize=cache_size)(
self.get_completion
)
Esto se basa en la clase anterior al decorar la función de generación con un caché LRU. La biblioteca de Python maneja el almacenamiento en caché automáticamente. Simplemente use CachedAutoComplete en lugar de AutoComplete y todo funcionará de la misma manera, excepto que el caché devolverá instantáneamente los resultados de las entradas procesadas previamente.
Ahora, optimicemos aún más el sistema para lograr un mejor rendimiento en tiempo real. Uno de los desafíos de la creación de un servicio es manejar varios usuarios simultáneamente, por lo que resulta beneficioso procesar varias entradas como un lote. Sin embargo, esto aumenta el uso de memoria. Puede mitigar la carga de trabajo adicional reduciendo el tamaño del modelo mediante números flotantes de 16 bits:
class OptimizedAutoComplete(CachedAutoComplete):
def __init__(self, **kwargs):
"""Initialize with optimizations."""
super().__init__(**kwargs)
self.tokenizer.pad_token = self.tokenizer.eos_token
if self.device == "cuda":
self.model = self.model.half() # Use FP16 on GPU
# use eval mode and cuda graphs
self.model.eval()
def preprocess_batch(self, texts):
"""Efficiently process multiple texts."""
# Tokenize all texts at once
inputs = self.tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
return inputs.to(self.device)
def generate_batch(self, texts, max_length=50):
"""Generate completions for multiple texts."""
# Preprocess batch
inputs = self.preprocess_batch(texts)
# Generate completions
with torch.no_grad():
outputs = self.model.generate(
inputs['input_ids'],
attention_mask=inputs['attention_mask'],
max_length=max_length,
num_return_sequences=1,
pad_token_id=self.tokenizer.eos_token_id,
do_sample=True,
temperature=0.7
)
# Decode completions
completions = self.tokenizer.batch_decode(outputs, skip_special_tokens=True)
# Extract new text
results = []
for text, completion in zip(texts, completions):
results.append(completion[len(text):])
return results
Convertir un modelo en un valor de punto flotante de 16 bits es tan sencillo como hacerlo self.model = self.model.half() en el constructor. La mayoría de las CPU no admiten valores de punto flotante de 16 bits. Por lo tanto, debe hacerlo solo si puede ejecutar el modelo en una GPU. Tenga en cuenta que la función generate_batch() es básicamente la misma que la función generate() anterior, pero debe procesar y colocar la salida por lotes en una lista.
A continuación se muestra el código completo, incluido cómo utilizar la generación por lotes:
from functools import lru_cache
from transformers import GPT2LMHeadModel, GPT2Tokenizer
import torch
class AutoComplete:
def __init__(self, model_name="gpt2"):
"""Initialize the auto-complete system."""
self.tokenizer = GPT2Tokenizer.from_pretrained(model_name, padding_side="left")
self.model = GPT2LMHeadModel.from_pretrained(model_name)
self.device = "cuda" if torch.cuda.is_available() else "cpu"
self.model.to(self.device)
self.model.eval() # Set to evaluation mode
def get_completion(self, text, max_length=50):
"""Generate completion for the input text."""
print("**** Completion:", text)
# Encode the input text
inputs = self.tokenizer(text, add_special_tokens=False, return_tensors="pt")
input_ids = inputs["input_ids"].to(self.device)
attn_masks = inputs["attention_mask"].to(self.device)
# Generate completion
with torch.no_grad():
outputs = self.model.generate(
input_ids,
attention_mask=attn_masks,
max_length=max_length,
num_return_sequences=1,
pad_token_id=self.tokenizer.eos_token_id,
do_sample=True,
temperature=0.7
)
# Decode and extract completion
full_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
completion = full_text[len(text):]
return completion
class CachedAutoComplete(AutoComplete):
def __init__(self, cache_size=1000, **kwargs):
"""Initialize with caching support."""
super().__init__(**kwargs)
self.get_completion = lru_cache(maxsize=cache_size)(
self.get_completion
)
class OptimizedAutoComplete(CachedAutoComplete):
def __init__(self, **kwargs):
"""Initialize with optimizations."""
super().__init__(**kwargs)
self.tokenizer.pad_token = self.tokenizer.eos_token
if self.device == "cuda":
self.model = self.model.half() # Use FP16 on GPU
# use eval mode and cuda graphs
self.model.eval()
def preprocess_batch(self, texts):
"""Efficiently process multiple texts."""
# Tokenize all texts at once
inputs = self.tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
return inputs.to(self.device)
def generate_batch(self, texts, max_length=50):
"""Generate completions for multiple texts."""
# Preprocess batch
inputs = self.preprocess_batch(texts)
# Generate completions
with torch.no_grad():
outputs = self.model.generate(
inputs["input_ids"],
attention_mask=inputs["attention_mask"],
max_length=max_length,
num_return_sequences=1,
pad_token_id=self.tokenizer.eos_token_id,
do_sample=True,
temperature=0.7
)
# Decode completions
completions = self.tokenizer.batch_decode(outputs, skip_special_tokens=True)
# Extract new text
results = []
for text, completion in zip(texts, completions):
results.append(completion[len(text):])
return results
# Example: Optimized batch completion
optimized_complete = OptimizedAutoComplete()
texts = [
"Machine learning is",
"Deep neural networks can",
"The training process involves"
]
completions = optimized_complete.generate_batch(texts)
for text, completion in zip(texts, completions):
print(f"\nInput: {text}")
print(f"Completion: {completion}")
Input: Machine learning is
Completion: the development of new applications that integrate with existing technology rather than develop new hardware and techniques. That is a very important distinction. As we continue to build new applications, we need to be able to develop new technologies that are less dependent
Input: Deep neural networks can
Completion: create a network of neurons capable of processing different types of information (e.g., the information that is received by a neuron and what is received by an electric field). The neural network that generates this information can then be used to
Input: The training process involves
Completion: three stages: the first is the initial setup, the second is the initial implementation, and the third is the final execution. The third stage consists of the execution of the training process, with the final step having been completed. The
15.6. Resumen#
En este tutorial, se ha visto cómo crear un sistema de autocompletado inteligente utilizando GPT-2. En concreto, se ha expuesto lo siguiente:
La teoría detrás de los sistemas de autocompletado neuronal
Cómo implementar el autocompletado básico
Cómo agregar almacenamiento en caché para un mejor rendimiento
Cómo hacer sugerencias teniendo en cuenta el contexto
Cómo optimizar para el uso en tiempo real
15.7. Bases de datos vectoriales.#
🚀