Software developer

🇺🇦 Рецепт навчання нейрнонних мереж

Переклад статті A Recipe for Training Neural Networks від імені автора (Andrej Karpathy). З деякими додатковими посиланнями.

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

Тож я подумав, що буде весело змести пил зі свого блогу аби розкрити свій твіт в об'ємнішому форматі, якого і заслуговує ця тема. Однак замість того щоб поглиблюватись в перелік ще більшої кількості частих помилок або їх конкретизацію, я хотів би копнути глибше та поговорити про те як оминути ці помилки цілком (або ж виправити їх дуже швидко). Фокус в тому, щоб слідувати певному процесу, який, наскільки я можу сказати, не часто документується. Давайте почнемо з двох важливих спостережень, які спонукали до цього.

1) Нейронні мережі це дірява абстракція

Це ніби просто почати навчати нейронні мережі. Кілька бібліотек та фреймворків пишаються показом магічних 30-рядкових шматків коду які вирішують проблеми з вашими даними, даючи (хибні) враження, що це все працює з коробки. Звично бачити подібні речі:

>>> your_data = # підставте свій датасет тут
>>> model = SuperCrossValidator(SuperDuper.fit, your_data, ResNet50, SGDOptimizer)
# підкоріть світ тут

Ці бібліотеки та приклади активують частину нашого мозку яка звична зі стандартними програмами - місце де чисті API та абстракції часто досяжні. Для прикладу бібліотека requests:

>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200

Круто! Сміливий розробник переклав на себе тягар розуміння рядків запитів, URL-адрес, GET/POST запитів, HTTP з'єднань, тощо, і багато в чому приховав складність за кількома рядками коду. Це те з чим ми знайомі та очікуємо. На жаль, нейронні мережі не схожі на це. Вони не "готова" технологія, коли ви трохи відхиляєтесь від навчання класифікатора ImageNet. Я намагався вказати на це у своїй публікації "Так ви маєте розуміти метод зворотного поширення помилки" (“Yes you should understand backprop”), вибравши метод зворотного поширення помилки та назвавши його "дірявою абстракцією", але ситуація, на жаль, набагато важча. "Зворотне поширення помилки" + "Стохастичний градієнтний спуск" не робить вашу нейронну мережу магічно працюючою. Пакетна нормалізація не змушує її магічно сходитись швидше. Рекурентні нейронні мережі не дозволяють магічно "вставити" текст. І лише тому, що ви можете сформулювати вашу проблему в формі "навчання з підкріпленням" не означає, що ви повинні це робити. Якщо ви наполягаєте на використанні технології, не знаючи як вона працює, ви, ймовірно, зазнаєте невдачі. Що підводить мене до...

2) Навчання нейронних мереж ламається мовчки

Коли ви неправильно написали або налаштували код ви часто отримуєте певне виключення. Ви передали ціле число там де очікується рядок. Функція очікує лише 3 аргументи. Цей імпорт невдалий. Той ключ не існує. Кількість елементів у двох списках не рівна. В додачу, часто можливо створити юніт-тести для певного функціоналу.

Це лише початок, коли справа стосується тренування нейронних мереж. Все може бути синтаксично вірно, але вкупі не впорядковано належним чином, і про це справді важко сказати (компілятору або інтерпретатору). "Можлива поверхня помилок" велика, логічна (на відміну від синтаксичної) та дуже складна для юніт-тестування. Наприклад, ви забули перевернути шар позначень коли перевертали зображення під час аугментації даних. Ваша мережа все ще (що шокує) може працювати досить добре, тому що ваша мережа може внутрішньо навчитися виявляти перевернуті зображення, а потім перевертати свої прогнози. Або, можливо, ваша авторегресивна модель випадково приймає те, що вона намагається передбачити, як інформацію на вході через непомітну помилку. Або ви намагалися обрізати свої градієнти, але замість цього обрізали втрату, що спричинило ігнорування викидів, під час навчання. Або ви ініціалізували ваші ваги з попереднього навчання, але не використали вихідне середнє. Або ви просто зіпсували налаштування регуляризації, швидкості навчання, розміру моделі, і т.д. Тому ваша неправильно налаштована нейронна мережа викине виключення, лише якщо вам пощастить; Здебільшого вона тренується, але мовчки працює трохи гірше.

Як результат, (і це дуууже складно переоцінити) "швидкий і лютий" підхід до навчання нейронних мереж не працює і призводить лише до страждань. Зараз страждання є цілком природною частиною того, щоб нейронна мережа працювала добре, але їх можна пом'якшити, якщо бути вдумливими, захищеними, параноїдальними та одержимими візуалізацією практично всього. Якість, яка на моєму досвіді найбільше корелює з успіхом у глибокому навчанні, - це терпіння та увага до деталей.

Рецепт

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

1. Станьте єдиними з даними

Перший крок до навчання нейронних мереж - це взагалі не торкатися коду нейронної мережі, а натомість почати з ретельної перевірки ваших даних. Цей крок критичний. Я люблю витрачати багато часу (вимірюється в годинах), перевіряючи тисячі прикладів, розуміючи їх розподіл та шукаючи закономірності. На щастя, ваш мозок добре з цим справляється. Одного разу я виявив, що дані містять приклади які повторюються. Іншого разу я виявив пошкоджені зображення / розмітку. Я шукаю дисбаланс даних та зміщення. Зазвичай я також звертаю увагу на свій власний процес класифікації даних, який натякає на види архітектур які ми з часом вивчимо. Як приклад - чи достатньо локальних особливостей, чи нам потрібен глобальний контекст? Скільки існує варіацій та яку форму вони приймають? Яка варіація хибна і може бути попередньо оброблена? Чи має значення просторове положення чи ми хочемо його усереднити (з допомогою операції average pool)? Наскільки важливі деталі і як далеко ми можемо дозволити собі зменшити розмір зображень? Наскільки шумна розмітка?

Крім того, оскільки нейронна мережа є фактично стисненою / скомпільованою версією вашого набору даних, ви зможете переглянути свої (помилкові) прогнози у вашій мережі та зрозуміти, звідки вони можуть надходити. І якщо ваша мережа дає вам прогноз який не відповідає тому, що ви бачили в даних, то щось пішло не так.

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

2. Налаштуйте наскрізний скелет навчання / оцінки + отримайте простий базис (базову модель)

Тепер, коли ми зрозуміли наші дані, чи можемо ми дістатись до нашої надзвичайної великомасштабної ASPP FPN ResNet та розпочати навчання чудових моделей? Точно ні. Це шлях до страждань. Наш наступний крок - створити повний скелет навчання + оцінка та завоювати довіру до його правильності шляхом серії експериментів. На цьому етапі найкраще вибрати якусь просту модель, яку не можна було якось зіпсувати - наприклад лінійний класифікатор або дуже крихітну згорткову мережу. Ми хочемо навчати мережу, візуалізувати втрати, будь-які інші показники (наприклад, точність), моделювати прогнози та проводити низку експериментів по відключенню частин мережі (при цьому висувати гіпотези як це вплине на результати) на всьому шляху.

Поради та підказки на цьому етапі:

3. Перенавчайте

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

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

Кілька порад та підказок на цьому етапі:

4. Регуляризуйте

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

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

5. Тюнінгуйте

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

6. Витисніть всі соки

Знайшовши найкращі типи архітектур та гіперпараметри, ви все ще можете скористатися ще кількома хитрощами, щоб вичавити останні каплі соку з системи:

Висновок

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

Thank you for attention!