Transformers documentation
Generación de texto
Generación de texto
La generación de texto es la aplicación más popular de los modelos de lenguaje grandes (LLM). Un LLM se entrena para generar la siguiente palabra (token) a partir de un texto inicial (prompt) junto con sus propias salidas generadas hasta una longitud predefinida o cuando alcanza un token de fin de secuencia (EOS).
En Transformers, la API generate() gestiona la generación de texto y está disponible para todos los modelos con capacidades generativas. Esta guía te mostrará las bases de la generación de texto con generate() y algunos errores comunes a evitar.
Para los siguientes comandos, asegúrese de que
transformers serveesté en ejecución.transformers chat Qwen/Qwen2.5-0.5B-Instruct
Generación predeterminada
Antes de comenzar, es útil instalar bitsandbytes para cuantizar modelos muy grandes y reducir su uso de memoria.
!pip install -U transformers bitsandbytes
Bitsandbytes admite varios backends además de las GPU basadas en CUDA. Consulte la guía de instalación multi-backend para obtener más información.
Carga un LLM con from_pretrained() y añade los siguientes dos parámetros para reducir los requisitos de memoria.
device_map="auto"habilita la función Big Model Inference de Accelerate para iniciar automáticamente el esqueleto del modelo y cargar y distribuir los pesos del modelo en todos los dispositivos disponibles, comenzando por el dispositivo más rápido (GPU).quantization_configes un objeto de configuración que define los ajustes de cuantización. Este ejemplo utiliza bitsandbytes como backend de cuantización (consulte la sección Cuantización para ver más backends disponibles) y carga el modelo en 4 bits.
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto", quantization_config=quantization_config)Tokeniza tu entrada y establece el parámetro padding_side() en "left" porque un LLM no está entrenado para continuar la generación desde tokens de relleno. El tokenizador devuelve los ids de entrada y la máscara de atención.
Procesar más de un prompt a la vez pasando una lista de cadenas al tokenizer. Agrupar las entradas en lotes para mejorar el rendimiento a un pequeño costo en latencia y memoria.
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to(model.device)Pasa las entradas a generate() para generar tokens y usa batch_decode() para convertir los tokens generados de nuevo en texto.
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
"A list of colors: red, blue, green, yellow, orange, purple, pink,"Configuración de generación
Todos los ajustes de generación están contenidos en GenerationConfig. En el ejemplo anterior, los ajustes de generación se derivan del archivo generation_config.json de mistralai/Mistral-7B-v0.1. Se utiliza una estrategia de decodificación predeterminada cuando no se guarda ninguna configuración con un modelo.
Inspeccione la configuración a través del atributo generation_config. Solo muestra los valores que difieren de la configuración predeterminada, en este caso, bos_token_id y eos_token_id.
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto")
model.generation_config
GenerationConfig {
"bos_token_id": 1,
"eos_token_id": 2
}Puedes personalizar generate() sobrescribiendo los parámetros y valores en GenerationConfig. Consulta esta sección más abajo para ver los parámetros que se ajustan con mayor frecuencia.
# enable beam search sampling strategy
model.generate(**inputs, num_beams=4, do_sample=True)generate() también se puede extender con bibliotecas externas o código personalizado:
- el parámetro
logits_processoracepta instancias personalizadas de LogitsProcessor para manipular la distribución de probabilidad del siguiente token; - El parámetro
stopping_criteriaadmite StoppingCriteria personalizados para detener la generación de texto; - otros métodos de generación personalizados se pueden cargar a través de la bandera
custom_generate(documentación).
Consulte la guía de Estrategias de generación para obtener más información sobre las estrategias de búsqueda, muestreo y decodificación.
Guardado
Cree una instancia de GenerationConfig y especifique los parámetros de decodificación que desee.
from transformers import AutoModelForCausalLM, GenerationConfig
model = AutoModelForCausalLM.from_pretrained("my_account/my_model")
generation_config = GenerationConfig(
max_new_tokens=50, do_sample=True, top_k=50, eos_token_id=model.config.eos_token_id
)Use save_pretrained() para guardar una configuración de generación específica y establezca el parámetro push_to_hub en True para subirlo al Hub.
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)Deja el parámetro config_file_name vacío. Este parámetro debe usarse cuando se almacenan varias configuraciones de generación en un solo directorio. Te permite especificar qué configuración de generación cargar. Puedes crear configuraciones diferentes para tareas generativas distintas (generación de texto creativo con muestreo, resumen con búsqueda de haces) para usarlas con un solo modelo.
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, GenerationConfig
tokenizer = AutoTokenizer.from_pretrained("google-t5/t5-small")
model = AutoModelForSeq2SeqLM.from_pretrained("google-t5/t5-small")
translation_generation_config = GenerationConfig(
num_beams=4,
early_stopping=True,
decoder_start_token_id=0,
eos_token_id=model.config.eos_token_id,
pad_token=model.config.pad_token_id,
)
translation_generation_config.save_pretrained("/tmp", config_file_name="translation_generation_config.json", push_to_hub=True)
generation_config = GenerationConfig.from_pretrained("/tmp", config_file_name="translation_generation_config.json")
inputs = tokenizer("translate English to French: Configuration files are easy to use!", return_tensors="pt")
outputs = model.generate(**inputs, generation_config=generation_config)
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))Opciones comunes
generate() es una herramienta potente que se puede personalizar en gran medida. Esto puede resultar abrumador para los usuarios nuevos. Esta sección contiene una lista de opciones de generación populares que puedes definir en la mayoría de las herramientas de generación de texto de Transformers: generate(), GenerationConfig, pipelines, la CLI chat, …
| Nombre de la opción | Tipo | Descripción simplificada |
|---|---|---|
max_new_tokens | int | Controla la longitud máxima de generación. Asegúrate de definirla, ya que por defecto suele tener un valor pequeño. |
do_sample | bool | Define si la generación muestreará el siguiente token (True) o si, en su lugar, será codiciosa (False). La mayoría de los casos de uso deben establecer esta bandera en True. Consulte esta guía para obtener más información. |
temperature | float | Qué tan impredecible será el siguiente token seleccionado. Los valores altos (>0.8) son adecuados para tareas creativas, mientras que los valores bajos (p. ej. <0.4) son para tareas que requieren “razonamiento”. Requiere do_sample=True. |
num_beams | int | Cuando se establece en >1, activa el algoritmo de búsqueda por haz (beam search). La búsqueda por haz es adecuada para tareas basadas en la entrada. Consulta esta guía para obtener más información. |
repetition_penalty | float | Establécelo en >1.0 si ves que el modelo se repite con frecuencia. Los valores más grandes aplican una penalización mayor. |
eos_token_id | list[int] | El o los tokens que harán que la generación se detenga. El valor predeterminado suele ser adecuado, pero puedes especificar un token diferente. |
Errores comunes
La sección siguiente aborda algunos problemas comunes que puede encontrar durante la generación de texto y cómo resolverlos.
Longitud de la salida
generate() devuelve hasta 20 tokens de forma predeterminada, a menos que se especifique lo contrario en la GenerationConfig de un modelo. Se recomienda encarecidamente establecer manualmente el número de tokens generados con el parámetro max_new_tokens para controlar la longitud de la salida. Los modelos Decoder-only devuelven el prompt inicial junto con los tokens generados.
model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to(model.device)generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5'generated_ids = model.generate(**model_inputs, max_new_tokens=50)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'Estrategia de decodificación
La estrategia de decodificación predeterminada en generate() es greedy search, que selecciona el siguiente token más probable, a menos que se especifique lo contrario en la GenerationConfig de un modelo. Aunque esta estrategia de decodificación funciona bien para tareas basadas en la entrada (transcripción, traducción), no es óptima para casos de uso más creativos (escritura de historias, aplicaciones de chat).
Por ejemplo, active una estrategia de muestreo multinomial para generar salidas más diversas. Consulte la guía de Estrategia de generación para conocer más estrategias de decodificación.
model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to(model.device)generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]generated_ids = model.generate(**model_inputs, do_sample=True)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]Lado de relleno
Las entradas deben rellenarse si no tienen la misma longitud. Sin embargo, los LLM no se entrenan para continuar la generación desde tokens de relleno, lo que significa que el parámetro padding_side() debe establecerse a la izquierda de la entrada. El relleno a la derecha es peor para los modelos de espacio de estado e híbridos, ya que su estado recurrente sigue actualizándose sobre los tokens de relleno finales, por lo que la caché ya no coincide con el final del prompt.
model_inputs = tokenizer(
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 33333333333'tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
tokenizer.pad_token = tokenizer.eos_token
model_inputs = tokenizer(
["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 3, 4, 5, 6,'Formato del prompt
Algunos modelos y tareas esperan un formato de entrada específico, y si el formato es incorrecto, el modelo devuelve una salida subóptima. Puede obtener más información sobre el prompting en la guía de ingeniería de prompts.
Por ejemplo, un modelo de chat espera la entrada como una plantilla de chat. Tu indicación debe incluir un role y un content para indicar quién participa en la conversación. Si intentas pasar tu indicación como una sola cadena de texto, el modelo no siempre devuelve la salida esperada.
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
model = AutoModelForCausalLM.from_pretrained(
"HuggingFaceH4/zephyr-7b-alpha", device_map="auto", quantization_config=BitsAndBytesConfig(load_in_4bit=True)
)prompt = """How many cats does it take to change a light bulb? Reply as a pirate."""
model_inputs = tokenizer([prompt], return_tensors="pt").to(model.device)
input_length = model_inputs.input_ids.shape[1]
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Aye, matey! 'Tis a simple task for a cat with a keen eye and nimble paws. First, the cat will climb up the ladder, carefully avoiding the rickety rungs. Then, with"messages = [
{
"role": "system",
"content": "You are a friendly chatbot who always responds in the style of a pirate",
},
{"role": "user", "content": "How many cats does it take to change a light bulb?"},
]
model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
input_length = model_inputs["input_ids"].shape[1]
generated_ids = model.generate(**model_inputs, do_sample=True, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Arr, matey! According to me beliefs, 'twas always one cat to hold the ladder and another to climb up it an’ change the light bulb, but if yer looking to save some catnip, maybe yer canRecursos
A continuación, echa un vistazo a algunas bibliotecas de generación de texto más específicas y especializadas.
- Optimum: una extensión de Transformers centrada en optimizar el entrenamiento y la inferencia en dispositivos de hardware específicos
- Outlines: una biblioteca para la generación de texto restringida (por ejemplo, generar archivos JSON).
- SynCode: una biblioteca para la generación guiada por gramáticas libres de contexto (JSON, SQL, Python).
- Text Generation Inference: un servidor listo para producción para LLMs.
- Text generation web UI: una interfaz web de Gradio para la generación de texto.
- logits-processor-zoo: procesadores de logits adicionales para controlar la generación de texto.