W programie nie będziemy posługiwali się tablicą symulującą kwadrat i komórki, a liczbą z zakresu 0-511, którą można opisać na 9 bitach, z których każdy będzie odpowiednikiem jednej komórki. I tak dla przykładu:
wartość 0 = 000 000 000 - czyli wszystkie komórki w kolorze białym, wartość 123 = 001 111 011 - komórki 3, 4, 5, 6, 8, 9 w kolorze szarym, wartość 511 = 111 111 111 - wszystkie komórki w kolorze szarymJeśli wiemy już czego szukamy, możemy opisać poszukiwane kwadraty w postaci liczbowej bo:
kwadrat 1 to 110 110 000 czyli liczba 432, kwadrat 2 to 011 011 000 czyli liczba 216, kwadrat 3 to 000 110 110 czyli liczba 54, kwadrat 4 to 000 011 011 czyli liczba 27Sieć powinna wskazać liczby 27, 54, 216, 432 jako jedno z rozwiązań. Wybrałem 3 podstawowe warunki, które muszą być spełnione aby zbliżyć się do rozwiązania.
Warunek 1 - w poprawnym rozwiązaniu, szare muszą być 4 komórki. Aby zachować separowalność liniową zbiorów, wykorzystam dwa neurony. Dzieje się tak dlatego, że neurony zawsze będą aktywne po osiągnięciu wartości wzbudzenia i tak:
neuron nr 1 - aktywny jeśli w kolorze szarym będą co najmniej 4 komórki (czyli 4, 5, 6, 7, 8, 9)
neuron nr 2 - aktywny jeśli w kolorze białym będzie co najmniej 5 komórek (czyli 5, 6, 7, 8, 9)
Dzięki takiemu rozwiązaniu, aktywacja obu neuronów jednocześnie, jest możliwa tylko jeśli będą 4 pola szare i 5 pól białych. Oczywiście można było rozwiązać problem przy pomocy jednego neuronu wykorzystując "identyczność" jako funkcję aktywującą, ale nie chciałem iść na łatwiznę i skorzystałem z progowej (bipolarnej) funkcji aktywującej.
Warunek 2 - istnieje zależność pomiędzy położeniem kwadratów i wielokrotnym wykorzystaniem komórek, można to opisać jednym neuronem:
neuron nr 3 - tutaj warto się zastanowić, bo poszczególne komórki w czterech prawidłowych rozwiązaniach powtarzają się. I tak, komórka 5 będzie szara we wszystkich rozwiązaniach, komórki 2, 4, 6, 8 będą szare w dwóch poprawnych rozwiązaniach, a komórki 1, 3, 7, 9 będą szare tylko w jednym rozwiązaniu. Wiedząc to, możemy dobrać odpowiednio wagi dla poszczególnych wejść neuronu. Przyjąłem, że:
wejścia 1, 3, 7, 9 - będą miały wagę 1,
wejścia 2, 4, 6, 8 - będą miały wagę 2,
wejście 5 - będzie miało wagę 4,
Warunek 3 - w każdym prawidłowym rozwiązaniu skrajne komórki 1, 3, 7, 9 muszą być koloru szarego. Ten warunek będzie sprawdzany w neuronie 4, dla którego wybrane komórki otrzymają odpowiednie wagi.
W każdym z neuronów wejściami będą poszczególne komórki - czyli będzie 9 wejść.
neuron nr 1 - wagi wszystkich wejść będą ustawione na 1, dopełnienie będzie wynosiło 0, a wartością aktywującą neuron będzie każda liczba >= 4,
neuron nr 2 - wagi wszystkich wejść będą ustawione na 1, dopełnienie będzie wynosiło 0, a wartością aktywującą neuron będzie każda liczba >= 5,
neuron nr 3 - wagi wejść będą ustawione w zależności od częstotliwości występowania komórek w prawidłowych rozwiązaniach, a wartością aktywującą neuron będzie każda liczba >= 9,
neuron nr 4 - wagi wejść będą ustawione w zależności od położenia komórki - skrajne są ważniejsze, a wartością aktywującą neuron będzie każda liczba >= 1
Ta prosta sieć neuronowa, spełniająca wymienione warunki, a zbudowana z 4 neuronów, wskazała 24 rozwiązania z 512 możliwych. Sieć nie posiada elementu uczącego, który dobierałby wagi do określonych wzorców. Wagi dobieramy samodzielnie realizując 3 wymienione warunki. Postać graficzna i liczbowa rozwiązań zaproponowanych przez sieć:
027 - 000 011 011 030 - 000 011 110 051 - 000 110 011 054 - 000 110 110 057 - 000 111 001 060 - 000 111 100 090 - 001 011 010 114 - 001 110 010 120 - 001 111 000 147 - 010 010 011 150 - 010 010 110 153 - 010 011 001 156 - 010 011 100 177 - 010 110 001 180 - 010 110 100 210 - 011 010 010 216 - 011 011 000 240 - 011 110 000 282 - 100 011 010 306 - 100 110 010 312 - 100 111 000 402 - 110 010 010 408 - 110 011 000 432 - 110 110 000
Sieć nie wykonuje skomplikowanych operacji, ale ze względu na ilość wejść w neuronach, kodu jest sporo. Dodatkowo, aby dowolnie manipulować wejściami neuronów, jest trochę nadmiarowego kodu obsługującego dopełnienie (bias).
OPTION DOTNAME option casemap:none .DATA output dw 512 dup(0) ; bufor z próbkami, które aktywowały wyjście sieci, ; ma rozmiar 1024 bajtów, bo 512 próbek pomnożone przez ; 16 bitów (word). Wykorzystujemy 9 bitów ale rejestry są ; 8, 16, 32, 64 i 128 - bitowe dlatego 16 bitów. weight_n1_1 db 1 ; wagi wejść dla neuronu pierwszego weight_n1_2 db 1 weight_n1_3 db 1 weight_n1_4 db 1 weight_n1_5 db 1 weight_n1_6 db 1 weight_n1_7 db 1 weight_n1_8 db 1 weight_n1_9 db 1 weight_n2_1 db 1 ; wagi wejść dla neuronu drugiego weight_n2_2 db 1 weight_n2_3 db 1 weight_n2_4 db 1 weight_n2_5 db 1 weight_n2_6 db 1 weight_n2_7 db 1 weight_n2_8 db 1 weight_n2_9 db 1 weight_n3_1 db 1 ; wagi wejść dla neuronu trzeciego, są zależne od tego weight_n3_2 db 2 ; jak często dana komórka jest wykorzystywane w weight_n3_3 db 1 ; prawidłowych rozwiązaniach. dlatego: weight_n3_4 db 2 ; wejścia 1, 3, 7, 9 - mają wagę 1, weight_n3_5 db 4 ; wejścia 2, 4, 6, 8 - mają wagę 2, weight_n3_6 db 2 ; wejście 5 - ma wagę 4 weight_n3_7 db 1 weight_n3_8 db 2 weight_n3_9 db 1 weight_n4_1 db 1 ; wagi dla neuronu czwartego są zależne od położenia komórki weight_n4_2 db 0 ; wejścia 1, 3, 7, 9 mają większą wagę, bo neuron weight_n4_3 db 1 ; bada czy próbka wykorzystuje skrajne komórki weight_n4_4 db 0 weight_n4_5 db 0 weight_n4_6 db 0 weight_n4_7 db 1 weight_n4_8 db 0 weight_n4_9 db 1 bias_n1_1 db 0 ; uzupełnienie dla wejść wszystkich neuronów bias_n1_2 db 0 ; wszędzie 0, ale dodałem gdyby ktoś chciał bias_n1_3 db 0 ; testować inne rozwiązania bias_n1_4 db 0 bias_n1_5 db 0 bias_n1_6 db 0 bias_n1_7 db 0 bias_n1_8 db 0 bias_n1_9 db 0 bias_n2_1 db 0 bias_n2_2 db 0 bias_n2_3 db 0 bias_n2_4 db 0 bias_n2_5 db 0 bias_n2_6 db 0 bias_n2_7 db 0 bias_n2_8 db 0 bias_n2_9 db 0 bias_n3_1 db 0 bias_n3_2 db 0 bias_n3_3 db 0 bias_n3_4 db 0 bias_n3_5 db 0 bias_n3_6 db 0 bias_n3_7 db 0 bias_n3_8 db 0 bias_n3_9 db 0 bias_n4_1 db 0 bias_n4_2 db 0 bias_n4_3 db 0 bias_n4_4 db 0 bias_n4_5 db 0 bias_n4_6 db 0 bias_n4_7 db 0 bias_n4_8 db 0 bias_n4_9 db 0 input_n1_1 db 0 ; ustalamy wejścia neuronu 1 na kolor biały input_n1_2 db 0 ; bo szukamy szarych komórek input_n1_3 db 0 input_n1_4 db 0 input_n1_5 db 0 input_n1_6 db 0 input_n1_7 db 0 input_n1_8 db 0 input_n1_9 db 0 input_n2_1 db 1 ; ustalamy wejścia neuronu 2 na kolor szary input_n2_2 db 1 ; bo szukamy białych komórek input_n2_3 db 1 input_n2_4 db 1 input_n2_5 db 1 input_n2_6 db 1 input_n2_7 db 1 input_n2_8 db 1 input_n2_9 db 1 input_n3_1 db 0 ; ustalamy wejścia neuronu 3 na kolor biały input_n3_2 db 0 ; bo szukamy szarych komórek input_n3_3 db 0 input_n3_4 db 0 input_n3_5 db 0 input_n3_6 db 0 input_n3_7 db 0 input_n3_8 db 0 input_n3_9 db 0 input_n4_1 db 0 ; ustalamy wejścia neuronu 4 na kolor biały input_n4_2 db 0 ; bo szukamy szarych komórek input_n4_3 db 0 input_n4_4 db 0 input_n4_5 db 0 input_n4_6 db 0 input_n4_7 db 0 input_n4_8 db 0 input_n4_9 db 0 .CODE start: main PROC xor r12, r12 ; rejestr zliczający ilość aktywnych neuronów dla próbki xor r13, r13 ; rejestr zliczający ilość poprawnych próbek xor rdx, rdx ; rejestr z kolejnymi próbkami lea r14, output ; adres z buforem dla poprawnych rozwiązań @set_input_1: test dx, 0000000000000001b ; testujemy pierwszą komórkę z próbki jz @set_input_2 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_1], 1 ; jeśli szara to ustawiamy wejście 1 neuronów mov BYTE PTR [input_n2_1], 0 mov BYTE PTR [input_n3_1], 1 mov BYTE PTR [input_n4_1], 1 @set_input_2: test dx, 0000000000000010b ; testujemy drugą komórkę z próbki jz @set_input_3 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_2], 1 ; jeśli szara to ustawiamy wejście 2 neuronów mov BYTE PTR [input_n2_2], 0 mov BYTE PTR [input_n3_2], 1 mov BYTE PTR [input_n4_2], 1 @set_input_3: test dx, 0000000000000100b ; testujemy trzecią komórkę z próbki jz @set_input_4 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_3], 1 ; jeśli szara to ustawiamy wejście 3 neuronów mov BYTE PTR [input_n2_3], 0 mov BYTE PTR [input_n3_3], 1 mov BYTE PTR [input_n4_3], 1 @set_input_4: test dx, 0000000000001000b ; testujemy czwartą komórkę z próbki jz @set_input_5 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_4], 1 ; jeśli szara to ustawiamy wejście 4 neuronów mov BYTE PTR [input_n2_4], 0 mov BYTE PTR [input_n3_4], 1 mov BYTE PTR [input_n4_4], 1 @set_input_5: test dx, 0000000000010000b ; testujemy piątą komórkę z próbki jz @set_input_6 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_5], 1 ; jeśli szara to ustawiamy wejście 5 neuronów mov BYTE PTR [input_n2_5], 0 mov BYTE PTR [input_n3_5], 1 mov BYTE PTR [input_n4_5], 1 @set_input_6: test dx, 0000000000100000b ; testujemy szóstą komórkę z próbki jz @set_input_7 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_6], 1 ; jeśli szara to ustawiamy wejście 6 neuronów mov BYTE PTR [input_n2_6], 0 mov BYTE PTR [input_n3_6], 1 mov BYTE PTR [input_n4_6], 1 @set_input_7: test dx, 0000000001000000b ; testujemy siódmą komórkę z próbki jz @set_input_8 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_7], 1 ; jeśli szara to ustawiamy wejście 7 neuronów mov BYTE PTR [input_n2_7], 0 mov BYTE PTR [input_n3_7], 1 mov BYTE PTR [input_n4_7], 1 @set_input_8: test dx, 0000000010000000b ; testujemy ósmą komórkę z próbki jz @set_input_9 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_8], 1 ; jeśli szara to ustawiamy wejście 8 neuronów mov BYTE PTR [input_n2_8], 0 mov BYTE PTR [input_n3_8], 1 mov BYTE PTR [input_n4_8], 1 @set_input_9: test dx, 0000000100000000b ; testujemy dziewiątą komórkę z próbki jz @neuron1 ; jeśli nie szara to przechodzimy do kolejnej mov BYTE PTR [input_n1_9], 1 ; jeśli szara to ustawiamy wejście 9 neuronów mov BYTE PTR [input_n2_9], 0 mov BYTE PTR [input_n3_9], 1 mov BYTE PTR [input_n4_9], 1 @neuron1: xor r8, r8 ; wyjście neuronu, aktywne jeśli r8 >= 4 xor rax, rax ; stan wejściowy xor rcx, rcx ; waga neuronu mov cl, BYTE PTR [weight_n1_1] mov al, BYTE PTR [input_n1_1] imul cl add al, BYTE PTR [bias_n1_1] add r8, rax mov cl, BYTE PTR [weight_n1_2] mov al, BYTE PTR [input_n1_2] imul cl add al, BYTE PTR [bias_n1_2] add r8, rax mov cl, BYTE PTR [weight_n1_3] mov al, BYTE PTR [input_n1_3] imul cl add al, BYTE PTR [bias_n1_3] add r8, rax mov cl, BYTE PTR [weight_n1_4] mov al, BYTE PTR [input_n1_4] imul cl add al, BYTE PTR [bias_n1_4] add r8, rax mov cl, BYTE PTR [weight_n1_5] mov al, BYTE PTR [input_n1_5] imul cl add al, BYTE PTR [bias_n1_5] add r8, rax mov cl, BYTE PTR [weight_n1_6] mov al, BYTE PTR [input_n1_6] imul cl add al, BYTE PTR [bias_n1_6] add r8, rax mov cl, BYTE PTR [weight_n1_7] mov al, BYTE PTR [input_n1_7] imul cl add al, BYTE PTR [bias_n1_7] add r8, rax mov cl, BYTE PTR [weight_n1_8] mov al, BYTE PTR [input_n1_8] imul cl add al, BYTE PTR [bias_n1_8] add r8, rax mov cl, BYTE PTR [weight_n1_9] mov al, BYTE PTR [input_n1_9] imul cl add al, BYTE PTR [bias_n1_9] add r8, rax @neuron2: xor r9, r9; ; wyjście neuronu, aktywne jeśli r9 >= 5 xor rax, rax ; stan wejściowy xor rcx, rcx ; waga neuronu mov cl, BYTE PTR [weight_n2_1] mov al, BYTE PTR [input_n2_1] imul cl add al, BYTE PTR [bias_n2_1] add r9, rax mov cl, BYTE PTR [weight_n2_2] mov al, BYTE PTR [input_n2_2] imul cl add al, BYTE PTR [bias_n2_2] add r9, rax mov cl, BYTE PTR [weight_n2_3] mov al, BYTE PTR [input_n2_3] imul cl add al, BYTE PTR [bias_n2_3] add r9, rax mov cl, BYTE PTR [weight_n2_4] mov al, BYTE PTR [input_n2_4] imul cl add al, BYTE PTR [bias_n2_4] add r9, rax mov cl, BYTE PTR [weight_n2_5] mov al, BYTE PTR [input_n2_5] imul cl add al, BYTE PTR [bias_n2_5] add r9, rax mov cl, BYTE PTR [weight_n2_6] mov al, BYTE PTR [input_n2_6] imul cl add al, BYTE PTR [bias_n2_6] add r9, rax mov cl, BYTE PTR [weight_n2_7] mov al, BYTE PTR [input_n2_7] imul cl add al, BYTE PTR [bias_n2_7] add r9, rax mov cl, BYTE PTR [weight_n2_8] mov al, BYTE PTR [input_n2_8] imul cl add al, BYTE PTR [bias_n2_8] add r9, rax mov cl, BYTE PTR [weight_n2_9] mov al, BYTE PTR [input_n2_9] imul cl add al, BYTE PTR [bias_n2_9] add r9, rax @neuron3: xor r10, r10 ; wyjście neuronu, aktywne jeśli r10 >= 9 xor rax, rax ; stan wejściowy xor rcx, rcx ; waga neuronu mov cl, BYTE PTR [weight_n3_1] mov al, BYTE PTR [input_n3_1] imul cl add al, BYTE PTR [bias_n3_1] add r10, rax mov cl, BYTE PTR [weight_n3_2] mov al, BYTE PTR [input_n3_2] imul cl add al, BYTE PTR [bias_n3_2] add r10, rax mov cl, BYTE PTR [weight_n3_3] mov al, BYTE PTR [input_n3_3] imul cl add al, BYTE PTR [bias_n3_3] add r10, rax mov cl, BYTE PTR [weight_n3_4] mov al, BYTE PTR [input_n3_4] imul cl add al, BYTE PTR [bias_n3_4] add r10, rax mov cl, BYTE PTR [weight_n3_5] mov al, BYTE PTR [input_n3_5] imul cl add al, BYTE PTR [bias_n3_5] add r10, rax mov cl, BYTE PTR [weight_n3_6] mov al, BYTE PTR [input_n3_6] imul cl add al, BYTE PTR [bias_n3_6] add r10, rax mov cl, BYTE PTR [weight_n3_7] mov al, BYTE PTR [input_n3_7] imul cl add al, BYTE PTR [bias_n3_7] add r10, rax mov cl, BYTE PTR [weight_n3_8] mov al, BYTE PTR [input_n3_8] imul cl add al, BYTE PTR [bias_n3_8] add r10, rax mov cl, BYTE PTR [weight_n3_9] mov al, BYTE PTR [input_n3_9] imul cl add al, BYTE PTR [bias_n3_9] add r10, rax @neuron4: xor r11, r11 ; wyjście neuronu, aktywne jeśli r11 >= 1 xor rax, rax ; stan wejściowy xor rcx, rcx ; waga neuronu mov cl, BYTE PTR [weight_n4_1] mov al, BYTE PTR [input_n4_1] imul cl add al, BYTE PTR [bias_n4_1] add r11, rax mov cl, BYTE PTR [weight_n4_2] mov al, BYTE PTR [input_n4_2] imul cl add al, BYTE PTR [bias_n4_2] add r11, rax mov cl, BYTE PTR [weight_n4_3] mov al, BYTE PTR [input_n4_3] imul cl add al, BYTE PTR [bias_n4_3] add r11, rax mov cl, BYTE PTR [weight_n4_4] mov al, BYTE PTR [input_n4_4] imul cl add al, BYTE PTR [bias_n4_4] add r11, rax mov cl, BYTE PTR [weight_n4_5] mov al, BYTE PTR [input_n4_5] imul cl add al, BYTE PTR [bias_n4_5] add r11, rax mov cl, BYTE PTR [weight_n4_6] mov al, BYTE PTR [input_n4_6] imul cl add al, BYTE PTR [bias_n4_6] add r11, rax mov cl, BYTE PTR [weight_n4_7] mov al, BYTE PTR [input_n4_7] imul cl add al, BYTE PTR [bias_n4_7] add r11, rax mov cl, BYTE PTR [weight_n4_8] mov al, BYTE PTR [input_n4_8] imul cl add al, BYTE PTR [bias_n4_8] add r11, rax mov cl, BYTE PTR [weight_n4_9] mov al, BYTE PTR [input_n4_9] imul cl add al, BYTE PTR [bias_n4_9] add r11, rax @neuron1_check: cmp r8, 4 ; sprawdzanie czy aktywować neuron 1 jl @neuron2_check inc r12 ; jeśli aktywny to zwiększamy r12 o jeden @neuron2_check: cmp r9, 5 ; sprawdzanie czy aktywować neuron 2 jl @neuron3_check inc r12 ; jeśli aktywny to zwiększamy r12 o jeden @neuron3_check: cmp r10, 9 ; sprawdzanie czy aktywować neuron 3 jl @neuron4_check inc r12 ; jeśli aktywny to zwiększamy r12 o jeden @neuron4_check: cmp r11, 1 ; sprawdzanie czy aktywować neuron 4 jl @next_pattern inc r12 ; jeśli aktywny to zwiększamy r12 o jeden cmp r12, 4 ; jeśli cztery neurony aktywne do próbka jest ok. jnz @next_pattern inc r13 ; tutaj zliczamy próbki które sieć uznała z prawidłowe mov WORD PTR [r14], dx ; zapisujemy próbkę do pamięci add r14, 2 ; zwiększamy adres bufora z próbkami o kolejny WORD @next_pattern: mov BYTE PTR [input_n1_1], 0 ; przywracamy stan początkowy neuronów mov BYTE PTR [input_n1_2], 0 mov BYTE PTR [input_n1_3], 0 mov BYTE PTR [input_n1_4], 0 mov BYTE PTR [input_n1_5], 0 mov BYTE PTR [input_n1_6], 0 mov BYTE PTR [input_n1_7], 0 mov BYTE PTR [input_n1_8], 0 mov BYTE PTR [input_n1_9], 0 mov BYTE PTR [input_n2_1], 1 mov BYTE PTR [input_n2_2], 1 mov BYTE PTR [input_n2_3], 1 mov BYTE PTR [input_n2_4], 1 mov BYTE PTR [input_n2_5], 1 mov BYTE PTR [input_n2_6], 1 mov BYTE PTR [input_n2_7], 1 mov BYTE PTR [input_n2_8], 1 mov BYTE PTR [input_n2_9], 1 mov BYTE PTR [input_n3_1], 0 mov BYTE PTR [input_n3_2], 0 mov BYTE PTR [input_n3_3], 0 mov BYTE PTR [input_n3_4], 0 mov BYTE PTR [input_n3_5], 0 mov BYTE PTR [input_n3_6], 0 mov BYTE PTR [input_n3_7], 0 mov BYTE PTR [input_n3_8], 0 mov BYTE PTR [input_n3_9], 0 mov BYTE PTR [input_n4_1], 0 mov BYTE PTR [input_n4_2], 0 mov BYTE PTR [input_n4_3], 0 mov BYTE PTR [input_n4_4], 0 mov BYTE PTR [input_n4_5], 0 mov BYTE PTR [input_n4_6], 0 mov BYTE PTR [input_n4_7], 0 mov BYTE PTR [input_n4_8], 0 mov BYTE PTR [input_n4_9], 0 inc dx ; przechodzimy do następnej próbki xor r12, r12 ; zerujemy licznik z aktywnymi neuronami cmp rdx, 512 ; sprawdzamy czy to już wszystkie próbki jnz @set_input_1 ; jeśli nie to wracamy na początek ret ; zakończenie programu main ENDP END
Brak komentarzy:
Prześlij komentarz