Машинне навчання · Блок 7 · Тема 35

Регуляризація нейромереж

Мережа на тисячу вісімсот параметрів здатна вивчити напам'ять сто двадцять прикладів разом із їхніми випадковими помилками. Питання не в тому, чи вона перенавчиться, а в тому, що ми з цим зробимо.

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

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

01 / ДіагнозМережа, що вчить напам'ять

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

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

Що з цього виходить, видно на числах. За триста епох навчальна крос-ентропія падає до 0.0562, а точність на навчальних оголошеннях доходить до 0.9833 — мережа помиляється на двох прикладах зі ста двадцяти. Втрата на відкладеній валідації за той самий час не падає, а росте: 0.4565 проти найкращого значення 0.2637, досягнутого аж на 51-й епосі. Розрив між навчальною й валідаційною втратою — 0.40. Це і є перенавчання, тільки замість кривої, що пірнає в мінус, ми бачимо дві розбіжні криві.

Експеримент, який вирішив суперечку

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

Беруть звичайний набір даних і перемішують мітки. Тепер між ознаками й відповіддю немає геть жодного звʼязку: мітка кожного прикладу випадкова. Вивчити тут нема чого — закономірності просто не існує. І мережу навчають на цьому.

Вона навчається. Навчальна втрата спадає майже до нуля, точність доходить до ста відсотків. Наша мережа на перемішаних мітках за дві тисячі епох дає навчальну втрату 0.0128 і точність 1.0000 — жодної помилки на ста двадцяти прикладах, у яких відповіді проставлені навмання. Тобто мережа не «шукає закономірність»: коли закономірності немає, вона спокійно запамʼятовує таблицю.

Схема 1 · Та сама мережа, два набори міток

Ліворуч — справжні мітки, праворуч — ті самі мітки, випадково перемішані між прикладами. Мережа, дані й код однакові.

Що читати: ліва пара — нормальне навчання: майже ідеально на навчальних, непогано на нових. Права пара — те саме навчання на безглуздих мітках: навчальна точність 1.0000, а на нових даних 0.7141, тобто гірше за найтупішу відповідь «усі оголошення чесні», яка дає 0.8372. Мережа вивчила шум досконало — і цим зіпсувала собі все інше.

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

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

02 / ПеренесенняСпад ваг: старий штраф на новому місці

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

Lповна = Lданих  +  λ · Σ w2

Читається так само, як раніше. Перший доданок — крос-ентропія, яка міряє, наскільки мережа промахується. Другий — сума квадратів усіх ваг мережі (зсуви зазвичай не штрафують, як не штрафували вільний член у лінійній моделі). λ — одне додатне число, ціна одиниці «розгону». У світі мереж цей самий прийом частіше називають спадом ваг (weight decay), і назва пояснюється похідною: доданок λ·Σw² дає в градієнті 2λw, тож кожен крок навчання додатково стягує кожну вагу до нуля на частку, пропорційну їй самій. Ваги спадають.

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

Інтерактив 1 · Сила спаду ваг на мережі

Мережа 2 → 10 → 1 на 70 навчальних точках, з яких 14 % розмічені неправильно. Змінюється одне число — λ.

помилка навч.
помилка тест.
норма ваг
розрив
Прожени всі вісім положень. При λ = 0 мережа помиляється на одній навчальній точці з сімдесяти (1.4 %) і на 28.2 % нових — вона обхопила кожну неправильно розмічену точку окремим острівцем. При λ = 0.01 навчальна помилка виросла до 15.7 %, а тестова впала до 17.8 %: мережа перестала сперечатися з викидами. При λ = 0.3 норма ваг дорівнює нулю, межа зникла зовсім, і обидві помилки — близько половини. Це той самий сюжет, що в темі 23, і саме тому він тут: ідея не змінилась від переходу до мереж.

03 / ТонкістьЧому спад ваг — не завжди L2

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

Є два способи реалізувати ту саму, здавалося б, ідею. Перший — дописати λ·Σw² у функцію втрат. Тоді до градієнта кожної ваги додається 2λw, і далі цей доданок іде звичайним шляхом — крізь оптимізатор. Другий — не чіпати втрату взагалі, а після кроку оптимізатора окремо відняти від кожної ваги η·λ·w.

Для простого градієнтного спуску ці два способи дають абсолютно однакові числа. Крок першого способу — w − η·(g + 2λw), крок другого — w − η·g − η·λ'·w. Розкрий дужки в першому: те саме, тільки λ' = 2λ. Різниця в позначенні, не в поведінці.

Для Adam це вже різні методи. Adam ділить крок на власний масштаб градієнта: m̂/(√ŝ + ε). Якщо доданок 2λw потрапив у градієнт, він проходить крізь обидва накопичувачі й крізь це ділення. Значить, фактична сила стягування до нуля залежить від того, наскільки великі градієнти отримувала ця конкретна вага. Параметр із дрібними градієнтами має малий знаменник — і його стягує сильно; параметр із великими градієнтами стягує ледь-ледь. Одне число λ перетворюється на різну силу для різних ваг, і залежність ця випадкова.

Другий спосіб від цього вільний: η·λ·w віднімається окремо і ділення не бачить. Оптимізатор, у якому спад ваг реалізовано саме так, зветься AdamW — літера W від weight decay. Практичний наслідок простий: у бібліотеках параметр weight_decay в Adam і в AdamW означає різні речі, і значення, підібране для одного, для другого не годиться.

Що з цього запамʼятати. «Спад ваг» і «L2 у функції втрат» — це той самий метод лише для методів без адаптивного масштабу: простий спуск, момент. Щойно з'явився поділ на √ŝ — це два різні методи з однаковою назвою. Якщо ти вчиш мережу на Adam і регуляризація не працює так, як очікувалось, першим ділом перевір, який саме із двох варіантів у тебе ввімкнено.

04 / DropoutDropout

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

Ідея звучить так, ніби це помилка в коді. На кожному кроці навчання випадково вимикаємо частину нейронів — просто ставимо їхній вихід у нуль. Вимкнені нейрони на цьому кроці ні в чому не беруть участі: ні в прямому проході, ні в градієнті. Наступного кроку жереб кидається наново, і вимикається вже інша частина. Частка вимкнених p — параметр методу, звичайні значення від 0.1 до 0.5.

Інтерактив 2 · Dropout наочно

Два приховані шари по дванадцять нейронів. Повзунок задає частку вимкнених; кнопка кидає жереб заново.

активних / 24
цей крок ÷ (1−p)
середнє за 200 кроків
повна сума
Що читати: кожен нейрон має своє число — його активацію; перекреслені вимкнені на цьому кроці. Наступний шар отримує суму активних, поділену на 1 − p — це третя комірка табло. Тисни «наступний крок» кілька разів: на окремому кроці це число гуляє навколо повної суми, іноді помітно. А середнє за 200 кроків тримається біля повної суми майже точно — ділення вирівнює саме середнє, і більшого від нього не вимагають.

Чому це працює: дві інтуїції

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

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

Найважливіше місце: що робиться на передбаченні

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

Порахуймо на числах. Нехай нейрон наступного шару отримує суму від дванадцяти попередніх, і за повного складу ця сума дорівнює 6.00. При p = 0.25 під час навчання в середньому активні девʼять із дванадцяти, тож сума в середньому дорівнює 4.50 — три чверті від повної. Мережа налаштовувала свої ваги під цей рівень сигналу. Якщо на передбаченні подати їй повні 6.00, кожен наступний нейрон отримає на третину більше, ніж очікує. У глибокій мережі така похибка множиться від шару до шару, і на виході з'являється систематичний зсув.

Лікується це масштабуванням, і робити його можна з двох боків:

Схема 2 · Навчання проти передбачення

Той самий шар у двох режимах. Числа — активації нейронів; унизу — що дістається наступному шару.

Головне: обидва режими мусять давати наступному шару сигнал однакового розміру. Ліворуч частина нейронів мовчить, тож суму, що лишилась, ділять на 1 − p. Праворуч мовчить лише сам dropout — і саме тому там нічого ділити не треба. Забудеш будь-яку з двох половин — і мережа на передбаченні працює не в тому масштабі, у якому вчилась.
Помилка, яку не видно по точності. У практиці цієї теми ми навчимо мережу з простим dropout при p = 0.5 і забудемо масштабування на передбаченні. Точність від цього майже не змінюється: 0.8897 проти 0.8910 — межа рішень зсунулась мало. А от крос-ентропія псується вдвічі: 0.5132 замість 0.2981, і середній прогноз падає з 0.1582 до 0.1033 при справжній частці шахрайських оголошень 0.1628. Тобто мережа лишилась приблизно правою у відповідях «так / ні», але стала систематично занижувати ймовірності. Якщо ти дивишся лише на точність, ця помилка проживе в проєкті роками.

05 / BatchNormПакетна нормалізація

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

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

Схема 3 · Що робить пакетна нормалізація

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

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

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

Чесно про пояснення. Автори методу пояснили його дію через «зсув внутрішніх коваріат» (internal covariate shift): мовляв, розподіл входів кожного шару постійно їде, бо попередні шари вчаться, і нормалізація його утримує. Пізніші роботи це пояснення поставили під сумнів: вдавалось навмисно додати зсуву після нормалізації, і метод усе одно працював. Нинішнє пояснення інше — нормалізація згладжує поверхню втрат і робить її поведінку передбачуванішою. Ситуація, коли прийом упевнено працює, а причина досі обговорюється, для машинного навчання нормальна, і не варто вдавати, ніби її немає.

06 / ЗупинкаРання зупинка

Найдешевший прийом у цій темі не додає до мережі нічого. Він лише каже, коли припинити.

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

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

Інтерактив 3 · Де саме зупинитись

Дві криві втрат протягом 300 епох. Повзунок ставить «стоп» на обрану епоху; кнопки — терпіння.

терпіння
вал. тут
вал. найкраща
терпіння спинить
зекономлено епох
Спробуй три речі. Постав повзунок на кінець — побачиш, наскільки гіршу модель віддаєш, довчивши до останньої епохи. Постав на дно кривої (епоха 53) — це найкраще, що взагалі можна взяти. І перемкни терпіння на 5: на 19-й епосі валідаційна втрата ненадовго підскочила, і нетерплячий сторож спиняє навчання вже на 20-й, віддаючи ваги 15-ї — задовго до справжнього дна. Терпіння 10 цей самий стрибок перечікує.

На нашій мережі рання зупинка дає найбільший ефект за найменші зусилля. Навчання до кінця (300 епох) дає валідаційну втрату 0.4565. Зупинка з терпінням 20 спрацьовує на 71-й епосі й повертає ваги 51-ї, де валідаційна втрата 0.2637 — майже вдвічі краще, і при цьому 229 епох із 300 просто не виконуються. Терпіння 5 на цій самій кривій зупиняється аж на девʼятій епосі й віддає ваги четвертої: втрата 0.3629, помітно гірша за досяжну. Занадто нетерплячий сторож шкодить.

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

07 / ДаніБільше даних і аугментація

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

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

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

08 / ВибірЩо з чим поєднувати

Таблиця 1 · Пʼять способів поруч

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

спосібколи брати першимточність на тестіз чим обережно
рання зупинказавжди — вона майже безкоштовна0.9038ні з чим не конфліктує; вимагає валідації
спад вагколи розрив великий і мережа явно розігналась0.9103в Adam це не те саме, що L2; бери AdamW
dropoutширокі повнозвʼязні шари, багато даних0.8846душить малу мережу; ставити перед BatchNorm не можна
BatchNormглибока мережа, яка погано вчитьсяінша поведінка на передбаченні; малі пакети ламають
більше данихзавжди, якщо можна купитиаугментація мусить зберігати відповідь
Про порожні клітинки: BatchNorm і аугментацію ми на цих даних не міряли — дві числові ознаки й повнозвʼязна мережа на 120 прикладів не той стенд, де ці прийоми показують себе. Ставити туди вигадане число було б гірше, ніж прочерк.

Три правила поєднання, які варто знати наперед.

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

Регуляризація не лікує недонавчання. Діагноз читається за двома помилками поруч, як у темі 20: великий розрив між навчальною й валідаційною — можна додати штрафу; обидві однаково високі — штраф навпаки треба зменшити, а модель ускладнити. Наш dropout це показав буквально: при p = 0.1 точність на тесті виросла з 0.8795 до 0.8846, при p = 0.2 вона впала до 0.8205, а при p = 0.3 і 0.5 мережа з двома ознаками й ста двадцятьма прикладами задихнулась зовсім. Її прогнози злиплись у вузьку смужку навколо базової частки, жоден не перетнув поріг, і точність стала рівно 0.8372 — стільки дає відповідь «усі оголошення чесні». Навчальна втрата при цьому 0.4475 проти 0.4506 у справжньої сталої відповіді. Це не поламаний код, це недонавчання від надлишку регуляризації.

Більше — не краще. На наших даних спад ваг найкраще спрацював при λ = 0.3 (точність 0.9103), а при λ = 3.0 валідаційна втрата знову виросла до 0.3435. Ця крива має дно, і воно посередині — так само, як мала дно крива α в темі 23. Загальний висновок цієї теми, якщо звести його до одного рядка: сила регуляризації — гіперпараметр, а не константа, і підбирати його треба вимірюванням, а не переконанням.

09 / ДаліКуди далі

Блок про нейромережі на цьому закінчується. Пʼять тем склались в одну робочу схему: будова мережіградієнтактивації й старткрок → стриманість. Останній пункт тримається на пʼятьох прийомах:

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

Якщо продовжувати нарощувати мережу далі — за точку, де вона вже ідеально запамʼятала навчальні дані, — помилка на нових даних після піку починає знову падати, і падає нижче за найкраще значення класичної U-подібної кривої. Явище зветься подвійним спуском (double descent), і воно пояснює, чому сучасні мережі з мільярдами параметрів працюють усупереч усьому, що ми щойно розібрали. Наступний блок починається саме з цього: тема 36 показує криву на числах, а тема 37 — її математику.

Далі в практиці. У practice.ipynb ти навмисно перенавчиш мережу на 120 прикладах і побачиш розрив 0.40 власними очима; додаси спад ваг і подивишся, як розрив стискається до 0.08; напишеш dropout з нуля — маску на навчанні й масштабування на передбаченні — і забудеш масштабування, щоб побачити ціну; поставиш ранню зупинку з терпінням і порахуєш зекономлені епохи; а наприкінці зведеш усі способи в одну таблицю на тих самих даних.

Далі в темі

Теорію прочитано. Тепер закріпи її на практиці.