Przedmowa
Zrozumieć głębokie uczenie jest owocem trzech lat wysiłków. Aby powstała książka, którą masz w ręku, napisałem co najmniej dwa razy więcej stron niż tu widoczne. Kilka rozdziałów zostało trzy lub cztery razy ponownie napisanych od nowa, zanim nadawały się do publikacji, po drodze zaś dodałem ważne rozdziały, które nie były częścią oryginalnego planu.
Co ważniejsze, wcześniej podjąłem dwie decyzje, które powinny zapewnić unikatową wartość książki: nie jest wymagane przygotowanie matematyczne wykraczające poza podstawową arytmetyką i nie opieram się na bibliotekach wysokiego poziomu, które mogłyby ukryć to, co naprawdę się dzieje. Innymi słowy, każdy może przeczytać tę książkę i zrozumieć, jak naprawdę działa głębokie uczenie. Aby to osiągnąć, musiałem wynaleźć nowe sposoby opisywania i wykładania podstawowych idei i technik bez zwracania się do zaawansowanej matematyki lub wyrafinowanego kodu napisanego przez kogoś innego.
Moim celem przy pisaniu Zrozumieć głębokie uczenie było ustawienie jak najniżej progu prowadzącego do praktykowania głębokiego uczenia. Nie będziesz po prostu poznawał teorii; będziesz odkrywać ją samodzielnie. Aby w tym pomóc, napisałem mnóstwo kodu i zrobiłem co w mojej mocy, aby wyjaśniać go we właściwej kolejności, tak by każdy fragment kodu potrzebnego dla działających demonstracji miał sens.
Ta wiedza, połączona z całą teorią, kodem i przykładami, które będziesz poznawać w tej książce, sprawi, że znacznie szybciej będziesz mógł przechodzić przez kolejne eksperymenty. Szybciej będziesz osiągać sukcesy i uzyskasz większe możliwości pracy, i w lepszym tempie poznasz nawet najbardziej zaawansowane koncepcje głębokiego uczenia.
W ciągu tych trzech lat nie tylko napisałem tę książkę, lecz także rozpocząłem studia doktoranckie na Oxfordzie, dołączyłem do zespołu Google'a i pomagałem szlifować narzędzia OpenMined, zdecentralizowanej platformy sztucznej inteligencji. Książka ta jest kulminacją trzech lat przemyśleń, uczenia się i wykładania.
Istnieje wiele innych źródeł, z których można uczyć się głębokiego uczenia. Cieszę się, że sięgnąłeś właśnie po to.
Podziękowania
Jestem niezmiernie wdzięczny wszystkim, którzy przyczynili się do powstania tej książki. Po pierwsze i przede wszystkim chcę podziękować wspaniałemu zespołowi wydawnictwa Manning. Są to: Bert Bates, który uczył mnie, jak pisać; Christina Taylor, która cierpliwie podtrzymywała mnie w pracy przez trzy lata; Michael Stephens, którego kreatywność pozwoliła książce odnieść sukces jeszcze przed opublikowaniem; oraz Marjan Bace, którego wsparcie pośród opóźnień wszystko zmieniło.
Zrozumieć głębokie uczenie nie byłoby tym, czym jest bez ogromnego udziału pierwszych Czytelników, których uwagi docierały do mnie e-mailem, na Twitterze i GitHubie. Jascha Swisher, Varun Sudhakar, Francois Chollet, Frederico Vitorino, Cody Hammond, Mauricio Maroto Arrieta, Aleksandar Dragosavljevic, Alan Carter, Frank Hinek, Nicolas Benjamin Hocker, Hank Meisse, Wouter Hibma, Joerg Rosenkranz, Alex Vieira i Charlie Harrington - mam ogromny dług wdzięczności względem was wszystkich za pomoc w dopieszczeniu tekstu i repozytorium kodu.
Chciałbym podziękować recenzentom, którzy poświęcali czas na czytanie rękopisu w różnych fazach jego powstawania: Alexander A. Myltsev, Amit Lamba, Anand Saha, Andrew Hamor, Cristian Barrientos, Montoya, Eremey Valetov, Gerald Mack, Ian Stirk, Kalyan Reddy, Kamal Raj, Kelvin D. Meeks, Marco Paulo dos Santos Nogueira, Martin Beer, Massimo Ilario, Nancy W. Grady, Peter Hampton, Sebastian Maldonado, Shashank Gupta, Tymoteusz Wołodźko, Kumar Unnikrishnan, Vipul Gupta, Will Fuger i William Wheeler.
Jestem też wdzięczny Matowi i Nikowi z Udacity, którzy dołączyli tę książkę do kursu Deep Learning Nanodegree, co bardzo pomogło we wczesnym dostrzeżeniu jej przez młodych praktyków głębokiego uczenia.
Muszę podziękować doktorowi Williamowi Hooperowi, który pozwolił mi wtargnąć do swego biura i zawracać głowę problemami informatycznymi, zrobił wyjątek, aby dołączyć mnie do (już pełnej) grupy Programming 1 i zainspirował mnie do wybrania ścieżki głębokiego uczenia. Jestem ogromnie wdzięczny za cierpliwość okazaną mi w moich początkach.
Na koniec chcę podziękować mojej żonie za cierpliwość okazaną w tych wszystkich nocach i weekendach, które spędzałem pracując nad książką, za wielokrotne korekty całego tekstu i za utworzenie i debugowanie repozytorium kodu na GitHubie.
O tej książce
Napisałem Zrozumieć głębokie uczenie, aby dać Czytelnikowi podstawy wiedzy pozwalającej na korzystanie z głównych platform głębokiego uczenia. Rozpoczniemy od podstaw sieci neuronowych, po czym przejdziemy do poznawania zaawansowanych warstw i architektur.
Kto powinien przeczytać tę książkę
Celowo napisałem ją w taki sposób, aby możliwie nisko ustawić próg wejściowy. Nie zakładam żadnej wiedzy na temat algebry liniowej, rachunku różniczkowego, optymalizacji funkcji wypukłych ani nawet samego uczenia się maszyn1. Wszystkie należące do tych tematów zagadnienia, które są niezbędne do zrozumienia głębokiego uczenia, zostaną wyjaśnione w trakcie wykładu. Jeśli ktoś opanował matematykę na poziomie licealnym i nieco kodował w Pythonie, jest gotowy do lektury tej książki.
Plan pracy
Książka zawiera 16 rozdziałów:
Rozdział 1 skupia się na tym, dlaczego warto poznać głębokie uczenie i co jest potrzebne, aby zacząć. Rozdział 2 zaczyna się od przeglądu fundamentalnych idei, takich jak uczenie się maszyn, modele parametryczne i nieparametryczne oraz nadzorowane i nienadzorowane uczenie się. Wprowadzimy w nim również paradygmat "przewidywanie, porównanie, nauka", który będzie stale wykorzystywany w kolejnych rozdziałach. Rozdział 3 poprowadzi Czytelnika przez wykorzystanie prostych sieci do tworzenia przewidywań, a także zapewni pierwszy wgląd w sieć neuronową. W rozdziale 4 nauczymy się, jak oceniać przewidywania wykonywane w rozdziale 3 i identyfikować błędy, pomagające w uczeniu modeli w kolejnym kroku. Rozdział 5 koncentruje się na części nauki paradygmatu "przewidywanie, porównanie, nauka". Rozdział ten pokazuje proces uczenia się na pogłębionym przykładzie. W rozdziale 6 zbudujemy naszą pierwszą "głęboką" sieć neuronową, jej kod i wszystko poza tym. Rozdział 7 przedstawia ogólny widok sieci neuronowej i jej działania w celu uproszczenia wyobrażeń. Rozdział 8 wprowadza pojęcia przeuczenia, wykluczania oraz miniwsadowej metody gradientowej i pokazuje, jak klasyfikować zbiór danych w nowej, dopiero co zbudowanej sieci. Rozdział 9 przedstawia funkcje aktywacji i ich stosowanie przy modelowaniu prawdopodobieństw. W rozdziale 10 wprowadzimy konwolucyjne sieci neuronowe, podkreślając użyteczność struktury do przeciwdziałania przeuczeniu. Rozdział 11 stanowi wprowadzenie do przetwarzania języka naturalnego (
natural language processing - NLP) i przedstawia podstawowe pojęcia oraz koncepcje z dziedziny głębokiego uczenia. W rozdziale 12 omówimy rekurencyjne sieci neuronowe, nowoczesne podejście stosowane w niemal każdym obszarze modelowania sekwencji, będące jednym z najbardziej popularnych narzędzi używanych w branży. Rozdział 13 jest szybkim wprowadzeniem do budowania od zera platformy głębokiego uczenia się, aby stać się zaawansowanym użytkownikiem platform głębokiego uczenia. W rozdziale 14 wykorzystamy naszą rekurencyjną sieć neuronową, aby zmierzyć się z bardziej wymagającym zadaniem: modelowaniem języka. Rozdział 15 skupia się na zagadnieniu prywatności w danych, wprowadzając podstawowe koncepcje zachowania prywatności, takie jak sfederowane uczenie się, szyfrowanie homomorficzne i idee powiązane z prywatnością różnicową i bezpiecznym przetwarzaniem wielopodmiotowym. Rozdział 16 przedstawia narzędzia i zasoby, które są potrzebne na dalszej drodze nauki głębokiego uczenia.
Konwencje kodu i pobieranie
Wszystkie przykłady kodu w książce zostały złożone czcionką stałopozycyjną, taką jak tutaj, aby oddzielić je od zwykłego tekstu. Niektóre listingi są opatrzone komentarzami, wyróżniającymi ważne koncepcje.
Całość kodu przykładów z tej książki można pobrać z witryny internetowej wydawcy pod adresem www.manning.com/books/grokking-deep-learning albo z repozytorium GitHub: https://github.com/iamtrask/grokking-deep-learning.
Zapraszamy do grokowania głębokiego uczenia
Za chwilę zaczniesz zdobywać jedną z najcenniejszych umiejętności w tym stuleciu!
Tak się cieszę, że jesteś tutaj! Ty też powinieneś! Deep learning (głębokie uczenie się) jest fascynującym połączeniem uczenia się maszyn i sztucznej inteligencji i stanowi bardzo znaczący przełom dla społeczeństwa i gospodarki. Metody omówione w tej książce zmieniają cały otaczający nas świat. Dotyczą wszystkiego, od optymalizowania silnika samochodu po decydowanie, jakie treści zobaczysz w mediach społecznościowych - są wszędzie, są potężne i, na szczęście, sprawiają frajdę!
Dlaczego warto opanować głębokie uczenie się
Jest skutecznym narzędziem stopniowego automatyzowania inteligencji.
Od samych początków ludzie budowali coraz lepsze i lepsze narzędzia, aby zrozumieć i kontrolować otaczające nas środowisko. Głębokie uczenie się to bieżący rozdział tej historii innowacji.
Tym, co sprawia, że ten właśnie rozdział jest tak pociągający, zapewne jest to, że mamy do czynienia raczej z innowacją mentalną niż mechaniczną. Podobnie jak w siostrzanych obszarach uczenia się maszyn, uczenie głębokie szuka sposobów automatyzowania inteligencji kawałek po kawałku. W ciągu kilku ostatnich lat osiągnięto niebywałe sukcesy i postęp w tym dążeniu, znacznie przekraczające wcześniejsze osiągnięcia w dziedzinie rozpoznawania obrazów, mowy, tłumaczenia mechanicznego i wielu innych zadań.
Jest to szczególnie zaskakujące, jeśli wziąć pod uwagę, że uczenie głębokie wydaje się używać zasadniczo tego samego algorytmu inspirowanego mózgiem (czyli sieci neuronowych) do realizacji tych osiągnięć w bardzo wielu obszarach. Mimo że głębokie uczenie się nadal jest dziedziną w trakcie aktywnego rozwoju z wieloma wyzwaniami, ostatnie osiągnięcia doprowadziły do wielkiej ekscytacji: być może to, co odkryliśmy, nie jest po prostu świetnym narzędziem, ale oknem do naszych własnych umysłów.
Głębokie uczenie się ma potencjał znaczącej automatyzacji wykwalifikowanej pracy.
Mamy do czynienia ze znaczącym szumem informacyjnym, jeśli chodzi o potencjalny wpływ głębokiego uczenia się, jeśli próbuje się ekstrapolować bieżący trend postępów z różnymi prędkościami. Choć wiele z tych prognoz jest przesadzonych, wierzę, że przynajmniej jedna zasługuje na szczególną uwagę: przesunięcie miejsc pracy. Sądzę, że ta teza wyróżnia się spośród reszty, gdyż nawet gdyby innowacje związane z głębokim uczeniem się zostały dziś zatrzymane, wywołały już niebywały wpływ na wykwalifikowanych pracowników na całym świecie. Operatorzy call center, taksówkarze czy niskopoziomowi analitycy biznesowi - wszystko to są przekonujące przykłady branż, w których głębokie uczenie może stanowić tańszą alternatywę.
Szczęśliwie gospodarka nie zmienia się z dnia na dzień; jednak pod wieloma względami minęliśmy już punkt krytyczny, biorąc pod uwagę bieżącą siłę technologii. Mam nadzieję, że ta książka pozwoli Tobie, mój Czytelniku (i ludziom, których znasz) przygotować się do przejścia z jednej z tych branż, które znikną do branży, przed którą stoi rozwój i dobrobyt: głębokiego uczenia.
Jest to zabawne i twórcze. Możemy zrozumieć, co to znaczy być człowiekiem, próbując zasymulować inteligencję i kreatywność.
Osobiście zająłem się głębokim uczeniem, gdyż jest to fascynujące. Jest to zadziwiające skrzyżowanie między człowiekiem a maszyną. Dokładne rozgryzanie, co to znaczy myśleć, rozumować i tworzyć jest oświecające, angażujące i - przynajmniej dla mnie - inspirujące. Wyobraźmy sobie, że mamy zbiór danych wypełniony wszystkimi namalowanymi kiedykolwiek obrazami i możemy go użyć, aby nauczyć maszynę, jak malować podobnie do Moneta. Choć brzmi to jak szaleństwo, jest to możliwe i fantastyczne będzie zobaczyć, jak to działa.
Czy trudno będzie się tego nauczyć?
Jak ciężko trzeba będzie popracować, zanim pojawi się "frajda"?
To moje ulubione pytanie. Moja definicja "frajdy" z nauki to doświadczenie obserwowania, jak coś, co zbudowałem, się uczy. Jest coś fascynującego w przyglądaniu się, jak dzieło naszych rąk robi coś takiego. Jeśli odczuwasz podobnie, wówczas odpowiedź jest prosta. Za kilka stron, w rozdziale 3 zbudujemy swoją pierwszą sieć neuronową. Jedyną pracą, jaką trzeba będzie wykonać do tego momentu, będzie (uważne!) przeczytanie stron zawartych między tym a tamtym miejscem.
Po rozdziale 3 kolejnym punktem, w którym powinna pojawić się frajda, będzie moment, gdy utrwalisz sobie w pamięci niewielki fragment kodu i dotrzesz w lekturze do połowy rozdziału 4. Każdy kolejny rozdział będzie działać w ten sposób: zapamiętanie małego segmentu kodu z poprzedniego rozdziału, przeczytanie kolejnego i doświadczenie satysfakcji ze stworzenia nowej, uczącej się sieci neuronowej.
Dlaczego powinieneś przeczytać tę książkę
Próg wejściowy jest wyjątkowo niski.
Powód, dla którego powinieneś przeczytać tę książkę, jest tym samym powodem, dla którego ją napisałem. Nie znam żadnego innego źródła (książki, wykładu, serii artykułów na blogu), które przedstawiałoby głębokie uczenie bez zakładania zaawansowanej wiedzy matematycznej (co najmniej na poziomie wyższej uczelni).
Nie należy źle mnie rozumieć: istnieje wiele naprawdę dobrych powodów, aby użyć matematyki do wykładania tego zagadnienia. Matematyka jest, pomijając wszystko inne, językiem. Nauczanie głębokiego uczenia przy użyciu tego języka zdecydowanie będzie bardziej wydajne, ale nie wydaje mi się, aby niezbędnie konieczne było zakładanie znajomości zaawansowanej matematyki, aby zostać sprawnym, rozumiejącym praktykiem, który dobrze pojmuje wszystkie how-to kryjące się za głębokim uczeniem się.
Zatem dlaczego powinieneś poznawać to zagadnienie przy użyciu tej książki? Ponieważ zakładam, że moi czytelnicy mają podstawy matematyczne na poziomie szkoły średniej (i to mocno zardzewiałe) i wyjaśniam wszystko inne, co będzie potrzebne, w trakcie wykładu. Pamiętasz, czym jest mnożenie? Pamiętasz wykresy na płaszczyźnie x-y (te kwadraty z liniami na nich)? Świetnie! Poradzisz sobie.
Pomoże zrozumieć, co kryje się wewnątrz platformy (Torch, TensorFlow i tak dalej).
Istnieją dwa główne rodzaje materiałów edukacyjnych dotyczących uczenia głębokiego (takich jak książki i wykłady). Jedna grupa skupia się na wykorzystaniu popularnych platform i bibliotek kodu, takich jak Torch, TensorFlow, Keras i inne. Druga grupa koncentruje się na poznawaniu samego uczenia głębokiego, czyli na wiedzy leżącej w tle tych głównych platform. Bez wątpienia poznanie obydwu jest ważne. Można to porównać do pragnienia zostania kierowcą NASCAR: konieczne jest poznanie zarówno konkretnego modelu samochodu, który będziemy prowadzić (platformy), jak i kierowania nim (wiedzy/umiejętności). Jednak nauka samej platformy byłaby podobna do poznawania zalet i wad modelu Chevrolet SS 6 generacji, zanim dowiemy się, czym jest drążek zmiany biegów. Ta książka zajmuje się tym, czym jest głębokie uczenie, tak by przygotować się do poznawania platformy.
Wszystkie treści powiązane z matematyką zostaną uzupełnione intuicyjnymi analogiami.
Ilekroć napotykam jakiś wzór matematyczny, przyjmuję dwustopniowe podejście. Pierwszym jest przetłumaczenie jego działania na intuicyjną analogię ze świata rzeczywistego. Niemal nigdy nie traktuję wzoru jako nominalnej wartości: rozbijam go na części i do każdej z nich dodaję jej własną historię. Takie też podejście zastosowałem w tej książce. Ilekroć natrafimy na jakąś koncepcję matematyczną, zaproponuję alternatywną analogię wyjaśniającą, co dany wzór w istocie robi.
Wszystko powinno się konstruować w sposób możliwie najprostszy, ale nie uproszczony. przypisywane Albertowi Einsteinowi
Wszystko po wprowadzających rozdziałach opiera się na "projektach".
Jeśli jest coś, czego naprawdę nie znoszę, gdy uczę się czegoś nowego, to konieczność zadania sobie pytania, czy to, czego się uczę, jest przydatne lub istotne. Gdyby ktoś wykładał mi wszystko, co można się dowiedzieć o młotkach, ale bez włożenia mi go do ręki i pokazania, jak wbić gwóźdź, w istocie nie nauczyłby mnie, jak używać młotka. Wiem, że pojawią się takie punkty, które nie wiążą się ze sobą i gdybym znalazł się nagle w prawdziwym świecie z młotkiem, pudełkiem gwoździ i stertą desek, musiałbym domyśleć się wielu rzeczy.
W tej książce daję Ci drewno, gwoździe i młotek, zanim zacznę opowiadać, co każde z nich ma robić. Każdy wykład polega na wybraniu konkretnych narzędzi i użyciu ich do zbudowania czegoś, wyjaśniając po drodze, jak to wszystko działa. W ten sposób na koniec nie będziesz miał jedynie listy faktów o różnych narzędziach, których możesz użyć; będzie miał umiejętność użycia ich do rozwiązywania problemów. Co więcej, zrozumiesz najważniejszą część: kiedy i dlaczego poszczególne narzędzia są właściwym wyborem dla każdego problemu, który trzeba rozwiązać. To właśnie ta wiedza umożliwi Ci kontynuację kariery w badaniach lub w praktycznych zastosowaniach.
Co jest potrzebne, aby zacząć
Zainstalowanie Jupyter Notebook oraz biblioteki NumPy języka Python.
Moim zdecydowanie preferowanym miejscem pracy jest środowisko Jupyter Notebook. Jedną z najważniejszych części nauki głębokiego uczenia (przynajmniej dla mnie) jest zdolność do zatrzymania działania sieci w trakcie uczenia i rozłożenie jej na części składowe, aby dowiedzieć się, jak to wygląda. Jupyter Notebook3 jest szczególnie przydatny do takiego działania.
Co do biblioteki NumPy, zapewne najbardziej pociągającą rzeczą w tej książce jest to, że będziemy używać tylko jednej biblioteki macierzowej, niczego nie pozostawiając odłogiem. W ten sposób zrozumiesz, jak wszystko działa, zamiast jedynie nauczyć się, jak wywoływać platformę. W tej książce wykładam głębokie uczenie od zera, od początku do końca.
Instrukcje instalacyjne dla tych dwóch narzędzi można znaleźć odpowiednio pod adresami http://jupyter.org dla Jupytera oraz http://numpy.org dla NumPy. Przykłady przedstawione w książce zostały zbudowane w wersji Python 2.7, ale przetestowałem je również dla wersji Python 3. Dla uproszczenia instalacji rekomenduję też użycie platformy Anaconda: https://docs.continuum.io/anaconda/install.
Matematyka na poziomie szkoły średniej.
Niektóre założenia matematyczne wykraczają poza zakres tej książki, ale moim celem jest przedstawienie wykładu głębokiego uczenia przy założeniu, że znasz tylko podstawy algebry.
Problem, którym jesteś osobiście zainteresowany.
Może się to wydawać opcjonalną "potrzebą", aby chcieć zacząć naukę. I zapewne tak może być, ale mówiąc poważnie, zdecydowanie warto znaleźć sobie taki problem. Każdy, kogo znam, a kto odniósł sukces w tej dziedzinie, miał jakiś własny problem, który próbował rozwiązać. Studiowanie głębokiego uczenia było po prostu "wymaganiem" dla poradzenia sobie z jakimś innym, interesującym zdaniem.
W moim przypadku próbowałem użyć Twittera do przewidywania kursów giełdowych. Było to po prostu coś, co wydawało mi się naprawdę ciekawe. To właśnie skłaniało mnie, aby siąść i przeczytać kolejny rozdział, a następnie budować kolejny prototyp.
Jak będzie można się przekonać, ta dziedzina jest tak nowa i zmienia się tak szybko, że jeśli ktoś spędzi następnych parę lat, cyzelując jeden projekt przy użyciu tych narzędzi, szybciej niż można się spodziewać stanie się jednym z wiodących ekspertów w tej konkretnej dziedzinie. W moim przypadku dopracowywanie mojej idei doprowadziło mnie ze stanu, gdy ledwo coś wiedziałem o programowaniu, do uzyskania grantu badawczego z funduszu hedgingowego na wykorzystanie tego, czego się nauczyłem - wszystko w około 18 miesięcy! W przypadku głębokiego uczenia posiadanie fascynującego problemu, który wiąże się z użyciem jednego zbioru danych w celu przewidzenia innego jest kluczowym katalizatorem! Warto znaleźć coś takiego!
Zapewne potrzebna jest jakaś znajomość Pythona
Python jest moim ulubionym narzędziem nauki, ale przedstawię również kilka innych.
Python jest niebywale intuicyjnym językiem. Jak sądzę, może być najszerzej stosowanym i najbardziej czytelnym językiem spośród dotąd skonstruowanych. Co więcej, społeczność Pythona ma skłonność do prostoty, której nie da się pokonać. Z tych powodów zamierzam trzymać się Pythona we wszystkich przykładach (pracuję w wersji Python 2.7). W dostępnym do pobrania kodzie źródłowym dla tej książki pod adresami: www.manning.com/books/grokking-deep-learning oraz https://github.com/iamtrask/Grokking-Deep-Learning, dołączam również wersje wszystkich przykładów dla kilku innych języków.
Jak duże doświadczenie w programowaniu jest potrzebne?
Warto przejrzeć kurs Python Codecademy (www.codecademy.com/learn/python). Jeśli potrafisz ze zrozumieniem przeczytać spis treści i nie odstraszają cię wymienione tam pojęcia, to wystarczy!
Jeśli nie, po prostu przejdź ten kurs i wróć, gdy go ukończysz. Został on zaprojektowany jako kurs dla początkujących i doskonale skonstruowany.
Podsumowanie
Jeśli masz już pod ręką notatnik Jupyter i czujesz się swobodnie w podstawach języka Python, możesz przejść do kolejnego rozdziału! Dla informacji, rozdział 2 jest ostatnim, który zawiera głównie dialog (bez budowania czegokolwiek). Ma on na celu przedstawienie ogólnego słownika, idei i pojęć dotyczących sztucznej inteligencji, maszynowego uczenia się i, co najważniejsze, głębokiego uczenia.
Czym jest głębokie uczenie?
Głębokie uczenie jest podzbiorem metod uczenia się maszyn.
Głębokie uczenie (deep learning, DL) to podzbiór uczenia się maszyn (machine learning, ML), czyli dziedziny dedykowanej badaniom i rozwijaniem maszyn, które mogą się uczyć, niekiedy z ostatecznym celem zbudowania ogólnej sztucznej inteligencji (artificial intelligence, AI).
W zastosowaniach branżowych głębokie uczenie używane jest do rozwiązywania zadań praktycznych w najrozmaitszych obszarach, takich jak widzenie komputerowe (rozpoznawanie obrazów), przetwarzanie języka naturalnego (tekst) lub automatyczne rozpoznawanie mowy (audio). Mówiąc w skrócie, głębokie uczenie jest podzbiorem metod należących do zestawu narzędzi uczenia się maszyn, głównie wykorzystujących sztuczne sieci neuronowe, które stanowią klasę algorytmów luźno inspirowanych działaniem ludzkiego mózgu.
Na rysunku tym można zauważyć, że nie cały zakres głębokiego uczenia dotyczy prób zbudowania ogólnej sztucznej inteligencji (myślących maszyn, jak w filmach). Wiele zastosowań tej technologii służy do rozwiązywania szerokiego zakresu problemów występujących w branży informatycznej. W tej książce staram się skupić na wykładaniu podstaw głębokiego uczenia zarówno dla potrzeb nowatorskich badań, jak i bieżących potrzeb branżowych, przygotowując Czytelnika do obu zakresów.
Czym jest uczenie się maszyn?
Obszar badań, które mają dać komputerom zdolność do uczenia się bez jawnego zaprogramowania. przypisywane Arthurowi Samuelowi
Skoro głębokie uczenie jest podzbiorem uczenia się maszyn, czym jest to ostatnie? Mówiąc najogólniej, dokładnie tym, co głosi nazwa. Uczenie się maszyn jest dziedziną informatyki, w której maszyny uczą się wykonywać zadania, które nie zostały jawnie zaprogramowane. Upraszczając, maszyny postrzegają pewien wzorzec i podejmują próbę naśladowania go w pewien sposób, bezpośrednio albo pośrednio.
Wymieniłem bezpośrednie i pośrednie naśladownictwo jako paralelę do dwóch głównych typów uczenia się maszyn: nadzorowanego i nienadzorowanego. Nadzorowane uczenie się maszyn jest bezpośrednim naśladowaniem wzorca występującego między dwoma zbiorami danych. Zawsze następuje próba wzięcia zbioru wejściowego i przekształcenia go na zbiór wyjściowy. Może to być niezwykle skuteczna i użyteczna umiejętność. Rozważmy następujące przykłady (wejściowe zbiory danych zostały wytłuszczone, wyjściowe zaś są wyróżnione kursywą):
Użycie
pikseli obrazu do wykrycia
obecności lub
nieobecności kota Użycie
filmów, które lubimy, do przewidzenia innych
filmów, które możemy lubić Użycie czyichś
słów do rozpoznania, czy jest on
szczęśliwy, czy
smutny Użycie
danych czujników pogodowych do przewidzenia
prawdopodobieństwa deszczu Użycie
czujników silnika samochodu do przewidzenia optymalnych
ustawień tuningowania Użycie
danych wiadomości prasowych do przewidzenia jutrzejszych
cen akcji Użycie
liczby na wejściu do przewidzenia
liczby o dwukrotnej wartości Użycie surowego
nagrania audio do przewidzenia treści
transkryptu tego nagrania
Wszystko to są zadania nadzorowanego uczenia się maszyn. We wszystkich przypadkach algorytm uczenia się maszyny próbuje tak naśladować wzorzec występujący między dwoma zbiorami danych, aby użyć jednego zbioru do przewidzenia drugiego. Wyobraźmy sobie, że dla dowolnego z tych przykładów mamy moc pozwalającą przewidzieć wyjściowy zbiór danych, mając jedynie zbiór wejściowy. Taka możliwość byłaby czymś bardzo istotnym.
Nadzorowane uczenie się maszyn
Nadzorowane uczenie przekształca zbiory danych.
Nadzorowane uczenie jest metodą przekształcania jednego zbioru danych w inny. Jeśli na przykład mamy zbiór danych o nazwie poniedziałkowe ceny akcji, zawierający ceny każdej akcji dla każdego poniedziałku z minionych 10 lat, oraz drugi zbiór wtorkowych cen zarejestrowanych w tym samym okresie, algorytm uczenia nadzorowanego może próbować użyć jednego zbioru do przewidzenia wartości w drugim zbiorze.
Jeśli uda nam się wytrenować algorytm nadzorowanego uczenia się maszyny dla danych z poniedziałków i wtorków z 10 lat, może on następnie przewidzieć ceny akcji dla dowolnego wtorku w przyszłości na podstawie cen z bezpośrednio poprzedzającego poniedziałku. Proponuję, abyśmy zatrzymali się teraz i rozważyli to przez chwilę.
Nadzorowane uczenie się maszyn to chleb powszedni stosowanej sztucznej inteligencji (nazywanej też słabą albo wąską AI). Jest użyteczne, gdy chcemy wziąć to, co wiemy jako wejście i szybko przekształcić to w to, co chcemy wiedzieć. Pozwala to algorytmom nadzorowanego uczenia się maszyn rozszerzyć ludzką inteligencję i możliwości na pozornie nieograniczoną liczbę sposobów.
Większość pracy wykorzystującej uczenie się maszyny prowadzi do uczenia nadzorowanego klasyfikatora jakiegoś rodzaju. Nawet nienadzorowane uczenie się maszyn (o którym więcej powiemy za chwilę) zazwyczaj służy temu, aby wspomóc projektowanie dokładnego algorytmu nadzorowanego uczenia się maszyny.
W pozostałej części tej książki będziemy tworzyć algorytmy, przyjmujące jako wejście dane, które są obserwowalne, rejestrowalne, a tym samym możliwe do poznania, i transformujące je w wartościowe dane wyjściowe, które wymagają analizy logicznej. Na tym właśnie polega siła nadzorowanego uczenia się maszyn.
Nienadzorowane uczenie się maszyn
Uczenie nienadzorowane grupuje nasze dane.
Uczenie nienadzorowane ma pewną wspólną cechę z uczeniem nadzorowanym: przekształca jeden zbiór danych w drugi. Jednak zbiór, do którego przekształcamy dane wejściowe, nie jest wcześniej znany ani zrozumiany. W przeciwieństwie do uczenia nadzorowanego, nie ma tu "poprawnej odpowiedzi", dla której próbujemy uzyskać model, który ją duplikuje. Nakazujemy algorytmowi nienadzorowanemu jedynie "znajdź wzorce w tych danych i opowiedz mi o nich".
Przykładem uczenia nienadzorowanego jest analiza skupień (grupowanie) zbioru danych. Analiza skupień przekształca sekwencję obserwacji w sekwencję etykiet grup. Jeśli zostanie odkrytych 10 skupień, etykiety te typowo będą liczbami od 1 do 10. Każdej obserwacji zostanie przypisany numer odpowiadający grupie, w której się znalazł. Tym samym nasz zbiór danych zmienia się z mnóstwa obserwacji w zbiór etykiet. Dlaczego etykiety są liczbami? Algorytm nie jest w stanie powiedzieć nam, czym są te grupy. Skąd mógłby to wiedzieć? Mówi jedynie "Hej, człowieku! Znalazłem jakąś strukturę. Wygląda na to, że w twoich danych są jakieś skupienia. Oto one!"
I tu mam dobrą wiadomość! Ta idea grupowania jest czymś, co możemy utrwalić sobie w pamięci jako definicję uczenia nienadzorowanego. Choć istnieje bardzo wiele form uczenia nienadzorowanego, każdą postać uczenia nienadzorowanego można postrzegać jako formę pewnego grupowania. W dalszej części książki poznamy więcej związanych z tym pojęć.
Przyjrzyjmy się temu przykładowi. Choć algorytm nie wyjaśnia, czym są nazwane grupy, czy możemy ustalić, jak pogrupował słowa? (odpowiedź: 1 == miłe oraz 2 == smaczne). Później wyjaśnimy, że inne formy nienadzorowanego uczenia są również po prostu formą grupowania i dlaczego te grupy (skupienia) są przydatne dla uczenia nadzorowanego.
Uczenie parametryczne kontra nieparametryczne
W uproszczeniu: uczenie się metodą prób i błędów kontra zliczanie i prawdopodobieństwo.
Na poprzednich stronach podzieliłem wszystkie algorytmy uczenia się maszyn na dwie grupy: nadzorowane i nienadzorowane. Teraz omówimy inny sposób podziału tych samych algorytmów uczenia się na dwie grupy: parametryczne i nieparametryczne. Jeśli więc zastanowimy się nad naszą małą chmurą uczenia się maszyn, ma ona dwa ustawienia:
Jak widać, w rzeczywistości mamy do wyboru cztery różne typy algorytmów. Algorytm jest albo nadzorowany, albo nienadzorowany oraz albo parametryczny, albo nieparametryczny. Podczas gdy poprzedni punkt o nadzorowaniu dotyczył rodzaju nauczanego wzorca, parametryczność dotyczy sposobu przechowywania tej nauki i często, przez rozszerzenie, metody uczenia się. Na początek przyjrzyjmy się formalnym definicjom parametryczności i nieparametryczności. Gwoli ścisłości, nadal toczą się dyskusje na temat ścisłego rozróżnienia tych pojęć.
Model parametryczny charakteryzuje się posiadaniem stałej (ustalonej) liczby parametrów, podczas gdy w modelu nieparametrycznym liczba parametrów jest nieskończona (zdeterminowana przez dane).
Dla przykładu przyjmijmy, że problem polega na dopasowaniu kwadratowego kołka do odpowiedniego (kwadratowego) otworu. Niektórzy (małe dzieci) będą po prostu wciskać kołek we wszystkie otwory, aż będzie gdzieś pasował (parametryczne). Nastolatek jednak może policzyć liczbę boków (cztery) i wyszukać otwór z taką samą liczbą brzegów (nieparametryczne). Modele parametryczne mają skłonność do stosowania metody prób i błędów, podczas gdy modele nieparametryczne skłaniają się w stronę liczenia. Przyjrzyjmy się temu bliżej.
Nadzorowane uczenie parametryczne
W uproszczeniu: Uczenie metodą prób i błędów przy użyciu pokręteł.
Nadzorowane parametryczne maszyny uczące się to maszyny wyposażone w skończoną liczbę pokręteł (to część parametryczna), przy czym uczenie się następuje poprzez obracanie tych pokręteł (regulowanie). Dane wejściowe są wprowadzane, następnie przetwarzane na podstawie położenia gałek, po czym transformowane w prognozę.
Uczenie się uzyskujemy przez przestawianie gałek na różne położenia. Jeśli próbujemy przewidzieć prawdopodobieństwo tego, że Red Sox wygrają rozgrywki World Series, model ten najpierw przyjmie dane wejściowe (takie jak statystyki sportowe z liczbą zwycięstw i porażek lub średnią liczbą gotowości do rzutów (toes) dla gracza) i wyliczy prognozę (taką jak prawdopodobieństwo 98%). Następnie model sprawdzi, czy Red Sox rzeczywiście wygrali, czy nie. Wiedząc już, czy wygrali, algorytm uczenia się może skorygować położenie gałek, aby uzyskać dokładniejszą prognozę następnym razem, gdy zobaczy te same lub podobne dane wejściowe.
Być może "podkręci" gałkę "rejestr zwycięstw/porażek", jeśli wskaźnik wygranych i porażek zespołu był dobrym prognostykiem. I odwrotnie, może "przykręcić w dół" gałkę dla "średniej liczby rzutów", jeśli ta obserwacja nie była. Tak właśnie uczy się model parametryczny!
Zauważmy, że wszystko, czego model się nauczył, można przechwycić jako pozycje gałek w dowolnym wybranym momencie. Można myśleć o tego rodzaju modelu uczenia się jako o algorytmie wyszukiwania. Po prostu "szukamy" odpowiedniej konfiguracji gałek, próbując różnych ustawień, korygując je i próbując ponownie.
Możemy też zauważyć, że uwaga o próbach i błędach nie jest definicją formalną, ale jest powszechną (z wyjątkami) cechą modeli parametrycznych. Gdy mamy arbitralnie wybraną (ale ustaloną) liczbę gałek, którymi możemy kręcić, potrzebny jest jakiś poziom poszukiwań, aby znaleźć optymalną konfigurację. Różni się to zasadniczo od uczenia nieparametrycznego, które często bazuje na zliczaniu i (w większym lub mniejszym stopniu) dodaje nowe gałki, gdy znajdzie coś nowego, co można policzyć. Spróbujmy podzielić parametryczne nadzorowane uczenie na trzy fazy.
Krok 1: Przewidywanie
Aby zilustrować przebieg parametrycznego nadzorowanego uczenia, będziemy kontynuować analogię sportową i próbowali przewidzieć, czy Red Rox wygrają rozgrywki World Series. Pierwszym krokiem, jak wspomniałem, jest zebranie statystyk sportowych, przepuszczenie ich przez maszynę i wyliczenie prognozy prawdopodobieństwa, że Red Sox zwyciężą.
Krok 2: Porównanie ze wzorcem (prawdą)
Drugim krokiem jest porównanie prognozy (98%) ze wzorcem, o który nam chodzi (czyli czy Red Sox wygrali). Nieszczęśliwie przegrali, zatem porównanie to
Prognoza: 98% > Prawda: 0%
W tej fazie stwierdzamy, że gdyby model przewidział 0%, doskonale przewidziałby nadchodzącą przegraną drużyny. Chcemy, aby maszyna była dokładna, co prowadzi nas do kroku 3.
Krok 3: Uczenie się wzorca
W tym kroku korygujemy ustawienia gałek, analizując zarówno to, jak bardzo model się pomylił (98%), jak i to, czym były dane wejściowe (statystyki sportowe) w momencie prognozowania. Krok ten następnie zmienia ustawienia gałek, aby uzyskać bardziej dokładne przewidywanie dla posiadanych danych wejściowych.
W teorii gdy w tym kroku pojawią się te same statystyki, nowa prognoza powinna być niższa niż 98%. Zauważmy, że każda gałka reprezentuje wrażliwość prognozy na różnego typu dane wejściowe. To właśnie zmieniamy, gdy się "uczymy".
Parametryczne uczenie nienadzorowane
Nienadzorowane uczenie parametryczne wykorzystuje bardzo podobne podejście. Przyjrzyjmy się poszczególnym fazom na wysokim poziomie. Pamiętajmy, że uczenie nienadzorowane sprowadza się do grupowania danych. Nienadzorowane uczenie parametryczne używa gałek do grupowania danych. Jednak w tym przypadku zazwyczaj mamy wiele gałek dla każdej grupy, z których każda odzwierciedla koligację danych wejściowych z tą konkretną grupą (z wyjątkami i niuansami - na razie zajmujemy się ogólnikowym opisem). Przyjrzyjmy się przykładowi, w którym zakładamy, że chcemy podzielić dane na trzy grupy.
W naszym zbiorze danych zidentyfikowałem trzy skupienia danych, które nasz model parametryczny powinien znaleźć. Zostały one oznaczone przez sformatowanie jako grupa 1, grupa 2 i grupa 3. Spróbujmy przepuścić pierwszą obserwację przez wytrenowany model nienadzorowany, pokazany poniżej. Zauważmy, że zostanie on najsilniej odwzorowany do grupy 1.
Dla każdej grupy maszyna próbuje przekształcić dane wejściowe na liczbę z przedziału od 0 do 1, informując o prawdopodobieństwie, z jakim konkretna obserwacja jest członkiem określonej grupy. Istniej wielka różnorodność technik uczenia takich modeli oraz ich wynikowych cech, ale na wysokim poziomie wykonują one dopasowywanie parametrów, aby przekształcić dane wejściowe do odpowiednich grup.
Uczenie nieparametryczne
W uproszczeniu: Metody oparte na zliczaniu.
Uczenie nieparametryczne jest klasą algorytmów, w której liczba parametrów jest oparta na samych danych (a nie wstępnie zdefiniowana). Prowadzi to do metod, które w ogólności zliczają coś w ten czy inny sposób, tym samym zwiększając liczbę parametrów na podstawie liczby elementów w danych. W wariancie nadzorowanym model nieparametryczny mógłby na przykład liczyć przypadki, gdy określony kolor świateł na skrzyżowaniu powoduje, że samochody "jadą". Po zliczeniu tylko kilku przykładów model ten będzie mógł przewidzieć, że środkowe światło zawsze (100%) powoduje, że samochody jadą, podczas gdy prawe światła powodują to tylko czasami (50%).
Zauważmy, że ten model będzie używać trzech parametrów: trzy liczniki wskazujące liczbę zapaleń każdego koloru, gdy samochody ruszyły (być może podzieloną przez całkowitą liczbę obserwacji). Gdyby świateł byłoby pięć, potrzebowalibyśmy pięciu liczników (pięciu parametrów). Tym, co sprawia, że ten prosty model jest nieparametryczny, jest jego cecha uzależniająca liczbę parametrów od samych danych (w tym przypadku liczby kolorów świateł). Różni się to zasadniczo od modeli parametrycznych, które zaczynają od ustalonej liczby parametrów, a co ważniejsze, mogą mieć więcej lub mniej parametrów wyłącznie na podstawie decyzji naukowca trenującego model (niezależnie od danych).
Uważne przyjrzenie się może podawać tę koncepcję w wątpliwość. Model parametryczny pokazany wcześniej wydawał się mieć "gałkę" dla każdej obserwacji. Większość modeli parametrycznych nadal musi mieć jakiś rodzaj wejścia zależnego od liczby klas w danych. Możemy zatem zauważyć, że między algorytmami parametrycznymi i nieparametrycznymi jest jakiś nieokreślony obszar. Nawet algorytmy parametryczne w jakiś sposób ulegają wpływowi liczby klas w danych, nawet jeśli nie są to jawnie wzorce zliczające.
Podkreśla to też fakt, że parametr jest terminem ogólnym, odnoszącym się tylko do zbioru liczb używanego w celu modelowania wzorca (bez żadnych ograniczeń pod względem sposobu użycia tych liczb). Liczniki są parametrami. Wagi są parametrami. Znormalizowane warianty liczników lub wag są parametrami. Współczynniki korelacji mogą być parametrami. Termin odnosi się do zbioru liczb używanych do modelowania wzorca. Jak się okazuje, głębokie uczenie jest klasą modeli parametrycznych. W dalszej części książki nie będziemy więcej omawiać modeli nieparametrycznych, ale jest to bardzo interesująca i skuteczna klasa algorytmów.
Podsumowanie
W tym rozdziale zeszliśmy jeden poziom głębiej w rozmaite odmiany uczenia się maszyn. Dowiedzieliśmy się, że algorytm uczenia się może być albo nadzorowany, albo nienadzorowany, a także parametryczny albo nieparametryczny. Co więcej, pokazaliśmy, co odróżnia od siebie te cztery grupy algorytmów. Nauczyliśmy się, że nadzorowane uczenie się maszyn jest klasą algorytmów, w których uczymy się przewidywać zawartość pewnego zbioru danych na podstawie innego, uczenie zaś nienadzorowane w ogólności polega na grupowaniu pojedynczego zbioru danych na różnego rodzaju skupienia (grupy). Dowiedzieliśmy się też, że algorytmy parametryczne mają ustaloną liczbę parametrów, algorytmy zaś nieparametryczne dopasowują liczbę używanych parametrów w zależności od zawartości zbioru danych.
Głębokie uczenie wykorzystuje sieci neuronowe do realizowania zarówno nadzorowanych, jak i nienadzorowanych przewidywań. Jak dotąd, pozostawaliśmy na poziomie koncepcyjnym, aby Czytelnik uzyskał orientację w całości rozważanej dziedziny i swojego miejsca w niej. W kolejnym rozdziale zbudujemy naszą pierwszą sieć neuronową i wszystkie kolejne rozdziały będą opierać się na projektach. Zatem wyciągamy swoje notatniki Jupyter i do przodu!
Krok 1: Prognoza
Ten rozdział dotyczy prognozowania.
W poprzednim rozdziale poznaliśmy paradygmat przewidywanie, porównywanie, nauka. W tym rozdziale zagłębimy się w jego pierwszy krok: przewidywanie. Przypomnijmy, że krok ten wygląda następująco:
W tym rozdziale dowiemy się więcej o tym, jak te trzy części prognozowania wykonywanego przez sieć neuronową wyglądają od środka. Zaczniemy od pierwszej: danych. W naszej pierwszej sieci neuronowej będziemy chcieli przewidzieć po jednym punkcie danych na raz, jak poniżej:
Później zobaczymy, że liczba obserwacji przetwarzanych jednocześnie ma znaczący wpływ na to, jak wygląda i zachowuje się nasza sieć. Ktoś mógłby postawić pytanie: "Jak mam wybrać, ile obserwacji ma być propagowanych jednocześnie?". Odpowiedź zależy od tego, czy (w naszej opinii) sieć neuronowa może być dokładna, mając te dane, które jej dostarczamy.
Dla przykładu jeśli próbujemy rozpoznać (przewidzieć), czy na zdjęciu jest widoczny kot, zdecydowanie muszę pokazać mojej sieci wszystkie piksele obrazu jednocześnie. Dlaczego? No cóż, gdybym przesyłał po jednym pikselu na raz, czy ktokolwiek byłby w stanie stwierdzić, czy na obrazku jest kot? Ja też bym nie umiał! (Nawiasem mówiąc, można to zapamiętać jako ogólną regułę: zawsze należy przekazać sieci wystarczające informacje, przy czym "wystarczające" można z grubsza zdefiniować jako informacje potrzebne, by człowiek był w stanie wykonać takie samo przewidywanie).
Na razie pominiemy samą sieć. Jak się okazuje, będziemy mogli utworzyć sieć dopiero wtedy, gdy zrozumiemy kształt wejściowych i wyjściowych zbiorów danych (na razie kształt będziemy rozumieć jak "liczbę kolumn" albo "liczbę obserwacji przetwarzanych jednocześnie"). Skupimy się na pojedynczej prognozie prawdopodobieństwa tego, że konkretna drużyna baseballowa zwycięży:
Teraz, gdy wiemy już, że zamierzamy przyjąć tylko jedną obserwację i uzyskać na wyjściu jedną prognozę, możemy utworzyć sieć neuronową. Ponieważ mamy tylko jedną daną wejściową i jedną wyjściową, będziemy budować sieć z jedną gałką, przekształcającą wartość wejściową na wyjściową. (Na poziomie abstrakcji te "gałki" są w rzeczywistości nazywane wagami i tak się będę do nich odnosił, poczynając od tego miejsca). Tak więc, bez dalszych ceregieli, oto nasza pierwsza sieć neuronowa z pojedynczą wagą mapującą daną wejściową "liczba rzutów" (# toes) na daną wyjściową "zwyciężył?" (win):
Jak można zauważyć, przy jednej wadze sieć ta przyjmuje po jednym punkcie danych na raz (średnią liczbę rzutów na gracza w drużynie baseballowej) i zwraca pojedynczą prognozę (to, czy jej zdaniem drużyna wygra).
Wykonywanie prognozy przez prostą sieć neuronową
Zacznijmy od najprostszej możliwej sieci neuronowej.
Czym jest sieć neuronowa?
Oto nasza pierwsza sieć neuronowa.
Aby uruchomić sieć neuronową, otwieramy notatnik Jupyter i uruchamiamy poniższy kod:
Następnie uruchamiamy poniższy fragment:
Właśnie zbudowaliśmy naszą pierwszą sieć neuronową i użyliśmy jej do przewidywań! Gratulacje! Ostatni wiersz powoduje wypisanie prognozy (pred). Powinna ona wynosić 0.85. Zatem czym jest sieć neuronowa? Na razie jest to jedna lub więcej wag, przez które możemy mnożyć dane wejściowe, aby uzyskać prognozę.
Czym są dane wejściowe?
Jest to liczba, którą zarejestrowaliśmy gdzieś w rzeczywistym świecie. Zazwyczaj jest to coś łatwo dostępnego, jak dzisiejsza temperatura, średnia uderzeń baseballisty (BA) czy wczorajsza cena jakiejś akcji.
Czym jest prognoza?
Prognoza jest tym, co sieć neuronowa może nam powiedzieć na podstawie otrzymanych danych wejściowych, na przykład "dla podanej temperatury istnieje 0% prawdopodobieństwa, że ludzie będą dziś nosić dresy" albo "dla podanego BA danego gracza istnieje 30% prawdopodobieństwa, że uderzenie doprowadzi do home run", albo "na podstawie wczorajszej ceny akcji dzisiejsza cena będzie wynosić 101,52".
Czy te prognozy są zawsze poprawne?
Nie. Sieci neuronowe będą popełniać błędy, ale mogą się na nich uczyć. Dla przykładu jeśli uzyskana prognoza będzie zbyt wysoka, sieć skoryguje swoją wagę, aby następnym razem podać niższą prognozę i vice versa.
Jak sieć się uczy?
Metodą prób i błędów! Najpierw próbuje dokonać jakiejś prognozy. Następnie może stwierdzić, czy prognoza ta była zbyt wysoka, czy zbyt niska. Następnie zmienia wagę (w górę lub w dół), aby przewidywać bardziej dokładnie następnym razem, gdy otrzyma te same dane wejściowe.
Co robi ta sieć neuronowa?
Mnoży dane wejściowe przez wagę. "Skaluje" dane wejściowe o określony czynnik.
W poprzednim podpunkcie wykonaliśmy pierwszą prognozę przy użyciu sieci neuronowej. W swej najprostszej postaci sieć neuronowa wykorzystuje siłę mnożenia. Przyjmuje wejściową obserwację (w tym przypadku liczbę 8,5) i mnoży ją przez wagę. Gdyby waga była równa 2, wówczas sieć neuronowa podwoiłaby dane wejściowe. Jeśli waga to 0,01, sieć podzieli dane wejściowe przez 100. Jak można zauważyć, niektóre wartości wagi powiększają, a inne zmniejszają dane wejściowe.
Interfejs sieci neuronowej jest prosty. Akceptuje ona zmienną input jako informację oraz zmienną weight (waga) jako wiedzę, po czym zwraca prediction (prognozę). Każda sieć neuronowa, jaką kiedykolwiek spotkamy, będzie działać w ten sposób. Wykorzystuje wiedzę zawartą w wagach do interpretowania informacji w danych wejściowych. Później zobaczymy sieci neuronowe akceptujące większe, bardziej złożone wartości zmiennych input i weight, ale w tle zawsze będą te same przesłanki.
W tym przypadku informacją jest średnią liczbą rzutów dla drużyny przed rozpoczęciem meczu. Możemy tu zauważyć kilka rzeczy. Po pierwsze, sieć neuronowa nie ma dostępu do żadnej informacji poza jednym wystąpieniem. Jeśli po tej prognozie przekażemy do niej number_of_toes[1], sieć nie będzie pamiętać prognozy wykonanej w ostatnim kroku. Sieć neuronowa wie tylko to, co przekażemy do niej jako wejście. Zapomina wszystko inne. Później pokażę, jak można dać sieci neuronowej "pamięć krótkoterminową", dostarczając jej jednocześnie wiele danych wejściowych.
Innym sposobem myślenia o wartościach wag w sieciach neuronowych jest traktowanie ich jako miary czułości między danymi wejściowymi sieci a jej prognozami. Jeśli waga jest bardzo duża, wówczas nawet najmniejsze wejście może utworzyć bardzo wielką wartość prognozy! Jeśli waga jest bardzo mała, wówczas nawet wielkie wartości wejściowe stworzą małe prognozy. Tę czułość można porównać z głośnością. "Podkręcenie wagi" wzmacnia prognozę względem danych wejściowych: waga jest regulatorem głośności!
W naszym przypadku to, co sieć neuronowa faktycznie robi, jest zastosowanie regulatora głośności do zmiennej number_of_toes. W teorii ten regulator potrafi nam podać prawdopodobieństwo zwycięstwa drużyny na podstawie średniej liczby udanych rzutów na gracza w drużynie. To może działać, choć nie musi. Prawdę mówiąc, gdyby członkowie drużyny mieli średnią 0 rzutów, zapewne graliby fatalnie. Jednak baseball jest znacznie bardziej złożony. W kolejny punkcie przekażemy wiele elementów informacji jednocześnie, tak by sieć neuronowa mogła podejmować lepsze decyzje.
Zauważmy, że sieci neuronowe nie muszą przewidywać jedynie dodatnich liczb - prognozy mogą być też liczbami ujemnymi, a także można przekazywać liczby ujemne jako wejście. Załóżmy, że chcemy przewidzieć prawdopodobieństwo, że ludzie będą dziś chodzić w płaszczach. Jeśli temperatura to -10 stopni Celsjusza, wówczas ujemna waga pozwoli przewidzieć wysokie prawdopodobieństwo tego, że ludzie założą płaszcze.
Wykonywanie prognozy dla wielu danych wejściowych
Sieci neuronowe mogą łączyć spostrzeżenia dla wielu obserwacji.
Poprzednia sieć neuronowa była w stanie przyjąć jedną obserwację jako wejście i wykonać jedną prognozę na tej podstawie. Mógłbyś jednak spytać, "Czy średnia liczba rzutów, sama jedna, w ogóle jest dobrym prognostykiem?". Jeśli tak, to słusznie się zastanawiasz. Co by było, gdybyśmy mogli przekazać sieci więcej informacji (jednocześnie), niż jedynie średnią liczbę rzutów na gracza? W takim przypadku sieć powinna, przynajmniej teoretycznie, być w stanie wykonać bardziej dokładne prognozy. I jak się okazuje, sieć może przyjmować wiele wejściowych obserwacji jednocześnie. Przyjrzyjmy się kolejnemu przykładowi:
Wiele danych wejściowych: Co robi ta sieć neuronowa?
Mnoży trzy dane wejściowe przez trzy wagi i sumuje je. Jest to suma ważona.
Pod koniec poprzedniego podpunktu doszliśmy do zrozumienia ograniczającego czynnika naszej prostej sieci neuronowej: był tylko jeden regulator głośności dla jednej obserwacji. W przykładzie tą obserwacją była średnia liczba rzutów na gracza danej drużyny baseballowej. Doszliśmy do tego, że aby przewidywać dokładniej, potrzebujemy sieci neuronowej łączącej wiele danych wejściowych w tym samym czasie. Szczęśliwie sieci neuronowe zdolne są działać w ten sposób.
Ta nowa sieć neuronowa może przyjmować wiele danych wejściowych jednocześnie dla każdej prognozy. Pozwala to sieci łączyć różnego typu informacje, aby podejmować decyzje na podstawie najlepszych informacji. Jednak fundamentalny mechanizm użycia wag nie uległ zmianie. Nadal pobieramy poszczególne dane wejściowe i przepuszczamy je przez ich własny regulator głośności. Inaczej mówiąc, każdą daną wejściową mnożymy przez jej własną wagę.
Nową cechą, którą możemy tu zauważyć, jest to, że ponieważ mamy wiele danych wejściowych, musimy zsumować odpowiadające im prognozy. Tak więc mnożymy każdą daną wejściową przez odpowiadającą jej wagę i sumujemy wyniki (lokalne prognozy). Nazywamy to sumą ważoną danych wejściowych lub w skrócie sumą ważoną. Niektórzy autorzy odnoszą się do sumy ważonej jako do iloczynu skalarnego (dot product).
Istotne przypomnienie
Interfejs sieci neuronowej jest prosty. Akceptuje ona zmienną input jako informację oraz zmienną weights jako wiedzę, po czym zwraca prognozę.
Ta nowa potrzeba przetwarzania wielu danych wejściowych jednocześnie usprawiedliwia użycie nowego narzędzia. Nazywamy je wektorem i jeśli podążasz za mną w swoim notatniku Jupyter, już go używałeś. Wektor nie jest niczym innym niż listą liczb. W aktualnym przykładzie zmienna input jest wektorem i zmienna weights jest wektorem. Czy zauważasz jakieś inne wektory w pokazanym kodzie? (Są tam jeszcze trzy).
Jak się okazuje, wektory są niebywale użyteczne, ilekroć potrzebujemy wykonać operacje wykorzystujące grupy liczb. W tym przypadku wykonujemy sumę ważoną między dwoma wektorami (iloczyn skalarny). Bierzemy dwa wektory o równej długości (input oraz weights), mnożymy przez siebie poszczególne liczby, bazując na ich pozycji (pierwsza pozycja w input jest mnożona przez pierwszą pozycję w weights i tak dalej), po czym sumujemy uzyskane wyniki.
Ilekroć wykonujemy operację matematyczną na dwóch wektorach, w której parujemy wartości zgodnie z ich pozycją w wektorach (przypomnijmy: pozycję 0 z 0, 1 z 1 i tak dalej), nazywamy to operacją według elementów (albo element po elemencie, ang. elementwise). Tak więc dodawanie według elementów sumuje, mnożenie zaś według elementów mnoży odpowiednie składowe dwóch wektorów.
Wyzwanie: Arytmetyka wektorów
Umiejętność manipulowania wektorami jest kamieniem węgielnym głębokiego uczenia. Sprawdź, czy potrafisz napisać funkcje, które będą wykonywać następujące operacje:
def elementwise_multiplication(vec_a, vec_b) def elementwise_addition(vec_a, vec_b) def vector_sum(vec_a) def vector_average(vec_a)
Następnie przekonaj się, czy potrafisz wykorzystać dwie z powyższych metod, aby zrealizować iloczyn skalarny!
Intuicyjne rozumienie tego, jak i dlaczego działa iloczyn skalarny (suma ważona) jest zdecydowanie jedną z najważniejszych części prawdziwego przyswojenia sobie tego, jak sieci neuronowe wykonują prognozy. Mówiąc w uproszczeniu, iloczyn skalarny daje nam pojęcie o podobieństwie dwóch wektorów. Rozważmy poniższe przykłady3:
a = [ 0, 1, 0, 1]
b = [ 1, 0, 1, 0]
c = [ 0, 1, 1, 0]
d = [.5, 0,.5, 0]
e = [ 0, 1,-1, 0]
w_sum(a,b) = 0
w_sum(b,c) = 1
w_sum(b,d) = 1
w_sum(c,c) = 2
w_sum(d,d) = .5
w_sum(c,e) = 0
Największa suma ważona (w_sum(c,c)) występuje dla pary wektorów, które są dokładnie takie same. Dla kontrastu, ponieważ a i b nie mają nakładających się wag, ich iloczyn skalarny jest równy zero. Być może najbardziej interesująca jest suma ważona wektorów c i e, gdyż jedna z wag e jest ujemna. Ta ujemna waga zneutralizowała dodatnie podobieństwo występujące między tymi wektorami. Jednak iloczyn skalarny e z sobą samym zwróci 2 mimo ujemnej wagi (iloczyn liczb ujemnych jest dodatni). Poznajmy bliżej różne właściwości operacji iloczynu skalarnego.
Niekiedy można przyrównać właściwości iloczynu skalarnego i logicznego AND (koniunkcji logicznej). Rozważmy następujące wektory a i b:
a = [ 0, 1, 0, 1]
b = [ 1, 0, 1, 0]
Jeśli zapytamy, czy a[0] AND b[0] (czyli czy a[0] oraz b[0] mają jednocześnie wartość), odpowiedź brzmi nie (czyli fałsz, używając terminologii logicznej). Jeśli sprawdzimy a[1] AND b[1], odpowiedzią ponownie jest nie. Ponieważ jest to zawsze prawdą dla wszystkich czterech składowych, finalny wynik wynosi 0. Dla każdej pary wartości logiczne AND zwraca fałsz.
b = [ 1, 0, 1, 0]
c = [ 0, 1, 1, 0]
Natomiast wektory b oraz c mają wspólną wartość dla jednej kolumny (składowej). W tym przypadku logiczne AND zwróci prawdę, gdyż b[2] oraz c[2] mają niezerowe wagi. Ta kolumna (i tylko ta) powoduje, że wynik jest zwiększany do 1.
c = [ 0, 1, 1, 0]
d = [.5, 0,.5, 0]
Szczęśliwie sieci neuronowe są w stanie modelować częściową koniunkcję logiczną. W tym przypadku c oraz d mają tę samą niezerową kolumnę, co b i c, ale ponieważ w wektorze d waga wynosi 0.5, finalny wynik jest równy tylko 0.5. Własność tę wykorzystamy przy modelowaniu prawdopodobieństw w sieciach neuronowych.
d = [.5, 0,.5, 0]
e = [-1, 1, 0, 0]
W tej analogii ujemna waga odpowiada zastosowaniu logicznego operatora NOT (negacji), biorąc pod uwagę, że dowolna dodatnia waga sparowana z ujemną powoduje zmniejszanie ogólnego wyniku. Co więcej, jeśli obydwa wektory mają wagi ujemne (tak jak w w_sum(e,e)), sieć neuronowa wykona podwójną negację i doda wartości bezwzględne tych wag. Dodatkowo ktoś mógłby powiedzieć, że jest to alternatywa (OR) po koniunkcji (AND), gdyż jeśli którykolwiek wiersz zawiera jakąś wagę, ma to wpływ na wynik. Tak więc dla w_sum(a,b), jeżeli (a[0] AND b[0]) OR (a[1] AND b[1]) i tak dalej, wówczas w_sum(a,b) zwraca dodatni wynik. Co więcej, jeśli jedna wartość jest ujemna, wówczas ta kolumna zostaje zanegowana.
Co zabawne, daje to nam pewnego rodzaju "zgrubny" język odczytywania wag. Spróbujmy przeczytać kilka przykładów? Zakładają one, że wykonujemy w_sum(input, weights) i pominięte "then" w tych instrukcjach if są abstrakcjami dla "zwraca największy wynik":
weights = [ 1, 0, 1] => if input[0] OR input[2]
weights = [ 0, 0, 1] => if input[2]
weights = [ 1, 0, -1] => if input[0] OR NOT input[2]
weights = [ -1, 0, -1] => if NOT input[0] OR NOT input[2]
weights = [ 0.5, 0, 1] => if BIG input[0] or input[2]
Zauważmy w ostatnim wierszu, że weight[0] = 0.5 oznacza, że odpowiadająca mu wartość input[0] musi być większa, aby skompensować mniejszą wagę. Jak wspomniałem, jest to bardzo zgrubnie przybliżający język. Wydaje się jednak niezmiernie przydany, gdy próbuję sobie zwizualizować, co się naprawdę dzieje. To może być bardzo pomocne w przyszłości, szczególnie gdy sieci neuronowe będziemy łączyć ze sobą na coraz bardziej złożone sposoby.
Opierając się na tych intuicjach, co to może znaczyć, gdy sieć neuronowa wykonuje prognozę? Mówiąc w uproszczeniu, oznacza to, że sieć zwraca największy wynik dla danych wejściowych, opierając się na tym, jak bardzo są one podobne do wag. W kolejnym przykładzie możemy zauważyć, że zmienna nfans jest całkowicie ignorowana w prognozowaniu, gdyż powiązana z nią waga wynosi 0. Najbardziej wrażliwą zmienną predykcyjną jest wlrec, gdyż odpowiada jej waga 0.2. Jednak dominujący wpływ na największy wynik ma liczba rzutów (ntoes), nie z powodu największej wagi, ale dlatego że dane wejściowe w powiązaniu z wagą dają zdecydowanie największy wynik.