Варіаційні автокодувальники (VAE): нові зображення з неперервного латентного простору
Генеративна модель із латентною змінною, VAE з нуля з трюком репараметризації, упорядкований латентний простір, генерування цифр із шуму проти звичайного автокодувальника, вплив β і колапс, інтерполяція та де використовують VAE.
Серія Основи ШІ Частина 44 з 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 тем
- Чому зі звичайного автокодувальника погано генерувати.
- Як працює VAE: розподіл замість точки, штраф KL і трюк репараметризації.
- Чого коштує β, чому зображення VAE розмиті і де VAE використовують сьогодні.
Що варто знати заздалегідь: Теорія інформації: ентропія, перехресна ентропія і KL-дивергенція — звідки беруться функції втрат
Автокодувальник із частини про представлення вміє стиснути зображення до кількох чисел і знову скласти його з них. Напрошується запитання: якщо декодер уміє з коду зробити цифру, чи не могли б ми дати йому код, який ми вигадали, і отримати нову цифру, якої ніхто не малював? Зі звичайним автокодувальником це майже не працює. Варіаційний автокодувальник — це його видозміна, яка саме це уможливлює, — і це перша з генеративних моделей, якими ми займатимемося в цьому розділі серії.
Продовжує частини Автокодувальники та представлення і Теорія інформації (KL-дивергенція).
1. Від стиснення до генерування
Означення — генеративна модель
Генеративна модель навчається з даних x1, …, xn розподілу p(x) так, щоб із нього можна було вибирати зразки — створювати нові x, які виглядають як дані, але не є їхніми копіями. Моделі з латентною змінною роблять це у два кроки: випадково вибирають код z із простого розподілу p(z) (наприклад, нормального), а декодер обчислює з нього x.
Класифікатор відповідає на «що це таке». Генеративна модель уміє відповісти на «покажи мені щось, що могло б бути в даних». Рецепт: киньте кубик кілька разів, передайте числа художникові (декодеру), і він за ними намалює картинку.
p(x) = ∫ p(x | z) · p(z) dz
- p(z)
- розподіл коду (апріорний) — обираємо його самі й простим, у нас N(0, I), бо з нього потім під час генерування вміємо вибирати
- p(x | z)
- декодер — наскільки ймовірне зображення x, якщо ми отримали код z; у нас це мережа, яка для кожного пікселя повертає ймовірність, що він світиться
- ∫ … dz
- сума за всіма можливими кодами — зображення могло виникнути з будь-якого коду; проте інтеграл за всім латентним простором ми обчислити не вміємо, тому VAE замінює його оцінкою (нижче)
Заковика звичайного автокодувальника: ми не знаємо, звідки брати код. Енкодер розміщує цифри в латентному просторі, де йому заманеться. У нашій мережі з двовимірним кодом коди тестових цифр лежать навколо точки (-3,9; -0,9) зі стандартним відхиленням 4,3 і 6,0, а між групами є діри, в яких декодер ніколи нічого не бачив.
2. Варіаційний автокодувальник
Означення — варіаційний автокодувальник (VAE)
VAE (Дідерік Кінгма і Макс Веллінг, 2013) має енкодер, який для зображення x повертає не одну точку, а нормальний розподіл q(z | x) = N(μ(x), diag σ²(x)). Він навчається мінімізацією втрати
L = −Ez ~ q[log p(x | z)] + β · KL(q(z | x) ‖ N(0, I)),
де перший член — помилка реконструкції (у нас бінарна перехресна ентропія пікселів), а другий — штраф за те, наскільки розподіл коду відрізняється від стандартного нормального. Для нормальних розподілів KL = ½ ∑j (μj² + σj² − log σj² − 1). При β = 1 величина −L є нижньою межею логарифма правдоподібності даних (ELBO).
Енкодер не може сказати «ця сімка живе саме тут», а лише «десь у цій хмаринці». Декодер тоді мусить уміти намалювати сімку з будь-якого місця хмаринки. А штраф KL штовхає всі хмаринки до початку координат і не дає їм бути надто малими — тож вони перекриваються, заповнюють простір, і між ними не лишається дір.
L(x) = −Ez ~ q(z | x)[ log p(x | z) ] + β · KL( q(z | x) ‖ N(0, I) )
- −Ez ~ q[log p(x | z)]
- помилка реконструкції — наскільки погано декодер намалює x із коду, вибраного з хмаринки. Математичне сподівання за всією хмаринкою (а не лише за її центром) змушує декодер малювати правильно в усьому околі коду; мінус тому, що логарифм імовірності ми хочемо якомога більшим, а втрату якомога меншою
- β
- вага штрафу — задає компроміс між точністю і порядком у просторі; β = 1 — це саме ELBO, інші значення ми випробовуємо в розділі про β
- KL(q(z | x) ‖ N(0, I))
- відстань хмаринки від розподілу, з якого ми вибиратимемо, — без неї енкодер стиснув би хмаринки до точок і розкидав їх далеко одна від одної (реконструкція була б кращою), і ми знову мали б звичайний автокодувальник
KL = ½ ∑j=1k ( μj² + σj² − log σj² − 1 )
- KL
- штраф із попередньої формули, для нормальних розподілів обчислений точно; координати коду незалежні, тому це сума за j
- μj²
- зсув центру хмаринки від початку координат — зростає квадратично, тож віддалені коди коштують багато, і енкодер стягує їх до нуля, звідки ми вибиратимемо
- σj² − log σj²
- ширина хмаринки — функція s − log s має мінімум 1 саме в s = 1; вона штрафує надто широку хмаринку, але передусім надто вузьку (−log σ² → ∞ при σ → 0), щоб хмаринка не перетворилася на точку
Теорема — ELBO є нижньою межею логарифма правдоподібності
Для будь-якого розподілу q(z | x) виконується
log p(x) = Eq[log p(x | z)] − KL(q(z | x) ‖ p(z)) + KL(q(z | x) ‖ p(z | x)) ≥ Eq[log p(x | z)] − KL(q(z | x) ‖ p(z)).
Доведення. log p(x) не залежить від z, тож дорівнює своєму математичному сподіванню за q. За теоремою Баєса p(x) = p(x | z) p(z) / p(z | x); дріб домножимо на q(z | x) / q(z | x):
log p(x) = Eq[log p(x | z)] + Eq[log (p(z) / q(z | x))] + Eq[log (q(z | x) / p(z | x))].
Другий член — це −KL(q ‖ p(z)), третій — KL(q ‖ p(z | x)). KL-дивергенція завжди невід’ємна (нерівність Гіббса з частини про теорію інформації), тож, відкинувши третій член, отримуємо нерівність. ∎
Права частина — це ELBO (evidence lower bound), і при β = 1 це саме −L. Мінімізуючи L, ми, отже, піднімаємо нижню межу log p(x), не обчислюючи інтеграла. Рівність настає, коли q(z | x) збігається з істинним апостеріорним розподілом p(z | x).
Означення — бінарна перехресна ентропія пікселів
Декодер повертає для кожного з 64 пікселів число yj ∈ (0, 1) і вважає його ймовірністю того, що піксель світиться. Для зображення з яскравостями xj ∈ [0, 1]
−log p(x | z) = −∑j=164 [ xj log yj + (1 − xj) log(1 − yj) ].
Приклад для одного пікселя: він світиться (x = 1), а декодер каже 0,9 → −ln 0,9 ≈ 0,105; каже 0,5 → ln 2 ≈ 0,693; не світиться (x = 0), а декодер каже 0,9 → −ln 0,1 ≈ 2,303. Найдорожче коштує впевнена помилка. Оскільки на виході сигмоїда, похідна за входом сигмоїди дорівнює просто yj − xj — так само, як у логістичній регресії.
Означення — трюк репараметризації (reparameterization trick)
Випадковий вибір z ~ N(μ, σ²) не можна диференціювати за μ і σ. Тому його записують як z = μ + σ · ε, де ε ~ N(0, 1) — шум, незалежний від параметрів. Тоді ∂z/∂μ = 1 і ∂z/∂σ = ε, і градієнт зворотним поширенням доходить аж до енкодера.
Випадковість ми «виносимо назовні»: замість «вибери точку з хмаринки» кажемо «вибери звичайний шум і зсунь та розтягни його так, як каже енкодер». Зсув і розтягування — це звичайні обчислення, а їх диференціювати можна.
zj = μj(x) + σj(x) · εj, σj = exp(½ · log σj²), εj ~ N(0, 1)
- μj(x)
- центр хмаринки, вихід енкодера — ∂z/∂μ = 1, градієнт декодера проходить в енкодер без змін
- σj(x)
- ширина хмаринки — енкодер повертає не σ, а log σ², яке може бути будь-яким дійсним числом; експонента завжди робить із нього додатну ширину, тож мережі не треба стежити за жодною умовою. ∂z/∂σ = ε
- εj ~ N(0, 1)
- уся випадковість — не залежить від жодного параметра, тож крізь неї нічого диференціювати не треба; під час генерування енкодер пропускаємо, а z вибираємо одразу з N(0, I)
Приклад — одна тестова цифра (0) у навченому VAE з k = 2
енкодер: μ = (0,285; 1,587), log σ² = (−2,695; −1,931) → σ = (0,260; 0,381)
KL1 = ½ (0,081 + 0,068 + 2,695 − 1) ≈ 0,922
KL2 = ½ (2,518 + 0,145 + 1,931 − 1) ≈ 1,797 → KL ≈ 2,72 ната
репараметризація з ε = (0,5; −1,0): z = (0,285 + 0,260 · 0,5; 1,587 − 0,381 · 1,0) = (0,415; 1,206)
Більшу частину штрафу тут дає не відстань від початку координат, а вузькість хмаринки: член −log σ² вносить 2,695 і 1,931. Енкодер хотів би якомога точніший код, а KL тримає його ширшим. Середня KL за тестовими цифрами становить 3,42 ната. Помилка реконструкції цієї цифри (з центру μ) становить 34,6 ната на 64 пікселі.
def krok_vae(davka, beta=1.0):
for x in davka:
mu, logvar = koder(x) # k + k чисел
sigma = exp(0.5 * logvar)
eps = normal(0, 1, size=len(mu)) # випадковість ззовні
z = mu + sigma * eps # трюк репараметризації
y = dekoder(z) # імовірності пікселів
rek = -sum(x * log(y) + (1 - x) * log(1 - y))
kl = 0.5 * sum(mu**2 + exp(logvar) - logvar - 1)
zpetne_sireni(rek + beta * kl) # градієнт іде z → mu, sigma → енкодер
adam_krok() # середній градієнт пакета
Наша мережа: 64 пікселі → 32 нейрони (tanh) → μ і log σ² (по k чисел) → 32 нейрони → 64 пікселі (сигмоїда), навчена методом Adam за 150 епох на 600 синтетичних цифрах. Та сама мережа, лише без шуму ε і без штрафу KL, — це звичайний автокодувальник, тож порівняння чесне.
3. Упорядкований латентний простір
Обидві мережі групують однакові цифри разом. Але автокодувальник розкидає їх по великій площі — обидва кола нормального розподілу порівняно з нею малі. Коди VAE лежать навколо початку координат зі стандартним відхиленням 1,14 і 1,04, тобто саме там, звідки ми вибиратимемо.
Як виглядає весь простір, покаже сітка: рівномірно розміщені точки латентного простору, кожна пропущена через декодер.
У VAE цифри плавно перетікають одна в одну, і майже кожна клітинка — це читабельна цифра. Чесно кажучи, на площині й декодер автокодувальника доволі гладкий, і його сітка теж містить переважно цифри. Різницю на повну покаже лише код із більшою кількістю вимірів.
4. Генерування: нові цифри з шуму
Випадково виберемо 200 кодів і декодуємо їх: для VAE з N(0, I), для автокодувальника (щоб мав чесний шанс) — з нормального розподілу, підігнаного під його справжні коди. Якість вимірюємо відстанню (середньоквадратичною похибкою) зразка до найближчої навчальної цифри. Справжні тестові цифри мають до найближчої навчальної в середньому 0,017, випадковий шум — 0,159.
Означення — відстань до найближчої навчальної цифри та підігнаний розподіл
Для зразка y ∈ [0, 1]64 і навчальних цифр x(1), …, x(600)
d(y) = mini (1/64) ∑j=164 (yj − x(i)j)²,
тобто середньоквадратична похибка (MSE) до найсхожішої цифри; якість генератора — це середнє d за 200 зразками. Мале d означає «схоже на якусь справжню цифру» — увага: нуль отримав би й генератор, який лише копіює навчальні дані.
Автокодувальник вибирає з zj = mj + sj · εj, де mj і sj — середнє та стандартне відхилення j-ї координати кодів тестових цифр (для k = 2: m = (−3,9; −0,9), s = (4,3; 6,0)). Координати вибираються незалежно — можливу залежність між ними підігнаний розподіл не вловить.
| розмір коду k | реконструкція AE (MSE) | реконструкція VAE (MSE) | зразки AE | зразки VAE |
|---|---|---|---|---|
| 2 | 0,051 | 0,063 | 0,042 | 0,044 |
| 8 | 0,025 | 0,036 | 0,090 | 0,054 |
| 16 | 0,017 | 0,039 | 0,112 | 0,055 |
З двовимірним кодом обидві мережі мають подібні результати (0,042 проти 0,044). З вісьмома вимірами автокодувальник розвалюється: його зразки мають відстань 0,090, більше ніж півдороги до шуму, тоді як VAE тримає 0,054. Із шістнадцятьма — 0,112 проти 0,055. Коди автокодувальника в багатьох вимірах лежать на тонкій викривленій поверхні, і випадкова точка з підігнаного нормального розподілу практично ніколи в неї не влучає.
Ціна: VAE реконструює гірше. При k = 16 його помилка реконструкції становить 0,039 проти 0,017 в автокодувальника, а його зображення розмитіші. Код зашумлений, тож декодер навчається малювати «середнє» того, що могло б бути в околі коду. Розмитість — відома слабкість VAE.
5. Реконструкція проти порядку: β
Вага β визначає, наскільки сильно штраф KL штовхає коди до нормального розподілу. П’ять VAE з кодом k = 2 і різним β:
| β | KL (натів на зображення) | реконструкція (MSE) | зразки (відстань) |
|---|---|---|---|
| 0,1 | 8,18 | 0,053 | 0,044 |
| 0,5 | 4,71 | 0,057 | 0,044 |
| 1 | 3,42 | 0,063 | 0,044 |
| 2 | 2,07 | 0,076 | 0,052 |
| 5 | 0,05 | 0,131 | 0,075 |
Мале β залишає кодам більше свободи (KL 8,2), і реконструкція точніша. Велике β стискає їх до нуля. При β = 5 KL падає до 0,05: енкодер перестав будь-що зберігати в коді, а декодер малює весь час приблизно те саме, хоч який код отримає. Це називають колапсом апостеріорного розподілу (posterior collapse).
Означення — нат і KL як ціна коду
Нат — одиниця інформації з натуральним логарифмом: 1 нат = 1 / ln 2 ≈ 1,443 біта. Середня KL за даними обмежує зверху взаємну інформацію між зображенням і кодом:
Ex KL(q(z | x) ‖ p(z)) = I(x; z) + KL(q(z) ‖ p(z)) ≥ I(x; z),
де q(z) = Ex q(z | x) — розподіл кодів усіх зображень разом. KL — це, отже, «ціна», яку енкодер платить за те, що зберігає в коді про зображення.
При β = 0,1 це щонайбільше 8,18 ната ≈ 11,8 біта на зображення, при β = 5 лише 0,05 ната ≈ 0,07 біта — менше ніж десята частина біта, тож код майже нічого не каже про зображення, і декодерові не лишається нічого іншого, як малювати весь час те саме.
Натомість β, більше за 1, свідомо використовує β-VAE (Ірина Гіґґінс та ін., 2017): сильніший тиск на незалежні координати коду призводить до того, що окремі виміри часто відповідають зрозумілим властивостям (нахил, товщина штриха).
6. Плавні переходи
Візьмемо коди двох тестових цифр (мережі з восьмивимірним кодом, від кожної цифри — зображення, яке VAE реконструює найкраще) і пройдемо прямою між ними за вісім кроків: z(t) = (1 − t) · za + t · zb для t = 0, 1/7, 2/7, …, 1, де za, zb — центри μ обох цифр. Кожну проміжну точку декодуємо.
В обох мереж перехід плавний: проміжні кроки — правдоподібні форми між обома цифрами. Прямою між двома справжніми кодами ми далеко від даних не відходимо, тож тут звичайний автокодувальник не відстає — його слабкість лише у виборі навмання. Той самий принцип у великих моделях дає змогу плавно змінювати, наприклад, вираз обличчя чи стиль зображення.
7. Де використовують VAE
- Стиснення для інших генераторів. Stable Diffusion (латентна дифузія, Робін Ромбах та ін., 2022) працює не з пікселями, а з кодом автокодувальника з малим штрафом KL: зображення 512 × 512 × 3 стискає до 64 × 64 × 4, і дифузія відбувається в цьому меншому просторі. Дифузії буде присвячена одна з наступних частин.
- Дискретні коди. VQ-VAE (Аарон ван ден Оорд та ін., 2017) замість неперервного коду вибирає елементи з навченого словника. Зображення так стає послідовністю «токенів», яку вміє генерувати трансформер.
- Наукові дані. Молекули, клітинні дані, звук — усюди, де корисний гладкий простір, у якому можна шукати та інтерполювати.
За різкістю зображень VAE програють GAN і дифузійним моделям. Зате в них стабільне навчання, справжня ймовірнісна інтерпретація і енкодер задарма.
8. Підсумок
- Генеративна модель навчається розподілу даних, щоб із нього можна було вибирати зразки; з латентною змінною вона вибирає код і декодує його.
- VAE кодує в розподіл N(μ, σ²), а втрата = реконструкція + β · KL до N(0, I). Трюк z = μ + σε дає змогу диференціювати крізь випадковий вибір.
- Коди VAE лежать навколо початку координат і заповнюють простір; коди автокодувальника розкидані й мають діри.
- З 8 вимірами коду: зразки автокодувальника 0,090, VAE 0,054 (справжні цифри 0,017, шум 0,159).
- Ціна — гірша реконструкція і розмитість; надто велике β веде до колапсу (KL 0,05).
Хочете спробувати самі? Попросіть ШІ-агента навчити VAE з двовимірним кодом на наборі даних MNIST і намалювати сітку декодованих зображень — ви побачите цілу «карту» рукописних цифр.
Маєте іншу думку? Напишіть на support@coden-app.com.