SZTUCZNA INTELIGENCJA
Transkrypt
SZTUCZNA INTELIGENCJA
POLITECHNIKA RZESZOWSKA WYDZIAŁ ELEKTROTECHNIKI I INFORMATYKI KATEDRA INFORMATYKI I AUTOMATYKI SZTUCZNA INTELIGENCJA PROJEKT Temat: Zrealizować sieć neuronową uczoną algorytmem wstecznej propagacji błędu z przyśpieszeniem metodą momentum (learnbpm) uczącą się identyfikacji spamu. Wykonał Mateusz Drozdowski II EF-DI P03 Spis treści. 1. Opis problemu........................................................................................................................................- 3 2. Przygotowanie danych. ..........................................................................................................................- 3 2.1. Atrybuty rekordów zawartych w repozytorium..............................................................................- 3 2.2. Wczytanie danych uczących. ..........................................................................................................- 4 2.3. Normalizacja danych. .....................................................................................................................- 4 3. Opis Algorytmu. ....................................................................................................................................- 5 3.1. Siec neuronowa...............................................................................................................................- 5 3.2. Opis metody ....................................................................................................................................- 6 3.3. Skrypt realizujący sieć neuronową. ................................................................................................- 7 4. Eksperymenty. .......................................................................................................................................- 8 5. Wnioski i podsumowanie.....................................................................................................................- 14 - -2- 1. Opis problemu. Celem projektu jest stworzenie sieci neuronowej, która na podstawie informacji dotyczących wiadomości e-mail rozpoznaje wiadomości i jest w stanie zaklasyfikować je jako zwykłą bądź też niechciany spam. E-mail spam - znany także jako "śmieci", niechciane wiadomości, jest podzbiorem spamu, który dotyczy praktycznie identycznych wiadomości wysłanych do dużej liczby odbiorców za pośrednictwem poczty elektronicznej. Powszechnym synonimem spamu jest niechciana poczta masowa (ang. UBE). Definicje spamu zazwyczaj zawierają aspekty, takie jak fakt, że email jest niechciany i wysłany do dużej liczby odbiorców. Istnieje także spam z gatunku "UCE", czyli niechciana oferta handlowa, spam o charakterze handlowym zakazany przez polskie prawo i dyrektywę UE. Dane użyte przy tworzeniu projektu zostały pobrane z repozytorium należącego do Uniwersytetu Kalifornijskiego w Irvine (http://archive.ics.uci.edu/ml/datasets/Spambase). Repozytorium zostało stworzone przez Marka Hopkinsa, Erika Reebera, George'a Formana, Jaapa Suermondta z HewlettPackard Labs. Analizie poddanych zostało 4601 wiadomości e-mail (każda wiadomość obejmuje jeden wiersz pliku z danymi). Wśród analizowanych wiadomości znajduje się 1813 wiadomości niechcianych, spamu i 2788 wiadomości zwykłych. Każda wiadomość została opisana 58 atrybutami (jeden atrybut to jedna kolumna), przy czym ostatnia kolumna mówi czy wiadomość należy do spamu czy nie. 2. Przygotowanie danych. 2.1. Atrybuty rekordów zawartych w repozytorium. Numer kolumny Typ danych Zakres danych 1-48 ciągły rzeczywisty [ 0 ... 100 ] 49-54 ciągły rzeczywisty [ 0 ... 100 ] 55 ciągły rzeczywisty [ 1, ... ] 56 ciągły całkowity [ 1, ... ] 57 ciągły całkowity [ 1, ... ] 58 nominalny { 0, 1 } Opis Procent słów ze słownika w stosunku do wszystkich słów w wiadomości. Procent znaków ze zbioru w stosunku do wszystkich znaków w wiadomości. Średnia długość nieprzerwanego ciągu wielkich znaków w danej wiadomości. Długość najdłuższego nieprzerwanego ciągu wielkich liter w danej wiadomości. Całkowita liczba wielkich liter w danej wiadomości. Oznaczenie, czy wiadomość jest spamem. Słownik wyrazów: make, address, all, 3d, our, over, remove, internet, order, mail, receive, will, people, report, addresses, free, business, email, you, credit, your, font, 000, money, hp, hpl, george, 650, lab, labs, telnet, 857, data, 415, 85, technology, 1999, parts, pm, direct, cs, meeting, original, project, re, edu, table, conference Zbiór znaków: ; ( [ ! $ # -3- Przed przygotowaniem danych, w pierwszej kolejności należy odpowiednio dostosować środowisko pracy. W celu dokonania tego, nasz skrypt powinien zaczynać się w następujący sposób: clc clear all close all nntwarn off warning off %wyczyszczenie okna poleceń %wyczyszczenie przestrzeni %zamknięcie aktualnie wyświetlanych wykresów %wyłączenie ostrzeżeń 2.2. Wczytanie danych uczących. data = load('spambase.data'); j = 1; for i=1:XX:length(data(:,1)) temp(j,:) = data(i,:); j=j+1; end clear data data = temp; % XX - należy podac, co ktory wiersz ma byc wczytany Napisany w ten sposób fragment skryptu wczytujący dane z pliku do zmiennej data daje nam trochę elastyczności, otóż możemy wczytać zarówno cały plik (w miejsce XX wpisać 1), bądź tylko wybiórcze dane uczące, np. co 5 wiersz. Po wczytaniu danych otrzymujemy macierz posiadającą 4601 wierszy i 58 kolumn. Pierwsze 57 kolumn zawiera informacje dotyczące wiadomości email, natomiast ostatnia kolumna zawiera informację czy dana wiadomość jest spamem, czy też nie. Należy oddzielić od siebie te 2 rzeczy. Kolumny 1-57 zostają przy użyciu odpowiedniego skryptu zapisane do wektora wejść P, natomiast ostatnia kolumna posłuży nam za wektor wyjść T: for i = 1:(length(data(1,:))-1) for j = 1:length(data(:,1)) P(j,i) = data(j,i); end end T=data( :,length(data(1,:)) ); 2.3. Normalizacja danych. Wczytane przez nas dane są już odpowiednio posortowane, jednak posiadają bardzo rozbieżne wartości i sieć nie będzie w stanie przetworzyć ich w odpowiedni sposób oraz nauczyć się. Należy zastosować normalizację danych, co zwróci nam dane z przedziału [ 0...1 ], a z taką formą sieć poradzi sobie bez problemu. Normalizacja przeprowadzona jest w następujący sposób: znajdujemy w danej kolumnie największy element, a następnie wszystkie elementy tej kolumny dzielimy przez znalezione maksimum. Proces ten realizuje poniższy skrypt: for i=1:length(P(1,:)) maximum(i) = max(P(:,i)); for j=1:length(P) P(j,i) = P(j,i)/maximum(i); end end -4- 3. Opis Algorytmu. 3.1. Siec neuronowa. Sieć neuronowa (sztuczna sieć neuronowa) to ogólna nazwa struktur matematycznych i ich programowych lub sprzętowych modeli, realizujących obliczenia lub przetwarzanie sygnałów poprzez rzędy elementów, zwanych sztucznymi neuronami, wykonujących pewną podstawową operację na swoim wejściu. Oryginalną inspiracją takiej struktury była budowa naturalnych neuronów oraz układów nerwowych, w szczególności mózgu. Sztuczna sieć neuronowa jest modelem matematycznym, składającym się z sieci węzłów obliczeniowych zwanych neuronami i ich połączeń. Model ten ma za zadanie symulować pracę neuronów w ludzkim mózgu, jednak istnieją znaczne różnice w ich działaniu. Z punktu widzenia matematycznego, dobrze skonstruowana sieć neuronowa jest w stanie "nauczyć się" aproksymować dowolną funkcję wielu zmiennych. W wyniku aproksymacji sieć jest w stanie uogólnić nabytą wiedzę na nieznane jej, choć podobne problemy. Zdolność ta nazywa się generalizacją. Dane wejściowe zostają pomnożone w neuronie przez odpowiednio przypisane wagi, a następnie sumowane i przekazywane na wyjście. Rys. 1 - model neuronu. x = [x1, x2, ..., xi, ..., xn]T - wektor sygnałów wejściowych w = [w1, w2, ..., wi, ..., wn]T - wektor wag y - sygnał wyjściowy ( ) N Sygnał wyjściowy neuronu wyraża się wzorem y = f ∑ wi xi = f wT x , gdzie f to odpowiednia i =0 funkcja aktywacji. -5- W projekcie wykorzystana jest trójwarstwowa sieć neuronowa, której model przedstawiony jest poniżej: 3.2. Opis metody Algorytmem uczenia sieci neuronowej w tym projekcie jest uczenie pod nadzorem metodą wstecznej propagacji błędu z przyspieszeniem metodą momentum (learnbpm). Zgodnie z tym algorytmem, wektor błędu sieci obliczany dla warstwy wyjściowej rzutowany zostaje wstecz poprzez kolejne jej warstwy. Zabieg ten umożliwia obliczenie nowych wartości współczynników wagowych poszczególnych warstw, a w efekcie zmniejszenie średniokwadratowego błędu sieci (SSE). W pierwszej kolejności wyliczany jest błąd ostatniej warstwy, w oparciu o sygnał wzorcowy i wyjściowy. W pozostałych warstwach błąd obliczany jest jako ustalona funkcja błędu neuronów warstwy poprzedzającej. Algorytm ten należy do gradientowych metod optymalizacji, gdyż opiera się o stwierdzenie, że gradient funkcji wskazuje kierunek jej najszybszego wzrostu, a zmieniając jego znak na przeciwny, uzyskujemy kierunek najszybszego spadku funkcji. Możemy w ten sposób minimalizować funkcję celu przez modyfikację współczynników wagowych w kierunku najszybszego spadku funkcji. Zmiana wartości współczynników wagowych i progowych dla i-tego wejścia i i-tego neuronu opisana jest zależnością: ?W(i,j) = mc * ?Wp(i,j) + (l - mc) * lr * d(i) * p(j) ?B(i) = mc * ?Bp(i) + (l - mc) * lr * d(i) Stała momentum (parametr mc) określa wpływ poprzedniej zmiany wag ?Wp i współczynników progowych ?Bp na zmianę dokonywaną obecnie. Zastosowanie metody momentum przyczynia się do likwidacji zbyt gwałtownych zmian wartości funkcji błędu sieci. Umożliwia to bezpieczne zwiększenie wartości współczynnika prędkości uczenia lr. -6- Wykorzystując oprogramowani firmy MathWorks opisaną metodę wywołuje się w następujący sposób: [dW, dB] = learnbpm (P,D,LR,MC,dW,dB) Gdzie odpowiednio: P - macierz wektorów wejściowych (wymiar R*Q, R - liczba wejść warstwy, Q - ilość wektorów), D - macierz pochodnych błędów warstwy (wymiar S*Q, S - liczba neuronów w warstwie), LR - współczynnik uczenia sieci, MC - wartość stałej momentum, dW - macierz przyrostów współczynników warstwy w poprzednim kroku (wymiar S*R), dB - wektor przyrostów współczynników progowych warstwy w poprzednim kroku (wymiar S*1). Wartości zwracane przez metodę: dW - nowa macierz przyrostów współczynników wagowych warstwy (wymiar S*R), dB - nowa macierz przyrostów współczynników progowych warstwy (wymiar S*1). 3.3. Skrypt realizujący sieć neuronową. T = T'; P = P'; %transponowanie macierzy T %transponowanie macierzy P [R,Q] = size(P); %ustawienie rozmiarów wejścia, R liczba wierszy, Q liczba kolumn [S3,Q] = size(T); %ustawienie rozmiarów wyjścia, %S3 liczba wierszy macierzy wejścia, Q liczba kolumn S1=10; %ustawienie liczby neuronów w warstwie S1 S2=7; %ustawienie liczby neuronów w warstwie S2 lr=0.01; %współczynnik uczenia mc=0.9; %stała momentum err_goal=0.1; %docelowy błąd %zainicjalizowanie neuronów i ich współczynników wagowych (1) [W1,B1] = nwtan(S1,R); [W2,B2] = nwtan(S2,S1); [W3,B3] = rands(S3,S2); %stworzenie tablic wypełnionych zerami dW1=zeros(size(W1)); dW2=zeros(size(W2)); dW3=zeros(size(W3)); dB1=zeros(size(B1)); dB2=zeros(size(B2)); dB3=zeros(size(B3)); disp_freq=100; %częstotliwość wyświetlania wyników max_epoch=30000; %liczba kroków uczenia error=[]; %wektor zawierający błędy kolejnych kroków uczenia A1 = tansig(W1*P,B1); %obliczenie wyjscia dla sieci, z funkcją aktywacji tansig A2 = tansig(W2*A1,B2); A3 = purelin(W3*A2,B3); %obliczenie wyjscia dla sieci, W1*P+B1 %z funkcją aktywacji purelin E = T-A3; %oblicznie błędu pomiędzy wzorcem a wyjściem z sieci SSE = sumsqr(E); %oblicznie funkcji celu, czyli sumy z kwadratów błędów -7- %pętla wykonująca algorytm uczenia sieci dla podanej liczby kroków uczenia for epoch=1:max_epoch, % zakończenie gdy funkcja celu jest mniejsza od docelowego błędu if SSE < err_goal, epoch=epoch-1; break; end, %obliczenie wektorów błędów warstw wyjściowych D3 = deltalin(A3,E); D2 = deltatan(A2,D3,W3); D1 = deltatan(A1,D2,W2); %obliczenie [dW1,dB1] = [dW2,dB2] = [dW3,dB3] = zmian wag przy uczeniu algorytmem wstecznej propagacji z momentum learnbpm(P,D1,lr,mc,dW1,dB1); learnbpm(A1,D2,lr,mc,dW2,dB2); learnbpm(A2,D3,lr,mc,dW3,dB3); %aktualizacja wag W1 = W1 + dW1; B1 = B1 + dB1; W2 = W2 + dW2; B2 = B2 + dB2; W3 = W3 + dW3; B3 = B3 + dB3; %obliczenie wyjscia z sieci dla nowych wag A1 = tansig(W1*P,B1); A2 = tansig(W2*A1,B2); A3 = purelin(W3*A2,B3); E = T-A3; SSE = sumsqr(E); %tworzenie funkcji celu, zapisywanie do wektora error jego %aktualnej wartości i nowej wartosci funkcji celu error = [error SSE]; %wyświetlanie wykresu i informacji o przebiegu uczenia if (rem(epoch,disp_freq) == 0) info = sprintf('Epoch: %g/%g, Err_goal: %g, SSE: %g, ANS: %g \n',epoch,max_epoch,err_goal,SSE, 100*(1-sum((abs(T-A3)>.5)')/length(T))); fprintf(info,0); plot(1:length(T),T,'r',1:length(T),A3,'g'); legend('Rzeczywiste','Wyuczone',1); pause(1e-100); end end (1) - generowanie macierzy wag i wektora biasu (przesunięcia) przy użyciu metody Nguyen-Widrow do inicjalizacji ich wartości dla warstwy tan-sigmoid - [W1,B1] = nwtan(S1,R). Stworzona zostaje macierz o wymiarach S1 × R i wektor B1 o wymiarze S1. [W3,B3] = rands(S3,S2) - generowanie macierzy wag i wektora biasu o wartościach statycznych o jednorodnym rozkładzie z zakresu [-1, 1]. Stworzona zostaje macierz W3 o wymiarach S3 × S2 i wektor B3 o wymiarze S3. 4. Eksperymenty. Eksperymenty wykonywane na gotowym skrypcie sieci neuronowej w głównej mierze opierały się na modyfikowaniu ilości neuronów w warstwie pierwszej i drugiej, a także współczynnika prędkości uczenia i stałej momentum, na podstawie wyników otrzymanych przy każdej z prób. Wczytując dane uczące z repozytorium otrzymujemy ogromną ilość informacji do przetworzenia. Wektor wejściowy zawiera macierz o wymiarach 4601 × 57, co daje nam 262257 danych. -8- Ustalono początkowe parametry sieci na poziomie: S1 S2 lr mc = = = = 25; 10; 0.01; 0.9; W efekcie otrzymano wynik: Epoch: 100/100000, Err_goal: 0.1, SSE: NaN, ANS: 100 Epoch: 200/100000, Err_goal: 0.1, SSE: NaN, ANS: 100 Epoch: 300/100000, Err_goal: 0.1, SSE: NaN, ANS: 100 Funkcja celu (SSE) już podczas uruchomienia skryptu okazała się mieć bardzo dużą wartość, która nie malała więc zmniejszony został współczynnik uczenia. lr = 0.001; Wynik: Epoch: 100/100000, Err_goal: 0.1, SSE: 1.46983e+091, ANS: 0 Epoch: 200/100000, Err_goal: 0.1, SSE: 9.44763e+181, ANS: 0 Epoch: 300/100000, Err_goal: 0.1, SSE: 6.07266e+272, ANS: 0 Wynik SSE w dalszym ciągu wzrasta, a celem sieci jest jego zmniejszenie do ustalonego celu. W takim wypadku zostaje zwiększony współczynnik stałej momentum. mc = 0.99; Epoch: 13000/100000, Err_goal: 0.1, SSE: 147.919, ANS: 96.1965 Epoch: 14000/100000, Err_goal: 0.1, SSE: 143.455, ANS: 96.2834 Epoch: 15000/100000, Err_goal: 0.1, SSE: 139.182, ANS: 96.5008 -9- Sieć neuronowa w końcu zaczęła się uczyć, jednak proces ten przebiegał strasznie wolno. Zmieniona zostaje ilość neuronów w obydwu warstwach. S1=100; S2=25; lr=0.001; mc=0.99; Epoch: 8000/100000, Err_goal: 0.1, SSE: 158.023, ANS: 95.9139 Epoch: 9000/100000, Err_goal: 0.1, SSE: 151.108, ANS: 96.0661 Epoch: 10000/100000, Err_goal: 0.1, SSE: 145.336, ANS: 96.2182 Zmieniając ilość neuronów w warstwach sieć w dalszym ciągu uczy się strasznie wolno. Dodatkowo ilość przetwarzanych informacji obciąża strasznie pamięć i procesor. W rezultacie prędkość przejść sieci podczas uczenia się wynosi średnio 2000 przejść / 1 min. W celu dokładniejszego i szybszego przetestowania sieci zbiór danych zostaje zredukowany do 460 rekordów. Na tak przygotowanym zbiorze danych przeprowadzono dalsze eksperymenty. Ustawienia początkowe sieci: S1=10; S2=5; lr=0.1; mc=0.9; Epoch: 100/100000, Err_goal: 0.1, SSE: 1.07609e+283, ANS: 0 Epoch: 200/100000, Err_goal: 0.1, SSE: NaN, ANS: 100 Epoch: 300/100000, Err_goal: 0.1, SSE: NaN, ANS: 100 - 10 - Funkcja celu wzrasta więc jak we wcześniejszym eksperymencie zmniejszony zostaje współczynnik uczenia: lr=0.01; Epoch: 100/100000, Err_goal: 0.1, SSE: 109.782, ANS: 60.6522 Epoch: 200/100000, Err_goal: 0.1, SSE: 109.78, ANS: 60.6522 Epoch: 300/100000, Err_goal: 0.1, SSE: 109.78, ANS: 60.6522 SSE pozostaje cały czas na niezmienionym poziomie. Postanowiono zarówno zwiększyć liczbę neuronów jak i jeszcze pomniejszyć współczynnik uczenia: S1=25; S2=10; lr=0.001; mc=0.9; Epoch: 10000/100000, Err_goal: 0.1, SSE: 11.069, ANS: 97.8261 Epoch: 20000/100000, Err_goal: 0.1, SSE: 6.11325, ANS: 98.6957 Epoch: 30000/100000, Err_goal: 0.1, SSE: 5.08459, ANS: 98.913 W wyniku tego eksperymentu zauważyć można postęp w uczeniu się sieci. Aby osiągnąć zamierzony cel liczba neuronów zostaje lekko zredukowana, a współczynnik uczenia zwiększony w celu przyspieszenia procesu: S1=10; S2=7; lr=0.01; mc=0.9; - 11 - W taki sposób dobrane dane pozwalają na nauczenie się sieci z założoną wielkością błędu uczenia na poziomie 0.1 Epoch: Epoch: Epoch: Epoch: 43000/100000, 44000/100000, 45000/100000, 45281/100000, Err_goal: Err_goal: Err_goal: Err_goal: 0.1, 0.1, 0.1, 0.1, SSE: SSE: SSE: SSE: 0.2265, 0.1091, 0.1013, 0.0999, ANS: ANS: ANS: ANS: 100 100 100 100 Chcąc sprawdzić zachowanie się sieci neuronowej dla jeszcze mniejszego zbioru danych wejściowych ograniczono dane do około 300 rekordów. Lekko zmieniając parametry nauczonej w powyższym eksperymencie sieci otrzymane zostały zadowalające wyniki: S1=11; S2=7; lr=0.01; mc=0.9; Epoch: Epoch: Epoch: Epoch: 6300/30000, 6400/30000, 6500/30000, 6527/30000, Err_goal: Err_goal: Err_goal: Err_goal: 0.1, 0.1, 0.1, 0.1, SSE: SSE: SSE: SSE: 0.1213, 0.1070, 0.1377, 0.0969, - 12 - ANS: ANS: ANS: ANS: 100 100 100 100 Epoch: Epoch: Epoch: Epoch: 21800/30000, 21900/30000, 22000/30000, 22097/30000, Err_goal: Err_goal: Err_goal: Err_goal: 0.01, 0.01, 0.01, 0.01, SSE: SSE: SSE: SSE: 0.0101851, ANS: 100 0.0101219, ANS: 100 0.0100596, ANS: 100 0.0100, ANS: 100 - 13 - 5. Wnioski i podsumowanie. Celem projektu było zapoznanie się ze strukturą wielowarstwowych sztucznych sieci neuronowych. Zagadnienie to zostało opracowane na przykładzie skryptu realizującego sieć neuronową uczoną algorytmem wstecznej propagacji błędu z przyspieszeniem metodą momentum (learnbpm) rozpoznającą wiadomości spam. Dane uczące wykorzystane w projekcie zostały pobrane ze strony Uniwersytetu Kalifornijskiego w Irvine (adres na str. 3). Przed rozpoczęciem realizacji zagadnienia środowisko MATLAB zostało odpowiednio przygotowane, a dane znormalizowane, ponieważ zawierały wartości z bardzo szerokiego zakresu zarówno liczb całkowitych jak i rzeczywistych. Realizując projekt z przyczyn technicznych zbiór danych uczących musiał zostać pomniejszony. Mimo dość dużej mocy obliczeniowej jedno przejście uczenia sieci trwały na tyle długo, by spowodować, że czas jednego eksperymentu był na poziomie kilku godzin. Na odpowiednio ograniczonym zbiorze danych uczących eksperymenty przebiegały znacznie szybciej, co pozwoliło na dobranie odpowiednich parametrów. Niestety wykorzystując metodę learnbpm nie ustalona została żadna zależność między parametrami sieci, a efektem końcowym. Zauważony został fakt, że nawet niewielkie zmniejszenie zbioru uczącego powoduje ponowny wymóg dostrojenia parametrów sieci w celu poprawnego nauczenia. Przeprowadzane eksperymenty mimo ograniczenia zbioru sprowadzały się do metody "prób i błędów". Manipulowano parametrami sieci przy jednoczesnej obserwacji zachowania się jej. Zmianie ulegała liczba neuronów w warstwach S1 i S2, współczynnik uczenia i stała momentum. Zmieniane były także dane uczące na wejściu sieci w celu wyeliminowania potencjalnie zbędnych rekordów. Ostatecznie udało się dobrać parametry sieci w taki sposób, aby osiągnąć zamierzony błąd na poziomie 0,1, a nawet przy ograniczonym zbiorze do 300 rekordów na poziomie 0,01, przy 100% nauczeniu sieci. Wraz z rozwojem technologii sieci neuronowe bezproblemowo mogą być wprowadzane w coraz szerszym zakresie dziedzin nauki i techniki. Odpowiednio zaprojektowana sieć mogłaby stanowić bardzo dobry filtr antyspamowy, który mógłby dokładnie filtrować niepożądane wiadomości mimo braku bezpośredniej zależności pomiędzy zwykłą wiadomością. Jedynym wymogiem jest dobranie odpowiedniej sieci neuronowej oraz nauczenie jej przy pomocy dość dużego zbioru danych uczących. - 14 -