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