Що бачить мережа

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

Мережа подивилась на зображення й відповіла: «коло». Упевненість — 0.995 із 1. Відповідь правильна. І тут виникає питання, від якого не відмахнутись, щойно модель виходить із зошита в реальну роботу: а чому вона так вирішила? На що вона дивилась? Що саме в цій картинці змусило її сказати «коло», а не «кільце»?

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

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

ПитанняМережа відповіла. Чому саме так?

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

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

Тримай цю підміну в голові всю тему. Жоден метод нижче не відповідає на питання «чому». Усі вони відповідають на питання «де». Карта, яка світиться на предметі, каже: «якби цієї ділянки не було, відповідь змінилась би». Вона не каже, що мережа там побачила, і не каже, чи це побачене має сенс.

Наскрізний приклад теми — той самий, що в усьому блоці: фігури 28×28 шести класів, згенеровані формулами з гаусовим шумом. Мережа теж маленька, і це навмисно: у ній усе видно наскрізь.

Conv2d(1 → 8,  3×3, padding=1) + ReLU     28×28, 80 ваг
MaxPool2d(2)                              14×14
Conv2d(8 → 16, 3×3, padding=1) + ReLU     14×14, 1 168 ваг
MaxPool2d(2)                              7×7
Conv2d(16 → 32, 3×3, padding=1) + ReLU    7×7, 4 640 ваг ← сюди чіплятимемо hook
AdaptiveAvgPool2d(1)                      глобальне усереднення, 32 числа
Linear(32 → 6)                            198 ваг

Разом 6 086 ваг. Після навчання (30 епох на 1800 прикладах, близько 30 секунд на одному ядрі) точність на перевірці — 0.968 при рівні вгадування 0.167. Будова — та сама, що в темі 09: тіло зі згорток, глобальне усереднення з теми 08 і один лінійний шар у голові.

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

ВагиНайпростіше: подивитись на ваги

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

Тема 07 уже показувала ці ядра одразу після навчання й ставила питання, на яке ми зараз відповімо числом: чи стають навчені ядра схожими на Собеля з теми 04?

Як порівняти два ядра числом

«Схоже» треба чимось міряти. Візьмемо косинусну подібність — величину, яка порівнює два набори чисел, не зважаючи на їхній масштаб. Розтягуємо обидва ядра в рядок із девʼяти чисел, множимо їх поелементно, додаємо результати й ділимо на добуток довжин обох рядків.

cos(a, b) = (a1b1 + … + a9b9) ÷ (‖a‖ · ‖b‖)

Тут a і b — два ядра, розкладені в рядки; ‖a‖ («норма») — довжина рядка, тобто корінь із суми квадратів усіх девʼяти чисел. Ділення на довжини робить головне: ядро, помножене на 10, вважається тим самим ядром. Результат лежить між −1 і +1. Одиниця — ядра однакові з точністю до яскравості. Нуль — спільного нічого. Мінус одиниця — одне є другим із протилежним знаком, а для згортки це той самий детектор, лише чорне з білим міняються місцями.

Порахуємо руками на маленькому прикладі, щоб число не було чарівним. Візьмемо ядро [1, 0, −1] і ядро [2, 0, −2]. Добуток: 1·2 + 0·0 + (−1)(−2) = 4. Довжина першого: √(1+0+1) = 1.41. Довжина другого: √(4+0+4) = 2.83. Ділимо: 4 ÷ (1.41 · 2.83) = 4 ÷ 4 = 1.0. Ті самі ядра, різна яскравість — і косинус це побачив.

Що вийшло на наших ядрах

Заміряно на всіх восьми ядрах першого шару після навчання. У таблиці — косинус із чотирма класичними ядрами й сума всіх девʼяти ваг. Собель-X і Собель-Y шукають перепад яскравості по горизонталі й по вертикалі — ті самі ядра з теми 04; лапласіан шукає різкий перепад одразу в усіх напрямках; рівномірне ядро нічого не шукає, воно просто усереднює девʼять сусідів.

ядроСобель-XСобель-Yлапласіанрівномірнесума ваг
00.3640.5150.179−0.123−0.30
10.2330.4530.277−0.245−0.60
20.2430.2910.1310.8472.61
30.1310.018−0.557−0.327−0.86
4−0.341−0.687−0.026−0.121−0.35
50.1790.0540.0590.9313.84
6−0.5610.0300.336−0.127−0.38
7−0.139−0.193−0.0980.8753.15

Детекторів меж тут немає, і це чесна відповідь. Найкращий збіг із Собелем — 0.687 (ядро 4). Багато це чи мало? Я взяв 200 цілком випадкових ядер 3×3 і порахував те саме: середній збіг випадкового ядра з Собелем — 0.398, найкращий із двохсот — 0.808. Тобто випадковий шум легко перевершує наше найкраще навчене ядро. Ті самі вісім ядер до навчання давали 0.646 — навчання зрушило це число на 0.04, тобто ні на що.

Чому це нормальний, а не поганий результат. Наші фігури — суцільні плями на порожньому тлі розміром 28×28. Межа фігури тут завтовшки в один піксель, і всередині фігури немає нічого — ні текстури, ні градієнта. Детектор меж на такому матеріалі не має що детектувати. Мережі вигідніше вивчити щось інше — і вона вивчила.

Що таки зʼявилось. Подивись на підсвічені рядки: ядра 2, 5 і 7 мають косинус із рівномірним ядром 0.847, 0.931 і 0.875, а суми їхніх ваг — 2.61, 3.84 і 3.15. Рівномірне ядро — це просто усереднення сусідів, «наскільки тут загалом світло». До навчання таких ядер було 0 із 8 (найбільша сума за модулем — 1.36), після — 3 із 8. Мережа вивчила не детектори меж, а детектори заповненості. Для шести суцільних фігур це рівно та ознака, яка розрізняє їх найдешевше.

Ядра першого шару: до й після навчання

Вісім ядер 3×3. Клікни по ядру — воно розкриється крупно, з девʼятьма числами і своїм відгуком на тестовому зображенні. Перемикач унизу показує ті самі ядра до навчання.

ваги
зображення
cos із Собелем—
cos із рівномірним—
сума ваг—
ядро—
Клікай по всіх восьми й перемикай «до / після». Найкращий збіг із Собелем після навчання — 0.687, до навчання — 0.646: детектори меж не зʼявились. Зате три ядра з восьми стали майже рівномірними (cos 0.85-0.93), а до навчання таких не було жодного. Відгук праворуч — це саме те, що бачить другий шар мережі.

Чому далі за перший шар так дивитись марно

Ядро другого шару має форму 8×3×3: воно приймає вісім карт ознак, а не один канал яскравості. Викласти 72 числа в картинку можна, але дивитись на неї безглуздо: «яскравість» тут означає «вага восьмої карти ознак у позиції (2,1)», а не колір чогось у світі. Третій шар ще гірший: 16×3×3 на кожне з 32 ядер. Тому далі за перший шар усі методи цієї теми дивляться не на ваги, а на активації — на те, що шар видає на конкретному зображенні.

АктиваціїКарти активацій по шарах

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

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

Друга міра в таблиці нижче потребує окремого слова. Маса в 10 % клітинок — це частка всієї суми активацій шару, яка припадає на десяту частину найбільших клітинок. Якби сигнал був розмазаний рівно, вийшло б близько 0.1; що ближче число до одиниці, то сильніше все зібралося в кількох місцях.

шарформаненульовихмаксимуммаса в 10 % клітинокмертвих карт
conv1 + ReLU8 × 28 × 280.6553.270.5880 з 8
conv2 + ReLU16 × 14 × 140.34119.790.7134 з 16
conv3 + ReLU32 × 7 × 70.55351.580.4859 з 32

Розрідження є, але воно не монотонне — і про це треба сказати прямо. Частка ненульових іде 0.655 → 0.341 → 0.553. Другий шар справді мовчазніший за перший, а третій знову розговорився. Підручникова картинка «від шару до шару відгук стає дедалі розрідженішим» на нашій мережі не відтворилась. Те саме на всіх трьох перевірених входах: для хреста 0.664 → 0.349 → 0.518, для трикутника 0.679 → 0.326 → 0.503.

Зате монотонне інше. Кількість карт, які на цьому зображенні мовчать цілком (усі значення — нулі), росте: 0 з 8, потім 4 з 16, потім 9 з 32. Це і є справжня спеціалізація: у глибшому шарі більшість карт налаштована на речі, яких у цьому зображенні немає, і вони просто не вмикаються. І максимум росте в пʼятнадцять разів — від 3.3 до 51.6.

Яскрава карта не означає «важлива». Спокуса очевидна: знайти найяскравішу карту активацій і оголосити її головною. Перевірмо це числом. Я порахував для кожної з 32 карт третього шару її середню яскравість, а потім — вагу, яку цій самій карті дає Grad-CAM із наступного розділу. Наскільки два списки чисел ідуть разом, міряють кореляцією (коефіцієнтом Пірсона): це число від −1 до +1, де одиниця означає «де в одному списку велике, там і в другому велике, завжди», нуль — звʼязку немає, мінус одиниця — звʼязок обернений. Кореляція між двома нашими списками — 0.169. Тобто майже нічого: карта може горіти яскраво й не впливати на відповідь, і навпаки. Яскравість каже, наскільки сильний сигнал; важливість каже, куди цей сигнал іде далі. Це різні речі, і плутати їх — найчастіша помилка при читанні картинок із активаціями.

Усі карти ознак кожного шару

Один вхід, три шари. Перемикай шар і зображення; чорні квадрати — карти, які на цьому вході мовчать цілком.

шар
вхід
ненульових—
максимум—
мертвих карт—
маса в 10 %—
Прогони всі три шари на всіх трьох входах. Частка ненульових падає з ~0.66 до ~0.34 і знову підіймається до ~0.52 — розрідження не монотонне. А от мертві карти накопичуються завжди: 0 → 4 → 9. Зверни увагу й на розмір клітинки: у conv3 одна клітинка карти відповідає квадрату 4×4 пікселі вхідного зображення.

Grad-CAMGrad-CAM: звідки береться карта

Тридцять дві карти 7×7 — це забагато, щоб дивитись очима. Хочеться одну карту: ось тут те, через що мережа сказала «коло». Grad-CAM («gradient-weighted class activation mapping», класова карта активацій, зважена градієнтом) робить саме це.

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

крок 1 · що ми маємо

Останній згортковий шар видав A — 32 карти розміром 7×7. Це остання точка в мережі, де ще є «де»: далі глобальне усереднення все просторове стирає. Тому карту будують саме тут, і саме тому вона буде 7×7.

крок 2 · що таке градієнт тут

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

g[k][i][j] = наскільки зросте логіт класу c,
якщо підняти клітинку (i, j) карти k

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

крок 3 · чому середнє по простору

Градієнт g має ту саму форму, що й A: 32 × 7 × 7. Але нам потрібно 32 числа — по одному на карту, а не на клітинку. Тож усереднюємо градієнт по всіх 49 клітинках карти:

w[k] = (g[k][0][0] + g[k][0][1] + … + g[k][6][6]) ÷ 49

Це навмисне стирання «де». Ми питаємо не «яка клітинка важлива» (на це відповість сама карта A), а «наскільки взагалі корисна вся карта k для класу c». Просторову інформацію ми беремо з A, а важливість — з w. Розділення праці.

крок 4 · зважена сума

Тепер складаємо 32 карти в одну, домноживши кожну на її вагу:

S[i][j] = w[0]·A[0][i][j] + w[1]·A[1][i][j] + … + w[31]·A[31][i][j]

Карти з додатною вагою додають яскравості, карти з відʼємною — забирають. На нашому колі ваги лежать у діапазоні від −0.0056 до +0.0083, і майже половина з них відʼємна.

крок 5 · навіщо relu

У сумі S є відʼємні клітинки. Вони означають «тут докази проти класу c». Grad-CAM їх викидає: relu(S) замінює все відʼємне на нуль. Причина в постановці питання: ми питаємо «де докази за цей клас», а не «де докази проти». На нашому колі relu обнуляє 40.8 % клітинок — тобто двадцять із сорока девʼяти.

карта = relu(S)

Далі карту 7×7 розтягують до розміру входу й накладають кольором. Розтягування — це вже косметика; уся змістовна робота закінчилась на relu.

Як це виглядає в коді

register_forward_hook ставить перехоплювач на потрібний шар: коли мережа проходитиме крізь нього вперед, наша функція отримає його вихід. retain_grad() просить PyTorch не викидати градієнт цього проміжного тензора (за замовчуванням він зберігає градієнти лише для ваг). Далі беремо логіт потрібного класу й запускаємо backward() від нього — не від помилки, як при навчанні, а саме від одного числа.

handle = model.relu3.register_forward_hook(hook) logits = model(image) logits[0, class_index].backward() a = stored_output[0] # 32 × 7 × 7 g = stored_output.grad[0] # 32 × 7 × 7 w = g.mean(dim=(1, 2)) # 32 cam = relu((w[:, None, None] * a).sum(0))
Чому hook саме на ReLU, а не на згортку. Класичний Grad-CAM бере карти ознак після нелінійності — тобто вже невідʼємні. Якщо почепити hook на conv3, отримаєш вихід до ReLU, де є відʼємні числа, і зважена сума почне поводитись інакше: відʼємна вага на відʼємну активацію дасть додатний внесок. Це не помилка, а інший метод з іншими властивостями. Ми беремо канонічний варіант — після ReLU.
Точна тотожність, яку дала наша архітектура. У нас за останнім згортковим шаром стоїть глобальне усереднення й один лінійний шар. Логіт класу c дорівнює сумі fc[c][k] помножених на середнє карти k. Похідна такого виразу по будь-якій клітинці карти k дорівнює fc[c][k] / 49 — і однакова в усіх 49 клітинках. Тому середнє градієнта дорівнює йому ж: w[k] = fc[c][k] / 49 рівно, без наближень. Перевірено чисельно: максимальна різниця 1.9 × 10−9. Наслідок серйозний — у такій мережі ваги Grad-CAM не залежать від зображення взагалі. Вони фіксовані для класу. Усе, що змінюється від картинки до картинки, — самі карти ознак. Тримай це в голові до розділу 08: саме звідси візьметься найдивніше число теми.

Grad-CAM крок за кроком

Тисни «наступний крок» і дивись, як із 32 карт ознак виходить одна карта. Показано вісім каналів із 32: чотири з найбільшою вагою і чотири з найменшою.

a = карти ознак (32×7×7)
g = градієнт логіта по a
w = g.mean(dim=(1,2))
S = sum(w[k] * a[k])
cam = relu(S)
накласти на зображення
що на екрані—
діапазон значень—
крок1 / 6
Головне видно на кроці 3. Ваги w — це 32 числа від −0.0056 до +0.0083, і майже половина відʼємна. На кроці 4 відʼємні карти віднімаються з суми, а на кроці 5 relu викидає 40.8 % клітинок — двадцять із сорока девʼяти. Саме тому карта Grad-CAM завжди має великі нульові ділянки.

Карта для іншого класу

Grad-CAM будується для класу, а не для зображення. На тому самому колі можна спитати: а де докази за «квадрат»? Заміряно: кореляція між картою правильного класу («коло») і картами інших пʼяти становить 0.944 для «квадрата», 0.353 для «ромба», −0.381 для «кільця», −0.312 для «хреста» і −0.615 для «трикутника». Тобто карти «коло» і «квадрат» майже збігаються.

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

Одне зображення, шість запитань

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

питаємо про клас
упевненість—
максимум карти—
кореляція з картою «коло»—
Перемкни на «квадрат». Карта майже не змінилась — кореляція 0.944, хоча мережа дає цьому класу лише 0.001 упевненості. А «трикутник» дає −0.615: там карта справді інша, майже дзеркальна. Карта міняється від класу до класу, але не завжди й не однаково.

РоздільністьЧому карта така груба

Наша карта має розмір 7×7, а зображення — 28×28. Ділимо: одна клітинка карти відповідає квадрату 4×4 = 16 пікселів. Уся фігура радіусом 7 пікселів займає приблизно 3×3 клітинки карти. Тобто вся «увага» описується девʼятьма числами.

Це прямий наслідок того, де карта будується: Grad-CAM працює на останньому згортковому шарі, де карти найменші, бо два пулінги зменшили 28 до 7. На справжніх мережах пропорція та сама, лише числа більші: у ResNet-50 на вході 224×224 остання карта теж 7×7, тобто одна клітинка дорівнює квадрату 32×32 пікселі.

Чому не взяти ранішній шар. Можна. Другий згортковий шар дає карту 14×14, тобто клітинку 2×2 пікселі — учетверо детальніше. Але там менше семантики. Компроміс формулюється так: що глибше шар, то грубіша карта й то більше вона про «клас»; що ближче до входу, то детальніша карта й то більше вона про «текстуру».

Заміряно на нашому колі (обидві карти перед порівнянням розтягнуто до 28×28): кореляція між картою з conv3 (7×7) і картою з conv2 (14×14) дорівнює 0.850 — вони кажуть майже те саме, тільки з різною подрібненістю. Цікаво інше: детальніша карта з conv2 виявилась ближчою до незалежного заміру заслоном (0.923 проти 0.836). На маленькій мережі «глибше = семантичніше» майже не спрацювало, бо трьох шарів замало, щоб зʼявилась різниця в рівні абстракції.

ЗаслінЗаслін: метод без градієнтів

Grad-CAM спирається на градієнти, тобто на внутрішню механіку мережі. Є спосіб простіший і чесніший за задумом: закрити частину зображення й подивитись, чи зіпсується відповідь. Мережа при цьому лишається чорною скринькою — ми не заглядаємо всередину взагалі. Англійською метод зветься occlusion sensitivity («чутливість до заслону»), і саме за цим словом його шукати в статтях і бібліотеках; далі в темі ми зватимемо його коротко — заслін.

Механіка: беремо квадрат p×p, заливаємо його сірим (значення 0.5), ставимо в позицію (r, c) і питаємо мережу. Записуємо, наскільки впала ймовірність правильного класу, пересуваємо квадрат на крок і повторюємо. Із зібраних падінь складається карта: де падіння велике, там лежить щось важливе.

падіння(r, c) = p(клас | ціле зображення) − p(клас | закрито квадрат у (r, c))

Заміряно на нашому колі. Базова впевненість мережі — 0.995. Квадрат 7×7 із кроком 1 дає 22 × 22 = 484 положення, і максимальне падіння становить 0.995: одне-єдине правильно поставлене вікно 7×7 обвалює впевненість практично до нуля.

квадраткрокпрогонівмакс. падіннямін. падіння
5 × 515760.993−0.003
7 × 714840.995−0.004
9 × 914000.994−0.004
11 × 1113240.906−0.004

Ціна методу. Grad-CAM коштує рівно два проходи — один прямий і один зворотний. Заслін квадратом 7×7 із кроком 1 коштує 484 прямі проходи, тобто у 242 рази більше. На нашій мережі це частки секунди; на ResNet-50 і зображенні 224×224 із вікном 32 і кроком 8 — 625 прогонів по 159 мс, понад півтори хвилини на одну картинку.

Прихована пастка методу: сірий квадрат — теж вхід. Мережа ніколи не бачила на навчанні зображень із сірим квадратом посередині. Падіння впевненості може означати «ми закрили важливе», а може означати «ми показали мережі щось небувале». Розрізнити ці дві причини заслін не вміє. Заміна заливки (нуль, середнє по датасету, розмиття, шум) дає різні карти — і жодна з них не є «правильною». Зверни увагу й на колонку «мін. падіння»: воно відʼємне (−0.004). Тобто в деяких позиціях заслін підвищує впевненість мережі, замість того щоб знижувати.

Заслін будується на очах

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

розмір квадрата
крок
прогонів мережі—
макс. падіння—
клітинок карти—
разів дорожче—
Прогони всі дванадцять комбінацій. Крок 4 замість 1 здешевлює метод у 13 разів (36 прогонів замість 484), але карта квадратом 7×7 стає 6×6 — грубішою за саму Grad-CAM. А квадрат 11×11 при кроці 1 закриває 15 % зображення й розмазує карту: максимальне падіння спадає з 0.995 до 0.906, бо великий квадрат майже завжди зачіпає фігуру.

ЗгодаЧи згодні два методи між собою

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

Порівнюємо кореляцією. Кореляція (точніше — коефіцієнт Пірсона) — це число від −1 до +1: одиниця означає «де в одній карті яскраво, там і в другій яскраво, завжди», нуль — звʼязку немає, мінус одиниця — де в одній яскраво, у другій темно. Обидві карти розтягуємо до 28×28 і рахуємо кореляцію по 784 пікселях:

зображенняупевненістькореляція картвисновок
коло0.995+0.836згодні
квадрат0.747+0.188майже не згодні
ромб0.868−0.170суперечать
кільце1.000+0.612загалом згодні
хрест0.994+0.658загалом згодні
трикутник0.911−0.085не повʼязані
середнє—+0.340—

Три з шести — згода, три з шести — ні. І це найважливіше число розділу. Мережа на всіх шести зображеннях відповіла правильно й упевнено. Обидва методи відпрацювали без помилок. А результат розходиться — на ромбі вони показують буквально в різні боки (−0.170).

Хто з них правий? Питання поставлене неправильно. Еталонної карти, з якою можна звірити обидві, немає: «правильної відповіді» на питання «куди дивилась мережа» не існує в природі, бо мережа нікуди не дивилась — вона перемножувала числа. Є два різні способи перекласти її обчислення в картинку, і вони дають різні картинки.

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

Два методи на одному зображенні

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

зображення
кореляція двох карт—
упевненість мережі—
відповідь—
Перебери всі шість. На колі хмара точок витягнута вздовж діагоналі — кореляція +0.836. На ромбі вона розвертається в другий бік (−0.170), а на трикутнику розсипається в безформну пляму (−0.085). Мережа при цьому в усіх шести випадках відповіла правильно.

ОсудністьПеревірка на осудність

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

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

Псуємо у два прийоми, від виходу до входу. Спершу тільки голову — останній лінійний шар на 198 ваг. Тіло зі згорток лишається навченим. Потім усе разом: голову й усі три згорткові шари.

Обидва зіпсовані варіанти дають точність 0.167 — рівно рівень вгадування на шести класах. Ці мережі не «трохи гірші», вони не знають нічого.

Потрібен орієнтир, інакше числа ні про що

Кореляція 0.2 — це багато чи мало? Щоб відповісти, я навчив другу мережу тієї самої форми з іншого випадкового початку. Вона теж вивчила задачу (точність 0.997). Кореляція між картами двох навчених мереж — ось наша верхня планка.

зображенняінша навченавип. головавип. тіло
коло+0.959−0.116−0.128
квадрат+0.560порожня карта−0.278
ромб+0.461−0.472+0.155
кільце+0.943+0.995+0.160
хрест+0.460порожня карта−0.136
трикутник+0.125+0.276+0.559
середнє+0.584+0.171+0.055

Загальний результат: наша Grad-CAM перевірку проходить. Дві навчені мережі згодні між собою на +0.584, а навчена й зіпсована — на +0.171 і +0.055. Тобто псування ваг карту таки міняє, і міняє сильно. Перевіримо це ще й другим способом: скільки з дванадцяти найяскравіших клітинок карти лишаються найяскравішими після псування? Вийшло 0.31 для випадкової голови і 0.15 для випадкового тіла, тоді як випадковий збіг дав би 12 ÷ 49 = 0.245. Тобто перекриття на рівні випадкового або нижче.

Але середнє тут ховає два неприємні факти, і замовчувати їх не можна.

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

Звідки це береться, ми вже вивели в розділі 04: ваги Grad-CAM дорівнюють рядку матриці fc, поділеному на 49, а карти ознак приходять із тіла, якого ми не чіпали. При псуванні лише голови карта = relu(випадкова комбінація тих самих карт ознак), і якщо комбінація випадково зберегла знаки в потрібних місцях — картинка збігається. На кільці так і сталося.

Факт другий: на двох зображеннях із шести метод узагалі не дав карти. Для квадрата й хреста випадкова голова видала порожню карту — усі 49 клітинок дорівнюють нулю. Зважена сума виявилась відʼємною скрізь, і relu її стерла. Кореляцію з порожньою картою порахувати не можна взагалі: у неї немає розкиду.

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

І деталь, яку видно тільки завдяки орієнтиру. На трикутнику дві навчені мережі згодні між собою лише на +0.125 — це найнижче число в колонці. А навчена й та, що з випадковим тілом, згодні на +0.559. Тобто зіпсована мережа дала карту, схожу на початкову сильніше, ніж мережа, яка задачу вивчила. Отже, орієнтир треба брати для кожного зображення окремо: середнє по таблиці приховало б і цей випадок теж.

Для повноти я прогнав той самий тест і на заслоні. Кореляція карти заслону навченої мережі з картою заслону мережі з випадковою головою — −0.610, з випадковим тілом — +0.093. Незалежний метод теж реагує на псування ваг, і на цьому зображенні навіть різкіше.

Перевірка на осудність

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

зображення
велика панель
з навченою—
орієнтир: інша навчена—
точність цієї мережі—
Обовʼязково подивись «кільце» + «вип. голова». Мережа з точністю 0.167 малює ту саму карту, що й мережа з точністю 0.968: кореляція +0.995. А на «квадраті» й «хресті» та сама випадкова голова дає порожню карту. Орієнтир для порівняння — друга незалежно навчена мережа, +0.584 у середньому.

МежіЧого карта не каже

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

Вона показує «де», а не «чому»

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

Вона не показує, чого мережі бракувало

Якщо модель помилилась, бо в навчальних даних не було потрібного випадку, карта цього не побачить. Вона показує вплив того, що є на зображенні, і не має способу вказати на те, чого немає.

Вона не доказ правильності — і це можна показати числом

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

що на входівідповідьупевненістьцентр карти ↔ центр фігури
квадрат у куткуквадрат ✅0.9903.1 px
квадрат по центруколо ❌0.7060.8 px
коло біля краюквадрат ❌0.6346.7 px
хрест унизуромб ❌0.5394.3 px

Другий рядок — головний. Мережа помилилась: назвала квадрат колом, з упевненістю 0.706. А карта при цьому ідеальна: її центр відхилився від центра фігури лише на 0.8 пікселя. Мережа дивилась рівно туди, куди треба, — і відповіла неправильно. Карта, показана окремо, виглядала б як доказ правильної роботи.

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

У карти немає нуля

Остання, найтихіша пастка. Карту завжди нормалізують перед показом: найяскравіша клітинка стає повністю червоною. Тому карта завжди виглядає впевненою, навіть коли жодна клітинка нічого не варта. На колі максимум карти — 1.533, на трикутнику — 0.229, усемеро менше; після нормалізації обидві виглядають однаково яскраво. Отже: дивись не тільки на карту, а й на її сирий максимум. Якщо він мізерний, кольорова пляма — це шум, розтягнутий до повної насиченості.

КористьДе це справді корисно

Після трьох розділів скепсису законно спитати: то навіщо це все? Карти корисні, але не там, де їх зазвичай показують.

Пошук артефактів у даних

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

Налагодження розмітки

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

Розмова з людьми, які не читають код

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

Протокол приймання моделі

Практичний порядок, який складається з усього, що ми поміряли:

  1. побудувати карту двома незалежними методами (градієнтним і заслоном);
  2. порахувати кореляцію між ними на десятку зображень;
  3. прогнати перевірку на осудність і записати число;
  4. окремо подивитись на помилки моделі, а не лише на вдалі випадки;
  5. кожну підозру, яку дала карта, перевірити експериментом із даними.

ІншеЩо є, крім карт

Карти — не єдиний спосіб зазирнути всередину, просто найдешевший. Решту назву коротко, щоб ти знав, що шукати, коли карт забракне.

Усі вони мають ту саму слабкість, що й карти, і всі потребують тієї самої перевірки на осудність.

ПідсумокЩо лишається в голові

ІдеяЩо вона насправді дає
Ваги першого шаруДетектори меж не зʼявились (0.687 проти 0.808 у випадкового шуму), зʼявились детектори заповненості: 3 ядра з 8
Карти активаційРозрідження не монотонне (0.655 → 0.341 → 0.553), зате мертвих карт більшає: 0 → 4 → 9. Яскравість майже не повʼязана з важливістю: кореляція 0.169
Grad-CAMВаги = середнє градієнта по простору, карта = relu зваженої суми, два прогони мережі. При глобальному усередненні ваги дорівнюють рядку fc ÷ 49 рівно
Роздільність7×7 на вході 28×28 — клітинка на 16 пікселів. Ранішній шар дає 14×14 і в нас краще збігається із заслоном (0.923 проти 0.836)
ЗаслінБез градієнтів, зате 484 прогони замість 2. Заливка квадрата — сама по собі артефакт
Згода методів+0.340 у середньому, від +0.836 до −0.170: три з шести — згода, три — ні
Перевірка на осудністьДві навчені мережі: +0.584. Навчена проти зіпсованої: +0.171 і +0.055. Але на одному зображенні з шести — +0.995, а на двох метод дав порожню карту
Межі картиПоказує «де», не «чому». Правильна відповідь із кривою картою (3.1 px) і хибна з бездоганною (0.8 px) трапляються однаково легко

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

Місток до наступної теми

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

Лишилось питання, з якого проєкт починається, а не закінчується: яку архітектуру взяти. У блоці ми розібрали AlexNet і VGG, ResNet, MobileNet і EfficientNet — кожну окремо. Наступна тема — 18. Порівняння архітектур — ставить їх поруч і питає, як обирати між ними під конкретне обмеження: точність, вагу файлу, час на пристрої чи кількість даних, які в тебе є.