Дифузійні моделі

У GAN дві мережі змагаються, і жодна з них не має чого мінімізувати. Дифузія відмовляється від змагання зовсім: вона псує зображення шумом за відомим правилом і вчить одну мережу цей шум упізнавати. Задача стає звичайною регресією — із втратою, яку можна читати.

Тема 38 лишила нас із незручним фактом: у GAN немає числа, яке падає, коли стає краще. Втрата генератора росте, коли дискримінатор розумнішає, і падає, коли той дурнішає, — а обидва рухи виглядають на графіку однаково. Тому навчання GAN доводиться пильнувати очима: подивитись на картинки, здогадатись, хто з двох переміг, і підкрутити швидкість навчання наосліп.

Дифузійна модель (diffusion model) відмовляється від змагання зовсім. Ідея спершу звучить як жарт: візьмімо зображення й зіпсуймо його самі, крок за кроком підмішуючи випадковий шум, доки від картинки не лишиться нічого. Ми зіпсували його власноруч, отже, точно знаємо, що саме підмішали. Далі вчимо мережу відповідати на просте питання: «ось зіпсоване зображення й номер кроку — який шум тут підмішаний?» Це вже не змагання, а звичайна регресія з правильною відповіддю, і в неї є одна втрата на всю модель.

А далі — дрібниця, яка й зробила ці моделі знаменитими: якщо мережа вміє прибирати шум, її можна запустити з чистого шуму й прибирати доти, доки з-під нього не проступить зображення, якого ніхто не малював.

Наскрізний приклад теми той самий, що в усьому блоці: шість фігур 28×28 — коло, квадрат, ромб, кільце, хрест і трикутник, — із випадковим центром, випадковим радіусом і шумом 0.06. Ті самі, що в темі 16, у 37 і в 38. Бібліотеки diffusers в нас немає, тож дифузію ми, як завжди в цьому курсі, будуємо руками — двадцять одна тисяча ваг, усе видно.

МотивЧому змагання довелося кинути

Порівняймо дві постановки чесно, без реклами.

GAN. Генератор і дискримінатор мінімізують різні втрати, і одна з них залежить від іншої. Рівновага, якої вони шукають, — це сідлова точка, а не мінімум. Немає жодної функції від пари мереж, яка падала б протягом усього навчання, — отже, немає й графіка, на який можна дивитись.

Дифузія. Мережа одна, втрата одна: середня квадратична похибка між підмішаним шумом і передбаченим. Мінімум у неї є, і він досяжний.

Ціна теж є, і вона чесно велика: одна картинка коштує не один прохід мережі, а десятки або сотні. GAN малює за один прохід, дифузія — за сто. Друга половина теми про те, скільки з тих сотень кроків справді потрібні.

Що таке «шум» у цій темі. Скрізь далі це гаусів шум: до кожного пікселя додається своє випадкове число з нормального розподілу із середнім 0. Наскільки великі ці числа, задає стандартне відхилення σ (сигма): при σ = 0.1 більшість доданків лежить у межах ±0.2, при σ = 1 — у межах ±2, тобто більше за весь діапазон яскравості. Іншої випадковості в дифузії немає.

Пряма дифузіяЯк псують зображення

Почнімо з єдиної частини моделі, у якій немає жодної ваги й нічого не навчається. Пряма дифузія (forward process) — це рецепт псування, записаний наперед. Беремо зображення x₀ і робимо T кроків. На кожному кроці трохи стискаємо картинку до нуля й трохи домішуємо свіжий шум:

xt = √(1 − βt) · xt−1  +  √βt · ε

Що тут що:

Послідовність β₁, β₂, …, βT зветься розкладом шуму (noise schedule). Її обирає інженер, а не мережа.

Пряма дифузія на одній фігурі

Повзунок веде по кроках ланцюга. Ліворуч — вихідна фігура, праворуч — вона ж після t кроків псування; смуга внизу показує весь ланцюг одразу.

фігура
ᾱ накопичене—
частка сигналу—
частка шуму—
β цього кроку—
Псування нерівномірне в часі. Перші двадцять кроків майже нічого не змінюють: β там крихітна. Основна руйнація припадає на середину ланцюга — саме там форма перестає бути впізнаваною, і саме там мережі найважче й найцікавіше працювати. Розклад тут книжковий: β лінійно від 0.0001 до 0.02, кроків 200.

Закрита формулаСтрибок замість ланцюга

Якби для навчання доводилось щоразу прокручувати ланцюг із сотні кроків, дифузія була б непідйомною. Але не доводиться: усю послідовність можна згорнути в одну формулу. Виведемо її на двох кроках руками — далі все повторюється.

крок 1 · один крок псування
x₁ = √(1−β₁)·x₀ + √β₁·ε₁

Позначмо αt = 1 − βt — це «частка, що лишилась від картинки». Тоді x₁ = √α₁·x₀ + √(1−α₁)·ε₁.

крок 2 · підставляємо в наступний
x₂ = √α₂·x₁ + √(1−α₂)·ε₂ = √(α₂α₁)·x₀ + √α₂·√(1−α₁)·ε₁ + √(1−α₂)·ε₂

Від x₀ лишився множник √(α₂α₁). А два шумові доданки — незалежні гаусові величини, і їх можна замінити одним.

крок 3 · два шуми складаються в один

Сума двох незалежних гаусових величин — теж гаусова, і її дисперсія дорівнює сумі дисперсій. Тут це α₂(1−α₁) + (1−α₂) = 1 − α₂α₁. Отже:

x₂ = √(α₂α₁)·x₀ + √(1 − α₂α₁)·ε,  де ε — один свіжий гаусів шум
крок 4 · загальний вигляд

Той самий доказ повторюється для будь-якого t. Уводимо накопичений добуток ᾱt = α₁·α₂·…·αt (значок над буквою читається «альфа з рискою»), і виходить головна формула теми:

xt = √ᾱt · x₀  +  √(1 − ᾱt) · ε

Словами: зіпсоване зображення на будь-якому кроці — це вихідне зображення, приглушене в √ᾱ разів, плюс шум із розмахом √(1−ᾱ). Два множники дають у сумі квадратів одиницю, тож √ᾱ природно назвати часткою сигналу, а √(1−ᾱ) — часткою шуму.

Наслідок практичний і величезний: щоб навчати мережу, ланцюг не потрібен зовсім. На кожному кроці навчання ми кидаємо жереб на t, стрибаємо на цей крок однією формулою й питаємо мережу про підмішаний шум.

Перевірка, а не обіцянка. Рівність можна не приймати на віру, а заміряти. Ми взяли 600 справжніх фігур, чесно прокрутили 50 кроків ланцюга — і окремо стрибнули на той самий крок однією формулою. Стандартне відхилення доданого шуму вийшло 0.3463 ітеративно й 0.3459 формулою при теоретичному √(1 − ᾱ₄₉) = 0.3463. Три числа збігаються до третього знака. Саме завдяки цій рівності навчання дифузії й коштує дешево.

Ланцюг проти стрибка

Ліворуч — результат чесних t кроків один за одним, праворуч — той самий крок, узятий однією формулою. Крива внизу показує розмах доданого шуму в обох способах.

ланцюгом—
формулою—
теорія √(1−ᾱ)—
розбіжність—
Дві картинки різні, а числа однакові — і це саме те, що треба. Ланцюг і формула тягнуть різні випадкові числа, тож пікселі не збігаються ніколи. Збігається розподіл: розмах доданого шуму той самий із точністю до третього знака. Саме тому навчання може стрибати одразу на потрібний крок і не проганяти сотню проміжних.

РозкладСкільки шуму треба насправді

Тепер найцікавіше в прямому процесі, і воно ж — найчастіша прихована поломка. Порахуймо накопичений добуток ᾱ для книжкового розкладу (β лінійно від 0.0001 до 0.02, кроків 200) і подивімось, що з ним стається до кінця ланцюга.

крок tᾱчастка сигналу √ᾱчастка шуму
100.9934190.99670.0811
500.8756160.93570.3527
1000.5963950.77230.6353
1990.1321830.36360.9316

Останній рядок — це діагноз. У кінці ланцюга від зображення лишається ще 0.3636 сигналу: x на останньому кроці — не чистий шум, а шум із помітною домішкою вихідної картинки. Тут ламається не арифметика, а вся ідея генерації. Малювати ми збираємось так: візьмемо чистий шум N(0, 1) і почнемо його прибирати. Але мережа чистого шуму ніколи не бачила — вона бачила «шум плюс третину фігури».

Розрив вимірний одним рядком. Беремо справжні фігури в діапазоні [−1, 1] (там середнє дорівнює −0.6919, бо фону в наших фігурах більше, ніж самої фігури) і рахує, що виходить на останньому кроці:

розкладсума β√ᾱ у кінцісереднє xTрозкид xT
книжковий 0.0001…0.022.0100.3636−0.25350.9614
стиснутий 0.0005…0.110.0500.0055−0.00461.0025
косинусний9.2420.0002−0.00180.9997

Читай стовпчик «середнє». Ми збираємось починати відбір із N(0, 1), у якого середнє дорівнює нулю. Кінець книжкового ланцюга має середнє −0.2535. Це не дрібниця в четвертому знаку — це чверть усього діапазону яскравості, зсунута туди, де мережа її не чекає.

Звідки взялася поломка й чому вона типова. Числа 0.0001 і 0.02 узяті з першої статті про DDPM, і там вони стоять при тисячі кроків. Сума β по тисячі кроків дорівнює приблизно 10 — саме стільки треба, щоб ᾱ впала до нуля. Скоротивши ланцюг до 200 кроків і лишивши ті самі β, ми лишили від потрібного шуму рівно пʼяту частину: 2.010 замість 10.05. Ось звідки в справжніх DDPM тисяча кроків — і ось чому переносити числа з чужої статті, не переносячи T, не можна. Лікування коштує один рядок: домнож β на 1000 / T.

Далі робочим беремо стиснутий лінійний розклад, а косинусний лишаємо для порівняння: у нього інша форма кривої, і це видно на числах — на кроці 100 в косинусного ᾱ = 0.4861, а в стиснутого лінійного вже 0.0728. Косинусний довше тримає картинку впізнаваною й руйнує її різко в кінці. Чи дає це кращі картинки — питання заміру, і ми його зробимо в розділі 9.

Три розклади шуму поруч

Крива показує частку сигналу √ᾱ уздовж ланцюга, смуга під нею — як та сама фігура псується за цим розкладом.

розклад
сума β—
√ᾱ у кінці—
де √ᾱ < 0.5—
зсув середнього—
Постав книжковий розклад і потягни T до 1000 — частка сигналу в кінці впаде з 0.3636 до 0.0067, і зелений вердикт повернеться. Це і є той самий рецепт із першої статті про DDPM, у своїх рідних умовах. Косинусний розклад доходить до нуля за будь-якого T, бо його β задані не числами, а формою кривої. «Зсув середнього» тут — це √ᾱT × (−0.6919): рівно стільки оригіналу лишається в кінці ланцюга, а −0.6919 — заміряне середнє справжніх фігур у діапазоні [−1, 1].

МережаВтрата, яку можна читати

Тепер про єдину навчану частину. Мережа дістає на вхід дві речі: зіпсоване зображення xt і номер кроку t. Номер кроку обовʼязковий: те саме сіре місиво на кроці 30 й на кроці 180 треба чистити по-різному, і без підказки, наскільки все зіпсовано, мережа мусила б угадувати.

Число t подають набором синусів і косинусів різної частоти. Причина та сама, з якої трансформерові потрібне позиційне кодування (тема 20): одне сире число погано розчиняється по мережі, а тридцять два періодичні канали дають і грубий масштаб («ми в кінці ланцюга»), і точний («саме крок 137»).

Тільки не плутай із тим, як це зроблено в темі 20. Там позиції патчів задає навчана таблиця: у нашому ViT це 2 400 ваг, у ViT-B/16 — 197 × 768 = 151 296, і мережа мусить вивчити їх із даних. Тут навпаки: синуси й косинуси — готова функція без жодної ваги, її нічого вчити. Так можна саме тому, що кроків рівно T і вони впорядковані від 0 до T — сусідні номери мають бути схожі, а далекі різні, і періодичні канали дають це задарма. Обидва способи розвʼязують одну задачу: як подати мережі число, яке саме собою нічого не важить.

Сама мережа — маленький U-Net із теми 30: 28×28 → 14×14 → 7×7 і назад, зі скіп-зʼєднаннями. Вибір не випадковий: вихід має бути того самого розміру, що вхід, і мусить тримати і грубу форму (видно на 7×7), і чіткий край (живе тільки на 28×28). У нашій моделі 21 697 ваг.

L = середнє по всіх прикладах і всіх t від  ‖ ε − ε̂(xt, t) ‖2

Словами: беремо шум, який самі підмішали, віднімаємо шум, який передбачила мережа, підносимо різницю до квадрата й усереднюємо. Це звичайна середня квадратична похибка — та сама, що в регресії. Ніякої другої мережі, ніякого змагання.

І тут проходить межа з темою 38. Втрата дифузії щось означає. Якщо вона впала, модель справді краще вгадує шум. У GAN такого зчитування немає: там втрата генератора вимірюється проти дискримінатора, який сам змінюється, і падіння може означати як «генератор порозумнішав», так і «дискримінатор здурнішав».

Але «означає» — заява, яку теж треба перевіряти, а не проголошувати. Замір такий: втрата рахується після кожної епохи, а в трьох контрольних точках навчання зупиняється, з моделі відбирається по 120 зображень і їхня якість міряється окремо. Якщо крива втрати щось каже про якість картинок, ці два числа мусять рухатись разом.

Втрата й якість поруч

Ліворуч — втрата в чотирьох заміряних точках; праворуч — якість згенерованого в трьох із них, де відбір справді робився.

контрольна точка
втрата—
FID—
класів із 6—
розкид FID—
Обидва числа падають разом. Це й означає «втрату можна читати»: не те, що вона гарна, а те, що її падіння відповідає покращенню картинок. Три точки — мало для серйозної статистики, і ми цього не приховуємо: твердження тут не «кореляція дорівнює 0.9969», хоч на цих трьох точках вона саме така, а «за весь час навчання жодного разу не сталося, щоб втрата впала, а якість погіршилась». Точки між виміряними ми не домальовуємо: відбір коштує дорого, і зроблено його рівно тричі.

Зворотний хідІз шуму у фігуру

Мережа вміє відповідати на питання «який тут шум?». Перетворимо це вміння на малювання.

Перший крок очевидний. Закриту формулу xt = √ᾱ·x₀ + √(1−ᾱ)·ε можна розвʼязати відносно x₀: підставляємо замість ε передбачення мережі й дістаємо здогад про чисте зображення прямо з будь-якого кроку:

x̂₀ = ( xt − √(1 − ᾱt) · ε̂ ) / √ᾱt

Здавалося б, готово: подаємо чистий шум, отримуємо x̂₀, і все. Але ні. На великому t знаменник √ᾱ крихітний — на останньому кроці це 0.0055, — і будь-яка похибка мережі множиться на 180. Одним стрибком із шуму виходить розмита каша: модель дає усереднену фігуру, бо не має підстав обрати конкретну.

Тому йдуть по одному кроку — до xt−1, а не одразу до x₀: на маленькому кроці похибка ще не встигає розлетітись. Правило переходу — це умовний розподіл xt−1, коли відомі і xt, і здогад x̂₀. На практиці воно має вигляд «зважена суміш двох відомих картинок плюс дрібка свіжого шуму»:

xt−1 = a · x̂₀  +  b · xt  +  σ · z a = √ᾱt−1·βt / (1 − ᾱt) b = √αt·(1 − ᾱt−1) / (1 − ᾱt) σ2 = βt·(1 − ᾱt−1) / (1 − ᾱt)

a і b — це просто ваги: наскільки вірити здогаду про чисте зображення й наскільки — тому, що вже є на руках. Вони не сталі, а їдуть уздовж ланцюга — і саме напрямок цієї їзди варто побачити одразу, бо словами його легко переплутати. Малювання йде справа наліво: від t = T − 1 до нуля. На тому кінці, звідки воно починається, a крихітна — здогаду про чисте зображення там майже не вірять; що ближче до нуля, то більша a, і на останньому кроці вона доростає до одиниці. А σ·z — дрібка нового шуму, яка робить кожен запуск іншим. Цей рецепт і зветься DDPM.

Один крок назад: із чого складається xt−1

Повзунок веде по кроках. Угорі — три ваги вздовж усього ланцюга, унизу — з чого саме змішано наступну картинку на обраному кроці.

a — вага x̂₀—
b — вага xt—
σ — свіжий шум—
ᾱ на цьому кроці—
Постав повзунок на 199 — туди, звідки починається малювання. Вага здогаду a = 0.0006: мережа щойно подивилась на чистий шум, і її здогадові про фігуру не вірять майже зовсім. Веди повзунок ліворуч — a росте, σ спадає, і на нульовому кроці лишається сама лише a = 1.0000: останній крок просто віддає здогад як відповідь. Саме тому одним стрибком із шуму виходить каша, а сотнею дрібних кроків — фігура. Розклад тут робочий, стиснутий, кроків 200.
Граблі, на які стане кожен. Здогад x̂₀ прийнято обрізати до [−1, 1]: картинка не буває яскравішою за біле. Я так і зробив — і ланцюг розійшовся, бо записав перехід в еквівалентному вигляді «через x̂₀ і ε̂» замість «через x̂₀ і xt». Дві форми рівні лише поки xt = √ᾱ·x̂₀ + √(1−ᾱ)·ε̂. Обрізання цю рівність ламає, доданки перестають узгоджуватись, і похибка накопичується по кроках: розкид x сягав 153 замість одиниці, а на виході виходили однакові плями. Лікування — брати формулу через xt, як вище. Симптом підступний тим, що жодна перевірка не падає: числа скінченні, картинки є, просто неправильні.

ВибірПередбачати шум чи зображення

Мережу можна вчити двом різним речам. Або нехай передбачає підмішаний шум ε — так зроблено в оригінальному DDPM і так робить наша модель. Або нехай одразу передбачає чисте зображення x₀. Одне з іншого перераховується тією самою закритою формулою, тож на папері це два записи однієї моделі.

На папері — так, а на практиці ні: вони по-різному зважують кроки ланцюга. Передбачення шуму нескладне на початку і дуже складне в кінці; з передбаченням зображення все навпаки. Вибір цілі — це прихований спосіб сказати мережі, на яких кроках старатися більше. Канонічна порада — «передбачай шум». Перевірмо її: три зерна на варіант, той самий кістяк, розклад і відбір.

що передбачаєFIDрозкидпо зернахкласів із 6
шум ε181.84±36.38139.1 · 228.0 · 178.44 · 4 · 4
зображення x₀938.54±225.39651.5 · 962.0 · 1202.13 · 1 · 1

Тут купи не перетинаються: найгірше зерно в передбачення шуму — 228.0, найкраще в передбачення зображення — 651.5. За критерієм курсу це справжня різниця, а не шум: на наших даних канонічна порада підтверджується. Покриття каже те саме — 4 · 4 · 4 проти 3 · 1 · 1. Причина, найімовірніше, у кінці ланцюга: там √ᾱ дорівнює 0.0055, і передбачати зображення доводиться майже з нічого, тоді як передбачення шуму в цьому місці тривіальне.

Чому це важливіше за саму відповідь. Три зерна — мінімум, який курс вимагає від будь-якого порівняння, і зміст вимоги саме такий: дивитись не на різницю середніх, а на те, чи перетинаються купи. Купи, що перетинаються, означають: на іншому наборі зерен упорядкування могло б перевернутись. Так само ми чинили в темі 26 і в темі 38.

МетрикаЇї спершу калібрують

Тут головний розділ теми, і він не про дифузію, а про те, як узагалі міряють генерацію.

У класифікації є правильна відповідь, і метрика питає про неї. У генерації правильної відповіді немає: модель намалювала фігуру, якої ніхто не малював, і порівнювати її нема з чим. Тому міряють не окрему картинку, а купу: наскільки розподіл згенерованого схожий на розподіл справжнього. Так і придумали FID.

FID = ‖μA − μB‖2 + tr( ΣA + ΣB − 2·√(ΣAΣB) )

Словами: наскільки далеко центри двох хмар (μ — середнє) і наскільки різна їхня форма (Σ — коваріація, тобто як ознаки розкидані й повʼязані між собою; tr — сума діагоналі матриці). Хмари яких чисел? Ознак, знятих із якоїсь мережі: у статтях це Inception, навчений на ImageNet. У нас його немає, тож ознаки беремо з власного судді — класифікатора шести фігур, навченого на справжніх даних. Його точність 0.9983.

Наше число FID не порівнюване з опублікованими. Воно пораховане на ознаках нашого судді, а не Inception, на 300 зображеннях, а не на 50 000. Воно годиться рівно на одне: порівнювати наші моделі між собою. Ставити його поруч із числом зі статті не можна — це різні лінійки.
І навіть із сусідньою темою — обережно. Тема 38 ставить таку саму таблицю калібрування на такому самому судді — і числа в неї інші: базова лінія «справжні проти справжніх» там 1.1582, а тут 3.0352; «лише кола» там 483.8364, а тут 423.1416. Обидва заміри чесні, просто зроблені на різних вибірках і з різними прогонами судді. Тобто FID тут — результат конкретного заміру, а не властивість набору, і порівнювати між собою можна тільки числа, зняті в одному прогоні. Саме тому базова лінія друкується поруч щоразу: без неї не видно, якою лінійкою міряли.

Тепер найважливіше: перш ніж вірити метриці, її треба зламати навмисне

Будь-яка метрика впорядкує тобі варіанти. Питання лише в тому, чи це те впорядкування, яке ти маєш на увазі. Перевірити просто: підсунути їй набори, про які ми заздалегідь знаємо відповідь. Таких наборів ми зібрали вісім. «Лише кола» — це повний колапс мод: один клас із шести, картинки бездоганні. «Розмита каша» — навпаки: усі класи на місці, але форми немає. «Усе чорне» й «усе біле» — це навіть не зображення. Метрика, яка поставить хоч щось із цього краще за робочу модель, непридатна, і всі числа, поміряні нею, доводиться викинути.

Рахуємо двома наборами ознак. Перший — 64 числа з передостаннього шару судді: там ще жива форма фігури. Другий — 32 «слабкі» ознаки: карти згорток, усереднені по простору. Усереднення викидає форму й лишає щось на кшталт «скільки чорнила де». Саме така версія метрики і є класичною пасткою.

що подаємоFID суддіFID слабкийкласів із 6
справжні (інша вибірка)3.03520.00036
лише кола423.14160.02381
кола + квадрати435.22840.02402
розмита каша1132.07930.18982
середнє всіх фігур1221.99780.22741
усе чорне1254.32910.25951
чистий шум1499.13580.42701
усе біле1693.28204.59291

Обидві версії впорядковують набори майже правильно: чим гірший набір, тим більше число — з єдиним винятком у сусідній парі, де «лише кола» дістають менше за «кола + квадрати», хоч клас у них один проти двох. Але порядок — не те, що треба перевіряти. Перевіряти треба запас: у скільки разів зіпсований набір гірший за робочу модель. Наша модель (розділ 9) дістане 175.78 за метрикою судді й 0.0235 за слабкою, і запас рахується проти цих двох чисел. Найменший запас метрики судді — 2.41× на рядку «лише кола». Найменший запас слабкої — 1.01× на тому самому рядку.

Прочитай це ще раз. «Лише кола» — це повний колапс мод, один клас із шести. Слабка метрика ставить його на один відсоток гірше за робочу модель, тобто не відрізняє їх узагалі. Саме цим і небезпечні усереднені ознаки: вони не брешуть відверто, вони просто перестають бачити те, заради чого метрику заводили.

Підсунь метриці завідомо погане

Обери набір — і подивись, що скажуть про нього обидві версії FID і покриття класів. Пунктир на смугах — місце, де стоїть наша робоча модель.

набір
FID судді—
FID слабкий—
класів із 6—
запас проти моделі—
Постав «лише кола» й порівняй дві смуги. Обидві метрики впорядковують набори однаково правильно — але шкала в них різна, і саме в шкалі вся справа. Числа тут заміряні; картинки ліворуч канва малює сама за тими самими правилами, за якими зібрано самі набори.
Правило, яке з цього виходить. Метрика генерації — це пара, а не число. FID каже, наскільки хмара згенерованого схожа на хмару справжнього; покриття класів каже, чи не забула модель половину даних. Поодинці не працює жодне: FID майже не розрізняє «лише кола» й «кола + квадрати» (423.1416 проти 435.2284), а покриття нічого не знає про те, наскільки криво намальована фігура. Далі скрізь друкуємо обидва числа й базову лінію поруч.

ЦінаСкільки кроків насправді треба

Тепер, коли метриці можна вірити, можна питати головне. Дифузія дорога рівно тому, що одна картинка коштує стільки проходів мережею, скільки кроків у відборі: сто кроків — у сто разів дорожче за GAN. Тож проганяємо відбір із 2, 5, 20 і 200 кроків, по три зерна на точку, і міряємо парою метрик.

кроківFID суддірозкидкласів із 6FID слабкий
26033.76±915.231 · 1 · 11.4241
5218.05±34.714 · 4 · 30.0330
20181.84±36.384 · 4 · 40.0229
200175.78±38.824 · 4 · 40.0235

Відповідь різка й не така, як очікуєш. Два кроки — катастрофа: 6033.76 при одному класі з шести на всіх трьох зернах. Але вже з пʼяти кроків модель повертається в робочий діапазон, а з двадцяти крива стає плоскою: 181.84 проти 175.78 при двохстах. Різниця 6.06 — вшестеро менша за розкид по зернах (±36.38), тобто за критерієм курсу різниці немає.

Отже, на наших фігурах двадцяти кроків із двохсот досить, а решта сто вісімдесят проходів витрачаються дарма. Це не спростування того, що великим моделям потрібні десятки кроків: наші шість фігур простіші за фотографію на кілька порядків, а чим простіший розподіл, тим менше кроків треба, щоб у нього потрапити. Але для нашої задачі число саме таке, і воно поміряне, а не вгадане.

Чому цей розділ стоїть після розділу 8. Останній стовпчик — та сама метрика з мізерним запасом. Тут вона називає найкращою кількість кроків 20, а справна — 200. Розходження невелике, і саме тому воно небезпечне: метрика, яка на одному питанні відповідає правильно, а на іншому ставить колапс мод урівень із робочою моделлю, не стає придатною — вона просто вгадала. Довіра до числа береться з калібрування, а не з того, що воно здалося розумним.

Уся таблиця вище — про DDIM, детермінований відбір, до якого ми дійдемо в розділі 10. Той самий замір для DDPM, схеми з розділу 6, зроблено у двох точках із чотирьох: на 2 і 20 кроках його не міряли, бо на такому пропуску кроків виведення DDPM уже не має сили.

кроківDDPM · FID суддірозкидкласів із 6
5312.53±102.935 · 3 · 4
200430.90±146.035 · 2 · 4
Тепер найнеприємніше в цих двох рядках, і я не буду це ховати. Із пʼятьма кроками DDPM дає 312.53, а з двомастами — 430.90. Тобто більше кроків гірше, і пара метрик цього не рятує: обидва числа кажуть одне й те саме.

Спокуслива відповідь — «метрика знову бреше». Але вона щойно пройшла калібрування із запасом 2.41×, тож звалювати на неї не можна. Правильна відповідь про нашу модель: DDPM домішує свіжий шум на кожному кроці, і кожен крок мусить прибрати те, що додав попередній. Коли ε̂ точний, це працює; коли модель груба, похибка накопичується рівно стільки разів, скільки кроків. Перевірка — у першій таблиці: DDIM, який не домішує нічого, поводиться монотонно — 218.05 → 181.84 → 175.78. Це властивість недонавченої моделі, а не дифузії, і сказати так чесніше, ніж списати на метрику.

Кроки, якість і покриття

Ліворуч — FID залежно від кількості кроків для обох схем відбору, праворуч — скільки класів із шести застало кожне зерно окремо.

схема відбору
FID судді—
розкид—
класів із 6—
проходів мережею—
Перемкни на DDPM і пройди від пʼяти кроків до двохсот. Крива піде вгору, а не вниз: схема, що домішує свіжий шум на кожному кроці, накопичує похибку недонавченої мережі рівно стільки разів, скільки кроків. У DDIM, який не домішує нічого, та сама крива йде вниз і виходить на полицю. Два кроки для DDPM ми не міряли — на такому пропуску його виведення вже не має сили. Три зерна на точку.

DDIMВідбір без жеребу

У формулі переходу з розділу 6 є доданок σ·z — свіжий шум на кожному кроці. Постає природне питання: а що, як його не додавати?

Виявляється, можна. Якщо взяти σ = 0, перехід стає детермінованим: з того самого початкового шуму виходить те саме зображення, щоразу. Це і є DDIM. Дві властивості роблять його стандартом практики.

Ціна теж є, і про неї кажуть рідше: детермінованість зменшує різноманіття. Увесь випадковий вибір тепер зосереджений у першому кидку.

На наших числах це видно так: на двохстах кроках DDIM дає 175.78 ± 38.82, а DDPM — 430.90 ± 146.03, і купи не перетинаються. На пʼяти кроках — 218.05 проти 312.53, і там купи вже перетинаються, тобто різниці не доведено. Читається це так: перевага DDIM у нас росте разом із довжиною ланцюга, і росте вона саме тому, що DDPM щокроку домішує шум, який недонавчена мережа не встигає прибрати. На добре навченій моделі різниця була б меншою — цього ми не перевіряли й не стверджуємо.

УмоваЯк просити фігуру на замовлення

Досі модель малювала будь-що. Тепер найдешевша зміна в усій темі, з якої виростає вся керована генерація. Мережа вже приймає номер кроку t — ми перетворюємо його на вектор і додаємо всередині кожного блоку. Додати клас коштує рівно те саме: заводимо таблицю з семи векторів (шість фігур плюс позначка «невідомо»), беремо потрібний рядок і додаємо його до вектора часу. Один шар nn.Embedding, три рядки коду.

умова = вектор_часу(t) + вектор_класу(y)

Далі тонкість, заради якої і зроблено сьому позначку. У десяти відсотках навчальних прикладів ми ховаємо клас, підставляючи «невідомо». Через це одна мережа вчиться обом режимам: малювати на замовлення й малювати будь-що. З цієї ж пари режимів виростає прийом, який зветься classifier-free guidance: під час відбору беруть обидва прогнози й підсилюють різницю між ними. Ми його не робимо — він у домашньому завданні.

Перевіримо, чи модель слухається: просимо по 50 зображень кожного класу, три зерна, і питаємо суддю. Поруч ставимо те, що та сама модель малює без замовлення — інакше число «влучили» нічого не означає: якщо модель і так малює переважно хрести, то влучання в хрест не є заслугою умови.

замовилибез умовина замовленняпідйомпо зернах
коло0.0300.00670.22×0 · 0.02 · 0
квадрат0.0030.00000.00×0 · 0 · 0
ромб0.1100.08670.79×0.06 · 0.16 · 0.04
кільце0.2330.39331.69×0.64 · 0.1 · 0.44
хрест0.3170.32001.01×0.4 · 0.08 · 0.48
трикутник0.3070.30671.00×0.22 · 0.4 · 0.3

Доводиться сказати неприємне: на нашому бюджеті умова майже не працює. Середнє влучання по шести класах — 0.1856 при 0.1667 у чистого вгадування. Підйом помітно більший за одиницю є рівно в одного класу з шести — кільця (1.69×). Хрест і трикутник лишаються там, де були (1.01× і 1.00×), а коло й квадрат на замовлення виходять рідше, ніж без нього.

Причина видна в другому стовпчику, і вона не в механізмі умови. Безумовна модель сама покриває лише чотири класи з шести: квадрат вона малює у 0.003 випадків, коло — у 0.030. Не можна замовити те, чого модель не вивчила. Умова вміє перерозподілити ймовірність між тим, що модель уміє малювати, і не вміє вигадати новий клас. У нашої моделі 21 697 ваг і двадцять сім секунд навчання — на цьому масштабі вона просто не встигла вивчити всі шість фігур. Механізм правильний, даних під ним замало, і це чесніший висновок, ніж підібрати зерно, на якому вийшло красиво.

Замовлення й що з нього виходить

Обери, що замовити моделі — і подивись, що суддя побачив у відповіді. Останній варіант «без умови» показує, що модель малює, коли її не просять.

замовлення
влучань—
підйом проти «без умови»—
по зернах—
Рамка на кожному стовпчику — це частка того самого класу без замовлення. Там, де суцільний стовпчик виходить за рамку, умова щось змінила; там, де не виходить, — не змінила нічого. Три зерна на клас.

І головне про цей розділ: нічого принципово іншого у великих моделях немає. У Stable Diffusion замість номера класу з шести подають послідовність векторів від текстового енкодера CLIP із теми 22, а замість додавання одного вектора — перехресну увагу. Механізм той самий: підказка входить у мережу разом із номером кроку й міняє те, що мережа бачить у шумі.

МасштабЛатентна дифузія і Stable Diffusion

Наші фігури — 28×28, тобто 784 числа. Фотографія 512×512 у трьох каналах — це 786 432 числа, у тисячу разів більше, і кожен крок зворотного ходу проганяє мережу по всьому цьому масиву. Помножимо на пʼятдесят кроків — і зрозуміло, чому перші дифузійні моделі малювали одну картинку хвилинами на дорогій відеокарті.

Розвʼязок, який зробив ці моделі масовими, звучить нахабно просто: шуміти не в пікселях. Спершу навчають автоенкодер із теми 37, який стискає зображення 512×512 у карту 64×64 з чотирма каналами — 16 384 числа замість 786 432, у 48 разів менше. Уся дифузія відбувається в цьому латентному просторі, а наприкінці декодер розгортає результат назад у пікселі.

Це і є Stable Diffusion. Три частини, кожна з яких у курсі вже була:

частиназвідки в курсіщо робить
енкодер і декодер (VAE)тема 37стискає зображення в латентну карту й розгортає назад
U-Net зі self-attentionтеми 30 і 20знешумлює латентну карту, крок за кроком
текстовий енкодер CLIPтема 22перетворює запит на вектори, які керують знешумленням

Третій рядок — рівно те, що ми зробили в розділі 11, тільки замість номера класу з шести туди подають ембединги слів.

Числа з літератури, не наші. В оригінальній статті про латентну дифузію стиснення в 8 разів по кожному боку (тобто в 48 разів за обсягом із урахуванням каналів) дало приблизно на порядок дешевше навчання при порівнянній якості; ваги Stable Diffusion 1.5 важать близько 4 ГБ, а сама модель навчалась на підмножині LAION-5B. Ці числа процитовані, а не заміряні нами: у нас немає ні таких даних, ні таких машин. Усе, що ця тема міряє сама, — на шести фігурах 28×28.
Ціна стиснення, про яку кажуть рідше. Автоенкодер — теж модель із похибкою, і все, чого він не вміє відновити, дифузія не намалює в принципі: дрібний текст, тонкі ґратки, обличчя на задньому плані. Класична скарга «не вміє малювати руки й літери» має дві причини, і одна з них саме тут — частина деталей губиться ще до того, як почалась дифузія.

МежаЩо з усім цим не так

Підсумуймо, що ця тема справді показала, і одразу — чого вона не показала.

Показала. Дифузія міняє змагання на регресію, і від цього зʼявляється крива втрати, яку можна читати. Прямий процес має закриту формулу, тому навчання дешеве. Розклад шуму — не декорація: числа з чужої статті, перенесені без T, ламають генерацію мовчки. Детермінований відбір дозволяє пропускати кроки. Умова на вході коштує один ембединг — і саме з неї виростає керування текстом.

Не показала. Наша модель — двадцять одна тисяча ваг, навчена за пів хвилини на шести геометричних фігурах; вона не доводить нічого про фотографії. Наш FID порахований на ознаках власного судді й не порівнюваний із жодним опублікованим числом. І головне: у розділі 8 ми на власних числах побачили, що метрику генерації доводиться перевіряти перед тим, як їй вірити — а це вже твердження не про дифузію, а про всю галузь.

Саме тут курс і закінчується — не тому, що теми скінчились, а тому, що далі питання перестають бути технічними. Модель, яка малює переконливе зображення чого завгодно, — це ще й спосіб зробити фотографію події, якої не було. Метрика, якій не можна вірити без калібрування, — це ще й спосіб показати замовнику красиве число. А датасет, на якому все це навчено, — це чиїсь фотографії, яких ніхто не питав.

Тема 40 — про це: що з усім побудованим не так, де межа застосовності, і що з цього зобовʼязаний знати інженер, а не тільки юрист.