GAN

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

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

Це і є GAN (generative adversarial network, породжувальна змагальна мережа). Аналогія з фальшивомонетником стоїть у самій статті 2014 року, і вона гарна. Але вона ховає найважче: у цій парі немає числа, яке падає, коли справи йдуть добре. І це руйнує всі звички, набуті за попередні тридцять сім тем курсу.

РозривВтрата, якої немає

У попередній темі ми зібрали автоенкодер і VAE. Обидва вчаться на одному й тому самому: подай картинку, віддай ту саму картинку, а різницю між входом і виходом мінімізуй. Ця різниця зветься похибкою відновлення, і вона зручна аж до нахабства — за нею видно, коли модель навчилась, коли перестала вчитись і коли зламалась.

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

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

Ідея GAN полягає в тому, щоб не мінімізувати нічого схожого. Ми не кажемо генераторові, якою має бути картинка. Ми ставимо поруч другу мережу, чия єдина робота — відрізняти справжнє від підробленого, і кажемо генераторові: обдури її. Розмита пляма дискримінатора не обдурить, бо в справжніх даних розмитих плям немає. Отже усереднювати відповіді стає невигідно, і генератор мусить вибрати одну.

Ціна цього — уся решта теми. Прибравши явну ціль, ми прибрали й прилад, за яким стежили. Далі доведеться будувати прилад окремо, і виявиться, що це важче, ніж навчити саму мережу.

ПравилаГра двох мереж

Розберемо гру точно. Учасників двоє.

Генератор G бере вектор випадкових чисел z — у нас їх шістнадцять, узятих із нормального розподілу — і робить із них картинку. Простір цих векторів ми вже називали латентним. Генератор нічого не бачить: до справжніх даних у нього немає доступу взагалі, жодного разу за все навчання.

Дискримінатор D бере картинку й видає одне число — наскільки він вірить, що вона справжня. Він бачить і справжні картинки, і підробки, і знає, де що. Це звичайна класифікація на два класи — «справжнє» і «підробка», — і навчається вона так само, як класифікатор фігур із теми 11: та сама згорткова мережа, та сама втрата, тільки класів у неї два, а не шість.

Схема · Хто що бачить у грі двох мереж

Той самий опис, що вище, але видно найважливіше: у генератора немає жодної стрілки від справжніх даних. Усе, що він про них знає, приходить крізь дискримінатора.

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

Тепер цілі. Дискримінатор хоче ставити високу ймовірність справжнім і низьку підробкам:

D мінімізує: −log D(x) − log(1 − D(G(z)))

Прочитаймо це словами, символ за символом. x — справжня картинка, G(z) — підробка. D(·) — ймовірність від нуля до одиниці, яку дискримінатор ставить події «це справжнє». Знак log — логарифм: функція, яка близько до одиниці дає майже нуль, а близько до нуля прямує до мінус нескінченності. Отже −log D(x) — це штраф, який дорівнює нулю, коли дискримінатор поставив справжній картинці одиницю, і стає величезним, коли він поставив їй нуль. Другий доданок робить те саме дзеркально для підробки. Разом це звичайна крос-ентропія на двох класах.

Генератор хоче протилежного — щоб D(G(z)) було високим. Формально пара утворює гру з нульовою сумою: що виграє один, те програє другий. Рівновага, до якої гра нібито мусить прийти, описується коротко: генератор малює рівно той самий розподіл, що й дані, і дискримінатор не може зробити нічого кращого, ніж казати «половина на половину» скрізь.

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

Перший рядок кодуЧому втрату генератора переписали

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

Дискримінатор насправді видає не ймовірність, а одне довільне число — його звуть логіт і позначають s. Ймовірність із нього дістають сигмоїдою: D = 1 / (1 + e−s). Це та сама сигмоїда, що в логістичній регресії: вона бере будь-яке число й притискає його у відрізок від нуля до одиниці. Літера e тут — стала, приблизно 2.718; запис ex означає «підняти цю сталу до степеня x», і ця функція росте дуже швидко: при x = 4 вона вже дорівнює 54.6, при x = 8 — майже три тисячі. Саме цим і пояснюється все, що буде далі в розділі.

За статтею генератор має мінімізувати log(1 − D). Порахуймо, який поштовх ця втрата дає генераторові. «Поштовх» — це похідна втрати по тому числу, на яке генератор впливає, тобто по логіту s: що вона більша за модулем, то сильніше зсунуться ваги за один крок. Усе виведення — пʼять коротких кроків, і крім правила ланцюжка та похідної логарифма в ньому нічого немає.

крок 1 · похідна самої сигмоїди

Запишімо D = 1 / (1 + e−s) і продиференціюймо по s. Похідна дробу 1/u дорівнює −u′/u², а тут u = 1 + e−s і u′ = −e−s, тож мінуси скорочуються:

dD/ds = e−s / (1 + e−s)2 = D · (1 − D)

Останню рівність видно з того, що 1 − D = e−s / (1 + e−s): відніми від одиниці той самий дріб і зведи до спільного знаменника. Отже похідна сигмоїди виражається через саму сигмоїду — це та властивість, заради якої її всюди й беруть.

крок 2 · насичена втрата зі статті

Похідна логарифма — це 1, поділена на те, що під логарифмом, помножена на похідну того, що під логарифмом (правило ланцюжка). Під логарифмом стоїть 1 − D, і його похідна — це −D(1 − D):

d/ds · log(1 − D) = [1 / (1 − D)] · (−D(1 − D)) = −D

Дужка (1 − D) скоротилась, і лишилось саме D. Модуль градієнта дорівнює D.

крок 3 · ненасичена втрата

Тепер те саме для −log D. Під логарифмом стоїть D, і його похідна — D(1 − D):

d/ds · (−log D) = −[1 / D] · D(1 − D) = −(1 − D) = D − 1

Модуль градієнта дорівнює 1 − D — дзеркально до кроку 2.

крок 4 · у скільки разів вони різняться

Поділімо один модуль на другий. Обидва — прості дроби з тим самим знаменником, тож ділення виходить точним:

(1 − D) / D = e−s

Тобто розрив між двома втратами не «десь у кілька разів», а рівно e у степені мінус логіт. Що впевненіший дискримінатор у тому, що перед ним підробка (що менший s), то більший цей розрив, і росте він експоненційно.

крок 5 · підставмо число

Візьмімо s = −4 — типова впевненість дискримінатора на початку навчання. Тоді e4 = 54.598, а D = 1 / (1 + 54.598) = 0.0180. Далі просто:

насичена: 0.0180  ·  ненасичена: 1 − 0.0180 = 0.9820  ·  відношення: 0.9820 / 0.0180 = 54.6

Те саме число дає й формула кроку 4: e4 = 54.6. Два незалежні шляхи, один результат.

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

Лікування коротке. Замість мінімізувати log(1 − D) генератор мінімізує −log D. Точка, де обом добре, та сама — D = 1, — а модуль градієнта тепер 1 − D. Це рівно те, чого хотілося: коли дискримінатор упевнений, що перед ним підробка, генератор отримує найбільший поштовх.

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

Де насичена втрата зупиняє генератора

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

D = σ(s)—
у скільки разів—
насичена—
ненасичена—
Читай так. Ліва частина осі — те, що діється на початку навчання: дискримінатор упевнений, що бачить підробку. Насичена крива там притиснута до нуля, ненасичена — до одиниці. Праворуч від нуля картина перевертається, але туди GAN потрапляє тільки тоді, коли генератор уже виграє.

Повзунок проганяє те саме виведення по всій осі, і найважливіша точка на ній — ліва: при s = −4 дискримінатор дає 0.0180, насичена втрата має градієнт 0.0180, ненасичена — 0.9820, тобто у 54.6 раза більший. Це не тонке налаштування, а різниця між «вчиться» й «не вчиться».

Що з цього забрати, навіть якщо GAN тобі не знадобиться. Дві функції втрат із однаковим мінімумом можуть мати цілком різні градієнти дорогою до нього. Оптимум описує, куди прийти; градієнт вирішує, чи дійдеш. Це стосується будь-якої задачі, а не лише змагальної.

Прилад зламаноКриві втрат нічого не кажуть

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

У звичайному навчанні крива втрат — головний прилад. Спадає — вчиться. Стоїть — застрягло. Стрибнула вгору — швидкість навчання завелика. За тридцять сім тем ця звичка встигла стати рефлексом.

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

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

Ті самі криві, різна якість

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

втрата D—
втрата G—
класів із 6—
розкид втрати G між конфігураціями—
Числа заміряні на зерні 0. Дві конфігурації з найнижчою й найвищою якістю мають майже однакові криві генератора, а конфігурація посередині — найдраматичнішу криву з усіх трьох. Порядок кривих і порядок якості між собою не повʼязані.

Найпростіше зведення тих самих даних у таблицю. Остання колонка — покриття класів, яке ми пояснимо через два розділи; поки досить знати, що більше означає краще.

конфігураціявтрата D наприкінцівтрата G наприкінцірозмах кривої Gкласів із 6
дискримінатор повільніший1.27820.70710.22512.33
однакові кроки1.00491.17511.04663.00
генератор швидший1.37160.71060.25634.67

Дивись на перший і третій рядки. Втрата генератора наприкінці — 0.7071 і 0.7106, різниця в третьому знаку. Розмах кривої — 0.2251 і 0.2563, теж майже однаково. А покриття — 2.33 проти 4.67, тобто вдвічі. Якби ми судили за втратами, ми б назвали ці дві конфігурації однаковими.

Практичний наслідок. «Рівна крива» в GAN не означає «добре навчається» — вона однаково буває ознакою здорової рівноваги й ознакою того, що генератор здався й малює одну картинку, яку дискримінатор чомусь пропускає. Єдиний спосіб дізнатись, який із двох випадків перед тобою, — подивитись на самі згенеровані картинки. Не на криву.

ПриладСуддя, якому не можна вірити

Отже дивитись треба на картинки. Але лекція, у якій кожне твердження спирається на замір, не може спиратись на «подивись очима». Потрібен прилад, який дивиться замість нас.

Прилад блоку 8 називається суддя — це окремий класифікатор наших шести фігур, навчений на справжніх даних і більше ні на чому. Ми проганяємо крізь нього шістсот згенерованих картинок і питаємо, що він у них бачить. На справжніх фігурах суддя дає точність 0.9950, тобто задача для нього тривіальна.

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

перше · покриття класів

Скільки з шести фігур дістали хоч 5 % вибірки. Максимум — 6. Це число ловить рівно те, чого боїться GAN: генератор, який малює лише кола, дістане одиницю, хоч би якими гарними були ті кола.

друге · FID

Відстань Фреше між купою справжніх картинок і купою згенерованих — але не між самими пікселями, а між 64 числами ознак, які видає передостанній шар судді. Формула порівнює два хмарні описи: середнє й розкид. Окремій картинці FID не ставлять — він має сенс лише для набору.

FID = |μ1 − μ2|2 + tr(Σ1 + Σ2 − 2·(Σ1Σ2)1/2)

Розберемо запис. μ (грецька «мю») — середнє по всій купі: шістдесят чотири числа, по одному на ознаку. Σ (велика «сигма») — коваріаційна матриця: таблиця 64 × 64, у якій записано, наскільки ознаки розкидані й наскільки повʼязані між собою. tr — слід матриці, сума чисел на її діагоналі. Перший доданок каже, наскільки далеко одна від одної стоять дві хмари; другий — наскільки різні вони за формою. Якщо хмари збіглися, обидва доданки нулі.

Лишився один символ, який без пояснення виглядає страшно: (Σ1Σ2)1/2 — корінь із добутку двох матриць. Це така матриця, яка, помножена сама на себе, дає Σ1Σ2: те саме, що квадратний корінь із числа, тільки для таблиць. Рахувати його руками не треба — бібліотека робить це одним викликом; знати треба інше: він потрібен, щоб порівняти форми двох хмар, а не просто їхні розміри.

Найпростіше побачити сенс формули на одному вимірі — коли ознака в нас не 64, а одна. Тоді Σ перетворюється на звичайну дисперсію s2, слід — на саме число, корінь із добутку — на s1s2, і вся формула згортається до шкільного виразу:

FID1D = (m1 − m2)2 + s12 + s22 − 2s1s2 = (m1 − m2)2 + (s1 − s2)2

Підставмо числа. Хай справжні картинки дають ознаку із середнім m1 = 2.0 і розкидом s1 = 1.0, а згенеровані — m2 = 3.0 і s2 = 0.4 (модель малює щось інше й до того ж одноманітне). Тоді FID = (2.0 − 3.0)2 + (1.0 − 0.4)2 = 1.00 + 0.36 = 1.36. Видно обидві складові: одиниця — плата за зсунуте середнє, 0.36 — за звужений розкид. І видно головне: якщо модель малює одну й ту саму картинку, розкид падає до нуля, і другий доданок росте, навіть коли середнє вгадане ідеально.

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

Головне правилоМетрику калібрують перед роботою

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

Метрику генерації не можна брати й міряти. Її спершу перевіряють на завідомо поганому.

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

Калібрування виглядає так: береш вісім наборів, про які заздалегідь знаєш, наскільки вони погані, і дивишся, чи впорядкує їх метрика правильно.

Вісім завідомо поганих наборів

Обери набір і подивись, як його бачить метрика. Шкала FID логарифмічна, інакше базова лінія зникає під сотнями.

FID—
класів із 6—
впевненість судді—
відносно базової лінії—
Порогом слугує робоча модель: найкращий GAN теми має FID 249.33 — при базовій лінії 1.1582, яку дають дві різні вибірки самих лише справжніх фігур. Кожен рядок калібрування мусить опинитись гірше за поріг 249.33 — інакше метриці не можна вірити. Пунктирна лінія на стовпчику й показує цей поріг. Саме число FID без базової лінії поруч не означає нічого: це не відстань у якихось одиницях, а величина, яку читають лише в порівнянні.
що подаємокласівFIDвпевненість судді
справжні, інша вибірка61.15820.9899
лише кола1483.83640.9771
кола + квадрати2466.80410.9806
розмита каша2918.32000.8103
середнє всіх фігур11035.51730.5218
усе чорне11133.58910.9957
чистий шум21089.87430.8004
усе біле11311.20060.5554

Три речі варто прочитати вголос.

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

Другий рядок — той, заради якого все затівалось. «Лише кола» — це повний колапс мод: одна фігура з шести. Метрика ставить йому 483.8364, тобто у 418 разів гірше за базову лінію й майже вдвічі гірше за наш найкращий GAN. Метрика впоралась, і тепер їй можна вірити.

Останній стовпчик — уже перша пастка теми. На «всьому чорному» суддя впевнений на 0.9957 — сильніше, ніж на справжніх фігурах (0.9899). Порожній кадр він з повною певністю називає квадратом. Тримай це в голові: до цієї пастки ми повернемось із заміром, і вона там зіграє проти інтуїції ще різкіше.

Чому одного числа мало. Подивись на рядки «лише кола» й «кола + квадрати»: FID у них практично однаковий (483.8364 і 466.8041), хоча в другому вдвічі більше класів. Сам по собі FID цієї різниці не бачить. А покриття бачить: 1 проти 2. Пара «FID + покриття» працює там, де кожне число окремо помиляється, — і це рівно та сама лінія, що йде крізь увесь курс.

МодельКрихітний DCGAN

Тепер самі мережі. Ми беремо DCGAN — найпростішу згорткову форму GAN, описану 2015 року й досі використовувану як відправна точка. Її рецепт короткий: жодних повнозвʼязних шарів усередині, у генератора — ConvTranspose2d, які подвоюють сторону, у дискримінатора — звичайні згортки з кроком 2, які її вдвічі зменшують.

генератор 16 чисел → 24×7×7 → 12×14×14 → 1×28×28 (24 877 ваг) дискримінатор 1×28×28 → 12×14×14 → 24×7×7 → одне число (6 013 ваг)

Дві деталі в цьому рецепті не косметичні, і обидві варто назвати.

Tanh на виході генератора. Картинки живуть у відрізку від −1 до 1, а не від 0 до 1, тому справжні дані ми туди ж і переносимо. Причина проста: tanh симетричний навколо нуля, і генераторові не треба зсувати весь вихід угору, перш ніж почати вчитись.

Adam із betas=(0.5, 0.999). Перше число — це інерція градієнта: оптимізатор памʼятає, куди йшов, і продовжує рухатись туди ж. За замовчуванням воно 0.9, тобто памʼять довга. У грі двох мереж «куди йшов» застаріває щокроку, бо суперник за цей крок змінився. Значення 0.5 скорочує памʼять удвічі, і це не примха автора DCGAN, а те, без чого навчання розвалюється.

ХворобаКолапс мод: перший замір

Тепер про головну хворобу GAN. Вона зветься колапс мод (mode collapse), і механізм у неї цілком логічний.

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

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

Заміряймо. Базова конфігурація: обидві мережі мають однакову швидкість навчання 2e-4, двадцять епох, 1800 фігур, три зерна.

Куди поділись три фігури з шести

Частка кожного класу у вибірці з шестисот згенерованих картинок. Пунктир — поріг 5 %, за яким клас вважається покритим.

класів ≥ 5 %—
найбільша частка—
кільце—
хрест—
Що впадає в око. Кільце стоїть найнижче в кожній із трьох конфігурацій і на кожному зерні — це вже не випадковість одного прогону. А от решта порядку не стала: у двох конфігураціях вибірку ділять між собою трикутник, коло й квадрат, а в прискореного генератора поруч із ними піднімається ще й хрест — 0.136 проти 0.122 у трикутника. Прожени всі три конфігурації й усі три зерна: незмінне тут одне — кільце.

Базова конфігурація покриває 3.00 класи з шести, і купа по зернах — [3, 3, 3], тобто всі три прогони дали однакове число. Половину датасету генератор просто не малює.

ПеревіркаКолапс чи просто недонавчання

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

Перевірка проста: збережімо знімки генератора на трьох епохах і подивімось, куди рухається покриття.

Покриття вздовж навчання

Скільки класів накрито на восьмій, чотирнадцятій і двадцятій епосі. Три лінії — три конфігурації, три зерна на кожну точку.

D повільніший—
однакові кроки—
G швидший—
розрив найкраща − найгірша—
Головне тут — восьма епоха. На ній усі три конфігурації дають рівно 2.33, тобто розрізнити їх неможливо взагалі. Розходяться вони пізніше, і розходяться в різні боки. Обирати конфігурацію за коротким прогоном — те саме, що кидати монету.
конфігураціяепоха 8епоха 14епоха 20FID на 20-й (база 1.1582)
дискримінатор повільніший2.331.672.33724.94
однакові кроки2.332.673.00569.69
генератор швидший2.333.334.67249.33

Відповідь на питання розділу — і те, і те, і це важливо розрізняти. Базова конфігурація справді трохи росте: 2.33 → 2.67 → 3.00. Частина втрачених класів — це недонавчання, і з часом вони повертаються. Але кільце не повертається ні на якій епосі, а конфігурація з повільним дискримінатором падає посередині (2.33 → 1.67) і не відіграє це до кінця. Її FID при цьому росте всі двадцять епох: 417.5 → 491.4 → 724.9 — тобто віддаляється від базової лінії 1.1582, а не наближається до неї. Це вже не «ще не навчився», це «навчився не тому».

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

РецептиСпіввідношення сил і рецепт, що зашкодив

Найпоширеніша порада в GAN звучить так: «дискримінатор надто сильний, послаб його». Логіка за нею начебто бездоганна. Якщо дискримінатор навчився розрізняти ідеально, то D(G(z)) притиснуте до нуля, генератор дістає слабкий сигнал і не рухається. Отже треба сповільнити дискримінатора, щоб він не відривався.

Ми поставили три точки на осі «хто швидший» і поміряли всі три однаково.

конфігураціяlr генератораlr дискримінаторавідношеннякласівпо зернах
дискримінатор повільніший2e-45e-54.02.33[3, 3, 1]
однакові кроки2e-42e-41.03.00[3, 3, 3]
генератор швидший5e-42e-42.54.67[5, 5, 4]

Три висновки, і кожен вартий окремої уваги.

Перший: різниця справжня. Купи по зернах — [3, 3, 3] проти [5, 5, 4] — не перетинаються. За критерієм курсу, введеним у темі 26, це сильніший доказ, ніж різниця середніх: жоден прогін базової конфігурації не дотягнув до найгіршого прогону прискореного генератора.

Другий: канонічний рецепт зашкодив. Сповільнення дискримінатора дало 2.33 замість 3.00, тобто гірше за те, з чого починали. І на одному зерні з трьох воно дало повний колапс: генератор малює саму лише одну фігуру, а покриття падає до одиниці. Порада, яку повторюють у кожному другому туторіалі, на нашому масштабі не працює.

Третій, і найцікавіший: справа не у відношенні. Подивись на колонку «відношення». Обидві крайні конфігурації роблять генератора відносно швидшим за дискримінатора — 4.0 і 2.5 проти 1.0 у середньої. Якби вирішувало відношення, обидві мали б бути кращими за середню. Насправді одна краща, а друга гірша. Отже «послабити дискримінатора» і «прискорити генератора» — це різні дії, а не одна, хоч у народному переказі вони й зливаються в одну пораду про «баланс».

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

І окремо про рецепти взагалі. Проти колапсу мод існує канонічний прийом — minibatch std: у дискримінатор додають канал, у якому лежить розкид активацій по пакету. Пакет із однакових картинок дає в цьому каналі нуль, і дискримінатор дістає змогу побачити те, чого не бачив: не картинку, а набір. Коштує це 384 ваги з шести тисяч. Прийом розумний — але перевіряти його ми залишаємо тобі в домашньому завданні, бо на нашому масштабі кожна така перевірка коштує трьох повних навчань.

Порядок вимиранняЯка фігура гине першою

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

фігураD повільнішийоднакові крокиG швидшийяскравих пікселів
трикутник0.5780.3460.1220.0868
коло0.0570.3170.4030.1756
квадрат0.3520.3090.2120.1544
ромб0.0060.0260.1080.1310
хрест0.0070.0020.1360.1479
кільце0.0000.0010.0190.1237

Кільце гине першим у всіх трьох конфігураціях — 0.000, 0.001 і 0.019 при рівномірних 0.167. Це єдине, що тримається скрізь. Другого місця з кінця вже немає: у середній конфігурації другим іде хрест (0.002), а в двох інших нижче за нього опиняється ромб — 0.006 проти 0.007 і 0.108 проти 0.136.

Верхня частина таблиці теж не стала. У перших двох конфігураціях вибірку ділять між собою трикутник, коло й квадрат — три суцільні опуклі плями, і на них припадає 0.987 і 0.972 усієї вибірки. А в прискореного генератора, найкращого з трьох, поріг у пʼять відсотків долають уже пʼять класів із шести, і хрест (0.136) обходить трикутник (0.122). Тобто колапс забирає не фіксований список фігур: стабільно гине лише кільце, а решта залежить від того, як швидко вчиться кожна з мереж.

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

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

Що витримує неохайність

Справжні фігури, розмиті однаковим вікном. Стовпчики — частка, яку суддя ще впізнає правильно.

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

Отже гіпотеза підтвердилась наполовину, і половину, яка не підтвердилась, ховати не варто. На розмитті радіуса 1 суддя ще впізнає трикутник у 0.990 випадків, квадрат у 0.950, коло в 0.320, кільце в 0.100, хрест у 0.010, а ромб — у 0.000. Поділ на «трійку, що тримається» і «трійку, що гине» збігається з тим, що робить GAN у двох конфігураціях із трьох, — а в третьої, найкращої, нижня трійка вже інша. Порядок усередині нижньої трійки не збігається зовсім.

А ось що гіпотезу просто спростовує: трикутник має найменше яскравих пікселів з усіх шести — 0.0868 проти 0.1756 у кола. Найменша фігура виявилась найживучішою. Отже справа не в «тонкості» в сенсі площі. Радше в тому, наскільки фігура терпить неточність: суцільній опуклій плямі можна помилитись на піксель по краю й лишитись собою, а кільце з такою помилкою перестає бути кільцем — у нього закривається отвір.

Чесний облік. Ми показали, що порядок вимирання не випадковий і що він частково передбачуваний простою перевіркою на розмиття. Ми не показали, чому кільце гине раніше за ромб. Правдоподібне пояснення в нас є — отвір усередині, — але воно не перевірене заміром, і тому лишається здогадом.

ЦінаРізкість проти покриття

Настав час поставити GAN поруч із VAE з теми 37 й поміряти обох однією метрикою. Умови однакові: той самий датасет, той самий латентний простір на 16 чисел, двадцять епох, три зерна.

Це не ті самі числа, що в темі 37, і ось чому. Щоб порівняння було чесним, VAE довелося навчити наново — у наших умовах: латент 16 замість восьми й двадцять епох замість дванадцяти. Покриття класів ми теж рахуємо по-своєму: клас вважається покритим від 5 % вибірки, а тема 37 брала поріг 1 %. Тому число покриття VAE тут (5.67) і число тієї самої моделі там — це два різні заміри, а не розбіжність. Порівнювати між собою можна лише рядки цієї таблиці.

Третє число в таблиці — різкість. Міряємо її найпростіше з можливого: частка пікселів, які ані чорні, ані білі, тобто значення між 0.25 і 0.75. У справжніх фігур із нашим шумом таких пікселів 0.0000 — межа різка. У розмитої картинки їх багато. Менше — різкіше.

Дві моделі, три числа

Перемикай модель і дивись, за що вона платить. Зразки намальовані схематично; числа заміряні.

класів із 6—
FID—
напівтонів—
по зернах—
Компроміс у двох стовпчиках. VAE накриває більше класів, але в 1.6 раза розмитіший. Найкращий GAN різкіший і має кращий FID, але губить від однієї до двох фігур. Жодне з двох чисел окремо переможця не називає.
моделькласів із 6по зернахFIDнапівтонів
справжні фігури6.00—1.15820.0000
VAE5.67[6, 6, 5]329.120.0925
GAN, генератор швидший4.67[5, 5, 4]249.330.0578
GAN, однакові кроки3.00[3, 3, 3]569.690.0595

Різкість. Найкращий GAN дає 0.0578 напівтонів проти 0.0925 у VAE — у 1.6 раза різкіше. І тут купи по зернах не перетинаються: [0.0454, 0.0469, 0.0811] у GAN проти [0.0878, 0.0890, 0.1006] у VAE, найгірше зерно GAN різкіше за найкраще зерно VAE. Це те, за чим по GAN і приходять, і воно вимірне без жодного «на око».

Покриття. VAE дає 5.67, GAN — 4.67. Але купи по зернах — [6, 6, 5] і [5, 5, 4] — перетинаються на пʼятірці. За правилом курсу це означає, що перевагу VAE в покритті над найкращим GAN ми не довели. Над базовим GAN — довели впевнено: [6, 6, 5] проти [3, 3, 3] не перетинаються ніяк.

FID. А ось тут упорядкування протилежне покриттю: у GAN 249.33, у VAE 329.12 — при базовій лінії 1.1582 в обох. FID дивиться і на різноманіття, і на схожість окремих зразків, і різкість переважила втрачений клас. Дві чесні метрики дали різні відповіді — і це вже пʼята тема курсу, де таке трапляється.

Так що ж краще? Питання поставлене неправильно, і в цьому головна думка розділу. VAE платить різкістю за повноту, GAN платить повнотою за різкість, і жодна пара чисел не скаже, що з цього дорожче — це вирішує задача. Але питання «а чи можна не платити взагалі?» поставлене правильно, і відповідь на нього є в наступній темі.

ПідсумокЩо з цього забрати

Сім речей, які варто винести з теми.

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

І місток уперед. Ми маємо дві моделі, кожна з яких платить своїм: VAE — різкістю, GAN — повнотою й стабільністю. Тема 39 уводить третю — дифузійні моделі. Їхня обіцянка звучить надто добре: різкість GAN без його нестабільності, бо навчання там знову має явну ціль — передбачити шум, який ми самі й додали, — і ця ціль не залежить від жодного суперника. Обіцянку доведеться перевірити тією самою метрикою, яку ми щойно відкалібрували, і там теж знайдеться пастка, де число не бреше, а просто міряє не те. А тема 40 закриє курс питанням, якого не уникнути після теми про породження підробок: що інженер робить з тим, що вміє робити.