Sieci neuronowe #3 - Implementacja sieci neuronowej z modelem asocjacji

in #pl-artykuly7 years ago (edited)

Wstęp

Cześć, w tym artykule chciałbym przedstawić wam implementację prostej sieci neuronowej opartej o model asocjacyjny. Tym razem wysiliłem się trochę bardziej i stworzyłem prostą wizualizację obrazków w htmlu. Poprzez dobranie odpowiednich znaczków i wprowadzeniu prostego cssa do kodu, otrzymałem całkiem niezły efekt, który będziecie mogli sami zobaczyć. Cały przykład został napisany w javascript, ponieważ jest prosty oraz łatwo można zrobić prostą wizualizację. Dodatkowo można to wystawić na stronę.

Opis modelu

Zadaniem modelu asocjacyjnego jest kojarzenie podobnych do siebie nauczonych bytów. Załóżmy, że mamy słowa kóbełek i kubełek oraz papuszka i papużka. Sieć używająca model asocjacji w tym algorytmie powinna rozpoznać "nieczyste" słowa na wejściu i zwrócić słowo kubełek oraz papużka.

Tak samo będzie w przypadku naszych obrazków. Najpierw podajemy obrazki, które nasza sieć ma się nauczyć, a następnie podajemy jej zniekształcone obrazki i oczekujemy, że sieć skojarzy odpowiednio przerobione obrazki z oryginalnymi obrazkami.

W tym przykładzie implementacji będziemy uczyli dwóch obrazków i podamy sieci także dwa zniekształcone obrazki.

Opis algorytmu

Ten algorytm jest trochę bardziej zaawansowany, ale wciąż na tyle prosty, że każdy może go w miarę zrozumieć.

Na początek definiujemy sobie obrazki, którymi chcemy uczyć sieć neuronową, a następnie definiujemy sobie dwa następne obrazki, którymi chcemy przetestować naszą sieć. Załóżmy, że piksel czarny to waga o wartości 1.0 a biały piksel to waga o wartości -1.0. każdy obrazek możemy zdefiniować jako wektor liczb 1.0 albo -1.0. Wektor to inaczej tablica. Pokażę wam teraz jaka jest wizualizacja wszystkich obrazków.
Pierwszy obrazek jakim będziemy uczyć sieć neuronową, to

Reprezentowany jest on przez następujący wektor:

Drugi obrazek wygląda tak:

A jego reprezentacja w kodzie wygląda tak:

Teraz przedstawię wam zaburzone obrazki.
Pierwszy z nich to:

Jego reprezentacja w kodzie to:

Natomiast drugi zaburzony obrazek to:

W kodzie wygląda tak:

Na początek, w mojej implementacji wyświetlam wszystkie zdefiniowane obrazki używając następującego kodu:

Funkcja display bierze jako argument tablicę, z której wyciąga informacje jak kolorować piksele.

W kodzie zareprezentowana jest następująco:

W skrócie przechodzimy przez całą tablicę i w sumie generujemy tabelkę z odpowiednimi kratkami. I co 5 elementów przechodzimy do nowej linijki.
Czy kod tej funkcji jest dobry? Nie wiem, ale działa xd Użyłem tu biblioteki jQuery w celu lekkiego przyśpieszenia pisania kodu.

Następny krok algorytmu było stworzenie macierzy 25 na 25 elementów. Ta macierz będzie nam potrzebna do zapisywania odpowiednich wag podczas nauki sieci neuronowej. Macierz to inaczej tablica dwuwymiarowa. Jest to macierz kwadratowa, czyli kolumny i wiersze są jednakowej długości. Wygenerowanie takiej macierzy w jsie to trochę zabawy i wygląda to tak:

Sposobów na to jest mnóstwo. W skrócie tworzymy tablicę 25 elementów tablic 25 elementowych i do każdej tablicy 25 elementowej wsadzamy liczbę -1.0.
Na końcu zwracamy nasz twór dalej.
Następny krok algorytmu to nauczenie sieci dwóch obrazków z0 i z1 i wrzucenie wyników do macierzy wag w. Ten krok wykonywany jest przez funkcję calculateWeightsMatrix.
W skrócie obliczamy wagi na podstawie naszych dwóch 25 pikselowych obrazków i wrzucamy wagę do pojedynczej komórki macierzy. Te miejsce tu jest kluczowe, ponieważ w tej funkcji sieć tworzy sobie wagi, które będą potem służyły przypisaniu odpowiednich pikseli do siebie podczas sprawdzania podobieństwa.
Kod powyższego opisu wygląda tak:

Gdy nasza sieć utworzyła już sobie wagi, to teraz nasz algorytm powinien z pomocą "nauczyciela" określić o jaki obrazek nam chodzi przy testowaniu zniekształconym obrazkiem. Do zwrócenia wyników nauczyciela użyjemy funkcji F, która bierze sobie wyuczone wagi oraz zniekształcony obrazek.
Funkcja F mnoży macierz wyuczonych wag z wektorem zawierającym podane piksele obrazka a na końcu każe nauczycielowi określić jakie mają wyjść kolory pikseli. To jest po prostu użycie działań z algebry w przypadku mnożenia.
Po wyliczeniu działania mnożenia otrzymamy wektor, który przepuszczamy przez naszego nauczyciela. W tym przypadku dla każdej wartości z wektora, funkcja signum określa czy ma zwrócić piksel biały czy czarny.
Na końcu działania funkcji F otrzymujemy skojarzony obrazek w postaci wektora z liczbami 1.0 i -1.0.
Ostatnim krokiem algorytmu jest wyświetlenie obrazka na ekranie, dzięki czemu my będziemy wstanie określić czy obrazki się zgadzają.

Kod powyższego wygląda tak:

Kod do wyświetlania obrazków już wcześniej pokazałem, więc nie będę go tu wstawiał ponownie.

Jeżeli chodzi o kod htmlowy, to on jest po prostu następujący:

To wszystko możecie zobaczyć w akcji tutaj, a cały kod został wrzucony tutaj

Cały kod (ponownie) zajmuje około 130 linijek. Oczywiście sam algorytm w wersji matematycznej zapisany jest w bardziej niezrozumiały sposób (przynajmniej dla mnie) i raczej nie zależy mi na próbie interpretacji go tutaj z racji tego, że nie jestem matematykiem :D
To co tutaj przedstawiłem, to wciąż prosta implementacja, ciekawiej zaczyna się, gdy wchodzimy w strefę "gradient" i "propagacja wsteczna". Te pojęcia wchodzą już na poziom matematyki na pograniczu akademickim, co trudniej jest zaimplementować. Moje zadanie to właśnie będzie implementacja z postaci "pseudo informatycznej" na postać kodu w konkretnym języku programowania. Używając javascript robię sobie trochę pod górkę, ale z drugiej strony mogę tutaj wszystko implementować od zera. A to pomoże potem, gdy chcemy implementować coś trudniejszego.

Jak już mówiłem we wcześniejszym artykule, to wszystko to jest moje obecne rozumowanie przedstawianego zagadnienia i może ono zawierać pewne uproszczenia w rozumowaniu (Nawet spore xd), więc proszę nie traktować to jako coś 100% merytoryczny tekst profesjonalisty.

Sort:  

Gratulacje, twój post został uwzględniony przez @OCD w dziennej międzynarodowej kompilacji o numerze #133!

Możesz także dodać @ocd do obserwowanych użytkowników – dzięki temu dowiesz się o innych projektach i poznasz różne perełki! Walczymy o transparentność.

Hej! Otrzymałeś losowo głos za swój post! Jeżeli chcesz uczestniczyć w projekcie związanym ze wspieraniem polskiej społeczności, to dodaj głos na ten komentarz :)
Jeżeli jesteś autorem postu i nie chcesz być losowany w przyszłości, to odpowiedz na ten komentarz "STOP", a zostaniesz dodany do listy "wyjątków".