Дифузійні моделі: як із чистого шуму постає зображення
Прямий процес додавання шуму, мережа, що оцінює шум, DDPM і DDIM, написані з нуля, вісім кластерів без колапсу мод, скільки кроків семплювання потрібно, порівняння з VAE і GAN на цифрах і шлях до зображень за текстом.
Серія Основи ШІ Частина 46 з 52
- Мапа штучного інтелекту: що є що і як усе це пов’язано
- Коротка історія штучного інтелекту: від Тюрінга до мовних моделей
- Дані, модель, тренування, інференс: основні поняття на одному прикладі
- Як читати математичний запис: символи, індекси, суми та квантори
- Множини й відношення: конструктор, з якого складаються означення в ШІ
- Функції й відображення: чому кожна модель у ШІ — це функція
- Логіка й доведення: правила, за якими міркують у ШІ
- Графи й дерева: структура, на якій тримаються пошук і нейронні мережі
- Лінійна алгебра для машинного навчання: вектори, матриці й чому ШІ передусім множить
- Похідні, градієнт і правило ланцюжка: як модель дізнається, у якому напрямку вчитися
- Градієнтний спуск: як навчається модель
- Що таке ймовірність: від кидка кубика до аксіом Колмогорова
- Умовна ймовірність і теорема Баєса: як змінити оцінку, коли дізнаєтеся щось нове
- Випадкова величина і функція розподілу: одна функція, яка каже про розподіл усе
- Функція щільності та функція маси ймовірності: чому неперервна величина має в точці ймовірність нуль
- Математичне сподівання, дисперсія і коваріація: де лежить розподіл, наскільки він широкий і що з чим пов’язано
- Огляд розподілів ймовірностей: Бернуллі, біноміальний, Пуассона, рівномірний, нормальний і експоненційний
- Закон великих чисел і центральна гранична теорема: чому середні поводяться так передбачувано
- Статистика й оцінювання параметрів: максимальна правдоподібність, MAP і довірчі інтервали
- Теорія інформації: ентропія, перехресна ентропія і KL-дивергенція — звідки беруться функції втрат
- Пошук у просторі станів: BFS, DFS, UCS і A* з анімаціями
- Ігри та суперник: мінімакс, альфа-бета відсікання і Monte Carlo tree search
- Задоволення обмежень: бектрекінг, поширення обмежень і AC-3 на судоку та мапі чеських країв
- Логіка й системи, засновані на знаннях: пряме і зворотне виведення, резолюція та експертні системи
- Планування: STRIPS, світ кубиків, евристики з релаксації та планування в AI-агентах
- Локальний пошук та імітація відпалу: комівояжер через обласні центри Чехії
- Генетичні алгоритми: популяція, схрещування, мутація і добір на рюкзаку для походу
- Еволюційні стратегії і генетичне програмування: від правила однієї п’ятої до закону Кеплера
- Оптимізація мурашиною колонією: як феромоновий слід знаходить короткий шлях
- Оптимізація роєм частинок: інерція, власний досвід і досвід рою
- Нейроеволюція: еволюція ваг і форми нейронних мереж та алгоритм NEAT
- Нечіткі множини й функції належності: як записати «трохи тепло»
- Нечітка логіка та ймовірність: чому «трохи тепло» не означає «імовірно тепло»
- Нечітка логіка: t-норми, імплікації та правила ЯКЩО–ТО
- Нечітке керування: Мамдані та Суґено від вентилятора до маятника на візку
- Нечітка кластеризація: алгоритм fuzzy c-means і точки між кластерами
- Нейро-нечіткі системи (ANFIS): нечіткі правила, які навчаються з даних
- Марковські ланцюги: матриця переходів, стаціонарний розподіл і PageRank
- Приховані марковські моделі: алгоритм Вітербі й нечесне казино
- Байєсівські мережі: чому трава мокра і що з цього випливає для дощувача
- Фільтр Калмана: як за неточними вимірюваннями оцінити, де авто і як швидко воно їде
- Види машинного навчання: з учителем, без учителя, з частковим залученням учителя та інші
- Промпти, контекст і RAG: як дати моделі правильну інформацію
- Варіаційні автокодувальники (VAE): нові зображення з неперервного латентного простору
- Генеративні змагальні мережі (GAN): фальшувальник проти детектива
- Дифузійні моделі: як із чистого шуму постає зображення
- Марковські процеси ухвалення рішень: стани, дії, винагороди й рівняння Беллмана
- Q-навчання і DQN: як навчитися цінності дій — від таблиці до нейронної мережі
- Policy gradient і PPO: навчання безпосередньо політики
- Як працює ШІ-агент: мовна модель у циклі з інструментами
- Програмування з AI-агентами: завдання, тести й перевірка
- Оцінювання і безпека систем ШІ: як вимірювати і як стежити
Повна програма серії Готово: 52 з 83 тем
- Як працюють прямий і зворотний процеси дифузії.
- Чому дифузія навчається стабільніше за GAN і чого коштує кількість кроків.
- Як із дифузії стає генератор зображень за текстом.
Що варто знати заздалегідь: Генеративні змагальні мережі (GAN): фальшувальник проти детектива, Варіаційні автокодувальники (VAE): нові зображення з неперервного латентного простору
Stable Diffusion, Midjourney, DALL·E 3 і моделі, що генерують відео, стоять на одній ідеї, і вона напрочуд проста. Зіпсувати зображення легко — досить поступово додавати до нього шум, доки не лишиться сам шум. Якби ми навчилися кожен маленький крок скасовувати, могли б почати з чистого шуму й крок за кроком вилущити з нього зображення. У цій частині ми запрограмуємо це з нуля й порівняємо з VAE і GAN на тих самих даних.
Спирається на частини Генеративні змагальні мережі та Варіаційні автокодувальники.
1. Прямий процес: зображення розчиняється в шумі
Означення — прямий (дифузійний) процес
Обирають кількість кроків T і розклад малих дисперсій β1, …, βT. На кожному кроці додається трохи шуму: xt = √(1 − βt) · xt−1 + √βt · ε, ε ~ N(0, I). Композиція кроків дає замкнений вигляд xt = √ᾱt · x0 + √(1 − ᾱt) · ε, де ᾱt = ∏s ≤ t (1 − βs). Для досить великого t маємо ᾱt ≈ 0, і xt — чистий шум.
Крапля чорнила в склянці води: якусь мить видно форму краплі, потім вона розпливається, а зрештою вода рівномірно забарвлена й початкову форму вже не впізнати. Замкнена формула каже, що до будь-якого моменту можна стрибнути напряму — не треба моделювати всі кроки.
xt = √ᾱt · x0 + √(1 − ᾱt) · ε
- xt
- зашумлене зображення на кроці t — саме те, що мережа отримує на вхід під час навчання
- √ᾱt
- скільки лишилося від початкового зображення; ᾱt — добуток усіх (1 − βs) до кроку t, тож з кожним кроком він спадає
- x0
- початкове зображення з даних
- √(1 − ᾱt)
- скільки там шуму; корені потрібні тому, що додаються дисперсії: (√ᾱ)² + (√(1 − ᾱ))² = 1, тож дані з дисперсією 1 мають дисперсію 1 на кожному кроці й наприкінці плавно переходять у N(0, I)
- ε
- один зразок шуму з N(0, I) — саме його мережа вгадуватиме; те, що ми його знаємо, робить із навчання звичайну регресію
Теорема — чому досить одного стрибка
Якщо xt−1 = √ᾱt−1 x0 + √(1 − ᾱt−1) ε′ з ε′ ~ N(0, I), то й xt = √ᾱt x0 + √(1 − ᾱt) ε з новим ε ~ N(0, I).
Доведення. Підставимо в один крок: xt = √(1 − βt) √ᾱt−1 x0 + √(1 − βt) √(1 − ᾱt−1) ε′ + √βt ε″. Перший доданок дорівнює √ᾱt x0, бо ᾱt = (1 − βt) ᾱt−1. Решта два — незалежні нормальні шуми із середнім 0; їхня сума знову нормальна, а дисперсії додаються: (1 − βt)(1 − ᾱt−1) + βt = 1 − (1 − βt) ᾱt−1 = 1 − ᾱt. Для t = 1 твердження справджується безпосередньо (ᾱ0 = 1), далі за індукцією. ∎
Приклад — наш розклад шуму в числах
β зростає лінійно: βt = β1 + (βT − β1) · (t − 1)/(T − 1), тобто на 0,00101 за крок.
| t | βt | ᾱt | √ᾱt (сигнал) | √(1 − ᾱt) (шум) |
|---|---|---|---|---|
| 1 | 0,00010 | 0,9999 | 1,000 | 0,010 |
| 2 | 0,00111 | 0,9988 | 0,999 | 0,035 |
| 25 | 0,02432 | 0,7351 | 0,857 | 0,515 |
| 37 | 0,03643 | 0,5045 | 0,710 | 0,704 |
| 38 | 0,03744 | 0,4856 | 0,697 | 0,717 |
| 50 | 0,04955 | 0,2830 | 0,532 | 0,847 |
| 100 | 0,10000 | 0,0056 | 0,075 | 0,997 |
Другий рядок перевіримо вручну: ᾱ2 = (1 − β1)(1 − β2) = 0,9999 · 0,99889 = 0,99879. Сигнал і шум зрівнюються (ᾱ = 0,5) між кроками 37 і 38; на кроці 100 початкове зображення має вагу лише 0,075 проти 0,997 у шуму.
У нас T = 100, а β зростає лінійно від 0,0001 до 0,1. Частка початкового сигналу √ᾱt на кроці 25 становить 0,86, на кроці 50 — 0,53, а на кроці 100 — уже лише 0,07.
2. Зворотний процес: мережа, що вгадує шум
Означення — DDPM (denoising diffusion probabilistic model)
DDPM (Джонатан Го, Аджай Джейн і Пітер Аббіл, 2020; ідея Яші Золь-Дікштайна та ін., 2015) навчає мережу εθ(xt, t) за зашумленим зображенням і номером кроку оцінити, який шум ε було додано. Функція втрат — звичайна середньоквадратична похибка E ‖ε − εθ(√ᾱt x0 + √(1 − ᾱt) ε, t)‖² з випадковим t. Семплюють від xT ~ N(0, I) назад: xt−1 = (xt − βt/√(1 − ᾱt) · εθ) / √(1 − βt) + √βt · z.
Мережа отримує розмите, зашумлене фото й запитання «скільки в ньому шуму і який він?». Якщо вона вміє його оцінити, то вміє його й трохи відняти. Повторюємо це сто разів, щоразу з дрібкою свіжої випадковості, — і з шуму виринає зображення. Навчання при цьому — звичайна регресія: жодного суперника, як у GAN, жодних компромісів, як у VAE.
L(θ) = Ex0, t, ε ‖ε − εθ(√ᾱt x0 + √(1 − ᾱt) ε, t)‖²
- ε
- шум, який ми самі додали до зображення, — правильна відповідь, тому ми її знаємо без жодного розмічування даних
- εθ(…, t)
- оцінка шуму мережею; вона отримує й номер кроку t, бо при t = 2 їй треба знайти мало шуму, а при t = 100 в xt майже сам шум
- √ᾱt x0 + √(1 − ᾱt) ε
- зашумлене зображення xt, отримане одним стрибком, — завдяки замкненій формулі для кожного прикладу досить випадково вибрати t та ε, нічого не моделюється крок за кроком
xt−1 = 1/√(1 − βt) · (xt − βt/√(1 − ᾱt) · εθ(xt, t)) + √βt · z
- xt
- поточний зашумлений стан — починаємо з чистого шуму xT ~ N(0, I)
- εθ(xt, t)
- оцінка шуму, який є в xt
- βt/√(1 − ᾱt)
- яку частину оціненого шуму відняти — лише частку, що припадає на один крок (βt), перераховану на загальний рівень шуму √(1 − ᾱt); у нас 0,01 на кроці 1 і 0,10 на кроці 100
- 1/√(1 − βt)
- скасовує зменшення з прямого кроку (там множили на √(1 − βt)); на кроці 100 це 1,054
- √βt · z
- свіжий шум z ~ N(0, I) (на останньому кроці z = 0) — зворотний процес випадковий, як і прямий; без нього зразки стягувалися б до усереднених зображень. Величина √βt — один із двох варіантів, які пробували Го та ін.
# навчання (DDPM)
повторюй 16 000×:
для кожного з 64 прикладів пакета:
x₀ = випадковий приклад з даних
t = випадково з 1 … 100
ε = вектор випадкових чисел з N(0, 1)
x_t = √ᾱ_t · x₀ + √(1 − ᾱ_t) · ε
похибка = ‖ε − ε_θ(x_t, код(t))‖² / розмірність
крок Adam за середньою похибкою
# семплювання (DDPM, 100 кроків)
x = вектор з N(0, 1)
для t = 100, 99, …, 1:
ε̂ = ε_θ(x, код(t))
z = вектор з N(0, 1), на кроці t = 1 нуль
x = (x − β_t / √(1 − ᾱ_t) · ε̂) / √(1 − β_t) + √β_t · z
поверни x
Означення — синусоїдальне кодування часу
Мережа не отримує число t напряму, а вісім чисел код(t) = (sin(fπt/T), cos(fπt/T)) для f = 1, 2, 4, 8. Повільні частоти кажуть «приблизно де в процесі ми є», швидкі розрізняють сусідні кроки; усі числа лежать між −1 і 1, тож жоден вхід не переважує інших.
Для t = 25 (чверть процесу, кути π/4, π/2, π і 2π): код(25) = (0,707; 0,707; 1,000; 0,000; 0,000; −1,000; 0,000; 1,000).
Наша мережа — звичайна багатошарова мережа з частини про GAN: на вході xt і вісім чисел синусоїдального кодування часу t (як позиційне кодування в трансформері), на виході оцінка шуму. На колі вона має два приховані шари по 64 нейрони, на цифрах — по 128. Навчається методом Adam 16 000 кроків.
3. Вісім кластерів без колапсу
Ті самі дані, що й у попередній частині: вісім кластерів на колі. Ось як виглядають 400 зразків під час зворотного процесу:
Ще на кроці 25 точки розкидані майже рівномірно (якість 3 %), на кроці 10 вимальовується коло, а за останні десять кроків точки збігаються в кластери. Наприкінці покрито всі 8 кластерів, і кожен отримав від 28 до 50 з 500 зразків. Якість (частка в межах 3σ від центру) становить 63 %.
Відмінність від GAN не в якості, а в надійності. GAN покрив усі вісім кластерів лише в одному з чотирьох запусків; дифузія зробила це в єдиному запуску, який ми зробили (один запуск — не доказ, але це узгоджується з тим, що про дифузію відомо). Функція втрат дифузії — не гра, а регресія, і мережу карають за кожен зразок даних — жоден кластер не можна «закинути».
4. Скільки кроків потрібно
Означення — DDIM
DDIM (Цзямін Сун, Ченьлінь Мен і Стефано Ермон, 2020) використовує ту саму навчену мережу, але семплює детерміновано й більшими стрибками: з оцінки шуму обчислює оцінку чистого зображення x̂0 = (xt − √(1 − ᾱt) εθ) / √ᾱt і з неї одразу xs = √ᾱs x̂0 + √(1 − ᾱs) εθ для будь-якого попереднього часу s < t.
Замість сотні дрібних кроків робимо двадцять більших. На кожному мережа питає «як, певно, виглядало б готове зображення?» і відповідно до цього стрибає на частину шляху. Коли стрибки надто великі, мережа не влучає.
xs = √ᾱs · x̂0 + √(1 − ᾱs) · εθ(xt, t), x̂0 = (xt − √(1 − ᾱt) εθ) / √ᾱt
- xt
- стан, у якому ми саме перебуваємо
- εθ
- оцінка шуму — та сама мережа, що й у DDPM, нічого не перенавчається
- x̂0
- оцінка готового зображення: замкнена формула прямого процесу, розв’язана відносно x0; ділиться на √ᾱt, яке на початку мале, тож саме тут оцінка найменш точна
- √ᾱs
- скільки зображення має бути в цільовий час s — той самий множник, що й у прямому процесі, лише для іншого часу
- √(1 − ᾱs)
- скільки шуму має лишитися; DDIM при цьому використовує той самий оцінений шум і нового не вибирає — тому він детермінований
Приклад — чому двох кроків замало (спрощено)
DDIM з n кроками йде рівномірно розподіленими моментами часу: з 5 кроками 100 → 80 → 60 → 40 → 20 → 0, з 2 кроками 100 → 50 → 0. Перший стрибок завжди з t = 100, де √ᾱ100 = 0,075.
Якщо мережа помилиться в оцінці шуму на δ, оцінка x̂0 помилиться на δ · √(1 − ᾱ100)/√ᾱ100 = 13,3 δ — похибка підсилюється більш ніж удесятеро. Після підстановки в стрибок до часу s новий стан відрізняється від правильного на δ · (√(1 − ᾱs) − √ᾱs · 13,3):
- 5 кроків, стрибок 100 → 80: множник −1,59,
- 2 кроки, стрибок 100 → 50: множник −6,23,
За малого стрибка хибна оцінка x̂0 домішується з малою вагою √ᾱ80 = 0,19, і наступні кроки її виправляють. За стрибка до середини процесу вона входить з вагою √ᾱ50 = 0,53, і лишається єдиний крок. Міркування стежить лише за однією похибкою на одному кроці й припускає, що в решті мережа оцінює точно; проте воно показує, чому перші, найбільш зашумлені кроки найчутливіші.
DDIM з 50 кроками досягає якості 79 % — більше, ніж DDPM зі 100 кроками (63 %), найімовірніше тому, що не додає випадкового шуму, який наша неточна мережа не встигає прибрати на останніх кроках. Навіть з 10 кроками це 70 %, з 5 кроками 60 %. При 2 кроках семплювання розвалюється (0 %). Кількість кроків — головна ціна дифузії: кожен крок — це один прохід мережею, тоді як GAN генерує зображення за один прохід.
5. Цифри: порівняння трьох генераторів
На цифрах 8 × 8 (пікселі переведені в діапазон від −1 до 1) мережа навчається 16 000 кроків.
| модель | відстань до найближчої цифри | найменш представлена цифра (з 200) | цифр із менш ніж 10 зразками |
|---|---|---|---|
| VAE (k = 8) | 0,054 | 10 | 0 |
| GAN, сід 1 | 0,049 | 3 | 3 |
| GAN, сід 2 | 0,042 | 0 | 6 |
| дифузія (100 кроків) | 0,063 | 12 | 0 |
Тут треба бути чесними: наша дифузія має відстань 0,063, гірше, ніж VAE (0,054) і GAN (0,042). На зображеннях видно залишковий шум. Зате цифри представлені рівномірно — найрідша цифра має 12 зразків, тоді як у GAN із сідом 2 дві цифри відсутні зовсім.
Чому чіткість гірша? Мала багатошарова мережа мусить знешумлювати зображення на всіх ста рівнях шуму водночас, а це складніше завдання, ніж одне відображення шум → зображення в GAN. Зате вона чесно покращується з обчисленнями: відстань зразків спадала під час навчання 0,096 (крок 4 000), 0,082 (крок 8 000), 0,068 (крок 12 000), 0,063 (крок 16 000) (швидка оцінка зі 100 зразків DDIM з 20 кроками). Жодного колапсу чи коливань. Справжні дифузійні моделі використовують згорткові мережі U-Net або трансформери із сотнями мільйонів параметрів і навчаються тижнями — і тоді виграють і в чіткості.
6. Від цифр до зображень за текстом
- Умова. Мережа εθ(xt, t, c) отримує ще й опис c — ембединг тексту з мовної моделі, під’єднаний через увагу (частина про увагу). Навчається на мільярдах пар зображення–підпис.
- Керування без класифікатора (classifier-free guidance, Джонатан Го і Тім Салиманс, 2021). Мережа навчається з описом і без нього, а під час семплювання оцінку зсувають у напрямку «з описом мінус без опису», підсиленому коефіцієнтом. Зображення тоді краще відповідає запиту ціною меншої різноманітності.
- Латентна дифузія. Дифузія працює в малому латентному просторі автокодувальника, а не в пікселях — див. частину про VAE. Завдяки цьому Stable Diffusion (2022) працює навіть на ігровій відеокарті.
- Менше кроків. Кращі семплери й дистиляція (мережа вчиться імітувати багато кроків за один чи кілька) скоротили генерування із сотень кроків до одиниць.
ε̃ = εθ(xt, t, ∅) + w · (εθ(xt, t, c) − εθ(xt, t, ∅))
- εθ(…, ∅)
- оцінка шуму без опису (порожня умова ∅) — «як виглядає будь-яке зображення»; мережа вчиться її тим, що під час навчання опис час від часу випадково відкидається
- εθ(…, c) − εθ(…, ∅)
- на скільки зміниться оцінка, коли мережа знає опис, — напрямок, у якому опис тягне зображення
- w
- сила керування: w = 0 ігнорує опис, w = 1 — звичайна умовна модель, w > 1 перебільшує вплив опису — зображення краще відповідає запиту, але зразки схожіші один на одного
7. Підсумок
- Прямий процес поступово додає шум; до будь-якого кроку можна стрибнути формулою √ᾱ x₀ + √(1 − ᾱ) ε.
- Мережа вчиться оцінювати доданий шум — звичайна регресія. Генерують назад від чистого шуму.
- На восьми кластерах дифузія покрила всі в єдиному запуску (DDIM з 50 кроками 79 %); GAN — лише в одному з чотирьох запусків.
- Менше кроків (DDIM) пришвидшує семплювання; з 10 кроками якість 70 %, з 2 кроками воно розвалюється.
- На цифрах дифузія покриває всі цифри, за чіткістю з нашою малою мережею відстає; проте стабільно покращується з обчисленнями.
Хочете спробувати самі? Попросіть ШІ-агента навчити малу DDPM на двовимірних даних (скажімо, точках у формі ваших ініціалів) і намалювати, як точки під час зворотного процесу складаються в літери.
Маєте іншу думку? Напишіть на support@coden-app.com.