T 61.3030 Neuraalilaskennan perusteet Harjoitustyö time series prediction 31.5.2007 Heikki Hyyti 60451P EST hhyyti@cc.hut.fi
Yleistä Harjoitustehtävässä piti Matlabin Neural Network Toolbox:n avulla luoda MLP feedforward verkko, ja opettaa se ennustamaan aikasarjaa. Tässä harjoitustyössä data oli annettu valmiina aikasarjana, Matlabin tiedostossa ts.mat. [1] Kuvassa 1 on esitetty koko aikasarja sekä lyhyt näyte mitattavasta aikasarjasta. Kuva 1: Tutkittava aikasarja ylemmässä kuvassa kokonaan ja alemmassa kuvassa lyhyeltä osalta. Aikasarjan esikäsittely Jotta Neural Network Toolbox:lla voitaisiin laskea aikasarjaa, pitää dataa käsitellä niin, että voimme yhtenä vektorina aina antaa neuroverkon syötteet x ja tarkistaa toivotun ulostulon t, joiden avulla verkko lasketaan backpropagation algoritmilla. Muutin aikasarjan ensin sellaiseen muotoon, että siinä on ensimmäisellä rivillä yhdellä viivästetty arvo, toisella rivillä kahdella viivästetty arvo ja niin edelleen. Lisäksi loin tavoitearvot oikeiden arvojen perusteella, niin että tavoitearvoksi verkolle tulee tämän hetkinen arvo. Tällöin edellisten N kpl arvojen perusteella verkko laskee nykyisen arvon. Käytin N arvoja 3, 5 ja 10. Lisäksi poistin ne aikasarjan arvot, joille en voinut tietää tarpeeksi edellisiä arvoja. (N ensimmäistä) Lisäksi aikasarja pitää jakaa testi ja harjoitusjoukkoihin. Jaoin joukot satunnaisessa järjestyksessä puoliksi. Satunnainen järjestys tallennettiin muistiin, jotta jälkeenpäin voitiin taas järjestää mittauspisteet oikeaan, alkuperäiseen, järjestykseen.
Laskenta Neural Network Toolbox:n avulla Seuraavaksi luotiin valmiiden työkalujen avulla MLP feedforward neuroverkko. Se toteutettiin Neural Network Toolbox:lla komennolla: net = newff(pr,[s1 S2...SNl],{TF1 TF2...TFNl},BTF,BLF,PF) Tässä komennossa PR on matriisi, jossa jokaista sisääntuloa vastaa minimi ja maksimiarvojen vektori. Seuraavaksi S1,S2, tarkoittavat piilokerrosten määrää ja neuronien määrää kullakin piilokerroksella niin, että S1 kertoo ensimmäisen piilokerroksen neuronien lukumäärän. Seuraavaksi aaltosulkeiden sisällä olevat TF1, TF2, tarkoittavat kuhunkin piilokerrokseen käytettävää siirtofunktiota. Käytin ensimmäisille piilokerroksille sigmoid funktiota ja viimeiselle lineaarista funktiota. Viimeiset kolme määritettä kertovat funktiolle käytettävät algoritmit ja metodit. BTF ilmaisee backpropagation algoritmin painokertoimien määritystavan. BLF taasen ilmaisee algoritmin bias kertoimien määritystavan ja PF ilmaisee virhefunktion laskentatavan. Käytin laskennassa eri funktioita, niin normaalia backpropagation algoritmia, kuin muunnelmaa, jossa mukaan on otettu momenttitermi kuin adaptiivisesti oppivaakin muunnelmaa. Havaitsin heti, että momenttitermi lisäsi oppimisnopeutta huimasti ja adaptiivisen oppimisen ja momenttitermin yhdistelmä toimi ehdottomasti parhaiten. Tulokset Laskin viisi erilaista kokonaisuutta erilaisella verkon rakenteella. Sain tuloksia, joista voi päätellä, että mitä enemmän verkossa on neuroneita (järkevään rajaan asti) ja mitä pitemmältä ajalta se aikasarjaa seuraa, sitä parempiin ennustustuloksiin päästiin. Seuraavassa on yksitellen esiteltynä jokainen viidestä testikerrasta. Tapaus 1 Ensimmäisenä testasin 5 aikaisemman arvon perusteella ennustamista. Neuroverkossani oli yksi piilokerros, jossa oli kymmenen neuronia. Piilokerroksen siirtofunktio oli sigmoidfunktio ja ulostulon siirtofunktio lineaarinen kerroin. Opetuksessa käytettiin normaalia backpropagation algoritmia ilman momenttia tai muuta apua. Suhteellisiksi virheiksi virheen ja oikean arvon varianssien osamääräksi sain testijoukolle 0.0395, opetusjoukolle 0.0430 ja kokonaisvirheeksi 0.0413. Kuvasta 2 nähdään opetuksen edistyminen ja kuvasta 3 voi havaita kuinka hyvin järjestelmä opetuksen jälkeen osasi ennustaa aikasarjan tulevaa arvoa. Kuvassa 3 on oikea arvo merkitty vaalealla katkoviivoituksella ja ennustettu arvo tummalla viivalla. X merkitsee testausdatapistettä ja O opetusdatapistettä.
Kuva 2: Kuvassa on ensimmäisen testin opetuksen tapahtumat Kuva 3: Oikea ja ennustettu aikasarja sekä opetusnäytteiden ja testausnäytteiden sijainti aikasarjalla 100 ensimmäiseltä aika askeleelta. Tapaus 2 Toinen tapaus on pitkälti samanlainen kuin ensimmäinenkin, mutta vähensin tarkasteltavien menneiden aika askelten määrän kolmeen ja piilokerroksen neuronien määrän kuuteen. Muuten tilanne pysyi täysin samana. Tämän tapauksen opetus näkyy kuvassa 4 ja ennustavuus näkyy kuvassa 5. Kuvat on tehty samalla periaatteella jokaisessa tapauksessa. Suhteelliseksi virheeksi saatiin tässä tapauksessa testijoukolle 0.0462, opetusjoukolle 0.0444 ja kokonaisvirheeksi 0.0453. Kuten kuvista huomataan, tapauksilla 1 ja 2 ei ole juurikaan eroa. Toisen tapauksen opetus kestää hieman kauemmin ja tulos on hieman huonompi, mutta ei mitään merkittäviä eroja.
Kuva 4: Toisen tapauksen verkon opetus Kuva 5: Toisen tapauksen aikasarjan ennustus ja oikea aikasarja piirrettynä samaan kuvaan mittauspisteiden kanssa. Tapaus 3 Tässä tapauksessa taas alettiin vertailla neuroverkon opetusmetodeja. Neuroverkko on muuten tehty täysin samalla tavalla kuin tapauksessa 2, mutta neuroverkkoon otettiin käyttöön momenttitermit ja adaptiivinen oppiminen neuronien painokertoimien määritykseen ja bias termien määritykseen momenttitermit. Tällöin oppiminen nopeutui erittäin paljon. Kuvasta 6 voidaan haita, että tapauksen 3 oppiminen on monikymmenkertaisesti nopeampaa, kuin tapauksen 2 oppiminen. Lisäksi kuvasta 7 voidaan taas havaita neuroverkon ennustavan hyvin aikasarjaa. Tässä tapauksessa suhteelliseksi virheeksi saatiin testijoukon osalta 0.0480, opetusjoukon osalta 0.0431 ja kokonaisvirheeksi 0.0456.
Kuva 6: Kuvassa on kolmannen tapauksen erittäin nopea oppimisprosessi. Kuva 7: Kuvassa on kolmannen tapauksen ennustettu ja oikea aikasarja. Tapaus 4 Kaksi viimeistä tapausta käytettiin virheen minimoimiseen ja ennustettavuuden parantamiseen. Pienensin ensinnäkin tavoitevirheen kymmenesosaansa. Lisäksi mittasin aikasarjaa kymmenen edeltävän askeleen pituudelta ja käytin ensimmäisellä piilokerroksella 20 neuronia. Käytin laskentaan tehokkaimmaksi havaitsemaani momenttitermin ja adaptiivisen laskennan yhdistelmää. Näin virheen sai todella pieneksi ja se olisi varmasti vielä pienentynyt nykyisestäkin, jos vain olisin vaatinut pienemmän virhetason. Kuvissa 8 ja 9 on taas sama kuvapari, kuin edellisissäkin tapauksissa. Tässä tapauksessa suhteellisiksi virheiksi tuli testijoukolle 0.0058, opetusjoukolle 0.0042 ja kokonaisvirheeksi 0.0050.
Kuva 8: Kuvassa on neljännen tapauksen hieman pidempi ja tarkempi opetus. Kuva 9: Kuvassa on neljännen tapauksen erittäin tarkka ennustavuus, joka on lähes joka puolella oikean viivan kanssa päällekkäin. Tapaus 5 Viimeisessä tapauksessa lisättiin verkkoon vielä toinen piilokerros, ja katsottiin vaikuttaisiko se mitenkään laskentatarkkuuteen tai nopeuteen. Pidin tapauksen 4 verkon muuten samana, mutta siirsin piilokerroksen 20 neuronia tasaisesti kahteen kerrokseen niin, että kumpaankin kerrokseen tuli 10 neuronia. Lisäksi havaitsin, että tarkan ennusteen saamiseen ei tarvita kovinkaan montaa edellistä arvoa, joten valitsin että 5 edellistä arvoa riittää. Tämän tapauksen kuvapari löytyy kuvista 10 ja 11. Suhteelliseksi virheeksi sain verkon testijoukolle 0.0055, opetusjoukolle 0.0042 ja kokonaisvirheeksi 0.0049. Olisin tässäkin tapauksessa varmasti päässyt parempaan lopputulokseen jos olisin odottanut pitempään ja vaatinut pienemmän virhekriteerin.
Kuva 10: Tapauksen 5 verkon opetus. Tässä tapauksessa kaksi oli piilokerrosta. Kuva 11: Tapauksen 5 ennustettu aikasarja ja oikea aikasarja ovat jo aivan päällekkäin. Päätelmät ja johtopäätökset Harjoitustyöstä havaittiin, että tällaisen jaksollisesti toistuvan kuitenkin satunnaiselta vaikuttavankin datan ennustaminen onnistuu melko hyvin MLP neuroverkon avulla. Jos aikasarjaa ennustaa niin pitkältä ajalta, että kaikki toistuvat kuviot näkyvät neuroverkolle historiassa, voidaan lähes mitä tahansa pystyä ennustamaan. Näin olisi mahdollista ennustaa esimerkiksi pörssikursseja, jos historiaa laskee vain tarpeeksi pitkältä ajalta, jotta toistuvuudet voidaan havaita.
Harjoitustyöstä opittiin myös se, että momenttitermillä ja muilla kehittyneemmillä backpropagation algoritmin muunnoksilla voidaan saavuttaa erittäin paljon nopeampi verkon oppiminen. Tällöin varsinkin suurien verkkojen laskennassa säästetään paljon aikaa ja resursseja. Kolmas huomaamani asia oli se, että kun verkko näkee tarpeeksi historiaa, ei ole enää juurikaan hyötyä lisätä sille enempää tietoa, vaan pienelläkin tietomäärällä voidaan päästä riittävän hyvään lopputulokseen, kuten tapauksesta 2 ja 3 voimme havaita. Näissä tapauksissa seurasin vain 3 edellistä aikasarjan näytettä ja laskin sitä kuudella piilokerroksen neuronilla. Näin pienelläkin laskennalla päästiin erittäin hyvään lopputulokseen verkon kokoon ja laskentamäärään suhteutettuna. Lähdeluettelo 1. Neuraalilaskennan perusteiden kotisivut, harjoitustehtävä aikasarja. Viitattu: 31.5.2007 Saatavilla: http://www.cis.hut.fi/opinnot/t 61.3030/harjtyo/aikasarja/timeseries.shtml
Liitteet Liite 1: Laskentaan käytetty Matlab ohjelmointikoodi %% Neuraalilaskennan harjoitus % Heikki Hyyti 60451P hhyyti@cc.hut.fi % aikasarjan ennustus clear all; %% Ensiksi piirretään muutama mallikuva aikasarjadatasta, jota meillä on % load ts.mat; x = 1:length(ts); figure(1); subplot(2,1,1); plot(x,ts,'k'); title('ennustettava data, ts.mat'); xlabel('mittausnäytteet 1...1000'); subplot(2,1,2); plot(x(100:200),ts(100:200),'k'); xlabel('mittausnäytteet 100...200'); %% Muutetaan mittausdata sellaiseen muotoon, että siinä on jokaisessa % sarakkeessa ensin 1 viivästetty, sitten 2 viivästetty jne. Mittausdata % kirjataan data_x matriisiin ja jokaisen oikea nollaviivästetty arvo % data_t vektoriin. % inputtien määrä eli aikaisempien arvojen määrä inputn = 5; for i = (inputn + 1):length(ts) for j = 1:inputN data_x(i inputn,j) = ts(i j); data_t(i inputn) = ts(i); end end %% jaetaan data satunnaisesti puoliksi harjoitus ja testijoukkoihin rind = randperm(length(data_x)); x_train=data_x(rind(1:floor(length(data_x)/2)),:); t_train=data_t(rind(1:floor(length(data_x)/2))); x_test=data_x(rind(floor(length(data_x)/2)+1:length(data_x)),:); t_test=data_t(rind(floor(length(data_x)/2)+1:length(data_x))); %% MLP verkko % net = newff(pr,[s1 S2...SNl],{TF1 TF2...TFNl},BTF,BLF,PF) % PR R x 2 matrix of min and max values for R input elements. % Si Size of ith layer, for Nl layers. % TFi Transfer function of ith layer, default = 'tansig'. % BTF Backpropagation network training function, default = 'traingdx'.
% BLF Backpropagation weight/bias learning function, default = 'learngdm'. % PF Performance function, default = 'mse'. % ensimmäisen kerroksen neuronien määrä N1 = 10; N2 = 10; % Rx2 min ja max arvot PR = [min(data_x)', max(data_x)']; net = newff(pr, [N1, N2, 1], {'tansig' 'tansig' 'purelin'},'traingdx','learngdm','mse'); %% alustetaan verkko pienillä satunnaisluvuilla % Piilokerroksen painot net.iw{1,1}=0.001*randn([n1 inputn]); % Output layer weights net.lw{2,1}=0.001*randn([n2 N1]); % Biases net.b{1,1}=0.001*randn([n1 1]); net.b{2,1}=0.001*randn([n2 1]); net.b{3,1}=0.001*randn; %% Opetetaan verkko % train(net,p,t,pi,ai,vv,tv) % net Neural Network. % P Network inputs. % T Network targets, default = zeros. % Pi Initial input delay conditions, default = zeros. % Ai Initial layer delay conditions, default = zeros. % VV Structure of validation vectors, default = []. % TV Structure of test vectors, default = []. net.trainparam.epochs = 100000; net.trainparam.goal = 0.001; [net,tr,y,e]=train(net,x_train',t_train); %% Testataan verkon toimintaa Y_test = sim(net, x_test'); Y_train = sim(net, x_train'); %% Kuvataan tulokset testausdatasta figure(2) % testidata ja harjoitusdata järjestettynä niin, että ensimmäisellä rivillä % on alkuperäinen indeksi, toisella rivillä testiarvo ja kolmannella % rivillä oikea arvo ja neljännellä rivillä virhe merkitään viidennelle
% riville nolla, jos kyseessä on harjoitusjoukko ja yksi jos kyseessä on % testijoukko, jotta ne voidaan myöhemmin erottaa toisistaan. YTE = [rind(floor(length(data_x)/2)+1:length(data_x))', Y_test', t_test', (Y_test t_test)', ones(length(y_test),1)]; YTR = [rind(1:floor(length(data_x)/2))', Y_train', t_train', (Y_train t_train)', zeros(length(y_train),1)]; Y_all = [YTE; YTR]; % järjestetään matriisi alkuperäisen indeksin mukaan Y_sort = sortrows(y_all,1); % lasketaan suhteellinen virhe, error = var(virhe) / var(oikea) error_test = var(yte(:,4))/var(yte(:,3)) error_train = var(ytr(:,4))/var(ytr(:,3)) error_all = var(y_sort(:,4))/var(y_sort(:,3)) % otetaan 100 ensimmäisen askeleen matkalta erikseen testidatan ja % harjoitusdatan pisteet piirtoa varten. index_tr = 1; index_te = 1; for i = 1:100 if Y_sort(i,5) == 0 plot_tr(index_tr,1:2) = [i, Y_sort(i,3)]; index_tr = index_tr + 1; else plot_te(index_te,1:2) = [i, Y_sort(i,3)]; index_te = index_te + 1; end end % Plotataan 100 askeleen pätkä dataa malliksi niin, että samassa kuvassa on % ennustettu ja oikea arvo. plot(1:100, Y_sort(1:100,3), ' g',1:100, Y_sort(1:100,2), ' k',... plot_tr(:,1), plot_tr(:,2), 'bo', plot_te(:,1), plot_te(:,2), 'bx'); legend('oikea','ennustettu', 'opetusdatapisteet', 'testausdatapisteet') title('näytteet 1...100, joita on ennustettu MLP verkolla');
Liite 2: kaikista eri mittauksista saatu mittauspöytäkirja // testi 1. // 5 askeleen ennustus 10 neuronilla. // net = newff(pr, [N1, 1], {'tansig' 'purelin'},'traingdm','learngd','mse'); error_test = 0.0395 error_train = 0.0430 error_all = 0.0413 // testi 2 // 3 askeleen ennustus 6 neuronilla // net = newff(pr, [N1, 1], {'tansig' 'purelin'},'traingdm','learngd','mse'); error_test = 0.0462 error_train = 0.0444 error_all = 0.0453 // testi 3 // 3 askeleen ennustus 6 neuronilla // net = newff(pr, [N1, 1], {'tansig' 'purelin'},'traingdx','learngdm','mse'); // erilaiset opetusmetodit siis (oppi 100x nopeammin) error_test = 0.0480 error_train = 0.0431 error_all = 0.0456 // testi 4 // oikein massiivinen testi // 10 askeleen ennustus 20 neuronilla ja tarkemmalla tarkkuusvaatimuksella. // net = newff(pr, [N1, 1], {'tansig' 'purelin'},'traingdx','learngdm','mse'); error_test = 0.0058 error_train = 0.0042 error_all = 0.0050 // testi 5 // lisää piilokerroksen neuroneita // 5 askeleen ennustus, kymmenen piiloneuronia kahdessa kerroksessa. (N1 = N2 = 10) // net = newff(pr, [N1, N2, 1], {'tansig' 'tansig' 'purelin'},'traingdx','learngdm','mse'); error_test = 0.0055 error_train = 0.0042 error_all = 0.0049