Spis treści[Ukryć][Pokazać]
Mózg jest porównywalny z sieciami neuronowymi. Jest to analogia, która jest zwykle używana, aby pomóc komuś nowemu w temacie zrozumieć idee uczenia maszynowego i sztucznych sieci neuronowych.
Ponieważ za kulisami zachodzi kilka warstw obliczeń matematycznych i statystycznych, zdefiniowanie tych sieci jako funkcji matematycznej jest bardziej zaawansowaną metodą.
To jest dla osób, które faktycznie interesują się uczeniem maszynowym i chcą zobaczyć, jak napisany jest kod sieci neuronowej w Pythonie.
W tym artykule pokażemy, jak zbudować od podstaw w pełni połączoną głęboką sieć neuronową (DNN) w Python 3.
Przegląd struktury plików dla naszego kodu sieci neuronowej Pythona
Tutaj zostaną utworzone trzy pliki. Pierwszym z nich jest prosty plik nn.py, który zostanie omówiony w rozdziałach „Konfigurowanie funkcji pomocniczych” i „Budowanie sieci neuronowej od podstaw”.
Będziemy mieli również plik o nazwie mnist loader.py do ładowania danych testowych, jak opisano w „Ładowanie danych MNIST”.
Na koniec otrzymamy plik o nazwie test.py, który zostanie uruchomiony w terminalu w celu przetestowania naszej sieci neuronowej.
Ten plik jest szczegółowo opisany w sekcji „Uruchamianie testów”.
Instalacja
Aby skorzystać z tego samouczka, należy pobrać bibliotekę NumPy Python. Możesz to zrobić, używając następującego polecenia na terminalu:
Importowanie modułów i konfigurowanie funkcji Helper
Jedyne dwie biblioteki, których potrzebujemy, to random i NumPy, które od razu zaimportujemy. W przypadku początkowych wag naszej sieci neuronowej przetasujemy je przy użyciu biblioteki losowej.
Aby przyspieszyć nasze obliczenia, użyjemy NumPy lub np (umownie jest to importowane jako np). Nasze dwie funkcje pomocnicze zostaną wykonane po naszym imporcie. Dwie funkcje sigmoidalne: jedna i sigmoidalna liczba pierwsza.
Regresja logistyczna klasyfikuje dane za pomocą funkcji sigmoidalnej, podczas gdy propagacja wsteczna obliczy deltę lub gradient za pomocą funkcji pierwszej sigmoidy.
Tworzenie klasy sieci
W tej sekcji skupiamy się tylko na zbudowaniu w pełni połączonej sieci neuronowej. Klasa sieci będzie obejmować wszystkie funkcje, które pojawią się później. Funkcja Object() { [kod natywny] } zostanie początkowo utworzona w naszej klasie sieciowej.
Jeden argument, rozmiary, jest wymagany przez funkcję Object() { [kod natywny] }. Zmienna size to zbiór wartości liczbowych reprezentujących liczbę węzłów wejściowych obecnych w każdej warstwie naszej sieci neuronowej.
Inicjujemy cztery właściwości w naszej metodzie __init__. Zmienne wejściowe, rozmiary, służą do ustawiania listy rozmiarów warstw i liczby warstw, odpowiednio liczba warstw.
Pierwszym krokiem jest losowe przypisanie początkowych odchyleń naszej sieci do każdej warstwy następującej po warstwie wejściowej.
Wreszcie, każde łącze między warstwami wejściową i wyjściową ma swoje wagi generowane losowo. Np.Random.Randn() daje losową próbkę pobraną z rozkładu normalnego dla kontekstu.
Funkcja podawania do przodu
W sieci neuronowej informacje są przesyłane dalej przez funkcję sprzężenia zwrotnego. Funkcja ta będzie wymagać jednego argumentu a, wskazującego bieżący wektor aktywacji.
Ta funkcja szacuje aktywacje w każdej warstwie poprzez iterację wszystkich odchyleń i wag w sieci. Odpowiedzią jest predykcja, czyli aktywacje ostatniej warstwy.
Mini-partia Gradient Descent
Wół roboczy naszej klasy Network to Gradient Descent. W tej wersji używamy mini-partii (stochastycznego) zejścia gradientowego, zmodyfikowanej odmiany zejścia gradientowego.
Oznacza to, że do aktualizacji naszego modelu zostanie użyta niewielka partia punktów danych. Do tej metody przekazywane są cztery wymagane i jeden opcjonalny argument. Cztery wymagane zmienne to zestaw danych treningowych, liczba epok, wielkość minipartii i szybkość uczenia się (eta).
Dane testowe są dostępne na żądanie. Dostarczymy dane testowe, gdy ostatecznie ocenimy tę sieć. Liczba próbek w tej funkcji jest początkowo ustawiana na długość listy po przekształceniu danych uczących w typ listy.
Ten sam proces stosujemy również do testowania danych, które są podane w. Dzieje się tak dlatego, że zamiast zwracać się do nas jako listy, są one w rzeczywistości plikami błyskawicznymi list. Gdy później załadujemy próbki danych MNIST, dowiemy się więcej na ten temat.
Jeśli możemy się upewnić, że udostępniamy oba rodzaje danych jako listy, to rzutowanie typów niekoniecznie jest niezbędne.
Gdy mamy dane, przechodzimy przez kolejne epoki treningowe w pętli. Okres uczenia to tylko jedna runda uczenia sieci neuronowych. Najpierw tasujemy dane w każdej epoce, aby zapewnić losowość przed utworzeniem listy mini-partii.
Funkcja aktualizacji miniwsadu, która jest omówiona poniżej, będzie wywoływana dla każdej miniwsadu. Dokładność testu zostanie również zwrócona, jeśli dane z testu będą dostępne.
Funkcja pomocnicza pochodnej od kosztów
Opracujmy najpierw funkcję pomocniczą zwaną pochodną kosztową, zanim naprawdę utworzymy kod wstecznej propagacji. Jeśli popełnimy błąd w naszej warstwie wyjściowej, funkcja pochodnej kosztu to pokaże.
Wymaga dwóch danych wejściowych: tablicy aktywacji wyjścia i współrzędnych y oczekiwanych wartości wyjściowych.
Funkcja propagacji wstecznej
Należy pamiętać o naszym obecnym wektorze aktywacji, aktywacji, jak również o wszelkich innych wektorach aktywacji, aktywacji i wektorach z, zs. Warstwa zwana warstwą wejściową jest aktywowana jako pierwsza.
Po ich założeniu przejdziemy w pętli przez każde nastawienie i wagę. Każda pętla obejmuje obliczenie wektora z jako iloczynu skalarnego wag i aktywacji, dodanie go do listy zs, ponowne obliczenie aktywacji i dodanie zaktualizowanej aktywacji do listy aktywacji.
Wreszcie matematyka. Delta, która jest równa błędowi z poprzedniej warstwy pomnożonemu przez sigmoidalną liczbę pierwszą ostatniego elementu wektorów zs, jest obliczana przed rozpoczęciem przejścia wstecz.
Ostatnia warstwa nabla b jest ustawiona jako delta, a ostatnia warstwa nabla w ma być iloczynem skalarnym delty i przedostatniej warstwy aktywacji (przetransponowana, abyśmy mogli właściwie policzyć) .
Postępujemy jak poprzednio, zaczynając od drugiej warstwy i kończąc na ostatniej, i powtarzamy proces po ukończeniu tych ostatnich warstw. Nabla są następnie zwracane jako krotka.
Aktualizowanie spadku gradientu mini-partii
Nasza wcześniejsza metoda SGD (stochastic gradient descent) obejmuje aktualizację mini-partii. Ponieważ jest używany w SGD, ale wymaga również podparcia, zastanawiałem się, gdzie umieścić tę funkcję.
W końcu zdecydowałem się opublikować to tutaj. Rozpoczyna się od wygenerowania 0 wektorów nablas biasów i wag, tak jak zrobiła to nasza funkcja backprop.
Wymaga mini-partii i szybkości uczenia eta jako dwóch danych wejściowych. W minipartii używamy następnie funkcji backprop, aby uzyskać deltę każdej tablicy nabla dla każdego wejścia x i wyjścia y. Listy nabla są następnie aktualizowane o te delty.
Na koniec używamy szybkości uczenia się i nabla do aktualizacji wag i odchyleń sieci. Każda wartość jest aktualizowana do najnowszej wartości, pomniejszona o szybkość uczenia się, pomnożona przez rozmiar minipartii, a następnie dodana do wartości nabla.
Oceń funkcję
Funkcja oceny jest ostatnią, którą musimy napisać. Dane testowe to jedyne dane wejściowe dla tej funkcji. W tej funkcji porównujemy tylko wyjścia sieci z oczekiwanym wynikiem y. Podając wejście, x, forward, określa się wyjścia sieci.
Kompletny kod
Kiedy połączymy cały kod, tak to wygląda.
Testowanie sieci neuronowej
Ładowanie danych MNIST
Połączenia Dane MNIST jest w formacie .pkl.gz, który otworzymy za pomocą GZIP i załadujemy za pomocą pickle. Napiszmy szybką metodę ładowania tych danych jako krotki o rozmiarze trzy, podzielonej na dane treningowe, walidacyjne i testowe.
Aby ułatwić zarządzanie naszymi danymi, napiszemy kolejną funkcję, która zakoduje y w 10-elementowej tablicy. Tablica będzie zawierać same zera z wyjątkiem jedynki, która odpowiada odpowiedniej cyfrze obrazu.
Użyjemy podstawowych danych ładowania i jednej metody gorącego kodowania, aby załadować nasze dane do czytelnego formatu. Zostanie napisana inna funkcja, która przekształci nasze wartości x na listę o rozmiarze 784, dopasowującą się do 784 pikseli obrazu, a nasze wartości y na ich pojedynczą, zakodowaną na gorąco formę wektorową.
Następnie połączymy wartości x i y tak, aby jeden indeks pasował do drugiego. Dotyczy to zestawów danych uczących, walidacyjnych i testowych. Następnie zwracamy zmienione dane.
Uruchomione testy
Utworzymy nowy plik o nazwie „mnist loader”, który zaimportuje zarówno sieć neuronową, którą założyliśmy wcześniej (proste nn), jak i program ładujący zestawy danych MNIST przed rozpoczęciem testów.
W tym pliku wszystko, co musimy zrobić, to zaimportować dane, zbudować sieć o rozmiarze warstwy wejściowej 784 i warstwie wyjściowej o rozmiarze 10, uruchomić funkcję sieciową SGD na danych uczących, a następnie przetestować ją przy użyciu danych testowych.
Należy pamiętać, że dla naszej listy warstw wejściowych nie ma znaczenia, jakakolwiek z liczb znajduje się między 784 a 10. Możemy zmienić inne warstwy w dowolny sposób; tylko rozmiary wejściowe i wyjściowe są stałe.
Trzy warstwy nie są konieczne; możemy użyć czterech, pięciu, a nawet tylko dwóch. Baw się z nim eksperymentując.
Wnioski
Tutaj za pomocą Pythona 3 tworzymy sieć neuronową od podstaw. Wraz z matematyką na wysokim poziomie omówiliśmy również specyfikę implementacji.
Zaczęliśmy od implementacji funkcji pomocniczych. Aby neurony działały, podstawowe funkcje esicy i esicy są kluczowe. Następnie stosujemy w praktyce funkcję feedforward, która jest podstawowym procesem dostarczania danych do sieci neuronowej.
Następnie stworzyliśmy funkcję spadku gradientu w Pythonie, silniku, który napędza naszą sieć neuronową. Aby zlokalizować „lokalne minima” i zoptymalizować ich wagi i odchylenia, nasza sieć neuronowa wykorzystuje opadanie gradientu. Stworzyliśmy funkcję propagacji wstecznej za pomocą opadanie gradientu.
Dzięki dostarczaniu aktualizacji, gdy dane wyjściowe nie pasują do właściwych etykiet, funkcja ta umożliwia sieci neuronowej „uczenie się”.
Na koniec umieściliśmy naszego zupełnie nowego Pythona sieci neuronowe do testu przy użyciu zestawu danych MNIST. Wszystko działało sprawnie.
Miłego kodowania!
Dodaj komentarz