Крутые запросы
Как правильно просить Stable Diffusion нарисовать картинку
Сегодняшняя тема — одна из самых важных в серии статей о генеративном искусственном интеллекте: мы будем составлять запросы, и делать это постараемся правильно.
Как появилась эта статья
Как‑то раз я помогал сгенерировать обложку для книги. У коллеги не задалось, а когда я попросил прислать запрос, увидел вот это:
A dynamic action shot captures a volleyball player in mid-air as she strikes the ball with her right hand, while wearing a forest green jersey with white and black accents, bearing the number 8. The player’s blonde hair is tied back in a ponytail, and her face shows intense focus on the task at hand. Her left arm is supported by a white sleeve or pad around the elbow. She wears knee-high white leg warmers and pink volleyball shoes with light blue soles. The volleyball, with its distinctive yellow exterior and blue sections divided by vertical ribbons, is held high above her head. In the foreground, two opposing players are attempting to block the serve; one is seen from behind with arms fully extended upwards, while another with the has both hands raised high, fingers spread wide. Both opponents wear dark jerseys with intricate red, white, and black patterns. They also have black arm sleeves, with sleeve showcasing a vibrant blue and pink pattern. Both players have their heads turned slightly towards the camera, revealing part of their faces. The net, spanning horizontally across the middle of the frame, features a white mesh structure with black lines forming a square grid pattern. The floor beneath them is teal blue, contrasting sharply with the orange area where the players are standing. The overall lighting is bright and even, typical of an indoor sports arena, highlighting the athleticism and competitive nature of the moment.
Честно говоря, понять, чего хочет вопрошающий, я не смог; мне пришлось прибегнуть к помощи ChatGPT, чтобы тот расшифровал запрос. Текстовые декодеры генеративных моделей ИИ далеко не так продвинуты, и нет ничего удивительного в том, что корректно обработать такой запрос они не смогли. Я же решил написать статью, которая, возможно, удержит тебя от издевательств над искусственным интеллектом.
Кого будем спрашивать?
Правила составления запросов разительно отличаются в зависимости от архитектуры модели и используемых в ней текстовых декодеров, а синтаксис — в зависимости от используемого для генерации софта. К примеру, модели на основе Flux лучше всего работают с текстовыми запросами, составленными другим искусственным интеллектом — большой языковой моделью (например, ChatGPT). Языковые модели умеют правильно структурировать запрос, в результате чего картинка получается более детальной и когерентной по сравнению с короткими запросами, составленными по правилам моделей SDXL.
В качестве примера приведу иллюстрацию, которую модель Flux выдала с первой или второй попытки.

В качестве запроса использовался текст, сгенерированный ChatGPT:
Title: Display the title "The Crazy Adventure of the Kung-Fu Chicken" in bold and playful text at the top or center of the poster.
Main Character: Depict a dynamic and charismatic ninja chicken in a heroic karate pose, wearing a traditional karate outfit, while still showing chicken features like feathers and a beak.
Background: Include a colorful and exciting backdrop with elements like a mystical forest, a bustling city, and an ancient temple to hint at various adventures. The background is vibrant and engaging.
Supporting Characters: Add a few quirky and fun supporting characters such as a wise old turtle, a mischievous squirrel sidekick, and a villainous fox.
Pixar Branding: Incorporate the Pixar logo at the bottom or top of the poster to establish it as an official Pixar movie.
Tagline: Include a tagline that reads: "A Kung-Fu Adventure" prominently on the poster.
Visual Style: Ensure the overall visual style is consistent with Pixar signature animation look: bright colors, expressive characters, and a touch of whimsy.
Вероятно, похожий результат можно было бы получить и более коротким запросом, но после нескольких попыток я предпочел пойти простым путем.
Другая современная модель, Lumina-2, в качестве текстового декодера использует полноценный LLM Gemma 2 2B. В документации рекомендуется использовать запросы, сформированные следующим образом:
You are an assistant designed to generate superior images with the superior degree of image-text alignment based on textual prompts or user prompts. <Prompt Start>
На практике работают и более интересные запросы. Например, запрос «You are a Chinese painter. Mixing oil paint and watercolor, draw a painting of a tranquil Chinese village, with white houses overlooking a river channel, and a boat floating along the river» выдаст примерно такую картинку.

Однако вернемся к созданию афиши. В случае с SDXL подобный запрос не то чтобы совсем не сработает, но не сработает так, как надо. Для начала придется отказаться от надписей: любые попытки сгенерировать когерентный текст длиннее одного‑двух слов в моделях SDXL обречены на провал. То же касается логотипа Pixar: мне не удалось добиться его достаточной убедительности. В результате останется куда более простой запрос:
Main Character: Depict a dynamic and charismatic ninja chicken in a heroic karate pose, wearing a traditional karate outfit, while still showing chicken features like feathers and a beak.
Background: Include a colorful and exciting backdrop with elements like a mystical forest, a bustling city, and an ancient temple to hint at various adventures. The background is vibrant and engaging.
Supporting Characters: Add a few quirky and fun supporting characters such as a wise old turtle, a mischievous squirrel sidekick, and a villainous fox.
Visual Style: Ensure the overall visual style is consistent with Pixar signature animation look: bright colors, expressive characters, and a touch of whimsy.
Попробуем сгенерировать картинку. После нескольких откровенно неудачных попыток получилось... нечто.

Персонаж объединяет в себе черты главного и второстепенных героев, причем второстепенных на картинке нет вообще. Почему так? Здесь мы подошли к концепции context bleeding, «утечки контекста»: модель не в состоянии однозначно атрибутировать заданные свойства конкретному объекту в кадре.
Проблема усугубляется тем, что наш запрос состоит из 131 токена (токенами считаются любые слова, включая артикли и предлоги), а текстовые декодеры SDXL ограничены 75 токенами. Соответственно, система разобьет наш запрос на две очереди: в первой очереди будут первые 75 токенов, во второй — то, что останется. Интерфейс WebUI подсчитывает количество токенов автоматически.

Первая цифра здесь — число токенов в запросе, вторая — число токенов с выравниванием по 75. На скриншоте выше видно, что запрос состоит из 131 токена, которые будут разбиты на две очереди по 75 токенов каждая.
Решить проблему можно несколькими способами. Существуют расширения — например, Regional Prompter или Forge Couple, позволяющие разделить внимание модели по регионам. Эти расширения интересны, но их рассмотрение выходит за рамки этой статьи; сегодня мы будем говорить о том, как решить проблему, оставаясь в рамках текстового запроса. Один из вариантов — разбить запрос на несколько очередей оператором BREAK.
Оператор BREAK
В интерфейсе WebUI A1111 и его производных (WebUI Forge и reForge) доступен оператор BREAK
. Его использование сигнализирует о разрыве в очереди токенов (я не смог подобрать лучшего перевода термину chunk, поэтому пусть будет «очередь»). Вставив оператор BREAK
перед каждым переводом строки, мы получим следующий запрос.

Обрати внимание: очередей запросов стало не две, а четыре.

Результат более убедительный: несмотря на то что второстепенные персонажи все так же отсутствуют, главный персонаж выглядит так, как должен, — и продолжает выглядеть так же в последующих генерациях. Тем не менее признаем, что сгенерированные LLM запросы, вероятно, не слишком хорошо подходят моделям с архитектурой SDXL.
Почему так происходит? Дело в том, что в Stable Diffusion XL и Flux применяются разные текстовые декодеры.
Flux использует пару декодеров: CLIP-L (простой текстовый декодер, созданный в OpenAI) и T5 (локальная языковая модель, LLM, разработанная Google). Использование полноценной, хоть и простой языковой модели T5 позволяет составлять заметно более сложные и длинные запросы естественным языком, в то время как CLIP-L помогает выделять и декодировать отдельные ключевые слова. Иначе говоря, CLIP-L лучше всего работает с короткими ключевыми словами, перечисленными через запятую, в то время как T5 обрабатывает весь запрос целиком.
T5 — тяжелая модель; она требует и заметных вычислительных ресурсов, и достаточно большого объема памяти. В архитектуре SDXL, разработчики которой ориентировались на актуальные в 2023 году потребительские видеокарты, вместо нее используется другой декодер: CLIP-G. Получается, что в моделях SDXL совместно работает пара декодеров CLIP-L (короткие запросы естественным языком и ключевые слова через запятую) и CLIP-G (сложные запросы естественным языком).
В то же время CLIP-G — быстрая, но очень простая модель; ее возможности по сравнению с T5 заметно ограниченны. Для моделей SDXL оптимальным будет запрос, составленный из комбинации несложных, не перегруженных смыслом (и уж тем более — «мусором») предложений на естественном языке в сочетании с ключевыми словами, перечисленными через запятую. Для несложных композиций, в которых не предусмотрено взаимодействие между объектами сцены, можно и вовсе ограничиться ключевыми словами через запятую.
Попробуем переформулировать запрос в рамках ограничений моделей CLIP. В начале поставим указатель на стиль, далее перечислим персонажей, затем детализируем внешний вид главного персонажа и, наконец, опишем желаемый фон.
Pixar animation style, a ninja chicken as a main character, a wise old turtle, a mischievous squirrel sidekick, a villainous fox BREAK
dynamic and charismatic ninja chicken in a heroic karate pose, wearing a traditional karate outfit BREAK
vibrant and engaging background including colorful backdrop, mystical forest, bustling city, ancient temple, to hint at various adventures, expressive characters, and a touch of whimsy

В рамках архитектуры SDXL — вполне неплохо, однако второстепенные персонажи так и не появились. Я испробовал несколько базовых моделей и даже задрал параметр CFG до фантастических значений, но и это не помогло. Максимального (хоть и весьма условного) приближения удалось достичь, лишь переформулировав первую очередь запроса следующим образом:
Pixar animation style, a ninja chicken as a main character surrounded by a wise old turtle, a mischievous squirrel sidekick, and a villainous fox BREAK

Негативные ключевые слова
Во времена Stable Diffusion 1.5 были популярны так называемые «шизоидные» запросы, когда строку негативных запросов заполняли мусорными токенами вроде «шесть пальцев, кривые пальцы, деформированные пальцы, деформированная анатомия».
Камлание с бубном не работает; даже если на отдельно взятой картинке с подобными ключевиками вдруг полный порядок, а на том же сиде без негативных ключевиков наблюдается проблема, это вовсе не означает, что магия сработала. Просто генерация пошла немного другим путем, и получилась другая картинка — по случайности без дефекта. Сгенерируй сотню картинок, и ты убедишься, что процент дефектов примерно одинаков что с негативными ключевыми словами, что без них.
Проблему неверного числа пальцев на руках решают другими способами: на этапе обучения или микширования модели, а также с помощью специализированных семплеров, режима HiDiffusion с повышенным разрешением и расширений класса ADetailer.
Зачем тогда вообще негативные ключевые слова? Они нужны для того, чтобы убрать из конкретной картинки нежелательный элемент или усилить действие позитивных ключевых слов. Например, использование термина monochrome в качестве негативного ключевого слова может поднять насыщенность изображения, а перечисление тех или иных объектов — убрать их из кадра. Иными словами, негативные ключевые слова — это еще один инструмент для уточнения запроса.
Разумеется, из этого правила есть исключения. Некоторые модели обучаются на изображениях разного качества, ведь для того, чтобы понять, что такое «хорошо», модель должна понимать, что такое «плохо». В таких моделях могут использоваться специальные теги (как позитивные, так и негативные) для указания желаемого качества изображения. В то же время использование таких тегов может ограничить разнообразие результатов, ведь выбор существенно сузится, если указать тег «шедевр» и заблокировать все «плохое» и «посредственное». Я обычно стараюсь не использовать такие теги, если это не ведет к существенной деградации качества картинки.
TL&DR: не используй случайные наборы негативных ключевых слов из чужих картинок. Используй только те ключевые слова, которые помогают убрать ненужное или усилить нужное для конкретного изображения. Также можно использовать (а можно и не использовать!) специфические ключевые слова для повышения качества генерации у конкретных моделей, обученных с использованием тегов качества.
Весовые коэффициенты
Усилить или ослабить вес любого токена или набора токенов можно следующим образом:
(токен или фраза:2)
Вместо двойки можно подставить любой весовой коэффициент, включая дробные. Работают коэффициенты в диапазоне от нуля до разумной верхней планки, которая зависит от конкретной модели. Как правило, имеет смысл использовать небольшие коэффициенты в диапазоне от 0 до 2, но в некоторых случаях допустимо использовать и большие величины.
Использование конструкции (
равнозначно (
, а ((
— то же самое, что и (
.
Также можно пользоваться квадратными скобками для снижения веса. Например, если написать [
, то это понизит весовой коэффициент взятого в квадратные скобки термина в 1,1 раза. Однако круглые скобки и дробный коэффициент и выглядят более понятно, и вводить их проще и быстрее: достаточно выделить строку, вес которой нужно модифицировать, и регулировать вес комбинацией клавиш Ctrl-вверх и Ctrl-вниз (каждое нажатие кнопки «вверх» или «вниз» повысит или понизит коэффициент на 0,1).
Весовые коэффициенты работают как в основном, так и в негативном запросе, однако использовать можно только положительные значения. Для использования отрицательных весовых коэффициентов вида (
нужно устанавливать специальное расширение negpip для Comfy или для WebUI.
Котапельсин или апельсокот?
В интерфейсе WebUI и его производных есть целый ряд продвинутых возможностей, связанных с синтаксисом запросов. Оператор BREAK
мы уже рассмотрели, им дело не ограничивается; разные дополнительные возможности интерфейса описаны в Wiki A1111.
Возьмем простую связку из кота и апельсина и попробуем сделать с этим что‑то интересное, зафиксировав сид в значении 614462921.
Вот так выглядит результат обработки запроса cat,
.

Context bleeding во всей красе. А если написать cat
?

Вполне прилично; то, чего и хотелось.
В WebUI есть интересная фича — можно комбинировать текстовые запросы, когда в начале генерации на вход подается одна строка, а в конце — другая. Синтаксис запроса такой:
[текст в начале генерации:текст в конце генерации:когда_переключать]
К примеру, строка [
указывает, что на ранних шагах будет генерироваться кошка, на поздних — собака, а переключение между кошкой и собакой произойдет на отметке 0.7 (то есть первые 70% шагов у нас будет «кошка», а оставшиеся 30% шагов будет генерироваться «собака»). Посмотрим, как это работает на практике.
Для начала сгенерируем кошку на белом фоне: cat,
.

Теперь собаку: dog,
.

А теперь — нечто среднее: [
.

Другая возможность — чередование запросов: на нечетных шагах генерации будет подаваться первая строка, а на четных — вторая. К примеру, таким образом модель обработала запрос с поочередной подачей на вход «кошки» и «апельсина».
[a cat|an orange]

На практике эту возможность можно использовать, например, для указания прически, цвета волос или одежды, когда не устраивает ни один из стандартных вариантов и хочется разнообразия.
Текстовые инверсии
Здесь все просто: текстовые инверсии скачиваются и складываются в папку Embeddings
, после чего их можно просто указывать в текстовом запросе как имя файла без расширения. Таким образом мы поможем модели «найти» ту или иную концепцию.
Текстовые инверсии можно использовать как в основной, так и в негативной частях запроса. Обрати внимание: текстовые инверсии имеют ограничения по совместимости. Они не просто подходят только к конкретной архитектуре (SD1.5 или SDXL), но иногда предназначены для конкретных классов моделей (общие модели SDXL, модели на базе Pony, модели на базе Illustrious и так далее).
Впрочем, тут кроется не только ограничение, но и возможность: иногда текстовые инверсии от одного класса моделей можно использовать в другом. Некоторые текстовые инверсии от Pony/Illustrious могут подойти к некоторым моделям SDXL, причем это работает и в обратную сторону.
Например, базовая модель Pony Diffusion имеет слабое представление об устройстве газонокосилок разных типов. Пользователя Reddit заинтересовала конкретная модель газонокосилки Bobcat; он создал для нее текстовую инверсию в базовой модели SDXL и продемонстрировал, что соответствующее изображение успешно генерируется в Pony. По его мнению, связано это с тем, что при создании модели Pony произошло «выгорание» текстового декодера в результате избыточного обучения.
Соответствующая концепция пропала из CLIP, но «знание» об устройстве подобных объектов осталось в UNet, унаследованной от базовой модели SDXL. Использование текстовой инверсии позволило извлечь из UNet одну из частей, которую невозможно было адресовать через обычный текстовый запрос.
От себя добавлю, что, несмотря на это, газонокосилка у Pony получилась весьма схематичной и напоминала скорее модель, собранную из случайных деталей детского конструктора, чем реальный объект.
Какие бывают текстовые инверсии и как их искать? Для них есть соответствующий тег на Civit.ai. В качестве концепций часто предлагают те или иные изобразительные стили (от фотореалистичного до концептуальных), персоналии (от публичных деятелей и актеров до просто оригинальных персонажей), позы и действия.
Composable Diffusion
Composable Diffusion — это метод, который помогает сочетать несколько идей в одном изображении. Продемонстрировать концепцию «котапельсина», как она описана в документации, оказалось сложнее. Тем не менее запрос a
дал один «котапельсин» и один «котопельсин».


Механизм позволяет объединять разные образы, используя оператор AND
. Например, запрос a
выдаст животное, сочетающее в себе черты кота и собаки. С оператором AND
прекрасно работают описанные ранее техники — от весовых коэффициентов до текстовых инверсий включительно. Так, если ты хочешь получить скорее кота, чем собаку, то весовой коэффициент кота можно увеличить:
a cat:1.2 AND a dog
Для чего это нужно? При помощи оператора AND
удобно смешивать художественные стили:
cyberpunk style AND oil painting
Можно создавать уникальных, детализированных персонажей:
a frog AND yellow eyes AND horns
Наконец, с оператором AND
можно использовать несколько текстовых инверсий. Попробуй, это отличный способ получить оригинальный результат, которого не достичь или трудно достичь другими.
Шпаргалка по составлению запросов
Для разных архитектур (а иногда и классов моделей в рамках одной архитектуры) используются разные способы построения текстовых запросов. В архитектурах, использующих в качестве текстовых декодеров большие языковые модели, хорошо работают детальные запросы, составленные другими языковыми моделями, например ChatGPT.
В архитектурах попроще лучше работают короткие предложения и простая терминология. У экзотических терминов эффект невелик, так как они редко используются при описании изображений, на которых обучаются модели, но в известных пределах это можно скомпенсировать повышением весового коэффициента: (
. Вес ключевого слова можно и понизить: (
; веса работают как в основной, так и в негативной части запроса.
В моделях, обученных на изображениях из booru, используются запросы, составленные из стандартных тегов danbooru. Модели на основе Pony практически утратили возможность воспринимать запросы, составленные естественным языком; в моделях на базе Illustrious (а точнее, NoobAI) эта возможность присутствует.
Очередь запросов в SDXL формируется из последовательностей, содержащих до 75 токенов. Длинные запросы будут разбиты автоматически. Иногда это происходит посреди предложения. Чтобы этого избежать, используй оператор BREAK.
Не стоит излишне увлекаться заимствованием запросов, особенно в их негативной части. В негативном запросе стоит указывать только те элементы, которых не должно быть на изображении, но которые модель все равно генерирует. В некоторых случаях можно (но не всегда нужно) использовать модификаторы качества.
Иногда могут оказаться полезными такие функции, как Composable Diffusion (оператор AND
) и условная генерация, когда разные текстовые запросы либо чередуются, либо подменяются на определенном этапе генерации.