Уяви фальшивомонетника й слідчого. Фальшивомонетник друкує банкноти, слідчий вчиться їх відрізняти від справжніх. Щоразу, коли слідчий ловить підробку, фальшивомонетник дізнається, за чим саме його спіймали, і виправляє це. Щоразу, коли підробка проходить, слідчий вчиться на своїй помилці. Ніхто з двох не бачив інструкції «як має виглядати справжня банкнота» — вони обидва здобувають її одне з одного.
Це і є GAN (generative adversarial network, породжувальна змагальна мережа). Аналогія з фальшивомонетником стоїть у самій статті 2014 року, і вона гарна. Але вона ховає найважче: у цій парі немає числа, яке падає, коли справи йдуть добре. І це руйнує всі звички, набуті за попередні тридцять сім тем курсу.
РозривВтрата, якої немає
У попередній темі ми зібрали автоенкодер і VAE. Обидва вчаться на одному й тому самому: подай картинку, віддай ту саму картинку, а різницю між входом і виходом мінімізуй. Ця різниця зветься похибкою відновлення, і вона зручна аж до нахабства — за нею видно, коли модель навчилась, коли перестала вчитись і коли зламалась.
За зручність платять розмиттям, і причина цілком арифметична. Уяви, що по одному короткому опису однаково правдоподібні дві картинки: коло радіуса 6 і коло радіуса 8. Модель мусить видати одну. Похибка відновлення — це середній квадрат різниці, і середній квадрат мінімізується не вибором однієї з двох, а їхнім середнім. Середнє двох різних кіл — це не коло, а розмита пляма з нечіткою межею. Мережа не помилилась: вона зробила рівно те, що ми в неї попросили.
Ідея GAN полягає в тому, щоб не мінімізувати нічого схожого. Ми не кажемо генераторові, якою має бути картинка. Ми ставимо поруч другу мережу, чия єдина робота — відрізняти справжнє від підробленого, і кажемо генераторові: обдури її. Розмита пляма дискримінатора не обдурить, бо в справжніх даних розмитих плям немає. Отже усереднювати відповіді стає невигідно, і генератор мусить вибрати одну.
Ціна цього — уся решта теми. Прибравши явну ціль, ми прибрали й прилад, за яким стежили. Далі доведеться будувати прилад окремо, і виявиться, що це важче, ніж навчити саму мережу.
ПравилаГра двох мереж
Розберемо гру точно. Учасників двоє.
Генератор G бере вектор випадкових чисел
z — у нас їх шістнадцять, узятих із нормального розподілу —
і робить із них картинку. Простір цих векторів ми вже називали
латентним. Генератор нічого не бачить: до
справжніх даних у нього немає доступу взагалі, жодного разу за все навчання.
Дискримінатор D бере картинку й видає одне число — наскільки він
вірить, що вона справжня. Він бачить і справжні картинки, і підробки, і знає, де що.
Це звичайна класифікація на два класи — «справжнє» і «підробка», — і навчається
вона так само, як класифікатор фігур із
теми 11: та сама згорткова мережа, та
сама втрата, тільки класів у неї два, а не шість.
Схема · Хто що бачить у грі двох мереж
Той самий опис, що вище, але видно найважливіше: у генератора немає жодної стрілки від справжніх даних. Усе, що він про них знає, приходить крізь дискримінатора.
Тепер цілі. Дискримінатор хоче ставити високу ймовірність справжнім і низьку підробкам:
Прочитаймо це словами, символ за символом. x — справжня картинка,
G(z) — підробка. D(·) — ймовірність від нуля до одиниці,
яку дискримінатор ставить події «це справжнє». Знак log — логарифм:
функція, яка близько до одиниці дає майже нуль, а близько до нуля прямує до мінус
нескінченності. Отже −log D(x) — це штраф, який дорівнює нулю, коли
дискримінатор поставив справжній картинці одиницю, і стає величезним, коли він
поставив їй нуль. Другий доданок робить те саме дзеркально для підробки. Разом це
звичайна крос-ентропія на двох класах.
Генератор хоче протилежного — щоб D(G(z)) було високим. Формально
пара утворює гру з нульовою сумою: що виграє один, те програє другий.
Рівновага, до якої гра нібито мусить прийти, описується коротко: генератор малює
рівно той самий розподіл, що й дані, і дискримінатор не може зробити нічого кращого,
ніж казати «половина на половину» скрізь.
Перший рядок кодуЧому втрату генератора переписали
Перше, з чим стикається кожен, хто пише GAN, — те, що формула зі статті в лоб не працює. І це не легенда: різницю можна порахувати руками за хвилину.
Дискримінатор насправді видає не ймовірність, а одне довільне число — його звуть
логіт і позначають s. Ймовірність із нього дістають
сигмоїдою: D = 1 / (1 + e−s). Це та
сама сигмоїда, що в логістичній регресії: вона бере будь-яке число й притискає його у
відрізок від нуля до одиниці. Літера e тут — стала, приблизно
2.718; запис ex означає «підняти цю сталу
до степеня x», і ця функція росте дуже швидко: при
x = 4 вона вже дорівнює 54.6, при x = 8 — майже три тисячі.
Саме цим і пояснюється все, що буде далі в розділі.
За статтею генератор має мінімізувати log(1 − D). Порахуймо, який
поштовх ця втрата дає генераторові. «Поштовх» — це похідна втрати по тому числу, на
яке генератор впливає, тобто по логіту s: що вона більша за
модулем, то сильніше зсунуться ваги за один крок. Усе виведення — пʼять коротких
кроків, і крім правила ланцюжка та похідної логарифма в ньому нічого немає.
Запишімо D = 1 / (1 + e−s) і
продиференціюймо по s. Похідна дробу
1/u дорівнює −u′/u², а тут
u = 1 + e−s і
u′ = −e−s, тож мінуси скорочуються:
Останню рівність видно з того, що
1 − D = e−s / (1 + e−s):
відніми від одиниці той самий дріб і зведи до спільного знаменника. Отже похідна
сигмоїди виражається через саму сигмоїду — це та властивість, заради якої її
всюди й беруть.
Похідна логарифма — це 1, поділена на те, що під логарифмом,
помножена на похідну того, що під логарифмом (правило ланцюжка). Під логарифмом
стоїть 1 − D, і його похідна — це −D(1 − D):
Дужка (1 − D) скоротилась, і лишилось саме D.
Модуль градієнта дорівнює D.
Тепер те саме для −log D. Під логарифмом стоїть D, і
його похідна — D(1 − D):
Модуль градієнта дорівнює 1 − D — дзеркально до кроку 2.
Поділімо один модуль на другий. Обидва — прості дроби з тим самим знаменником, тож ділення виходить точним:
Тобто розрив між двома втратами не «десь у кілька разів», а рівно
e у степені мінус логіт. Що впевненіший дискримінатор у тому, що
перед ним підробка (що менший s), то більший цей розрив,
і росте він експоненційно.
Візьмімо s = −4 — типова впевненість дискримінатора на
початку навчання. Тоді e4 = 54.598, а
D = 1 / (1 + 54.598) = 0.0180. Далі просто:
Те саме число дає й формула кроку 4:
e4 = 54.6. Два незалежні шляхи, один
результат.
Прочитаймо, що з цього виходить. На початку навчання генератор малює сміття, і
дискримінатор упевнено ставить йому D близьке до нуля. Насичена втрата
дає при цьому градієнт D, тобто теж близький до нуля: генератор стоїть
саме тоді, коли йому найбільше треба вчитись.
Лікування коротке. Замість мінімізувати log(1 − D) генератор
мінімізує −log D. Точка, де обом добре, та сама — D = 1, —
а модуль градієнта тепер 1 − D. Це рівно те, чого хотілося: коли
дискримінатор упевнений, що перед ним підробка, генератор отримує найбільший
поштовх.
Цей обхід не є пізнішим винаходом — його описали вже в первісній статті, поруч із самою формулою, і відтоді він стоїть за замовчуванням у кожній реалізації. Але за нього є й ціна, яку варто назвати: гра перестає бути строго нульовою за сумою. Виграш генератора більше не дорівнює програшу дискримінатора, а отже акуратне доведення збіжності з попереднього розділу перестає стосуватися того, що ми справді запускаємо. Ми свідомо міняємо теорему на працездатність.
Де насичена втрата зупиняє генератора
Модуль градієнта обох втрат як функція від упевненості дискримінатора. Ліворуч — криві, праворуч — два стовпчики в поточній точці.
Повзунок проганяє те саме виведення по всій осі, і найважливіша точка на ній — ліва: при s = −4 дискримінатор дає 0.0180, насичена втрата має градієнт 0.0180, ненасичена — 0.9820, тобто у 54.6 раза більший. Це не тонке налаштування, а різниця між «вчиться» й «не вчиться».
Прилад зламаноКриві втрат нічого не кажуть
Тепер найважливіша відмінність GAN від усього, що було в курсі досі — і найлегша для перевірки.
У звичайному навчанні крива втрат — головний прилад. Спадає — вчиться. Стоїть — застрягло. Стрибнула вгору — швидкість навчання завелика. За тридцять сім тем ця звичка встигла стати рефлексом.
У GAN вона не працює, і причина не в поганій реалізації. Втрата дискримінатора міряє, наскільки добре він розрізняє проти поточного генератора. Втрата генератора міряє, наскільки добре він обманює поточного дискримінатора. Обидві величини рахуються відносно суперника, який змінюється щокроку. Це як міряти свій зріст лінійкою, яку тримає той, з ким змагаєшся.
Далі — заміряна ілюстрація. Три конфігурації GAN, які відрізняються лише швидкістю навчання й дають дуже різну якість, поставлені поруч зі своїми кривими.
Ті самі криві, різна якість
Втрати обох мереж по епохах для трьох конфігурацій. Унизу — скільки класів із шести накрив генератор на кінець навчання.
Найпростіше зведення тих самих даних у таблицю. Остання колонка — покриття класів, яке ми пояснимо через два розділи; поки досить знати, що більше означає краще.
| конфігурація | втрата D наприкінці | втрата G наприкінці | розмах кривої G | класів із 6 |
|---|---|---|---|---|
| дискримінатор повільніший | 1.2782 | 0.7071 | 0.2251 | 2.33 |
| однакові кроки | 1.0049 | 1.1751 | 1.0466 | 3.00 |
| генератор швидший | 1.3716 | 0.7106 | 0.2563 | 4.67 |
Дивись на перший і третій рядки. Втрата генератора наприкінці — 0.7071 і 0.7106, різниця в третьому знаку. Розмах кривої — 0.2251 і 0.2563, теж майже однаково. А покриття — 2.33 проти 4.67, тобто вдвічі. Якби ми судили за втратами, ми б назвали ці дві конфігурації однаковими.
ПриладСуддя, якому не можна вірити
Отже дивитись треба на картинки. Але лекція, у якій кожне твердження спирається на замір, не може спиратись на «подивись очима». Потрібен прилад, який дивиться замість нас.
Прилад блоку 8 називається суддя — це окремий класифікатор наших шести фігур, навчений на справжніх даних і більше ні на чому. Ми проганяємо крізь нього шістсот згенерованих картинок і питаємо, що він у них бачить. На справжніх фігурах суддя дає точність 0.9950, тобто задача для нього тривіальна.
З відповідей судді ми беремо два різні числа, і брати треба саме два.
Скільки з шести фігур дістали хоч 5 % вибірки. Максимум — 6. Це число ловить рівно те, чого боїться GAN: генератор, який малює лише кола, дістане одиницю, хоч би якими гарними були ті кола.
Відстань Фреше між купою справжніх картинок і купою згенерованих — але не між самими пікселями, а між 64 числами ознак, які видає передостанній шар судді. Формула порівнює два хмарні описи: середнє й розкид. Окремій картинці FID не ставлять — він має сенс лише для набору.
Розберемо запис. μ (грецька «мю») — середнє по всій купі:
шістдесят чотири числа, по одному на ознаку. Σ (велика
«сигма») — коваріаційна матриця: таблиця 64 × 64, у якій записано, наскільки ознаки
розкидані й наскільки повʼязані між собою. tr — слід матриці, сума чисел
на її діагоналі. Перший доданок каже, наскільки далеко одна від одної стоять дві
хмари; другий — наскільки різні вони за формою. Якщо хмари збіглися, обидва доданки
нулі.
Лишився один символ, який без пояснення виглядає страшно:
(Σ1Σ2)1/2
— корінь із добутку двох матриць. Це така матриця, яка, помножена сама на себе,
дає Σ1Σ2: те саме, що
квадратний корінь із числа, тільки для таблиць. Рахувати його руками не треба —
бібліотека робить це одним викликом; знати треба інше: він потрібен, щоб порівняти
форми двох хмар, а не просто їхні розміри.
Найпростіше побачити сенс формули на одному вимірі — коли ознака в нас не 64, а
одна. Тоді Σ перетворюється на звичайну дисперсію
s2, слід — на саме число, корінь із добутку —
на s1s2, і
вся формула згортається до шкільного виразу:
Підставмо числа. Хай справжні картинки дають ознаку із середнім
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 | впевненість судді |
|---|---|---|---|
| справжні, інша вибірка | 6 | 1.1582 | 0.9899 |
| лише кола | 1 | 483.8364 | 0.9771 |
| кола + квадрати | 2 | 466.8041 | 0.9806 |
| розмита каша | 2 | 918.3200 | 0.8103 |
| середнє всіх фігур | 1 | 1035.5173 | 0.5218 |
| усе чорне | 1 | 1133.5891 | 0.9957 |
| чистий шум | 2 | 1089.8743 | 0.8004 |
| усе біле | 1 | 1311.2006 | 0.5554 |
Три речі варто прочитати вголос.
Перший рядок — базова лінія, а не нуль. Дві різні вибірки справжніх фігур дають FID 1.1582, а не нуль, бо шістсот картинок — це скінченна вибірка, і її середнє з розкидом трохи гуляють. Цю величину треба друкувати поруч завжди, інакше читач сприйме її за відстань.
Другий рядок — той, заради якого все затівалось. «Лише кола» — це повний колапс мод: одна фігура з шести. Метрика ставить йому 483.8364, тобто у 418 разів гірше за базову лінію й майже вдвічі гірше за наш найкращий GAN. Метрика впоралась, і тепер їй можна вірити.
Останній стовпчик — уже перша пастка теми. На «всьому чорному» суддя впевнений на 0.9957 — сильніше, ніж на справжніх фігурах (0.9899). Порожній кадр він з повною певністю називає квадратом. Тримай це в голові: до цієї пастки ми повернемось із заміром, і вона там зіграє проти інтуїції ще різкіше.
МодельКрихітний DCGAN
Тепер самі мережі. Ми беремо DCGAN — найпростішу згорткову форму GAN,
описану 2015 року й досі використовувану як відправна точка. Її рецепт
короткий: жодних повнозвʼязних шарів усередині, у генератора —
ConvTranspose2d, які подвоюють сторону, у дискримінатора — звичайні
згортки з кроком 2, які її вдвічі зменшують.
Дві деталі в цьому рецепті не косметичні, і обидві варто назвати.
Tanh на виході генератора. Картинки живуть у відрізку від −1 до
1, а не від 0 до 1, тому справжні дані ми туди ж і переносимо. Причина проста:
tanh симетричний навколо нуля, і генераторові не треба зсувати весь
вихід угору, перш ніж почати вчитись.
Adam із betas=(0.5, 0.999). Перше число — це
інерція градієнта: оптимізатор памʼятає, куди йшов, і продовжує рухатись туди ж. За
замовчуванням воно 0.9, тобто памʼять довга. У грі двох мереж «куди йшов» застаріває
щокроку, бо суперник за цей крок змінився. Значення 0.5 скорочує памʼять удвічі, і це
не примха автора DCGAN, а те, без чого навчання розвалюється.
ХворобаКолапс мод: перший замір
Тепер про головну хворобу GAN. Вона зветься колапс мод (mode collapse), і механізм у неї цілком логічний.
Генераторові платять рівно за одне: обдурити дискримінатора. Йому ніхто не платить за різноманіття — у втраті немає жодного доданка, який би цього вимагав. Отже, знайшовши дві-три картинки, які надійно проходять, генератор має всі підстави малювати тільки їх. З погляду його власної цільової функції це не поразка, а оптимум.
Дискримінатор, узагалі кажучи, мав би це помітити: він бачить, що всі підробки однакові. Але дивиться він на кожну картинку окремо, а «всі однакові» — це властивість набору, а не картинки. Тому колапс мод — не збій реалізації, а дірка в самій постановці задачі.
Заміряймо. Базова конфігурація: обидві мережі мають однакову швидкість навчання
2e-4, двадцять епох, 1800 фігур, три зерна.
Куди поділись три фігури з шести
Частка кожного класу у вибірці з шестисот згенерованих картинок. Пунктир — поріг 5 %, за яким клас вважається покритим.
Базова конфігурація покриває 3.00 класи з шести, і купа по зернах — [3, 3, 3], тобто всі три прогони дали однакове число. Половину датасету генератор просто не малює.
ПеревіркаКолапс чи просто недонавчання
Перш ніж називати те, що ми побачили, колапсом мод, треба закрити нудне пояснення: а може, генератор просто не встиг навчитись? Двадцять епох — небагато, і кільце може бути не «загубленим», а «ще не досягнутим».
Перевірка проста: збережімо знімки генератора на трьох епохах і подивімось, куди рухається покриття.
Покриття вздовж навчання
Скільки класів накрито на восьмій, чотирнадцятій і двадцятій епосі. Три лінії — три конфігурації, три зерна на кожну точку.
| конфігурація | епоха 8 | епоха 14 | епоха 20 | FID на 20-й (база 1.1582) |
|---|---|---|---|---|
| дискримінатор повільніший | 2.33 | 1.67 | 2.33 | 724.94 |
| однакові кроки | 2.33 | 2.67 | 3.00 | 569.69 |
| генератор швидший | 2.33 | 3.33 | 4.67 | 249.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-4 | 5e-5 | 4.0 | 2.33 | [3, 3, 1] |
| однакові кроки | 2e-4 | 2e-4 | 1.0 | 3.00 | [3, 3, 3] |
| генератор швидший | 5e-4 | 2e-4 | 2.5 | 4.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.578 | 0.346 | 0.122 | 0.0868 |
| коло | 0.057 | 0.317 | 0.403 | 0.1756 |
| квадрат | 0.352 | 0.309 | 0.212 | 0.1544 |
| ромб | 0.006 | 0.026 | 0.108 | 0.1310 |
| хрест | 0.007 | 0.002 | 0.136 | 0.1479 |
| кільце | 0.000 | 0.001 | 0.019 | 0.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 — інакше ми пояснюватимемо один незрозумілий результат іншим.
Перевірка така: візьмемо справжні фігури й зіпсуємо їх однаково для всіх класів — просто розмиємо. Далі спитаємо суддю, яку частку кожного класу він ще впізнає. Якщо гіпотеза правильна, кільце обвалиться першим.
Що витримує неохайність
Справжні фігури, розмиті однаковим вікном. Стовпчики — частка, яку суддя ще впізнає правильно.
Отже гіпотеза підтвердилась наполовину, і половину, яка не підтвердилась, ховати не варто. На розмитті радіуса 1 суддя ще впізнає трикутник у 0.990 випадків, квадрат у 0.950, коло в 0.320, кільце в 0.100, хрест у 0.010, а ромб — у 0.000. Поділ на «трійку, що тримається» і «трійку, що гине» збігається з тим, що робить GAN у двох конфігураціях із трьох, — а в третьої, найкращої, нижня трійка вже інша. Порядок усередині нижньої трійки не збігається зовсім.
А ось що гіпотезу просто спростовує: трикутник має найменше яскравих пікселів з усіх шести — 0.0868 проти 0.1756 у кола. Найменша фігура виявилась найживучішою. Отже справа не в «тонкості» в сенсі площі. Радше в тому, наскільки фігура терпить неточність: суцільній опуклій плямі можна помилитись на піксель по краю й лишитись собою, а кільце з такою помилкою перестає бути кільцем — у нього закривається отвір.
ЦінаРізкість проти покриття
Настав час поставити GAN поруч із VAE з теми 37 й поміряти обох однією метрикою. Умови однакові: той самий датасет, той самий латентний простір на 16 чисел, двадцять епох, три зерна.
Третє число в таблиці — різкість. Міряємо її найпростіше з можливого: частка пікселів, які ані чорні, ані білі, тобто значення між 0.25 і 0.75. У справжніх фігур із нашим шумом таких пікселів 0.0000 — межа різка. У розмитої картинки їх багато. Менше — різкіше.
Дві моделі, три числа
Перемикай модель і дивись, за що вона платить. Зразки намальовані схематично; числа заміряні.
| модель | класів із 6 | по зернах | FID | напівтонів |
|---|---|---|---|---|
| справжні фігури | 6.00 | — | 1.1582 | 0.0000 |
| VAE | 5.67 | [6, 6, 5] | 329.12 | 0.0925 |
| GAN, генератор швидший | 4.67 | [5, 5, 4] | 249.33 | 0.0578 |
| GAN, однакові кроки | 3.00 | [3, 3, 3] | 569.69 | 0.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 дивиться і на різноманіття, і на схожість окремих зразків, і різкість переважила втрачений клас. Дві чесні метрики дали різні відповіді — і це вже пʼята тема курсу, де таке трапляється.
ПідсумокЩо з цього забрати
Сім речей, які варто винести з теми.
- GAN викидає явну втрату — і разом із нею прилад. Розмиття, яким платить VAE, береться з мінімізації квадрата різниці. Прибравши її, ми дістали різкість і втратили число, за яким можна стежити.
- Криві втрат у GAN не говорять про якість. Дві конфігурації з покриттям 2.33 і 4.67 мають криві генератора, що збігаються в третьому знаку: 0.7071 і 0.7106. Це не збіг, а наслідок того, що обидві втрати міряються відносно суперника, який змінюється щокроку.
- Метрику генерації калібрують перед першим використанням. Вісім завідомо поганих наборів, і повний колапс мод мусить опинитись гірше за робочу модель. Наша метрика ставить «лише кола» у 418 разів гірше за базову лінію — тільки після цього їй можна вірити.
- Одного числа мало. «Лише кола» і «кола + квадрати» мають майже однаковий FID (483.8364 і 466.8041) при різному покритті. Пара «FID + покриття» працює там, де кожне число окремо помиляється.
- Колапс мод вимірний і систематичний. Базовий DCGAN покриває 3.00 класи з шести на всіх трьох зернах, а кільце гине першим у кожній конфігурації й на кожному зерні. Далі систематичності вже немає: другим із кінця буває то хрест, то ромб, а в найкращої конфігурації хрест узагалі опиняється у верхній половині.
- Рецепти з підручника не є законами. Найпоширеніша порада «послаб дискримінатора» дала 2.33 замість 3.00, а на одному зерні — повний колапс. Прискорення генератора дало 4.67 із непересічними купами. Обидві зміни рухають відношення швидкостей в один бік, а результат дають протилежний.
- Впевненість класифікатора — не міра якості генерації. Найвища впевненість судді, 0.9129, дісталась найгіршій конфігурації; найкраща конфігурація має найнижчу — 0.8116. На порожньому чорному кадрі суддя впевнений на 0.9957, тобто сильніше, ніж на справжніх фігурах.
Останній пункт варто сказати ще раз іншими словами, бо він виглядає як дрібниця, а насправді ламає найпоширенішу звичку. Класифікатор навчений відповідати на питання «яка це з шести фігур», а не «чи це взагалі фігура». Він і відповідає — на що завгодно, включно зі сміттям, і відповідає впевнено. Саме тому для генерації довелося вигадати окрему метрику, яка дивиться на розподіл, а не на окремий знімок.
І місток уперед. Ми маємо дві моделі, кожна з яких платить своїм: VAE — різкістю, GAN — повнотою й стабільністю. Тема 39 уводить третю — дифузійні моделі. Їхня обіцянка звучить надто добре: різкість GAN без його нестабільності, бо навчання там знову має явну ціль — передбачити шум, який ми самі й додали, — і ця ціль не залежить від жодного суперника. Обіцянку доведеться перевірити тією самою метрикою, яку ми щойно відкалібрували, і там теж знайдеться пастка, де число не бреше, а просто міряє не те. А тема 40 закриє курс питанням, якого не уникнути після теми про породження підробок: що інженер робить з тим, що вміє робити.