В прошлом месяце Stability AI выпустила Stable Diffusion XL 1.0 (SDXL) и дала открытый доступ к его исходному коду всем желающим.
Релиз прошел практически незамеченным, потому что шумиха вокруг генеративного искусственного интеллекта немного поутихла. Все слишком заняты ChatGPTом и прочими ИИ, генерирующими текст.
Примечательно, что это одна из первых моделей с открытым исходным кодом, которая может генерировать изображения с разрешением 1024×1024 без махинаций, а значит, позволяет отображать гораздо больше деталей. На самом деле SDXL состоит из двух моделей: базовой и дополнительной модели улучшения, которая значительно повышает детализацию. А поскольку улучшение не замедляет скорость генерации, я настоятельно рекомендую по возможности его использовать.
Отсутствие ажиотажа вокруг SDXL не означает, что он не достоин внимания. Теперь, когда модель имеет полную поддержку для диффузоров от Hugging Face в библиотеке Python с соответствующими оптимизациями производительности, мы можем ее использовать. Дело в том, что демонстрации SDXL в диффузорах просты и легко настраиваются:
import torch
from diffusers import DiffusionPipeline, AutoencoderKL
# load base SDXL and refiner
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix",
torch_dtype=torch.float16)
base = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
vae=vae,
torch_dtype=torch.float16,
variant="fp16",
use_safetensors=True,
)
_ = base.to("cuda")
refiner = DiffusionPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-refiner-1.0",
text_encoder_2=base.text_encoder_2,
vae=base.vae,
torch_dtype=torch.float16,
variant="fp16",
use_safetensors=True,
)
_ = refiner.to("cuda")
# generation using both models (mixture-of-experts)
high_noise_frac = 0.8
prompt = "an astronaut riding a horse"
negative_prompt = "blurry, bad hands"
image = base(
prompt=prompt,
negative_prompt=negative_prompt,
denoising_end=high_noise_frac,
output_type="latent",
).images
image = refiner(
prompt=prompt,
negative_prompt=negative_prompt,
denoising_start=high_noise_frac,
image=image,
).images[0]
Я загрузил облачную виртуальную машину с новым графическим процессором среднего уровня L4 и приступил к работе. С графическим процессором L4 генерация каждого изображения 1024×1024 занимает около 22 секунд. В отличие от предыдущих моделей Stable Diffusion на графических процессорах среднего уровня вы можете генерировать только одно изображение за раз, поскольку используется 100% мощности графического процессора. Так что придётся запастись терпением.
В меньшем разрешении вы можете генерировать быстрее, но делать это не рекомендуется, потому что результаты будут намного хуже.
Диффузоры также обеспечили поддержку двух новых функций, с которыми я раньше не экспериментировал: prompt weighting (Вес подсказки), а также обучение и инференс Dreambooth LoRA. Поддержка веса подсказки с помощью диффузоров принудительно использует библиотеку Python, чтобы использовать вес подсказки более математически. Вы можете добавить любое количество +
или -
к заданному слову, чтобы увеличить или уменьшить его «вес» (важность) в результирующем позиционном встраивании текста и, следовательно, в окончательной генерации. Вы также можете усилить фразы: например, если вы создаете фотореалистичный Сан-Франциско San Francisco landscape by Salvador Dali, oil on canvas (Сан Франциско пейзаж от Сальвадора Дали, холст масло)
, вы можете усилить изобразительное средство San Francisco landscape by Salvador Dali, (oil on canvas)+++
чтобы Stable Diffusion вел себя более предсказуемо. Тестирование показало, что пофиксилась большая часть проблем с подсказками Stable Diffusion 2.0 и выше, особенно с более высоким значением classifier-free guidance (по умолчанию guidance_scale составляет
7,5; я предпочитаю использовать 13).
Все сгенерированные примеры из моделей LoRA в этой статье используют значение guidance_scale
13.
Исследование LoRA
Но что наиболее важно, так это поддержка Dreambooth LoRA, которая позволяет создавать модели Stable Diffusion на заказ. Dreambooth — это метод тонкой настройки Stable Diffusion на очень небольшом наборе исходных изображений и ключевом слове-триггере, позволяющем использовать «концепцию» из этих изображений в других контекстах с заданным ключевым словом.
Обучение самой Stable Diffusion, даже небольших моделей, требует много часов на дорогих графических процессорах. Вот тут-то и появляется LoRA: вместо целой модели обучается небольшой адаптер на визуальную модель. Это значит, что достаточно одного дешевого GPU и 10 минут времени. При этом качество финальной модели + LoRA сравнимо с полной тонкой настройкой. Обученные LoRA представляют собой небольшой дискретный двоичный файл, а значит, им можно легко делиться с другими пользователями или в репозиториях, таких как Civitai.
Небольшой недостаток LoRA в том, что вы можете иметь только один актив одновременно: можно объединить несколько LoRA, чтобы получить преимущества от всех, но это непросто.
До того, как LoRA со Stable Diffusion получили более широкое распространение, существовала текстовая инверсия, которая позволяла кодировщику текста выучить концепцию. Но на её обучение уходят часы, при этом результаты могут оказаться разочаровывающими.
В предыдущей статье я тренировал текстовую инверсию на меметике Ugly Sonic (Уродливый Соник), так как его не было в исходном наборе данных Stable Diffusion и он был бы уникален. Результаты были неоднозначными:
Попробовать LoRA на Ugly Sonic могло бы стать хорошей проверкой потенциала SDXL. К счастью, Hugging Face предоставляет train dreambooth lora_sdxl.py script для обучения LoRA с использованием базовой модели SDXL, которая работает «из коробки», хотя пришлось немного подправить параметры. Сгенерированные образы Уродливого Соника из обученной LoRA вышли намного лучше и точнее по соответствию подсказкам.
WRONG!
Добившись такого успеха, я решил заново провести еще один эксперимент, который делал с текстовой инверсией. Только теперь я обучил LoRA на сильно искаженных, мусорных изображениях в качестве wrong
подсказки. Я надеялся, что LoRA сможет использовать wrong
в качестве «негативной подсказки» и избегать создания подобных изображений. Я написал Jupyter Notebook для создания синтетических «неправильных» изображений с использованием самого SDXL. На этот раз я использовал различный вес подсказок, чтобы получить более четкие примеры плохих изображений (blurry
и bad hands)
. Как ни странно, нам нужно использовать SDXL для создания изображений низкого качества с высоким разрешением.
Я обучил и загрузил LoRA в базовую модель Stable Diffusion XL и написал Jupyter Notebook, чтобы сравнить результаты с заданной подсказкой:
-
Базовый уровень + улучшение. Без LoRA. (наш базовый уровень)
-
Без использования отрицательной подсказки
wrong
(чтобы убедиться, что нет эффекта плацебо) -
С использованием LoRA отрицательной подсказки
wrong
(наш целевой результат)
Каждый вариант имеет один и тот же источник, поэтому композиция изображения должна быть одинаковой для всех трех случаев, а влияние отрицательной подсказки wrong
и LoRA на базовое изображение должно быть очевидным.
Начнем с простой подсказки из демо SDXL 0.9 :
Подсказка wrong
на базовой модели добавляет листву и дополнительную глубину изображению леса, но LoRA добавляет гораздо больше: более четкое освещение и тени, более детализированную листву и изменение позы волка, чтобы он смотрел в камеру, что смотрится более интересно.
Мы можем получить другую перспективу с похожей композицией фотографии, добавив к подсказке «очень крупный план», используя тот же исходник.
Версия с LoRA имеет гораздо лучшую текстуру, яркость и резкость, чем другие. Примечательно, что само по себе добавление wrong
подсказки меняет перспективу.
Еще один хороший пример — фуд-фотография, особенно странная фуд-фотография, которую я создал с помощью DALL-E 2 . Могут ли SDXL + wrong
LoRA обрабатывать неевклидовы гамбургеры с усиленным весом подсказки, чтобы сделать их действительно странными.
К сожалению, не может даже после нескольких попыток. Тем не менее, результат все еще интересен: базовый SDXL, похоже, воспринял «инопланетную» часть подсказки более буквально, чем ожидалось (и изобразил миленького инопланетянина в шляпке-булочке!), но LoRA лучше понимает именно дух подсказки. Он делает «инопланетный» бургер, который людям было бы трудно съесть. Ну и сама подача куда эффектнее.
Заметно улучшилась читаемость текста в Stable Diffusion 2.0. Могут ли SDXL и wrong
LoRA сделать текст еще более читабельным? Например, нормально изобразить развороты газет с большим количеством текста?
По сравнению со Stable Diffusion 2.0 читаемость текста стала лучше, но не слишком. Что примечательно, в LoRA макет страницы стал более «современным» с различной вёрссткой статей, а заголовки имеют правильный размер и толщину шрифта. Между тем, базовая модель даже с
негативной подсказкой wrong,
имеет скучную компоновку и почему-то сделана на состаренной пожелтевшей бумаге.
А как насчет изображений людей? Решает ли LoRA с помощью wrong
печально известную проблему рук? В обучающие данные LoRA мы включали немало таких негативных примеров. Давайте изменим подсказку про Тейлор Свифт из моей первой попытки со Stable Diffusion 2.0:
Посмотрите на правую руку Тейлор: в SDXL по умолчанию она крайне нереалистична и на самом деле становится даже хуже при добавлении wrong
, но в LoRA это исправлено! Цветокоррекция с помощью LoRA намного лучше: пиджак более белый, а не желтовато-белый. Но с руками всё ещё проблема: создавать людей с помощью SDXL 1.0 по-прежнему сложно и результат нестабилен.
Теперь ясно, что wrong
+ LoRA работает более интересно, чем просто отрицательная подсказка wrong
, поэтому мы просто сравним базовый результат с результатом LoRA. Вот еще несколько примеров сравнения базовой модели с wrong
LoRA:
LoRA wrong
доступен здесь, хотя я не могу гарантировать его эффективность в интерфейсах, отличных от диффузоров. Все ноутбуки, используемые для создания этих изображений, доступны в этом репозитории GitHub, включая общий блокнот wrong
SDXL 1.0 + Refine + LoRA Colab, который вы можете запустить на бесплатном графическом процессоре T4. И если вы хотите увидеть показанные здесь изображения в более высоком разрешении, можете просмотреть их в исходном коде сообщения.
Что не так с подсказкой wrong?
На самом деле я не уверен на 100%, что происходит под капотом. Я думал, что трюк с wrong
LoRA просто улучшает качество и четкость сгенерированного изображения, но, похоже, LoRA заставляет SDXL вести себя более разумно и более точно соответствовать духу подсказки. На техническом уровне отрицательная подсказка устанавливает область скрытого пространства, где начинается процесс диффузии; эта область одинакова как для базовой модели, использующей отрицательную подсказку wrong
, так и для wrong в
LoRA. Думаю, что LoRA изменяет эту нежелательную область обширного многомерного скрытого пространства, чтобы она была более похожа на начальную область, поэтому маловероятно, что нормальная генерация ее улучшит.
Обучение SDXL на плохих изображениях с целью его улучшения технически является формой обучения с подкреплением на основе отзывов людей (RLHF): та же техника, которая использовалась при обучении ChatGPT и сделала его настолько мощным. В то время как OpenAI использует обучение с подкреплением, чтобы улучшить модель на основе позитивных взаимодействий с пользователем и неявно уменьшить негативное поведение, я использую негативные взаимодействия с пользователем (т. е. выбор заведомо плохих изображений) для неявного усиления позитивного поведения. Но с Dreambooth LoRA вам не нужно столько входных данных, сколько требуется большим языковым моделям.
Есть ещё множество путей для развития «отрицательных LoRA»: мои параметры генерации синтетического набора данных можно было бы значительно улучшить, а LoRA можно было бы обучать дольше. Но пока что я очень доволен результатами и буду рад провести больше тестов с отрицательными LoRA. Например, слияние с другими LoRA, чтобы понять, способно ли это их улучшить (особенно LoRA + Ugly Sonic LoRA! wrong
)
Хотите верьте, хотите нет, но это только верхушка айсберга. SDXL теперь имеет поддержку ControlNet для строгого управления общей формой и композицией сгенерированных изображений:
ControlNet также можно использовать с LoRA, а это уже повод для новой статьи…
Автор: Cloud4Y