Transformers documentation
Estrategias de generación
Estrategias de generación
Una estrategia de decodificación determina cómo un modelo debe seleccionar el siguiente token generado. Existen muchos tipos de estrategias de decodificación, y elegir la adecuada tiene un impacto significativo en la calidad del texto generado.
Esta guía te ayudará a comprender las diferentes estrategias de decodificación disponibles en Transformers y cómo y cuándo utilizarlas.
Métodos básicos de decodificación
Estos son métodos de decodificación bien establecidos y deben ser tu punto de partida para las tareas de generación de texto.
Búsqueda voraz
La búsqueda voraz es la estrategia de decodificación predeterminada. Selecciona el token más probable en cada paso. A menos que se especifique en GenerationConfig, esta estrategia genera un máximo de 20 tokens nuevos.
La búsqueda voraz funciona bien para tareas con salidas relativamente cortas donde la creatividad no es una prioridad. Sin embargo, falla al generar secuencias más largas porque comienza a repetirse.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to default length because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'Muestreo
El muestreo, o muestreo multinomial, selecciona un token de forma aleatoria según la distribución de probabilidad sobre todo el vocabulario del modelo (a diferencia del token más probable, como en la búsqueda codiciosa). Esto significa que cada token con una probabilidad distinta de cero tiene la posibilidad de ser seleccionado. Las estrategias de muestreo reducen la repetición y pueden generar salidas más creativas y diversas.
Habilite el muestreo multinomial con do_sample=True y num_beams=1.
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'Búsqueda por haz
La búsqueda por haz (beam search) mantiene el seguimiento de varias secuencias generadas (haces) en cada paso de tiempo. Después de un cierto número de pasos, selecciona la secuencia con la probabilidad global más alta. A diferencia de la búsqueda codiciosa (greedy search), esta estrategia puede “mirar hacia adelante” y elegir una secuencia con una probabilidad global más alta, incluso si los tokens iniciales tienen una probabilidad más baja. Es la más adecuada para tareas basadas en la entrada, como describir una imagen o el reconocimiento de voz. También puede usar do_sample=True con la búsqueda por haz para muestrear en cada paso, pero la búsqueda por haz aún recortará de forma codiciosa las secuencias de baja probabilidad entre pasos.
Echa un vistazo al visualizador de beam search para ver cómo funciona el beam search.
Active la búsqueda por haz con el parámetro num_beams (debe ser mayor que 1, de lo contrario es equivalente a la búsqueda codiciosa).
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator
device = Accelerator().device
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"Métodos de generación personalizados
Los métodos de generación personalizados permiten un comportamiento especializado, como:
- que el modelo continúe pensando si no está seguro;
- revertir la generación si el modelo se atasca;
- manejar tokens especiales con lógica personalizada;
- utilizar cachés KV especializadas;
Habilitamos métodos de generación personalizados a través de repositorios de modelos, asumiendo una etiqueta de modelo y una estructura de archivos específicas (consulte la subsección siguiente). Esta función es una extensión del código de modelado personalizado y, al igual que este, requiere establecer trust_remote_code=True.
Si un repositorio de modelos contiene un método de generación personalizado, la forma más sencilla de probarlo es cargar el modelo y generar con él:
from transformers import AutoModelForCausalLM, AutoTokenizer
# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
# with custom generation code -> calling `generate` uses the custom generation method!
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
model = AutoModelForCausalLM.from_pretrained(
"transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
)
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
gen_out = model.generate(**inputs)
# you should now see its custom message, "✨ using a custom generation method ✨"
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'Los repositorios de modelos con métodos de generación personalizados tienen una propiedad especial: su método de generación se puede cargar desde cualquier modelo a través del argumento custom_generate de generate(). Esto significa que cualquier persona puede crear y compartir su método de generación personalizado para que funcione potencialmente con cualquier modelo de Transformers, sin necesidad de que los usuarios instalen paquetes de Python adicionales.
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")
inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# `custom_generate` replaces the original `generate` by the custom generation method defined in
# `transformers-community/custom_generate_example`
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'Debes leer el archivo README.md del repositorio que contiene la estrategia de generación personalizada para ver si existen diferencias en los nuevos argumentos y el tipo de salida. De lo contrario, puedes asumir que funciona como el método base generate().
Puedes encontrar todos los métodos de generación personalizados buscando su etiqueta personalizada,
custom_generate.
Considere el repositorio del Hub transformers-community/custom_generate_example como ejemplo. El README.md indica que tiene un argumento de entrada adicional, left_padding, que añade un número de tokens de relleno antes del prompt.
gen_out = model.generate(
**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
)
print(tokenizer.batch_decode(gen_out)[0])
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'Si el método personalizado tiene requisitos de Python fijos que tu entorno no cumple, se producirá una excepción por requisitos faltantes. Por ejemplo, transformers-community/custom_generate_bad_requirements tiene un conjunto de requisitos imposible definido en su archivo custom_generate/requirements.txt, y verás el mensaje de error siguiente si intentas ejecutarlo.
ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`: foo (installed: None) bar==0.0.0 (installed: None) torch>=99.0 (installed: 2.6.0)
Actualizar los requisitos de Python en consecuencia eliminará este mensaje de error.
Creación de un método de generación personalizado
Para crear un nuevo método de generación, debe crear un nuevo repositorio de Model y subir algunos archivos a él.
- El modelo con el que has diseñado tu método de generación.
custom_generate/generate.py, que contiene toda la lógica de tu método de generación personalizado.custom_generate/requirements.txt, usado para agregar opcionalmente nuevos requisitos de Python y/o fijar versiones específicas para usar correctamente su método.README.md, donde debe añadir la etiquetacustom_generatey documentar aquí cualquier argumento nuevo o diferencia en el tipo de salida de su método personalizado.
Después de que hayas agregado todos los archivos requeridos, tu repositorio debería verse así
your_repo/
├── README.md # include the 'custom_generate' tag
├── config.json
├── ...
└── custom_generate/
├── generate.py
└── requirements.txtAñadiendo el modelo base
El punto de partida para su método de generación personalizado es un repositorio de modelos como cualquier otro. El modelo que debe agregarse a este repositorio es el modelo con el que diseñó su método, y está destinado a ser parte de un par funcional y autónomo de modelo-generación. Cuando se carga el modelo de este repositorio, su método de generación personalizado reemplazará a generate. No se preocupe: su método de generación aún puede cargarse con cualquier otro modelo de Transformers, como se explica en la sección anterior.
Si simplemente quieres copiar un modelo existente, puedes
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
model.save_pretrained("your/generation_method", push_to_hub=True)generate.py
Este es el núcleo de su método de generación. Debe contener un método llamado generate, y este método debe contener un argumento model como su primer argumento. model es la instancia del modelo, lo que significa que tiene acceso a todos los atributos y métodos del modelo, incluidos los definidos en GenerationMixin (como el método base generate).
generate.pydebe colocarse en una carpeta llamadacustom_generate, y no en el nivel raíz del repositorio. Las rutas de archivo para esta función están codificadas de forma fija.
Por debajo, cuando se llama al método base generate() con un argumento custom_generate, primero comprueba sus requisitos de Python (si los hay), luego localiza el método generate personalizado en generate.py y, finalmente, llama al generate personalizado. Todos los argumentos recibidos y model se reenvían a su método generate personalizado, con la excepción de los argumentos utilizados para activar la generación personalizada (trust_remote_code y custom_generate).
Esto significa que su generate puede tener una mezcla de argumentos originales y personalizados (así como un tipo de salida diferente), como se muestra a continuación.
import torch
def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
generation_config = generation_config or model.generation_config # default to the model generation config
cur_length = input_ids.shape[1]
max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens
# Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
if left_padding is not None:
if not isinstance(left_padding, int) or left_padding < 0:
raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")
pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
if pad_token is None:
raise ValueError("pad_token is not defined")
batch_size = input_ids.shape[0]
pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
input_ids = torch.cat((pad_tensor, input_ids), dim=1)
cur_length = input_ids.shape[1]
# Simple greedy decoding loop
while cur_length < max_length:
logits = model(input_ids).logits
next_token_logits = logits[:, -1, :]
next_tokens = torch.argmax(next_token_logits, dim=-1)
input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
cur_length += 1
return input_idsSiga las prácticas recomendadas a continuación para asegurarse de que su método de generación personalizado funcione como se espera.
- Puede reutilizar libremente la lógica de validación y preparación de entrada del generate() original.
- Fija la versión de
transformersen los requisitos si usas algún método o atributo privado enmodel. - Considera añadir validación del modelo, validación de la entrada o incluso un archivo de pruebas separado para ayudar a los usuarios a verificar que tu código funcione correctamente en su entorno.
Su método generate personalizado puede importar código de forma relativa desde la carpeta custom_generate. Por ejemplo, si tiene un archivo utils.py, puede importarlo de la siguiente manera:
from .utils import some_functionSolo se admiten importaciones relativas desde la carpeta custom_generate del mismo nivel. Las importaciones de carpetas padre o hermanas no son válidas. El argumento custom_generate también funciona localmente con cualquier directorio que contenga una estructura custom_generate, que es el flujo de trabajo recomendado para desarrollar su método de generación personalizado.
gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)Cargar un directorio local también ejecuta su
custom_generate/generate.py, por lo que requieretrust_remote_code=Trueal igual que un repositorio de Hub. Solo pasetrust_remote_code=Truepara código que haya escrito o revisado.
requirements.txt
Puedes especificar opcionalmente requisitos adicionales de Python en un archivo requirements.txt dentro de la carpeta custom_generate. Estos se comprueban en tiempo de ejecución y se lanzará una excepción si faltan, lo que anima a los usuarios a actualizar su entorno en consecuencia.
README.md
El README.md de nivel raíz en el repositorio del modelo suele describir el modelo en cuestión. Sin embargo, dado que el enfoque del repositorio es el método de generación personalizado, recomendamos encarecidamente cambiar su enfoque para describir el método de generación personalizado. Además de una descripción del método, recomendamos documentar cualquier diferencia en las entradas y/o salidas respecto al generate() original. De esta manera, los usuarios pueden centrarse en lo que es nuevo y confiar en la documentación de Transformers para los detalles de implementación genéricos.
Para mejorar la visibilidad, le recomendamos encarecidamente que agregue la etiqueta custom_generate a su repositorio. Para ello, la parte superior de su archivo README.md debe parecerse al ejemplo siguiente. Después de enviar el archivo, ¡debería ver la etiqueta en su repositorio!
--- library_name: transformers tags: - custom_generate --- (your markdown content here)
Prácticas recomendadas:
- Documenta las diferencias de entrada y salida en generate().
- Agregue ejemplos autocontenidos para facilitar la experimentación rápida.
- Describe los requisitos no estrictos, como si el método solo funciona bien con una cierta familia de modelos.
Reutilización de la preparación de la entrada de generate
Si estás añadiendo un nuevo bucle de decodificación, es posible que quieras conservar la preparación de la entrada presente en generate (expansión de lotes, máscaras de atención, procesadores de logits, criterios de parada, etc.). También puedes pasar un callable a custom_generate para reutilizar el pipeline completo de preparación de generate() y sobrescribir solo el bucle de decodificación.
def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
next_tokens = input_ids
while input_ids.shape[1] < stopping_criteria[0].max_length:
logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
next_token_logits = logits_processor(input_ids, logits[:, -1, :])
next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
input_ids = torch.cat((input_ids, next_tokens), dim=-1)
attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
return input_ids
output = model.generate(
**inputs,
custom_generate=custom_loop,
max_new_tokens=10,
)Si publicas un repositorio de
custom_generate, tu implementación degeneratepuede definir un callable y pasarlo amodel.generate(). Esto te permite personalizar el bucle de decodificación mientras sigues beneficiándote de la lógica de preparación de entradas integrada en Transformers.
Búsqueda de métodos de generación personalizados
Puedes encontrar todos los métodos de generación personalizados buscando su etiqueta personalizada, custom_generate. Además de la etiqueta, curamos dos colecciones de métodos custom_generate:
- Métodos de generación personalizados - Comunidad — una colección de métodos potentes aportados por la comunidad;
- Métodos de generación personalizados - Tutoriales — una colección de implementaciones de referencia para métodos que antes formaban parte de
transformers, así como tutoriales paracustom_generate.
Recursos
Lee la publicación de blog Cómo generar texto: uso de diferentes métodos de decodificación para la generación de lenguaje con Transformers para una explicación de cómo funcionan las estrategias de decodificación más comunes.
Update on GitHub