Transformers documentation
Генерация текста
Генерация текста
Генерация текста — самое популярное применение больших языковых моделей (LLM). LLM обучается генерировать следующее слово (токен) на основе начального текста (промпта) и собственных ранее сгенерированных выходов до достижения заданной длины или токена конца последовательности (EOS).
В Transformers API generate() отвечает за генерацию текста и доступен для всех моделей с генеративными возможностями. В этом руководстве вы познакомитесь с основами генерации текста с помощью generate() и узнаете о типичных ошибках, которых следует избегать.
Для следующих команд убедитесь, что
transformers serveзапущен.transformers chat Qwen/Qwen2.5-0.5B-Instruct
Генерация по умолчанию
Прежде чем начать, рекомендуется установить bitsandbytes для квантования очень больших моделей с целью снижения потребления памяти.
!pip install -U transformers bitsandbytes
Bitsandbytes поддерживает несколько бэкендов помимо CUDA-совместимых GPU. Подробнее см. в руководстве по установке с несколькими бэкендами.
Загрузите LLM с помощью from_pretrained() и добавьте следующие два параметра для снижения требований к памяти.
device_map="auto"включает функцию Big Model Inference в Accelerate, которая автоматически инициализирует каркас модели и загружает и распределяет веса модели по всем доступным устройствам, начиная с самого быстрого (GPU).quantization_config— это объект конфигурации, определяющий параметры квантования. В данном примере в качестве бэкенда квантования используется bitsandbytes (см. раздел Quantization для списка доступных бэкендов), а модель загружается в режиме 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)Токенизируйте входные данные и установите параметр padding_side() в значение "left", так как LLM не обучена продолжать генерацию от токенов отсечки. Токенизатор возвращает идентификаторы входных данных и маску внимания.
Обрабатывайте несколько промптов одновременно, передавая в токенизатор список строк. Группируйте входные данные в батчи, чтобы повысить пропускную способность ценой небольшого увеличения задержки и потребления памяти.
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)Передайте входные данные в generate(), чтобы сгенерировать токены, а затем используйте batch_decode(), чтобы преобразовать сгенерированные токены обратно в текст.
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,"Конфигурация генерации
Все параметры генерации содержатся в GenerationConfig. В примере выше параметры генерации берутся из файла generation_config.json модели mistralai/Mistral-7B-v0.1. Если с моделью не сохранена конфигурация, используется стратегия декодирования по умолчанию.
Осмотрите конфигурацию через атрибут generation_config. Он отображает только значения, отличающиеся от конфигурации по умолчанию, в данном случае это bos_token_id и 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
}Вы можете настроить generate(), переопределив параметры и значения в GenerationConfig. См. раздел ниже для часто настраиваемых параметров.
# enable beam search sampling strategy
model.generate(**inputs, num_beams=4, do_sample=True)generate() также можно расширить с помощью внешних библиотек или собственного кода:
- параметр
logits_processorпринимает пользовательские экземпляры LogitsProcessor для манипуляции распределением вероятностей следующего токена; - Параметр
stopping_criteriaподдерживает пользовательские StoppingCriteria для остановки генерации текста; - другие пользовательские методы генерации можно загрузить с помощью флага
custom_generate(документация).
См. руководство Стратегии генерации, чтобы узнать больше о стратегиях поиска, выборки и декодирования.
Сохранение
Создайте экземпляр GenerationConfig и укажите нужные параметры декодирования.
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
)Используйте save_pretrained(), чтобы сохранить конкретную конфигурацию генерации, и установите параметр push_to_hub в True, чтобы загрузить её на Hub.
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)Оставьте параметр config_file_name пустым. Этот параметр следует использовать при хранении нескольких конфигураций генерации в одной директории. Он позволяет указать, какую именно конфигурацию генерации нужно загрузить. Вы можете создавать разные конфигурации для различных генеративных задач (креативная генерация текста с использованием сэмплинга, суммаризация с beam search) для использования с одной моделью.
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))Общие параметры
generate() — это мощный инструмент, который можно сильно настроить. Для новых пользователей это может показаться сложным. В этом разделе приведен список популярных параметров генерации, которые можно задать в большинстве инструментов текстовой генерации в Transformers: generate(), GenerationConfig, pipelines, CLI chat, …
| Название параметра | Тип | Упрощенное описание |
|---|---|---|
max_new_tokens | int | Управляет максимальной длиной генерации. Обязательно задайте это значение, так как по умолчанию оно обычно устанавливается на небольшой размер. |
do_sample | bool | Определяет, будет ли генерация выбирать следующий токен методом выборки (True) или жадным алгоритмом (False). В большинстве случаев этот флаг следует установить в True. Подробнее см. в этом руководстве. |
temperature | float | Насколько непредсказуемым будет следующий выбранный токен. Высокие значения (>0.8) подходят для творческих задач, низкие значения (например, <0.4) — для задач, требующих «размышлений». Требуется do_sample=True. |
num_beams | int | При значении >1 активируется алгоритм beam search. Beam search хорошо работает на задачах, привязанных к входным данным. Подробнее см. в этом руководстве. |
repetition_penalty | float | Установите значение >1.0, если модель часто повторяет себя. Большие значения означают более сильный штраф. |
eos_token_id | list[int] | Токен(ы), которые приведут к остановке генерации. Значение по умолчанию обычно подходит, но вы можете указать другой токен. |
Подводные камни
Раздел ниже описывает ряд типичных проблем, с которыми вы можете столкнуться при генерации текста, и способы их решения.
Длина вывода
generate() по умолчанию возвращает не более 20 токенов, если иное не указано в GenerationConfig модели. Настоятельно рекомендуется вручную задавать количество генерируемых токенов с помощью параметра max_new_tokens, чтобы контролировать длину вывода. Модели Decoder-only возвращают исходный промпт вместе с сгенерированными токенами.
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,'Стратегия декодирования
Стратегия декодирования по умолчанию в generate() — это жадкий поиск, который выбирает следующий наиболее вероятный токен, если в GenerationConfig модели не указано иное. Хотя эта стратегия хорошо работает для задач, основанных на входных данных (транскрипция, перевод), она не является оптимальной для более творческих сценариев использования (написание рассказов, чат-приложения).
Например, включите стратегию multinomial sampling, чтобы получать более разнообразные результаты. Дополнительные сведения о стратегиях декодирования см. в руководстве Generation strategy.
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]Сторона отступов
Входные данные необходимо дополнять (padding), если их длины различаются. Однако LLM не обучены продолжать генерацию от токенов дополнения, поэтому параметр padding_side() должен быть установлен в значение left для входных данных. Правое дополнение хуже для рекуррентных и гибридных моделей, поскольку их рекуррентное состояние продолжает обновляться на хвостовых токенах дополнения, из-за чего кэш перестаёт соответствовать концу промпта.
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,'Формат запроса
Некоторые модели и задачи ожидают определённый формат входного промпта, и если формат неверен, модель возвращает неоптимальный результат. Подробнее о промптинге можно узнать в руководстве по инженерии промптов.
Например, чат-модель ожидает входные данные в формате шаблона чата. Ваш промпт должен содержать role и content, чтобы указать, кто участвует в разговоре. Если вы попытаетесь передать промпт как одну строку, модель не всегда вернёт ожидаемый результат.
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 canРесурсы
Ниже представлены более специализированные библиотеки для генерации текста.
- Optimum: расширение Transformers, ориентированное на оптимизацию обучения и инференса на конкретных аппаратных устройствах
- Outlines: библиотека для генерации текста с ограничениями (например, генерация файлов JSON).
- SynCode: библиотека для генерации, управляемой контекстно-свободной грамматикой (JSON, SQL, Python).
- Text Generation Inference: готовый к работе в продакшене сервер для LLM.
- Text generation web UI: веб-интерфейс на Gradio для генерации текста.
- logits-processor-zoo: дополнительные logits-процессоры для управления генерацией текста.