Тестування підрозділу - ваш друг
Серед письменників є приказка, що "Все письмо переписується" - тобто більша частина написання переглядається. Для програмістів (або принаймні науковців даних) вираз можна переформулювати як "Все кодування є налагодженням".
Щоразу, коли ви пишете код, вам потрібно переконатися, що він працює за призначенням. Найкращий спосіб, який я коли-небудь знайшов для перевірки правильності, - це розбити свій код на невеликі сегменти та перевірити, чи працює кожен сегмент. Це можна зробити, порівнюючи вихід сегмента з тим, що ви знаєте, як правильну відповідь. Це називається одиничним тестуванням . Складання хороших одиничних тестів є ключовим елементом стати хорошим статистиком / вченим даними / експертом машинного навчання / практикою нейронної мережі. Замінника просто немає.
Ви повинні перевірити, що ваш код не містить помилок, перш ніж ви зможете налаштувати мережеву продуктивність! В іншому випадку ви можете також переставляти шезлонги на RMS Titanic .
Є дві особливості нейронних мереж, які роблять перевірку навіть важливішою, ніж для інших типів машинного навчання або статистичних моделей.
Нейронні мережі не є "позаштатними" алгоритмами таким чином, як випадкові лісові чи логістичні регресії. Навіть для простих мереж, що передаються в режим подачі, в основному користувач приймає численні рішення щодо налаштування, підключення, ініціалізації та оптимізації мережі. Це означає написання коду, а код написання означає налагодження.
Навіть коли код нейронної мережі виконується без винятку, у мережі все одно можуть бути помилки! Ці помилки можуть бути навіть підступним видом, для якого мережа буде тренуватися, але застрягти в неоптимальному рішенні, або отримана мережа не має потрібної архітектури. ( Це приклад різниці між синтаксичною та смисловою помилкою .)
У цій середній публікації Чейза Робертса " Як розділити код випробувального машинного навчання " більш детально розглядаються одиничні тести для моделей машинного навчання. Я запозичив цей приклад баггі-коду зі статті:
def make_convnet(input_image):
net = slim.conv2d(input_image, 32, [11, 11], scope="conv1_11x11")
net = slim.conv2d(input_image, 64, [5, 5], scope="conv2_5x5")
net = slim.max_pool2d(net, [4, 4], stride=4, scope='pool1')
net = slim.conv2d(input_image, 64, [5, 5], scope="conv3_5x5")
net = slim.conv2d(input_image, 128, [3, 3], scope="conv4_3x3")
net = slim.max_pool2d(net, [2, 2], scope='pool2')
net = slim.conv2d(input_image, 128, [3, 3], scope="conv5_3x3")
net = slim.max_pool2d(net, [2, 2], scope='pool3')
net = slim.conv2d(input_image, 32, [1, 1], scope="conv6_1x1")
return net
Ви бачите помилку? Багато з різних операцій фактично не використовуються, оскільки попередні результати перезаписані новими змінними. Використання цього блоку коду в мережі все одно буде тренуватися, а ваги будуть оновлюватися, а втрати можуть навіть зменшитися - але, безумовно, код не робить те, що було призначено. (Автор також суперечить використанню одно- або подвійних лапок, але це суто стилістично.)
Найбільш поширені помилки програмування, що стосуються нейронних мереж
- Змінні створюються, але ніколи не використовуються (як правило, через помилки копіювання-вставки);
- Вирази для оновлення градієнта невірні;
- Оновлення ваги не застосовуються;
- Функції втрат не вимірюються за правильною шкалою (наприклад, перехресна ентропія втрат може бути виражена через ймовірність або логіти)
- Втрата не підходить для завдання (наприклад, використання категоричної крос-ентропійної втрати для регресійного завдання).
Повзати перед тим, як піти; Гуляйте перед тим, як бігти
Широкі та глибокі нейронні мережі та нейронні мережі з екзотичною проводкою - це Гаряча річ зараз у машинному навчанні. Але ці мережі не почали повністю формуватися; їхні дизайнери споруджували їх із менших одиниць. Спочатку побудуйте невелику мережу з одним прихованим шаром і переконайтеся, що вона працює правильно. Потім поступово додайте додаткову складність моделі та переконайтеся, що кожна з них також працює.
Занадто мало нейронів у шарі може обмежувати уявлення, яке вивчає мережа, спричиняючи недостатність. Занадто багато нейронів можуть спричинити переналагодження, оскільки мережа "запам'ятовує" дані тренувань.
Навіть якщо ви зможете довести, що математично існує лише невелика кількість нейронів, необхідних для моделювання проблеми, часто трапляється так, що наявність «ще кількох» нейронів полегшує оптимізатору знайти «гарну» конфігурацію. (Але я не думаю, що ніхто повністю не розуміє, чому це так.) Я надаю приклад цього в контексті проблеми XOR: Чи не потрібні мої ітерації для навчання NN для XOR з MSE <0,001 занадто високими? .
Вибір кількості прихованих шарів дозволяє мережі вивчити абстрагування від необроблених даних. Глибоке навчання в цей час викликає всю гніт, і мережі з великою кількістю шарів показали вражаючі результати. Але додавання занадто багато прихованих шарів може спричинити загрозу надмірного розміщення або ускладнити оптимізацію мережі.
Вибір розумної мережевої проводки може зробити для вас багато роботи. Чи підходить ваше джерело даних до спеціалізованих мережевих архітектур? Конволюційні нейронні мережі можуть досягти вражаючих результатів на "структурованих" джерелах даних, зображення чи аудіоданих. Повторювані нейронні мережі можуть добре працювати з послідовними типами даних, такими як натуральна мова або дані часових рядів. Залишкові з'єднання можуть покращити глибокі мережі передачі даних.
Навчання нейронної мережі - це як вибір блокування
Щоб досягти найсучасніших, а то й просто хороших результатів, вам доведеться створити всі частини, налаштовані для того, щоб добре працювати разом . Налаштування нейромережевої конфігурації, яка насправді вчиться, дуже схоже на вибір блокування: всі частини повинні бути вишикувані прямо. Так само, як недостатньо мати єдиний тумблер у потрібному місці, також недостатньо правильно встановити лише архітектуру чи лише оптимізатор.
Налаштування варіантів конфігурації насправді не така проста, як сказати, що один тип вибору конфігурації (наприклад, швидкість навчання) є більш-менш важливим, ніж інший (наприклад, кількість одиниць), оскільки всі ці варіанти взаємодіють із усіма іншими варіантами, тому один вибір може бути добре в поєднанні з іншим вибором, зробленим в іншому місці .
Це невичерпний список параметрів конфігурації, які також не є параметрами регуляризації чи параметрами чисельної оптимізації.
Усі ці теми є активними напрямами досліджень.
Ініціалізацію мережі часто не помічають як джерело помилок нейронної мережі. Ініціалізація через занадто великий інтервал може встановити занадто велику початкову вагу, це означає, що окремі нейрони мають негативний вплив на поведінку мережі.
Ключова відмінність нейронної мережі від регресійної моделі полягає в тому, що нейронна мережа - це склад багатьох нелінійних функцій, званих функціями активації . (Див.: Яка суттєва різниця між нейронною мережею та лінійною регресією )
Результати класичної нейронної мережі орієнтовані на функції сигмоїдальної активації (логістичні або функції). Нещодавній результат показав, що блоки ReLU (або подібні), як правило, працюють краще, оскільки мають більш круті градієнти, тому оновлення можна застосовувати швидко. (Див.: Чому ми використовуємо ReLU в нейромережах і як ми їх використовуємо? ) Однією обережністю щодо ReLU є явище "мертвого нейрона", яке може стимізувати навчання; непроникна релюс та подібні варіанти уникають цієї проблеми. Побачититан
Існує ряд інших варіантів. Див.: Повний перелік функцій активації в нейронних мережах із плюсами / мінусами
Залишкові зв’язки - це акуратний розвиток, який може полегшити тренування нейронних мереж. "Глибоке залишкове навчання для розпізнавання зображень"
Каймін Хе, Сянчжу Чжан, Шаокін Рен, Цзянь Сонце В: CVPR. (2016). Крім того, зміна порядку операцій в залишковому блоці може ще більше покращити отриману мережу. " Зображення ідентичності в глибоких залишкових мережах " Каймінг Хе, Сянчжу Чжан, Шаокін Рен та Цзянь Сон.
Невипукла оптимізація важка
Об'єктивна функція нейронної мережі є лише опуклою, коли немає прихованих одиниць, всі активації є лінійними, а матриця проектування є повнорозмірною - тому що ця конфігурація ідентично є звичайною проблемою регресії.
У всіх інших випадках проблема оптимізації є невипуклою, а неконвексова оптимізація - важкою. Проблеми тренування нейронних мереж добре відомі (див.: Чому важко тренувати глибокі нейронні мережі? ). Крім того, нейронні мережі мають дуже велику кількість параметрів, що обмежує нас виключно методами першого порядку (див.: Чому метод Ньютона не широко застосовується в машинному навчанні? ). Це дуже активний напрямок досліджень.
Встановлення занадто великого рівня навчання призведе до того, що оптимізація буде розходитися, оскільки ви переходите з однієї сторони "каньйону" на іншу. Якщо встановити це занадто мало, це не дозволить вам досягти реального прогресу і, можливо, дозволить шуму, властивому SGD, перевершити ваші оцінки градієнта.
Відсікання градієнта повторно масштабує норму градієнта, якщо він перевищує деякий поріг. Раніше я вважав, що це параметр встановлення і забуття, як правило, 1,0, але я виявив, що можу зробити модель мови LSTM значно кращою, встановивши її на 0,25. Я не знаю, чому це так.
Планування швидкості навчання може знизити рівень навчання протягом курсу навчання. На мій досвід, спроба використовувати планування багато в чому схожа на регулярний вираз : він замінює одну проблему ("Як мені навчитися продовжувати після певної епохи?") На дві проблеми ("Як мені навчитися продовжувати після певної епохи" ? "та" Як вибрати хороший графік? "). Інші люди наполягають на тому, що планування є важливим. Я дам вам вирішити.
Вибір хорошого розміру міні-партії може побічно впливати на навчальний процес, оскільки більша міні-партія буде мати меншу дисперсію ( закономірність великих чисел ), ніж менша міні-партія. Ви хочете, щоб міні-пакет був достатньо великим, щоб був інформаційним про напрямок градієнта, але досить малий, щоб SGD міг регулювати вашу мережу.
Існує ряд варіантів стохастичного градієнтного спуску, які використовують імпульс, адаптивну швидкість навчання, оновлення Нестерова і так далі, щоб поліпшити ванільний SGD. Проектування кращого оптимізатора - це дуже активна область досліджень. Деякі приклади:
Коли він вперше з'явився, оптимізатор Адама викликав чималий інтерес. Але деякі останні дослідження показали, що SGD з імпульсом може випереджати адаптаційні методи градієнта для нейронних мереж. " Гранична цінність адаптивних градієнтних методів у машинному навчанні " Еся Ч. Вілсон, Ребекка Рулофс, Мітчелл Стерн, Натан Сребро, Бенджамін Рехт
Але з іншого боку, цей останній документ пропонує новий адаптивний оптимізатор швидкості навчання, який нібито зі швидкістю закриває розрив між методами адаптивного курсу та SGD. " Закриття прогалини узагальнення адаптивних градієнтних методів у навчанні глибоких нейронних мереж " Цзіньхуей Чен, Quanquan Gu
Спостерігалися адаптивні градієнтні методи, які застосовують історичну градієнтну інформацію для автоматичного регулювання швидкості навчання, щоб узагальнити гірше, ніж стохастичний градієнтний спуск (SGD) з імпульсом при навчанні глибоких нейронних мереж. Це залишає, як закрити розрив узагальнення адаптивних градієнтних методів відкритою проблемою. У цій роботі ми показуємо, що адаптаційні градієнтні методи, такі як Адам, Амсград, іноді «над адаптованими». Ми розробляємо новий алгоритм, який називається методом частково адаптивного імпульсу (Padam), який об'єднує Адама / Амсграда з SGD для досягнення найкращого з обох світів. Експерименти зі стандартними орієнтирами показують, що Padam може підтримувати швидкий рівень конвергенції як Адам / Амсград при одночасному узагальненні, а також SGD при навчанні глибоких нейронних мереж.
Нормалізація
Масштаб даних може істотно змінитись у навчанні.
Перед поданням даних у нейронну мережу стандартизація даних, що мають 0 середньої та одиничної дисперсії, або лежати в невеликому інтервалі, як може покращити навчання. Це означає попередню підготовку та знімає ефект, який має вибір в одиницях на ваги мережі. Наприклад, довжина в міліметрах і довжина в кілометрах обидва представляють одне і те ж поняття, але вони знаходяться в різних масштабах. Точні деталі стандартизації даних залежать від того, як виглядають ваші дані.[ - 0,5 , 0,5 ]
Нормалізація рівня може вдосконалити мережеву підготовку, зберігаючи середнє значення бігу та стандартне відхилення для активації нейронів. Невірно зрозуміло, чому це допомагає навчанню, і залишається активною зоною досліджень.
- " Розуміння нормалізації партії " Йохана Бьорка, Карли Гомес, Барта Сельмана
- " До теоретичного розуміння партії нормалізації " Йонас Колер, Хаді Данешманд, Ауреліен Луччі, Мін Чжоу, Клаус Неймайр, Томас Хофманн
- " Як нормалізація партії допомагає оптимізувати? (Ні, мова не йде про внутрішній коваріатний зсув) " Шибані Сантуркар, Дімітріс Ципрас, Ендрю Ільяс, Олександр Мадрі
Регуляризація
Вибір та налаштування регуляризації мережі є ключовою частиною побудови моделі, яка добре узагальнює (тобто модель, яка не є надмірною для навчальних даних). Однак, коли ваша мережа намагається зменшити втрати на навчальних даних - коли мережа не навчається - регуляризація може затьмарити, у чому полягає проблема.
Коли моя мережа не навчається, я вимикаю все регуляризацію та переконуюсь, що нерегульована мережа працює правильно. Потім я додаю кожен шматок регуляризації назад і переконуюсь, що кожен із них працює по шляху.
Ця тактика може визначити, де деяка регуляризація може бути погано встановлена. Деякі приклади є
L2Регуляризація (інакше зменшення ваги) або регуляризація встановлена занадто великою, тому ваги не можуть рухатися.L1
Дві частини регуляризації конфліктують. Наприклад, широко спостерігається, що нормалізацію шару та випадання шарів важко використовувати разом. Оскільки або самостійно дуже корисно, розуміння того, як використовувати обидва, є активною областю дослідження.
Ведіть Журнал експериментів
Коли я встановлюю нейронну мережу, я не жорстко кодую жодні параметри параметрів. Натомість я роблю це у файлі конфігурації (наприклад, JSON), який читається та використовується для заповнення деталей конфігурації мережі під час виконання. Я зберігаю всі ці файли конфігурації. Якщо я ввожу будь-яку модифікацію параметра, я створюю новий файл конфігурації. Нарешті, я додаю в коментарі всі втрати за епоху під час навчання та перевірки.
Причина, по якій я настільки нав'язлива щодо збереження старих результатів, полягає в тому, що це дозволяє дуже легко повернутися назад і переглянути попередні експерименти. Він також захищає від помилкового повторення того ж тупикового експерименту. Психологічно, це також дозволяє озирнутися назад і спостерігати «Ну, проект не може бути там , де я хочу, щоб це було сьогодні, але я роблю успіхи по порівнянні з якою я був тижнів тому.»k
Як приклад, я хотів дізнатися про мовні моделі LSTM, тому вирішив зробити бота Twitter, який пише нові твіти у відповідь на інших користувачів Twitter. Я працював над цим у вільний час, між середньою школою та моєю роботою. Минуло близько року, і я переглянув понад 150 різних моделей, перш ніж перейти до моделі, яка зробила те, що я хотіла: створити новий англомовний текст, який (свого роду) має сенс. (Одним із ключових моментів і частиною причини, що потребує такої кількості спроб, є те, що недостатньо просто отримати низьку втрату, яка не є вибіркою, оскільки ранні моделі з низькими втратами встигли запам'ятати дані тренувань, тож це було просто відтворення германних блоків тексту дослівно у відповідь на підказки - це потребувало певного налаштування, щоб зробити модель більш спонтанною та все ще мати низькі втрати.)