Привет, Хабр, я Павел Бузин, работаю аналитиком в компании Cloud.ru и занимаюсь решением задач, требующих применения различных математических методов, в том числе используемых для машинного обучения. 

С появлением нейронных сетей почти каждый может попробовать себя в роли художника или дизайнера. Уверен, что будет неплохо максимально простым языком рассказать, каких правил стоит придерживаться, чтобы ваши работы получались на профессиональном уровне. В основе этих правил лежат закономерности, которые описаны на языке математики. Надеюсь, что понимание сути методов поможет вам найти новые и интересные дизайнерские решения.

В этой статье обсудим общие закономерности, так что если вы дизайнер, промпт-инженер или просто неравнодушны к прекрасному, вас ждет путешествие от Древней Греции до современных компьютеров с CAD и генеративными моделями. Математики и технари, добро пожаловать под кат, здесь вы будете чувствовать себя как дома. Гуманитарии, не пугайтесь, всё будет страшно только на первый взгляд. 

Это база

Создавая красивый кадр, картину или макет, профессиональные фотографы, художники и дизайнеры пользуются правилами композиции, которые имеют в своей основе красивые закономерности, описываемые простыми формулами. Кто-то делает это осознанно, кто-то просто мотивирует свой выбор «Ну так же красивее!». Давайте взглянем, что это за правила делают композицию гармоничной и какие формулы их описывают.

Правило третей

Первое правило композиции, с которого начинаются уроки в любой художке — никому не рассказывай о композиции делим план изображения на девять равных частей параллельными линиями, двумя вертикальными и двумя горизонтальными. Важные элементы изображения располагаем вдоль этих линий или на их пересечениях. Это правило настолько популярно и хорошо работает, что линии сетки есть даже у камер в сотовых телефонах. 

Источник: https://habrastorage.org/r/w1560/getpro/habr/upload_files/ef2/295/b51/ef2295b5125d5608771549c17802ce9e.jpg

Правило третей является эмпирическим, то есть сформулированным по результатам человеческого опыта. Его создание приписывают английскому художнику 18 века Джошуа Рейнольдсу. И хотя в основе этого метода нет сложных обоснований, в правиле третей появляются соотношения 1:2 и 2:3 — а это первые числа последовательности Фибоначчи. Кстати о ней…

Золотое сечение и числа Фибоначчи

Золотое сечение — это такое деление отрезка, при котором отношение большей части к меньшей равно отношению всей длины отрезка к его большей части. Мы можем записать это следующим образом. Мы делим отрезок длины c на части длиной a и b. Тогда a и b будут связаны соотношением: 

Отношение a к b является решением квадратного уравнения вида x^2 – x -1 = 0. Положительное решение, получившее название «Золотое число» и обозначение Φ (буква древнегреческого алфавита, читается как «фи»).

Обратное число, обозначаемое строчной буквой ?, имеет интересное свойство 

На практике это выглядит так, что объект сохраняет гармоничные пропорции и «на боку».

Золотое сечение было известно и активно применялось строителями уже в Древней Греции. Спустя много сотен лет в 12 веке Леонардо Пизанский, также известный под именем Фибоначчи, изучал большое количество практических задач, которые в дальнейшем легли в основу теории чисел и исследования рядов. 

Фибоначчи исследовал последовательность чисел, формируемых по следующим правилам:

  • первые два числа последовательности — это 0 и 1,

  • каждое следующее число последовательности образуется сложением двух предыдущих чисел.

Эта последовательность знакома очень многим, ее значения — 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, и т. д.

У чисел Фибоначчи много интересных свойств. Например, если сложить друг с другом квадраты со сторонами, равными числам Фибоначчи, они образуют спираль: 

Источник: https://www.google.com/url?sa=i&url=https%3A%2F%2Fwww.zimerka.ru%2Fpage%2Fustroystva-aktualizatsii-bytiya%3Flang%3Dru&psig=AOvVaw3Guqr7SIVKVXgN846vnKIT&ust=1723734139581000&source=images&cd=vfe&opi=89978449&ved=0CBcQjhxqFwoTCLiw0Jrg9IcDFQAAAAAdAAAAABAQ

Давайте сразу расставим точки над i: золотое сечение и последовательность Фибоначчи — не одно и то же. А они как-то связаны?! Да, вот так: золотое сечение — это специфическое иррациональное число с уникальными свойствами пропорций, в то время как числа Фибоначчи — это бесконечная последовательность целых чисел, которые через свое соотношение приближаются к этому числу, но все-таки не равны ему. 

Но поскольку разница эта скорее математическая, чем визуальная, оба понятия активно применяются в архитектуре, поскольку такие пропорции не просто приятны человеческому глазу, но еще и прочны и эффективны при строительстве, подтверждением чему являются сохранившиеся памятники древности. 

Источник: https://www.google.com/url?sa=i&url=https%3A%2F%2Fdzen.ru%2Fa%2FXwTBGFKQgFj6vSzv&psig=AOvVaw2XCF0OyOHZC7QBkLB3gb8d&ust=1723736346613000&source=images&cd=vfe&opi=89978449&ved=0CBcQjhxqFwoTCIj7wbjo9IcDFQAAAAAdAAAAABAY 

Немного элегантной математики

Теперь, когда основы позади, перейдем к более хардкорным вещам, которые лежат в основе современных систем автоматизированного проектирования. Каждый дизайнер, архитектор, 3D-художник использует их в своей практике, иногда даже сам того не подозревая. 

Гладкие функции и поверхности

Гладкие кривые и поверхности являются важной частью окружающего нас комфорта — посмотрите на ваши мышку и iPhone. 

Чтобы понять, что такое гладкость с математической точки зрения и каким законам подчиняется гармония гладкости, нам придется обратиться либо к функции одного аргумента на плоскости (привычная нам со школы кривая осях х и y), либо к функции нескольких аргументов, которые задают поверхность в пространстве. 

Итак, функцию называют гладкой k-порядка если, сама функция и k ее производных являются непрерывными. Если рука гуманитария на этой строчке потянулась за пистолетом валокардином, спокойно, я сейчас всё объясню! Вы точно помните, как выглядит график линейной функции, вот так: 

Производная функции — это то, насколько круто (с какой скоростью) меняется функция в любой конкретной точке. Для прямой этот показатель будет одинаковым в любой точке графика и будет равен угловому коэффициенту — k.  А теперь давайте усложним задачу и возьмем любую кривую, как определить, гладкая она или нет? 

Проверить, можно ли взять производную от ее производной в любой точке графика. С графиком слева, например, этот фокус не пройдет по очевидной причине — он не является непрерывным в точке 0. А вот с правой вполне прокатит. Если получилось так сделать один раз — это будет гладкая кривая 1-го порядка. Если можно брать производную от производной в любой точке графика, а потом от нее еще k раз (дифференцировать) —  гладкой кривой k-порядка. 

На практике человек очень плохо различает разрывы третьей и последующих производных: это относится и к визуальному, и к тактильному восприятию. Но при этом человек очень хорошо различает линии и поверхности разной кривизны. Короче, чтобы понять насколько гладкая ваша кривая, посмотрите на нее, если она примерно  как на правой картинке выше — она гладкая, а если как на левой — она только притворяется и ее неплохо бы побрить. Ну или нет. Тут зависит от того, гармонии или дисгармонии вы хотите добиться. В общем, если кривые в вашем творении такой формы, что от них можно взять производную и не раз, а два или даже три — будьте уверены, вы создали шедевр. 

О производных наглядно от пользователей Pikabu
О производных наглядно от пользователей Pikabu

Кстати, о кривизне. Математическое понятие кривизны ввел Эйлер в 18 веке. Кривизна определяется в каждой конкретной точке и вычисляется как величина, обратная радиусу окружности, касающейся этой кривой k = 1/R. В общем случае методы вычисления радиуса окружности требуют применения методов дифференциального исчисления, но можно ограничиться приближением, как показано на рисунке.

Сказанное выше справедливо для плоскости, а для поверхности в трехмерном пространстве радиусы будут определяться в двух перпендикулярных плоскостях.  

Для наших целей применения в 3D-графике и дизайне важно одно: если поверхность будет «накрывать» одну сферу, мы получим фигуру типа половинки яйца (эллиптический параболоид), а если «накроет» сразу две сферы — получится седло (гиперболический параболоид). 

Какими бывают кривые поверхности. Источник: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B2%D0%B5%D1%80%D1%85%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B3%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B0
Какими бывают кривые поверхности. Источник: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B2%D0%B5%D1%80%D1%85%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B2%D1%82%D0%BE%D1%80%D0%BE%D0%B3%D0%BE_%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BA%D0%B0

Кстати, плоскость у нас определяется как гладкая поверхность нулевой кривизны. А теперь достаем двойные листочки и описываем функцию, задающую такую фигуру:

Ладно-ладно, я пошутил! Но я не просто так вспомнил слона Экзюпери: как раз для того чтобы описывать такие сложные кривые и поверхности, существует такое математическое ухищрение как кусочно-определяемая функция. Это когда, чтобы описать сложную форму, мы берем эту дольку от ежа (красивой, гладкой гиперболы), эту дольку от чижа (элегантной параболы), а в месте их стыка просто обеспечиваем непрерывность. 

Это как если бы у нас было много фотографий совершенно идеальных женщин и мы пытались бы из отдельных их частей собрать фоторобот вашей новой знакомой: брови как у Анджелины Джоли, улыбка Киры Найтли. Вот этот кусочек фотки условного идеала (непрерывной функции), взятый от одного места стыка до другого называется сплайном. 

Кривые и поверхности Безье

Чего общего у автомобиля Citroën DS, Adobe Photoshop и CSS-анимации? Да, они: кривые Безье. 

До того как все телевизоры стали плоскими, а автомобили начали выпускаться на единых платформах, французская компания Citroën выпускала Citroën DS. На этом чуде инженерной мысли катались президент Де Голль, Фантомас и менталист Патрик Джейн. Даже спустя почти 70 лет этот дизайн не оставляет равнодушным. 

Очевидно, дело в красивых изгибах корпуса. Но как эти изгибы создавались, если никаких систем автоматизированного проектирования и тем более 3D-моделирования тогда и в помине не было? Придется начать эту историю издалека…

Полиномы Бернштейна

В далеком 1912 году российский и советский математик Сергей Бернштейн изучал полиномы, которые в общем виде задаются следующими формулами:

В данном случае является биномиальным коэффициентом.

Что это за набор букв такой? Объясняю. 

Представим, что у нас есть какая-то особенно хитровыдуманная кривая (поезд), которую нам нужно повторить. Чтобы ее повторить, нам нужно математически описать форму, но нет простой единой формулы, которая позволяет это сделать. Тогда мы разбираем кривую на «запчасти», каждая из которых описывается суммами отдельных многочленов Бернштейна (тележки, колесные пары, рессоры, сцепки, платформы, крепеж). В этом случае мы можем собрать кривую (поезд) очень или не очень похожую на интересующую нас модель. 

У полиномов есть замечательное свойство: они все гладкие и непрерывные (как в предыдущей части статьи). Это значит, если мы зададим в пространстве n опорных точек P0, P1, … Pn, повторяющих исходную кривую, у нас будет возможность подобрать такую совокупность кривых, которая гармонично будет проходить через все интересующие нас точки. 

Вот, например, вам очень хочется сникерс. Можно купить молочный шоколад, арахис, сварить нугу, карамель и замутить собственный батончик очень похожий на сникерс. Или можно взять спортивный протеин, намешать из него что-то, добавить орехов, покрыть шоколадом. Получится отдаленно похоже, только радости калорий будет меньше. Вот с полиномами Бернштейна примерно так же.

Вот некоторые базовые «запчасти», из которых можно собрать подавляющее большинство кривых: 

Вижу в ваших глазах немой вопрос: причем тут Citroën DS? А притом, что во второй половине 50-х математик из компании Citroën Поль де Кастельжо изобрел алгоритм построения кривых, где полиномы Бернштейна играют ключевую роль. Но поскольку разработки де Кастельжо защищались коммерческой тайной, более широкую известность этот алгоритм получил под именем другого француза — Пьера Безье. Безье работал на конкурирующий Renault и сумел первым опубликовать свои труды. Давайте разберемся, что это был за алгоритм такой? 

Мы все со школьных времен привыкли записывать функции в виде y = f(x). Но при такой форме записи сложно нарисовать многозначные кривые, даже простую окружность. Для этого придется воспользоваться уравнением x2 + y2 = R2. Или y = √(R2 – x2) (верхняя половина) и y = -√(R2 – x2) (нижняя половина). 

Но если мы введем третью переменную t, которая будет меняться от 0 до 1, то мы сможем записать наше уравнение в более лаконичном и приятном виде: 

Теперь применим параметрическую запись к многочленам Бернштейна на плоскости.

Вернемся к написанию координат в виде x1, x2, …, xm для того чтобы в дальнейшем нам было легко масштабировать наши вычисления на трехмерное и многомерное пространства.

Тогда каждая нужная нам кривая будет задаваться как множество точек B(t), координаты x1 и x2, которых удовлетворяют условиям:

или в общем виде: 

Вот примерно по такой формуле все графические редакторы мира рисуют кривые Безье. У меня, к сожалению, не было возможности подглядеть исходный код таких программ как MS Paint, Adobe Illustrator, CorelDraw и GIMP, но по всем признакам для построения криволинейных форм там используются кривые, составленные из кусочков кубических кривых Безье (сплайны кривых Безье).

Если ни разу не доводилось с ними работать, давайте попрактикуемся. Зададим наши точки P0 и P3 (эти точки P называют опорными точками) в виде векторов, т. е. P0 болд = (x0, y0), а P3 болд = (x3, y3). Аналогично и для других опорных точек. Мы возьмем 4 точки с номерами 0, 1, 2 и 3, для иллюстрации этого достаточно, но желающие могут взять и больше: 

Следом добавим точку P1, визуально проведя перпендикулярные прямые вниз от точки P1 и вправо от точки P0:

Теперь через точки P0 и P3 проведем 2 прямые так, чтобы они пересекались под углом 90°, и на этом пересечении добавим точку P2:

Итого у нас получится S-образная кривая на плоскости, построенная с помощью 2 контрольных точек и 2 опорных. В данном случае точки будут расположены на углах квадрата:

Но создавать кривые Безье можно не только на плоскости, но и в пространстве! Если точки P0 и P3  не лежат в одной плоскости, мы получим такое изображение:

Источник: https://youtu.be/_4_GNXiXETM?t=1194

Кривая Безье для одной точки P0 есть сама точка P0

Если n=1, то двум точкам P0  и P1 соответствует отрезок, соединяющий эти точки. Кривая задается уравнением  

и называется линейной кривой Безье.

Квадратичная кривая Безье для n = 2 задается тремя опорными точками: P0, P1 и P2.

Иллюстрация квадратичной кривой Безье
Иллюстрация квадратичной кривой Безье

Кубическая кривая Безье задается параметрическим уравнением: 

При этом точки P1 и P2 могут быть в одной плоскости с P0 и P3, так и в разных плоскостях, что позволяет строить трехмерные объемные кривые. 

Пример кубической кривой Безье приведен выше, а вот так иллюстрируется построение кривой Безье на анимации из вики:

Источник: https://upload.wikimedia.org/wikipedia/commons/d/db/B%C3%A9zier_3_big.gif
Источник: https://upload.wikimedia.org/wikipedia/commons/d/db/B%C3%A9zier_3_big.gif

Как видите, достижения математики находят широкое применение в дизайне, и этот процесс приобрел новые импульсы для развития после появления цифровой фотографии и компьютерной графики. 

Анатомия генеративных моделей

Многие имели опыт работы с такими генеративными сетями как MidJourney, DALL-E, Kandinsky и другими. К сожалению, в силу достаточно высокой сложности применяемых методов и алгоритмов большинство пользователей вынуждены воспринимать эти сети как черный ящик. Попробую описать процесс их работы более понятно, а применение — более осмысленным для читателя. Основываться буду на документации и статьях разработчиков данных моделей, а также собственном опыте работы в проектах по машинному обучению. Давайте сначала коротко пробежимся по основополагающим понятиям.

Эмбеддинги, метрики, расстояния

Эмбеддинг в переводе с английского означает «встраивание». Так называют процесс (и результат) сопоставления интересующих нас объектов — слов, фраз, картинок с векторами, соответствующим этим объектам в многомерном пространстве. 

Почему для сопоставления и генерации изображений и слов используются именно векторы? У них есть свойства, которые очень удобны для анализа таких сложных явлений, как естественные языки и визуальные образы: 

  • близким понятиям соответствуют близкие векторы в многомерном пространстве, например «кошка» и «кот» будут где-то рядом;

  • с векторами легко производить математические операции, например, примерно (подчеркну: ПРИМЕРНО) выполняются следующие равенства:  «нога + мяч = футбол», «конь - мужчина + женщина = лошадь»;

  • векторы — это направленные отрезки, мы всегда знаем, где у них начало, а где конец, соответственно, даже если некоторые «точки маршрута», через которые проходит вектор, повторяются, при анализе мы не спутаем «масть» и «месть», «карету» и «корыто» и даже омографы и омофоны будут представлены немного разными векторами;

  • поскольку мы имеем дело с векторами в многомерном пространстве, нам становится доступен анализ схожести и различия понятий по разным критериям: например, «маленький синий резиновый кубик» и «маленький желтый резиновый кубик» будут отличаться только в пространстве, определяющем яркость красного и синего цветов в RGB-палитре, а во всех остальных направлениях их векторы будут совпадать.

Вот несколько известных моделей, которые работают с эмбеддингами: Word2Vec, GloVe, BERT, GPT, CLIP.

Расстояние необходимо нам для численной оценки разницы между двумя векторами. Казалось бы: проведи прямую между двумя объектами и дело в шляпе. Но что делать, когда мы оперируем в n-мерном пространстве? Для таких случаев часто используют  так называемое «манхэттенское расстояние» или «расстояние городских кварталов» — это расстояние между двумя точками, измеренное вдоль осей, расположенных под прямым углом друг к другу (как городские кварталы). Его вычисляют путем нахождения суммы абсолютных разностей соответствующих координат векторов. Так для векторов A = (x1, y1, z1) и B = (x2, y2, z2) манхэттенское расстояние рассчитывается так: |x1 - x2| + |y1 - y2| + |z1 - z2|. 

Расстояние городских кварталов удобно в машинном обучении еще и потому, что менее подвержено погрешностям в многомерном пространстве. Приведу пример: вы смотрите телевизор в своей квартире: формально расстояние до соседа сверху и через стенку в эвклидовом пространстве между вами незначительно — 3 метра. Только, чтобы дойти до соседа сверху, вам понадобится пройти по коридору, выйти на лестницу, подняться на этаж выше и постучать в дверь. А сосед через стену может оказаться как ближе, так и дальше, в зависимости от того, живет он в вашем подъезде или в соседнем. Но если мы вообще не учитываем такое измерение как «подъезд», то вы и ваш сосед через стену для товарища сверху примерно одно и то же. 

Есть у такого способа измерения расстояний и интересные свойства. Допустим, у нас есть два близких объекта A и B, между которыми расстояние R. С одной стороны очевидно, что они не равны друг другу. Но если мы немного увеличим расстояние между этими объектами (на небольшую величину r), в область между R и R+r попадет большое число не сильно связанных с ними объектов. В конце статьи расскажу, как это использовать. 

Метрика тоже очень важная величина: она используется для измерения ошибки предсказания нашей модели в сравнении с желаемым результатом. 

Обычно чем меньше значение метрики, тем лучше, но это не обязательно. Отметим, что одной из метрик является расстояние, о котором я уже рассказал выше. 

Какие метрики мы можем использовать, чтобы сравнить два изображения, одно из которых является целевым? 

Французский математик Рене Фреше (эх, любят же французы кривые!) предложил сравнивать сходство двух кривых A(t) и B(t) с помощью выражения: 

Дышите, понимаю, выглядит страшно. Смысл этого жуткого нагромождения скобок в следующем: мы берем все доступные нам точки на этих кривых A(t) и B(t), которые могут зависеть от набора параметров α и β соответственно, измеряем расстояние между этими точками для равных значений t, находим максимальное значение этого расстояния в зависимости от параметров α и β. Минимальное значение (нижняя граница) функции F(A(α), B(β)) и есть искомое расстояние. Короче, мы ищем минимум максимума. 

Для наглядности давайте посмотрим на более приятном примере: например, человек гуляет с корги. Хозяин идет своим путем, обходя лужи, корж бодро трусит где-то рядом по своей собственной траектории и со своей скоростью. Путь каждого в отдельности — кривая, а расстоянием Фреше между ними будет минимальная длина поводка, которая потребуется, чтобы и пес, и хозяин, полностью прошли свой путь. 

Как расстояние Фреше поможет нам сравнить картинки? А вот как: представим, что у нас есть нейронная сеть-классификатор, которая определяет вероятности того, что изображено на нашей картинке. Обычно ответ выглядит так:

Собака – 25%

Волк – 15%

Лиса – 5%

Сова – 3% 

Если мы пойдем дальше и вместо функций будем вычислять расстояние между вероятностями нашей и эталонной картинки и считать для них расстояние Фреше — мы получаем метрику Frechet inception distance (FID), что можно перевести как начальное расстояние по Фреше. Такой метод значительно эффективное попиксельного сравнения картинок, ведь если мы сфотографируем один и тот же объект с немного разных ракурсов, расстояние между пикселями изменится, а вот расстояние Фреше останется примерно тем же. 

Такой метод оказался значительно эффективнее попиксельного сравнения картинок, который сразу выдает большую ошибку при небольших сдвигах и поворотах изображений и имеет и другие недостатки.

 Проиллюстрируем это на примере.

Возьмем две последовательности A и B пикселей красного цвета, у которых меняется яркость. Одна последовательность отличается от другой только на 1 единицу яркости.   

В цветовой гамме RGB (для простоты иллюстации мы выделяем только R) сдвиг на 1 пиксель выглядит так:

Иллюстрация почему сдвиг при попиксельном сравнении дает большую ошибку
Иллюстрация почему сдвиг при попиксельном сравнении дает большую ошибку

Значения яркости, приведенные в каждом пикселе и выделенные желтым, меняются в диапазоне от 0 до 255. В табличном виде это выглядит так:

Разница между A и B — 8.

Разница между A и B при сдвиге B на 1 пиксель — 236.

Расстояние Фреше между A и B при сдвиге на 1 пиксель (с округлением до целого) — 2.  

Генерация: GAN против диффузии

Третий закон Кларка гласит, что любая достаточно развитая технология неотличима от магии. При первом появлении работа генеративных сетей воспринималась как настоящая магия. Но за этой магией стоят математические алгоритмы, понять работу которых сможет каждый. 

Широкое распространение сегодня получили два метода генерации изображений: генеративные состязательные сети (GAN) и диффузионные модели. Результат их работы для пользователя очень похож, но технологии под капотом совершенно разные. Оба подхода могут генерировать высококачественные данные, но диффузионные модели часто показывают лучшее качество и большее разнообразие результатов, особенно в задачах, связанных с генерацией изображений.

GAN — это алгоритм который сталкивает 2 нейросети: одна из которых генерирует образцы чего-либо, а другая пытается установить их подлинность. Проще говоря, одна нейросеть изображает что-нибудь, а вторая кричит «не верю» до тех пор, пока предложения первой не станут похожи на что-то настоящее: портрет, пейзаж или дизайнерскую сумочку. 

С диффузией же всё намного сложнее. Возможно, некоторые из читателей имели возможность наблюдать работу художников, особенно если они рисуют пейзажи на холсте. Художник наносит последовательно грунт, основу фона, контуры основных элементов, отрисовывает сначала крупные, а потом мелкие детали. Работа художника и процесс генерации изображения диффузионной моделью имеют очень много общего.

Представим, что у нас есть набор изображений. 

Этап 1. Сделаем картинки для обучения моделей (таких картинок нужно много). Последовательно для каждой картинки будем проводить набор следующих операций:

  • добавим случайным образом немного пятен;

  • повторим процесс много раз до тех пор, пока от исходное изображение не пропадет совсем. 

Компьютер позволяет нам очень быстро выделить разницу между картинками на каждом этапе и проделать тот же набор действий в обратном порядке. Провернем этот фарш назад — и картина будет словно появляться на холсте, пока пятна последовательно исчезают. Эти искажения, которые добавляют на картинки называются шумом (noise), а процесс их удаления — denoising.

Этап 2. Используем пары последовательно изменяемых картинок для обучения нейросети. Так как компьютер может сравнить два изображения с использованием метрик, о которых мы говорили ранее, и определить, какое изображение ближе к оригинальному, у нас появляется возможность последовательно отделять искажения от оригинального изображения как показано на рисунке ниже. 

Источник: https://www.assemblyai.com/blog/minimagen-build-your-own-imagen-text-to-image-model/ 

Так как модель не знает, какое должно получиться восстановленное изображение, она использует специальные модули — сэмплеры, а помогают им промпты. В процессе восстановления сэмплер после каждого шага уточняет: картина на шаге n+1 больше похожа на промпт, нежели картинка на шаге n? И так шаг за шагом наша модель, словно художник, очень большим количеством мазков кистью рисует картину от крупных деталей к мелким. Эта часть, процесс восстановления изображения, получила название обратной диффузии (backward diffusion). 

А теперь, собственно, магия: если машина может нарисовать обратно то, что есть, то может нарисовать и то, чего нет. Можно сгенерировать шум и шаг за шагом подсказывать, где нужно стереть шум, чтобы получить что-то похожее на то, что хочет пользователь. 

Как думает модель?

Теперь у нас есть все необходимое, чтобы понять основные принципы работы генеративных нейронных сетей. Воспользуюсь материалами о модели, выложенными в репозитории

Посмотрим на внутреннее устройство модели Kandinsky. Как и другие мультимодальные модели, Kandinsky умеет работать с текстом и изображениями, а с версии 3.0 — даже с видео.

Используя модель Kandinsky, мы можем создавать изображения на основе текстового описания сюжета, создавать изображения по мотивам других изображений и объединять сюжеты двух изображений в одно. 

Kandinsky в разрезе
Kandinsky в разрезе

Как видно из иллюстрации, при каждом сценарии работы на первом этапе Kandinsky с помощью нейросети CLIP-ViT-G осуществляет преобразование изображений и текстов в эмбеддинги. На следующем шаге мы производим операции с эмбеддингами-векторами. При этом мы можем их не только складывать, но и вычитать. Это необходимо для исключения каких-либо нежелательных элементов в итоговом изображении, а сам процесс получил название negative prompting или «негативная подсказка».

На следующем этапе с помощью модели U-Net производится восстановление изображения, используя механизм диффузии и эмбеддинги как подсказки для кристаллизации. 

На заключительном этапе модель MOVQ улучшает изображение.

«Ну и для чего я всё это прочитал?»

А теперь перейдем к итогам. Как повлиять на то, какой получится ваша картинка?

Если вы никогда не учились в художке и не читали книг по основам дизайна и композиции, чтобы сделать красивые фотографии или получить удачный опыт рисования картин, стоит учитывать базу: располагать значимые элементы на пересечении линий горизонтальных и вертикальных третей, а также руководствоваться пропорциями Фибоначчи при построении композиций, пространств или декора. 

Если вы профессиональный художник, дизайнер или 3D-артист, то раздел про элегантную математику поможет вам понять, как менять радиусы закругления углов, где поставить опорные точки для получения нужной формы кривой и какие параметры поверхностей задавать для достижения нужного вам эффекта. Теперь, если вам нужно создать какой-нибудь предмет обтекаемых форм, вы сможете понять, насколько гармонична его гладкость: непритязательные могут на глазок прикинуть, не намешаны ли там гладкие кривые разного порядка, а дотошные возьмут производную и будут уверены наверняка. 

Если вы создаете картинки с помощью нейросетей, помните, что самое главное — промпты-подсказки. В роли промптов могут выступать и текст, и базовые изображения. Тут я вам, конечно, Америку не открыл, но если вы не первый день знакомы с нейросетями, то наверняка знаете: в них всё очень быстро меняется, и конкретные слова, которые вчера давали один результат, послезавтра могут дать другой. Медленнее всего изменениям подвержен математический фундамент генеративных моделей, именно поэтому его понимание помогает стабильно воспроизводить желаемые результаты. 

Как мы выяснили сегодня, то, какими именно будут промпты, и как они повлияют на результат, зависит от количества параметров (измерений) в модели, того, какие значения окажутся рядом с искомыми в многомерном пространстве, того, что получается при сложении значений и даже от…языка запроса! Ведь некоторые слова могут являться омографами или синонимами в одном языке, и не иметь таких свойств в другом, а, соответственно, их векторное представление для разных языков будет отличаться. Например, на заре разработки многих text-to-image моделей, когда цензурой еще не успели озаботиться, разработчики сетовали, что слишком много пользователей хотят генерить…синичек. Пары больших синичек, если вы понимаете о чем я. 

Иногда синички — это просто синички
Иногда синички — это просто синички

Для закрепления материала давайте проиллюстрирую на примере запросов к нейросети Kandinsky, как меняется результат в зависимости от промпта. По запросу «голубое небо» он почти всегда (по крайней мере, по состоянию на июль 2024) генерирует небо над морем или полем с линией горизонта: 

Результат по запросу «голубое небо»
Результат по запросу «голубое небо»

При этом по запросу «светло-голубое небо» всегда выдается небо без посторонних примесей:

Результат по запросу «светло-голубое небо»
Результат по запросу «светло-голубое небо»

Текстовых промптов можно задать несколько, перечислив их через запятую, например «черное море, звездное небо»:

Результат по запросу «черное море, звездное небо»
Результат по запросу «черное море, звездное небо»

Чтобы избежать попадания на картинку назойливых «соседей» по векторному пространству, о которых мы говорили в части про манхэттенское расстояние, можно использовать негативный промпт. Он предназначен для избегания появления указанных объектов на изображении. Пример: «черное море» + негативный промпт «звездное небо». 

Так меняет картинку добавление негативного промпта «звездное небо»
Так меняет картинку добавление негативного промпта «звездное небо»

Опытные промпт-инженеры, конечно, уже знают про использование негативных промптов и прочий файн-тюнинг, но готов поспорить, немногие думали о том, почему это работает именно так с математической точки зрения. 

Надеюсь, мне, как автору статьи, удалось доступно рассказать о сути математических методов, которые в том или ином виде используются всеми, кто рисует красивое. По крайней мере, я очень старался и буду рад вопросам и комментариям. Про отбор полученных результатов, файн-тюнинг, развертывание собственных сервисов генерации изображений и прочее, расскажу уже для тех, кто более углубленно работает с text-to-image моделями и как-нибудь в другой раз. Спасибо, что осилили столько букв!


Интересное в блоге:

Комментарии (5)