Зміст[Сховати][Показати]
Мозок можна порівняти з нейронними мережами. Це аналогія, яка зазвичай використовується, щоб допомогти новачкам зрозуміти ідею машинного навчання та штучних нейронних мереж.
Оскільки існує кілька рівнів математичних і статистичних обчислень, що відбуваються за лаштунками, визначення цих мереж як математичної функції є більш просунутим методом.
Це для людей, які справді цікавляться машинним навчанням і хочуть побачити, як пишеться код нейронної мережі Python.
У цій статті ми продемонструємо, як побудувати повноцінну глибоку нейронну мережу (DNN) з нуля в Python 3.
Огляд файлової структури для нашого коду нейронної мережі Python
Тут буде створено три файли. Перший — це простий файл nn.py, який буде розглянуто в розділах «Налаштування допоміжних функцій» і «Створення нейронної мережі з нуля».
У нас також буде файл під назвою mnist loader.py для завантаження тестових даних, як описано в розділі «Завантаження даних MNIST».
Нарешті, у нас буде файл під назвою test.py, який буде запущено в терміналі для тестування нашої нейронної мережі.
Цей файл детально описано в розділі «Виконання тестів».
установка
Бібліотеку NumPy Python потрібно завантажити, щоб слідувати цьому посібнику. Це можна зробити за допомогою такої команди на терміналі:
Імпорт модулів і налаштування функції Helper
Єдині дві бібліотеки, які нам потрібні, це random і NumPy, які ми негайно імпортуємо. Для початкових ваг нашої нейронної мережі ми перетасуємо їх за допомогою випадкової бібліотеки.
Щоб пришвидшити наші обчислення, ми будемо використовувати NumPy або np (за домовленістю його часто імпортують як np). Наші дві допоміжні функції будуть створені після нашого імпорту. Дві сигмоїдні функції: один і сигмоїдний штрих.
Логістична регресія класифікує дані за допомогою сигмоїдної функції, тоді як зворотне поширення обчислить дельту або градієнт за допомогою сигмоїдної простої функції.
Створення мережевого класу
Побудова повністю пов’язаної нейронної мережі є єдиною темою цього розділу. Клас мережі охоплюватиме всі наступні функції. Функція Object() { [власний код] } буде спочатку створена в нашому мережевому класі.
Для функції Object() { [власний код] } потрібен один аргумент — sizes. Змінна sizes — це набір числових значень, які представляють кількість вхідних вузлів, присутніх на кожному рівні нашої нейронної мережі.
Ми ініціалізуємо чотири властивості в нашому методі __init__. Вхідні змінні sizes використовуються для встановлення списку розмірів шарів і кількості шарів num layers відповідно.
Першим кроком є випадкове призначення початкових зміщень нашої мережі кожному шару, який слідує за вхідним шаром.
Нарешті, кожен зв’язок між вхідним і вихідним шарами має випадково згенеровані ваги. Np.Random.Randn() дає випадкову вибірку, взяту з нормального розподілу для контексту.
Функція подачі вперед
У нейронній мережі інформація передається за допомогою функції прямого передавання. Для цієї функції буде потрібний один аргумент a, що вказує на поточний вектор активації.
Ця функція оцінює активації на кожному рівні шляхом повторення всіх зміщень і ваги в мережі. Надана відповідь є прогнозом, який є активацією останнього шару.
Міні-серія Градієнтний спуск
Робоча конячка нашого мережевого класу — градієнтний спуск. У цій версії ми використовуємо міні-пакетний (стохастичний) градієнтний спуск, модифікований варіант градієнтного спуску.
Це означає, що для оновлення нашої моделі буде використано невелику партію точок даних. Чотири обов'язкових і один необов'язковий аргумент передаються цьому методу. Чотири необхідні змінні – це набір навчальних даних, кількість епох, розмір міні-серій і швидкість навчання (eta).
Тестові дані доступні за запитом. Ми надамо тестові дані, коли зрештою оцінимо цю мережу. Кількість зразків у цій функції спочатку встановлюється відповідно до довжини списку після того, як навчальні дані перетворено на тип списку.
Ми також застосовуємо той самий процес, щоб перевірити надіслані дані. Це тому, що замість списків вони повертаються нам, а насправді є копіями списків. Коли ми пізніше завантажимо зразки даних MNIST, ми дізнаємося про це більше.
Якщо ми можемо переконатися, що надаємо обидва типи даних у вигляді списків, то це приведення типів не обов’язково є необхідним.
Отримавши дані, ми циклічно переглядаємо епохи навчання. Період навчання — це лише один раунд навчання нейронної мережі. Ми спочатку перемішуємо дані в кожній епосі, щоб забезпечити випадковість, перш ніж складати список міні-серій.
Функція оновлення міні-пакета, про яку йдеться нижче, буде викликана для кожного міні-пакета. Точність тесту також буде повернено, якщо дані тесту доступні.
Допоміжна функція похідної вартості
Давайте спочатку розробимо допоміжну функцію, яка називається похідною від вартості, перш ніж ми справді створимо код зворотного поширення. Якщо ми припустимося помилки на нашому вихідному рівні, функція похідної вартості покаже це.
Для цього потрібні два входи: масив вихідних активацій і координати y очікуваних вихідних значень.
Функція зворотного поширення
Наш поточний вектор активації, активація, а також будь-які інші вектори активації, активації та z-вектори, zs, повинні мати на увазі. Першим активується шар, який називається вхідним.
Ми проглянемо кожне зміщення та вагу після їх розміщення. Кожен цикл передбачає обчислення вектора z як скалярного добутку вагових коефіцієнтів і активації, додавання його до списку zs, перерахунок активації та додавання оновленої активації до списку активацій.
Нарешті, математика. Дельта, яка дорівнює похибці попереднього шару, помноженій на сигмоподібний штрих останнього елемента векторів zs, обчислюється перед початком нашого зворотного проходу.
Останній шар nabla b встановлюється як дельта, а останній шар nabla w встановлюється як скалярний добуток дельти та передостаннього рівня активацій (транспонованих, щоб ми могли фактично зробити математику) .
Ми продовжуємо, як і раніше, починаючи з другого шару і закінчуючи останнім, і повторюємо процес після завершення цих останніх шарів. Набла потім повертаються як кортеж.
Оновлення міні-пакетного градієнтного спуску
Наш попередній метод SGD (стохастичний градієнтний спуск) включає міні-пакетне оновлення. Оскільки вона використовується в SGD, але також вимагає підтримки, я обмірковував, де розмістити цю функцію.
Нарешті я вирішив опублікувати це тут. Він починається з генерації 0 векторів набла зміщень і ваг, як це робила наша функція backprop.
Для цього потрібні міні-пакет і швидкість навчання eta як два входи. Потім у міні-пакеті ми використовуємо функцію backprop, щоб отримати дельту кожного масиву nabla для кожного входу x і виходу y. Потім списки nabla оновлюються цими дельтами.
Нарешті, ми використовуємо швидкість навчання та nablas, щоб оновити вагові коефіцієнти та зміщення мережі. Кожне значення оновлюється до останнього значення, за вирахуванням швидкості навчання, помноженого на розмір міні-пакета, а потім додається до значення nabla.
Оцініть функцію
Функція evaluate є останньою, яку нам потрібно написати. Тестові дані є єдиним входом для цієї функції. У цій функції ми лише порівнюємо вихідні дані мережі з очікуваним результатом, y. Подаючи вхід x вперед, визначаються виходи мережі.
Повний код
Коли ми об’єднуємо весь код, він виглядає ось як.
Тестування нейронної мережі
Завантаження даних MNIST
Команда дані MNIST має формат .pkl.gz, який ми відкриємо за допомогою GZIP і завантажимо за допомогою pickle. Давайте напишемо швидкий метод завантаження цих даних у вигляді кортежу розміром три, розділених на дані навчання, перевірки та тестування.
Щоб полегшити керування нашими даними, ми напишемо ще одну функцію для кодування y у масив із 10 елементів. У масиві будуть усі 0, за винятком 1, який відповідає правильній цифрі зображення.
Ми використаємо базові дані завантаження та один метод гарячого кодування, щоб завантажити наші дані у читабельний формат. Буде написана інша функція, яка перетворюватиме наші значення x у список розміром 784, що відповідає 784 пікселям зображення, а наші значення y — у їх єдину гарячу закодовану векторну форму.
Потім ми об’єднаємо значення x і y так, щоб один індекс відповідав іншому. Це стосується наборів даних для навчання, перевірки та тестування. Потім ми повертаємо змінені дані.
Запуск тестів
Ми створимо новий файл під назвою «mnist loader», який імпортуватиме як нейронну мережу, яку ми створили раніше (простий nn), так і завантажувач набору даних MNIST, перш ніж ми почнемо тестування.
У цьому файлі все, що нам потрібно зробити, це імпортувати дані, побудувати мережу з розміром вхідного рівня 784 і розміром вихідного рівня 10, запустити мережеву функцію SGD на навчальних даних, а потім протестувати її за допомогою тестових даних.
Майте на увазі, що для нашого списку вхідних шарів немає різниці, які числа знаходяться між 784 і 10. Ми можемо змінювати інші шари як завгодно; лише вхідні та вихідні розміри фіксовані.
Три шари не потрібні; ми можемо використовувати чотири, п’ять або навіть два. Весело експериментуйте з цим.
Висновок
Тут, використовуючи Python 3, ми створюємо нейронну мережу з нуля. Разом з математикою високого рівня ми обговорили і особливості реалізації.
Ми почали з впровадження допоміжних функцій. Для того, щоб нейрони працювали, функції сигмовидної та сигмовидної первинної є вирішальними. Потім ми застосували на практиці функцію прямого передавання даних, яка є основним процесом передачі даних у нейронну мережу.
Потім ми створили функцію градієнтного спуску в Python, механізмі, який керує нашою нейронною мережею. Щоб знайти «локальні мінімуми» та оптимізувати їх ваги та зміщення, наша нейронна мережа використовує градієнтний спуск. Ми створили функцію зворотного поширення за допомогою градієнтний спуск.
Надаючи оновлення, коли вихідні дані не відповідають належним міткам, ця функція дозволяє нейронній мережі «навчатися».
Нарешті ми поставили наш абсолютно новий Python нейронної мережі до тесту з використанням набору даних MNIST. Все працювало без проблем.
Щасливе кодування!
залишити коментар