Transformers documentation
Génération de texte
Génération de texte
La génération de texte est l’application la plus populaire des grands modèles de langage (LLM). Un LLM est entraîné à générer le mot suivant (jeton) à partir d’un texte initial (invite) ainsi que de ses propres sorties générées, jusqu’à une longueur prédéfinie ou lorsqu’il atteint un jeton de fin de séquence (EOS).
Dans Transformers, l'API generate() gère la génération de texte et est disponible pour tous les modèles dotés de capacités génératives. Ce guide vous présente les bases de la génération de texte avec generate() ainsi que les pièges courants à éviter.
Pour les commandes suivantes, assurez-vous que
transformers serveest en cours d'exécution.transformers chat Qwen/Qwen2.5-0.5B-Instruct
Génération par défaut
Avant de commencer, il est utile d'installer bitsandbytes pour quantifier les très grands modèles afin de réduire leur consommation mémoire.
!pip install -U transformers bitsandbytes
Bitsandbytes prend en charge plusieurs backends en plus des GPU basés sur CUDA. Consultez le guide d’installation multi-backend pour en savoir plus.
Chargez un LLM avec from_pretrained() et ajoutez les deux paramètres suivants pour réduire les besoins en mémoire.
device_map="auto"active la fonctionnalité Big Model Inference d’Accelerate, qui initialise automatiquement le squelette du modèle et charge et répartit les poids du modèle sur tous les dispositifs disponibles, en commençant par le dispositif le plus rapide (GPU).quantization_configest un objet de configuration qui définit les paramètres de quantification. Cet exemple utilise bitsandbytes comme backend de quantification (voir la section Quantization pour d'autres backends disponibles) et charge le modèle 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)Tokenisez votre entrée et définissez le paramètre padding_side() sur "left", car un LLM n'est pas entraîné à poursuivre la génération à partir de jetons de bourrage. Le tokeniseur renvoie les identifiants d'entrée et le masque d'attention.
Traitez plusieurs invites à la fois en passant une liste de chaînes au tokenizer. Regroupez les entrées en lots pour améliorer le débit, au prix d'un léger surcoût en latence et en mémoire.
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)Transmettez les entrées à generate() pour générer des jetons, puis utilisez batch_decode() pour convertir les jetons générés en texte.
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,"Configuration de génération
Tous les paramètres de génération sont contenus dans GenerationConfig. Dans l’exemple ci-dessus, les paramètres de génération sont dérivés du fichier generation_config.json de mistralai/Mistral-7B-v0.1. Une stratégie de décodage par défaut est utilisée lorsqu’aucune configuration n’est enregistrée avec un modèle.
Inspectez la configuration via l'attribut generation_config. N'affiche que les valeurs différentes de la configuration par défaut, en l'occurrence bos_token_id et 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
}Vous pouvez personnaliser generate() en surchargeant les paramètres et les valeurs de GenerationConfig. Consultez cette section ci-dessous pour les paramètres couramment ajustés.
# enable beam search sampling strategy
model.generate(**inputs, num_beams=4, do_sample=True)generate() peut également être étendu avec des bibliothèques externes ou du code personnalisé :
- le paramètre
logits_processoraccepte des instances personnalisées de LogitsProcessor pour manipuler la distribution de probabilité du jeton suivant ; - le paramètre
stopping_criteriaprend en charge des StoppingCriteria personnalisés pour arrêter la génération de texte ; - d'autres méthodes de génération personnalisées peuvent être chargées via le drapeau
custom_generate(docs).
Consultez le guide Stratégies de génération pour en savoir plus sur les stratégies de recherche, d'échantillonnage et de décodage.
Enregistrement
Créez une instance de GenerationConfig et spécifiez les paramètres de décodage souhaités.
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
)Utilisez save_pretrained() pour enregistrer une configuration de génération spécifique et définissez le paramètre push_to_hub sur True pour le téléverser sur le Hub.
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)Laissez le paramètre config_file_name vide. Ce paramètre doit être utilisé lors du stockage de plusieurs configurations de génération dans un même répertoire. Il vous permet de spécifier quelle configuration de génération charger. Vous pouvez créer différentes configurations pour différentes tâches génératives (génération de texte créatif avec échantillonnage, résumés avec beam search) à utiliser avec un seul modèle.
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))Options courantes
generate() est un outil puissant qui peut être fortement personnalisé. Cela peut intimider les nouveaux utilisateurs. Cette section contient une liste des options de génération populaires que vous pouvez définir dans la plupart des outils de génération de texte de Transformers : generate(), GenerationConfig, pipelines, le CLI chat, …
| Nom de l'option | Type | Description simplifiée |
|---|---|---|
max_new_tokens | int | Contrôle la longueur maximale de génération. Assurez-vous de le définir, car il est généralement défini par défaut sur une valeur faible. |
do_sample | bool | Définit si la génération échantillonne le jeton suivant (True) ou si elle est au contraire gloutonne (False). La plupart des cas d’utilisation doivent définir ce drapeau sur True. Consultez ce guide pour plus d’informations. |
temperature | float | Mesure de l’imprévisibilité du prochain jeton sélectionné. Des valeurs élevées (>0.8) sont adaptées aux tâches créatives, tandis que des valeurs faibles (par ex. <0.4) conviennent aux tâches nécessitant du « raisonnement ». Nécessite do_sample=True. |
num_beams | int | Lorsqu'il est défini sur >1, active l'algorithme de beam search. Le beam search est efficace pour les tâches fondées sur l'entrée. Consultez ce guide pour plus d'informations. |
repetition_penalty | float | Définissez-le à une valeur >1.0 si vous constatez que le modèle se répète souvent. Des valeurs plus élevées appliquent une pénalité plus importante. |
eos_token_id | list[int] | Le(s) jeton(s) qui provoqueront l'arrêt de la génération. La valeur par défaut est généralement bonne, mais vous pouvez spécifier un jeton différent. |
Pièges
La section ci-dessous aborde certains problèmes courants que vous pouvez rencontrer lors de la génération de texte et comment les résoudre.
Longueur de la sortie
generate() renvoie par défaut jusqu’à 20 jetons, sauf si une autre valeur est spécifiée dans la GenerationConfig du modèle. Il est fortement recommandé de définir manuellement le nombre de jetons générés à l’aide du paramètre max_new_tokens afin de contrôler la longueur de la sortie. Les modèles Decoder-only renvoient le prompt initial ainsi que les jetons générés.
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,'Stratégie de décodage
La stratégie de décodage par défaut dans generate() est la recherche gloutonne, qui sélectionne le jeton le plus probable, sauf si une autre stratégie est spécifiée dans la GenerationConfig d’un modèle. Bien que cette stratégie de décodage fonctionne bien pour les tâches ancrées dans l’entrée (transcription, traduction), elle n’est pas optimale pour les cas d’usage plus créatifs (rédaction de récits, applications de chat).
Par exemple, activez une stratégie de multinomial sampling pour générer des sorties plus variées. Consultez le guide Generation strategy pour en savoir plus sur les stratégies de décodage.
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]Côté de bourrage
Les entrées doivent être remplies (padding) si elles n’ont pas la même longueur. Mais les LLM ne sont pas entraînés à poursuivre la génération à partir de jetons de remplissage, ce qui signifie que le paramètre padding_side() doit être défini à gauche de l’entrée. Le remplissage à droite est plus défavorable pour les modèles à espace d’état et hybrides, car leur état récurrent continue de se mettre à jour sur les jetons de remplissage de fin, si bien que le cache ne correspond plus à la fin du 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,'Format du prompt
Certains modèles et tâches attendent un format de prompt d’entrée spécifique, et si le format est incorrect, le modèle renvoie une sortie sous-optimale. Vous pouvez en savoir plus sur le prompting dans le guide prompt engineering.
Par exemple, un modèle de chat s’attend à recevoir l’entrée sous forme de chat template. Votre invite doit inclure un role et un content pour indiquer qui participe à la conversation. Si vous essayez de passer votre invite sous forme d’une seule chaîne de caractères, le modèle ne renvoie pas toujours la sortie attendue.
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 canRessources
Consultez ci-dessous quelques bibliothèques de génération de texte plus spécifiques et spécialisées.
- Optimum : une extension de Transformers axée sur l’optimisation de l’entraînement et de l’inférence sur des dispositifs matériels spécifiques
- Outlines : une bibliothèque pour la génération de texte contrainte (générer des fichiers JSON, par exemple).
- SynCode : une bibliothèque pour la génération guidée par grammaires sans contexte (JSON, SQL, Python).
- Text Generation Inference : un serveur prêt pour la production destiné aux LLM.
- Text generation web UI : une interface web Gradio pour la génération de texte.
- logits-processor-zoo : processeurs de logits supplémentaires pour contrôler la génération de texte.