tiistai 12. toukokuuta 2015

Luento 13.5: Audiokompressio + vanhat kandityöt


Tänään käsiteltiin ensimmäisellä tunnilla prujun viimeinen kappale: audiokompressio. Audiokompression ideana on tallentaa äänisignaali häviöllisesti poistaen bittejä sieltä missä kuulo ei niitä havaitse. Tässä auttaa kuulon ominaisuuksien tuntemus, joista olennaisin osa on kuulokäyrä. Kuulo havaitsee matalia ja korkeitä ääniä heikommin kuin keskiääniä. Tämän vuoksi epätarkemmin havaittavat taajuudet voidaan esittää pienemmällä bittimäärällä.

Tässä yhteydessä on hyvä muistaa että jokainen poistettu bitti lisää kvantisointikohinaa kuudella desibelillä. Kysymys voidaan siis asettaa muotoon: "montako kuuden desibelin palikkaa kuulokäyrän alle mahtuu kullakin taajuudella". Lisätilaa kuuden desibelin palikoille saadaan havaitsemalla, että äänet peittävät heikompia ääniä alleen. Tässä tapauksessa siis itse kompressoitava signaali peittää näitä heikompia kuuden desibelin palikoita.

Luennolla nähtiin myös esimerkki siitä miltä tulosmaski saattaisi näyttää yksittäisen piippauksen ympäristössä. Jotta kuulomallia voitaisiin käyttää, täytyy signaali jakaa taajuuskaistoihin. Tämä tehdään kaistanpäästösuotimilla, ja kaistoja mp3-standardissa on 32. Kukin kaista voidaan alinäytteistää kertoimella 32, jolloin dataa on saman verran kuin alun perin. Nämä kaistat voidaan sitten kvantisoida kuulomallin mukaisesti. Palautettaessa alkuperäistä näytteenottotaajuutta riittää tehdä ylinäytteistys (nollien lisääminen) kertoimella 32, jolloin havaitaan, että aiemmin laskostunut signaali pomppaakin oikealle paikalleen ja vieläpä oikein päin --- siinäkin tapauksessa, että se olisi sattunut laskostumaan peilikuvakseen.

Tunnin luotiin katsaus laitoksella tehtyihin kanditöihin. Työt löytyvät täältä. Tunnus on sgnkandi ja salasana motiivi.

Luennon jälkeen kommentoitiin että kandityöt näyttivät laajoilta ja vaativilta suorituksilta. On huomattava että esitellyt työt olivat kaikki parhaasta päästä; nelosen ja viitosen töitä. Lisäksi laitos pyrkii tieteellisen fokuksensa mukaisesti panostamaan kanditöihin ja niissä opiskeltavaan tieteelliseen kirjoittamiseen, joten uskon kanditöidemme olevan keskimääräisiä laajempia (ja reilusti yli 8 op arvoisia). Hyvä kandityöhän toimii myös käyntikorttina D-työpaikkaa haettaessa, joten sen tasolla on suuri merkitys tulevaisuuden kannalta.

Kiitos kaikille kurssilaisille ja hyvää kesää! Onnea tenttiin, muista antaa palautetta.

tiistai 5. toukokuuta 2015

Luento 6.5: Hermoverkot


Tänään jatkettiin hahmontunnistusjärjestelmien opiskelua.

Aluksi muisteltiin edellisen viikon asioita lyhyesti, ja vilkaistiin mm. Matlab-demoa, jolla voidaan piirtää hiirellä projektiosuora kaksiulotteisen datan koordinaatistoon. Kun kaksi pistettä suoralta on merkitty, Matlab-skripti projisoi datan tälle suoralle ja piirtää tuloksena saatavien yksiulotteisten näytteiden jakauman sekä luokitteluprosentin. Hyvillä projektiosuorilla data oli täydellisesti luokiteltavissa, mutta huonoilla joukot menivät päällekkäin projisoinnin jälkeen. Fisherin lineaarinen erottelija laskee tämän suoran automaattisesti niin että erottelu on optimaalinen.

Tämän jälkeen paneuduttiin hermoverkkoihin sekä niiden opetukseen, ja mainittiin  lyhyesti opetusalgoritmin perustuvan derivaattaan ja ketjusääntöön. Näiden avulla voidaan päätellä suunta, jossa luokitteluvirhe pienenee jyrkimmin, ja kyseiset kaavat löytyvät esim. täältä. Perus-backpropagationin lisäksi on olemassa kehittyneempiä ja nopeampia opetusalgoritmeja, ja esim. Matlabissa niitä on lähes parikymmentä. Olennaisin ero algoritmien välillä on niiden nopeudessa ja muistin tarpeessa.

Luentotauolla Matlabilla opetettiin hermoverkko, joka osasi tunnistaa eurooppalaisista rekisterikilvistä kerättyjä merkkejä.Opetus kesti noin 15 minuuttia, ja virheen kehittyminen on esitetty oikealla olevassa kuvassa. Opetuksen aikana mitattiin luokittelijan virhettä opetusaineistossa (10 000 merkkiä) sekä erillisessä testiaineistossa (1 000 merkkiä). Kuvasta nähdään että virhe oli selvästi pienempi opetusaineistolla kuin testijoukossa. Ilmiöstä käytetään nimeä ylioppiminen, ja se tarkoittaa että järjestelmä alkaa oppia opetusaineiston epäolennaisia ja satunnaisia ominaisuuksia, jotka eivät ole yleisesti voimassa. Ensisijainen ratkaisu tähän on lisätä opetusmateriaalin määrää (joko todellisella uudella datalla tai augmentoimalla käytettävissä olevaa dataa; esim. venyttelemällä kuvia, lisäämällä kohinaa jne.).

Verkkoa testattiin esimerkkikuvilla, joista näytettiin hiirellä merkin sijainti. Testissä havaittiin luokittelun toimivan täysin oikein kun merkki oli hyvin laatikon sisällä. Jos merkin lisäksi 10x10-laatikon sisällä oli muutakin, luokittelu meni väärin.

Tavallisen hermoverkon herkkyys merkin oikealle kohdistukselle on yleinen ongelma. Tämä on saatu valtaosin ratkaistua uudemmissa ns. konvoluutioverkoissa, jotka esiteltiin alun perin jo 1980-luvulla, mutta ovat saavuttaneet valtavan suosion vasta laskentatehon lisäännyttyä 2010-luvulla. Syvät (yli 3 tasoa; jopa 30 tasoa) konvoluutioverkot ovat aiheuttaneet läpimurron kuvan- ja puheentunnistuksessa. Alla on lista luennolla vilkaistuista julkaisuista (ja muuten vaan kiinnostavista tuoreista tuloksista):
CVPR-konferenssi on yksi alan merkittävimmistä foorumeista, ja laitos on ylpeä saatuaan julkaisunsa mukaan kesäkuun konferenssiin. Julkaisut ovat suurelta osin vapaasti saatavissa täällä.

Jos haluat tutustua moderneihin hermoverkkoihin, niin yleisimmin käytetyt paketit ovat Caffe, pylearn2 ja Torch7. Aiheeseen liittyvää keskustelua löytyy mm. Redditistä.

tiistai 28. huhtikuuta 2015

Luento 29.4: Koneoppiminen

Tänään aloitimme kappaleen 11, joka käsittelee hahmontunnistusta. Hahmontunnistusjärjestelmän ideana on esittää järjestelmälle näytteitä ja opettaa se tuottamaan oikea ulostulo kun sille esitetään opetusjoukkoon kuulumaton uusi näyte. Yksi oppivien järjestelmien osajoukko ovat luokittelijat, jossa ulostulo kertoo luokan johon esitetty näyte kuuluu.

Suosittuja luokittelualgoritmeja ovat ainakin seuraavat (kasvavan monimutkaisuuden järjestyksessä):

Näistä neljä ensimmäistä käsiteltiin luennolla. KNN on ideana yksinkertaisin: kaikki opetusdata pidetään muistissa ja uuden näytteen tullessa etsitään k samanlaisinta näytettä, ja valitaan näistä yleisin luokka. Tyypillisesti k on vajaan kymmenen luokkaa, mutta voi olla suurempikin; esim. 30. Mitä suurempi k on, sitä sileämpi luokkarajasta tulee. Vaikka KNN:n luokittelutulos onkin melko hyvä, on sen ongelmana suuri muistin tarve sekä laskennallinen kompleksisuus. Koko opetusjoukko täytyy nimittäin säilyttää muistissa, josta etsitään k lähintä naapuria jokaisen luokittelun yhteydessä. Sekä tilantarve että etsinnän vaatima aika voivat olla ongelmallisia jos opetusjoukossa on esim. 100000 alkiota.

Luentomonisteen seuraava menetelmä on Fisherin diskriminantti eli LDA. Tässä vilkaistiin mm. alla olevan kuvan mukaista Matlab-demoa, jolla voidaan piirtää hiirellä projektiosuora kaksiulotteisen datan koordinaatistoon. Kun kaksi pistettä suoralta on merkitty, Matlab-skripti projisoi datan tälle suoralle ja piirtää tuloksena saatavien yksiulotteisten näytteiden jakauman sekä luokitteluprosentin. Hyvillä projektiosuorilla data oli täydellisesti luokiteltavissa, mutta huonoilla joukot menivät päällekkäin projisoinnin jälkeen. Fisherin lineaarinen erottelija laskee tämän suoran automaattisesti niin että erottelu on optimaalinen.


Tukivektorikone ja logistinen regressio ovat myös lineaarisia luokittimia, mutta niiden opetusalgoritmi on eri kuin LDA:n. Tukivektorikoneen erityispiirre on sen käyttö yhdessä kernelitempun kanssa ja logistisen regression ominaisuutena on sen todennäköisyystulkinta: LR antaa myös luokan todennäköisyyden, ei pelkästään ennustettua luokkaa.

Seuraavaksi pohjustettiin seuraavan viikon hermoverkkoaihetta vilkaisemalla helmikuussa 2015 ilmestynyttä artikkelia, jossa hermoverkko opetettiin pelaamaan vanhoja Atari 2600 tietokonepelejä. Alla on video kuinka verkko pelaa Breakout-peliä. Ks. myös Google research blog.

tiistai 21. huhtikuuta 2015

Luento 22.4: Kuvankäsittely


Tänään paneuduttiin kappaleeseen 10 (ks. kurssimonisteen liite), joka tarkastelee kuvankäsittelyä.

Alkuosa koostuu enimmäkseen yksiulotteisten lineaaristen järjestelmien yleistyksestä kahteen ulottuvuuteen. Fourier-muunnoksen yhteydessä todettiin, että kaksiulotteinen tapaus voidaan toteuttaa kahden yksiulotteisen FFT:n avulla, mikä mahdollistaa nopean laskennan.

Tämän jälkeen tarkasteltiin dekonvoluutiota, eli konvoluution käänteistä operaatiota. Monisteen esimerkin lisäksi esimerkkinä mainittiin Hubble-avaruusteleskoopin varhainen ongelma, joka aiheutti kuvaan jonkin verran epätarkkuutta. Ennen kuin kiertoradalle päästiin korjaamaan linssi kuntoon, täytyi linssin virhe mallintaa konvoluution avulla. Varhaisia kuvia myös korjattiin dekonvoloimalla virheelliset kuvat. Linssi kuitenkin lopulta vaihdettiin, koska dekonvoluutio ei voi tuottaa yhtä täydellistä tulosta kuin fyysinen korjaus. Tämä johtuu siitä, että PSF ei koskaan ole täysin oikea, vaan siinä on numeerista epätarkkuutta. Lisäksi informaatiota saattaa kadota konvoluution yhteydessä, jos taajuustason funktiossa H(n,m) on nollia kertoimina.

Kolmantena aiheena kappale tarkastelee piste-ehostusta: kontrastin parannusta gamma-korjauksella sekä histogrammin ekvalisoinnilla. Molemmat löytyvät kaikista kuvankäsittelyohjelmista. Lisäksi vilkaistiin Androidin tarjoamia 3A-kuvankäsittelyoperaatioita, joihin kuuluvat auto exposure, auto-white-balance sekä auto-focus.

Aivan lopuksi tutustuttiin sovelluksena automaattiseen rekisterikilven tunnistukseen, jota olen ollut kehittämässä tamperelaisessa Visy Oy:ssä sivutoimisesti jo toistakymmentä vuotta.

tiistai 14. huhtikuuta 2015

Luento 15.4: Interpolointi D/A-muunnoksessa sekä signaalprosessorit


Ensimmäisen tunnin aiheena oli 1-bittinen D/A-muunnos, jonka tavoitteena on yksinkertaistaa analogiapuolta äärimmilleen kvantisoimalla D/A-muunnettava signaali 1-bittiseksi. Ratkaisusta käytetään nimeä kohinanmuokkaus, englanniksi noise shaping tai sigma delta modulation. Kvantisointi onnistuu äänenlaatua heikentämättä, kun nostetaan näytteenottotaajuus ensin riittävän suureksi. Tällöin näytteiden suuri määrä kompensoi niiden heikkoa tarkkuutta. Pelkkä ylinäytteistys ei kuitenkaan vielä riitä: ilman muita temppuja näytteenottotaajuus pitäisi nostaa jopa miljardikertaiseksi, mikä ei käytännössä ole mahdollista. Siksi täytyy ottaa käyttöön alla olevan lohkokaavion mukainen takaisinkytkentä, joka aiheuttaa kvantisointivirheen siirtymisen korkeammille taajuuksille.




Korkeilla taajuuksilla kohina ei haittaa, koska se voidaan erottaa hyötysignaalista analogisella alipäästösuodatuksella D/A-muunnoksen jälkeen. Jäljelle jäävän kvantisointikohinan määrä voidaan laskea, ja havaitaan että suuruusluokassa 1500 oleva muunnoskerroin riittää (miljardien sijaan). Ratkaisua voidaan edelleen tehostaa tarkastelemalla korkeampiasteisia kohinanmuokkaimia, jotka siirtävät vieläkin tehokkaammin kvantisointikohinaa korkeammalle.

Jotkin audioformaatit kuten Super Audio CD tallentavat äänen suoraan yksibittisenä. Tästä on etuna se, että kohinanmuokkaus täytyy tehdä vain kerran äänitysstudiossa eikä jokaisessa kuluttajalaitteessa erikseen.

Toisella tunnilla käsiteltiin kappale signaaliprosessoreista. Tärkeimmät syyt niiden käyttöön ovat yksinkertaisuus, halvempi hinta sekä pienempi virrankulutus (ks. esim TI). Kuitenkin niistä saa riittävästi tehoa signaalinkäsittelyn tarpeisiin, koska alan tarvitsemat operaatiot (kertolasku, yhteenlasku) ovat nopeita sekä rinnakkaisia. Esimerkiksi FIR-suodatuksen tai kompressiossa käytettävän kaksiulotteisen DCT:n tarvitsemat kertolaskut ja yhteenlaskut voidaan pistetuloina laskea rinnakkain ns. MAC-operaation avulla. Vastaavia operaatioita on nykyisin myös tavallisissa prosessoreissa, ja ensimmäinen tällainen laajennus oli Intelin MMX-käskykanta vuodelta 1997.


Kahden viikon päästä olevissa viikkoharjoituksissa koodataan FIR-suodin luokan TC303 signaaliprosessoreille. Olennaisimmat vaiheet olivat:
  1. Suodin suunniteltiin Matlabin fir1-rutiinilla.
  2. Kertoimet kopioitiin C-koodiin.
  3. C-kieliseen pohjaan kirjoitettiin for-silmukka, jossa kertoimet käydään läpi.
  4. Ulostulonäyte kirjoitetaan D/A-muuntimelle.
Vaiheessa 3 on kiinnitettävä huomiota circular buffering-tekniikkaan, jotta viitataan oikeisiin aiemmin sisään tulleisiin alkioihin.
Aivan toisen tunnin loppupuolella luotiin katsaus GPU-laskentaan ja sen sovelluksiin koneoppimisessa. GPU on keskeinen työkalu esim. syvien neuroverkkojen opetuksessa, ja mm. GPU-valmistaja Nvidialla on oma DNN-kirjastonsa. Aiheesta lisää hahmontunnistuksen yhteydessä.

Myös Matlabissa on GPU-tuki. Seuraava koodinpätkä kertoo matriisit A ja B keskenään GPU:lla:

tic();

A = gpuArray(rand(2000, 2000));
B = gpuArray(rand(2000, 2000));
C = A * B;

elapsedTime = toc();
disp(['Matriisikertolaskuun kului ', num2str(elapsedTime), ' sekuntia.'])

 
Käyttö on siis helppoa: funktio gpuArray() siirtää matriisin GPU:lle, jonka jälkeen laskenta toimii kuten muutenkin.

Omalla kannettavallani (Intel i7 + Nvidia NVS 5200M) GPU-versio on noin 4 kertaa nopeampi kuin CPU-versio (joka saadaan poistamalla gpuArray-funktio).

keskiviikko 1. huhtikuuta 2015

Luento 1.4: Näytteenottotaajuuden muuntelu


Tänään desimointi ja interpolointi, jotka toimivat kokonaislukukertoimilla. Näitä yhdistelemällä saadaan kaikki rationaalikertoimet. Molemmat operaatiot tarvitsevat alipäästösuodattimen, joka on yleensä FIR, ja suunnitellaan normaaleilla menetelmillä. Suotimen siirtymäkaistasta todettiin, että se laitetaan aina rajataajuuden alapuolelle. Näin signaaliin tulee vähemmän virhettä kuin jos laskostumista pääsisi tapahtumaan.

Desimoinnissa tapahtuva näytteenottotaajuuden pieneminen toteutetaan yksinkertaisesti jättämällä näytteitä pois tasaisin väliajoin. Esimerkiksi kertoimella kolme jätetään vain joka kolmas näyte jäljelle. Tämä kuitenkin aiheuttaa laskostumista, koska signaalin sisältämät taajuudet pysyvät samoina mutta näytteenottotaajuus pienenee. Tämä saadaan luonnollisesti estettyä suodattamalla signaali ennen alinäytteistämistä sopivalla alipäästösuotimella.

Interpolointi puolestaan koostuu nollien lisäämisestä sekä tämän operaation tuottamien roskien poistamisesta. Nollien lisääminenhän tuottaa kopioita ja peilikuvia alkuperäisestä spektristä, jotka voidaan myös poistaa kätevästi alipäästösuodatuksella. Oikealla olevassa kuvassa on luennolla ollut esimerkki näytteenottotaajuuden kolminkertaistamisesta, jossa kahden näytteen väliin sijoitetaan aina 2 nollaa (yläkuva). Alakuvassa on tuloksen spektrogrammi, jossa näkyy selkeästi kolme versiota alkuperäisestä (kaista 0-4000 Hz) taajuuskaistasta (kopio-peilikuva-kopio).

Kappaleessa luodaan myös katsaus interpoloinnin ja desimoinnin yhdistämiseen, jolloin päästään yksinkertaisempaan rakenteeseen huomaamalla kokonaisuudessa olevan kaksi suodatinta peräkkäin, jotka molemmat poistavat tietyn kaistan ylätaajuuksilta. Näin ollen vain toinen niistä on tarpeellinen. Piirtämällä kuva näiden suodinten amplitudivasteista voidaan päätellä kumpi on tarpeeton (aina se, jota vastaava muunnoskerroin on isompi).

Toisen tunnin lopuksi tutustuttiin interpoloinnin sovellukseen D/A-muunnoksessa. Menetelmää käytettiin jo ensimmäisissä CD-soittimissa 1980-luvun alussa ja sen ideana on tehostaa nollannen asteen pitopiirin toimintaa nostamalla näytteenottotaajuus korkeammaksi ennen pitopiiriä. Tämä näkyy aikatasossa porraskuvion hienontumisena ja tätä kautta pitopiirin virheen pienenemisenä jä siirtymisenä korkeammille taajuuksille. Taajuustasossa yli 22,05 hertsin taajuuksille tulee vastaavia heijastuksia kuin interpoloinnin yhteydessäkin. Erona on, että nyt heijastumat vaimenevat sitä enemmän mitä korkeammalle mennään. Digitaalinen interpolointi helpottaa näiden heijastusten poistamista: ilman digitaalista interpolointia tarvittavan analogisen suotimen siirtymäkaistan leveys olisi 2,05 kHz (20kHz...22.05kHz), kun esim. nelinkertaisella interpoloinnilla se saadaan yli 130 kHz:n levyiseksi (väli 20kHz...154,35 kHz).

keskiviikko 25. maaliskuuta 2015

Luento 25.3: Äärellinen sananpituus


Tänään käsiteltiin äärellisen sananpituuden vaikutuksia. Meidän tarkastelussamme nämä ilmenevät A/D-muunnoksen yhteydessä sekä suodatettaessa äärellisellä laskentatarkkuudella. Pääpaino on ensimmäisessä tyypissä. Luennolla käsiteltiin näytteistyksessä käytettävät kvantisointitasot: esimerkiksi (1+7) bitin esityksessä käytettävissä ovat seuraavat 256 tasoa: -128/128, -127/128, ..., 0, ..., 126/128, 127/128. 
 
Pyöristettäessä lähimpään lukuun syntyvä kvantisointivirhe on aina välillä -1/256...1/256. Yleisesti pyöristys (1+b) bittiin aiheuttaa enintään virheen 2^(-b) / 2 suuntaan tai toiseen. Vasemmalla olevassa kuvassa on esimerkkitapaus jossa "seiska" kvantisoidaan 1+9 bittiin.

 
Seuraavaksi tätä yksinkertaista virhemallia käytettiin johdettaessa arvio virheen varianssille, joka on suoraan verrannollinen syntyvän kvantisointivirheen tehoon. Tätä kautta määritellään SNR, eli signaali-kohinasuhde, eli häiriöetäisyys. Tämä suure kertoo jotain äänenlaadusta, ja saatavia tuloksia tullaan tarvitsemaan kappaleessa 6, kun päätellään montako bittiä signaalista uskalletaan poistaa kompressiossa ilman äänenlaadun havaittavaa heikkenemistä.

Jos ehtojen oletetaan olevan voimassa, voidaan osoittaa kohinan odotusarvon olevan nolla ja varianssin yhtä kuin 2^(-2b) / 12.


Yllä olevaa kaavaa voidaan edelleen jalostaa signaali-kohinasuhteen käsitteeksi (SNR), joka kertoo signaalin tehon suhteessa kohinan tehoon. Kun kaavaa pyöriteltiin, havaittiin jokaisen ylimääräisen bitin (per näyte) nostavan SNR:ää kuudella desibelillä.

Lopuksi johdettiin kaava varianssille suodatuksen jälkeen ja sekä tutkittiin suotimen kertoimien pyöristämisen vaikutusta. Tämähän täytyy tehdä aina kun suodin toteutetaan huonomman tarkkuuden alustalla kuin Matlab (esim. tällä 17-bitin DSP:llä).

Toisen tunnin lopuksi käsiteltiin alku kappaleesta "näytteenottotaajuuden muuntelu". Kappale tarkastelee menetelmiä, joilla voidaan muuntaa näytteenottotaajuus näytteistämisen jälkeen toiseksi. Perusoperaatiot ovat desimointi ja interpolointi, jotka toimivat kokonaislukukertoimilla. Näitä yhdistelemällä saadaan kaikki rationaalikertoimet. Molemmat operaatiot tarvitsevat alipäästösuodattimen, joka on yleensä FIR, ja suunnitellaan normaaleilla menetelmillä. 

tiistai 17. maaliskuuta 2015

Luento 18.3: IIR-suodinten suunnittelu


Tänään luennon aluksi käytiin läpi viimeviikkoinen välikoe, minkä jälkeen tutkittiin IIR-suodatusta sekä Matlabin valmiita IIR-suodattimen suunnittelumenetelmiä.

Välikoetta ei ole vielä tarkastettu. Pyrin hoitamaan asian ensi viikkoon mennessä.

IIR-suodinten suunnittelun aluksi muisteltiin ns. pole-zero-placement -suunnittelumenetelmää, jossa hiirellä sijoiteltiin napoja ja nollia yksikköympyrälle ja laskettiin näitä vastaava suodin. Alla olevassa kuvassa on eräs näin saatu napanollakuvio, jossa tavoitellaan alipäästösuodinta. Tätä vastaava amplitudivaste on seuraavassa kuvassa, jossa selvästi erottuu hyppäys ylös- tai alaspäin jokaisen lähellä kehää olevan navan tai nollan kohdalla. Alimmassa kuvassa on vielä esitetty siirtofunktion itseisarvo |H(z)|, josta saadaan keskimmäinen amplitudivasteen |H(exp(iw))| kuvaaja sijoittamalla exp(iw) lausekkeessa z:n tilalle.
 

Menetelmä ei luonnollisestikaan ole kovin tarkka. Kappaleessa 6 esitetäänkin menetelmiä tarkempaan IIR-suodinten suunnitteluun, ja ne käydään melko yleisellä Matlab-komentojen osaamisen tasolla. Kappaleen ydin on koottu monisteen taulukkoon, jossa suodintyyppejä vertaillaan amplitudivasteen ominaisuuksien ja kertoimien määrän suhteen. Kertoimia tarvitaan eri menetelmillä 29+28, 13+12 ja 8+7 kappaletta. Suurin määrä tulee Butterworth-suotimella ja pienin elliptisellä suotimella. Kahden Chebyshev-suotimen kerroinmäärä on näiden kahden ääripään välissä. Vertailun vuoksi FIR-suotimen kertoimien määrä vastaavilla vaatimuksilla olisi N = [5.5/0.035] = 159 käytettäessä Blackman-ikkunaa.

Muita luennolla esiin tulleita seikkoja olivat mm.

  • Matlabin kerroinvektorit a ja b eivät ole suoraan käytettävissä ulostulon y(n) laskennassa, vaan takaisinkytkentäkertoimien (siis esim. termin y(n-1) kertoimen) merkki täytyy vaihtaa vastakkaiseksi.
  • Elliptisellä suotimella on aina vähemmän kertoimia kuin muilla. Lisäksi tasavärähtely-ominaisuus on yleensä hyvä asia.
IIR-suotimen etuna on siis pienempi kertoimien tarve. Haittapuolina mahdollinen epästabiilisuus sekä numeeriset ongelmat toteutuksessa. Tästä esimerkkinä on esim. kurssin SGN-16006 signaaliprosessorityö, jossa täytyy toteuttaa IIR-suodin. Käytännössä yli toisen asteen IIR-suodinta ei voi toteuttaa numeeristen ongelmien vuoksi. Sen sijaan suodin täytyy jakaa peräkkäisiin toisen asteen lohkoihin esim. Matlabin TF2SOS-funktiolla. Harjoitustyössä on yhtenä tehtävänä ns. Goertzel-algoritmin toteutus yksittäisen taajuuden tunnistuksessa. Goertzel-algoritmi hyödyntää epästabiilia suodinta, joka vahvistaa etsittävää taajuutta äärettömän paljon. Tästä ei kuitenkaan seuraa katastrofia, jos suotimen annetaan toimia vain vähän aikaa (esim 256 näytettä). 

Luennolla kysyttiin mistä IIR-suodintyyppien nimet ovat peräisin.
  • Butterworth-suodin on nimetty fyysikko Stephen Butterworthin mukaan, joka esitteli analogisen Butterworth-suotimen 1930.
  • Chebyshev-suotimet juontavat juurensa Chebyshev-polynomeihin, joita käytetään numeerisessa approksimoinnissa: esim. Matlab saattaa laskea logaritmifunktion todellisuudessa Chebyshev-polynomin avulla, jossa kertoimet on sovitettu niin että polynomi on paikallisesti lähellä logaritmia. Chebyshev-polynomien hyvä ominaisuus on, että niillä saatava maksimivirhe on mahdollisimman pieni ("minimax criterion"; "minimal L-Infinity norm"). Tämä on sama asia kuin tasavärähtely-ominaisuus.
  • Elliptinen suodin perustuu ns. elliptisiin rationaalifunktioihin, ja yhteys on varsin matemaattinen.
Suodinsuunnittelussa on paljon yhteistä numeerisen approksimoinnin kanssa, koska sitähän suodinsuunnittelu olennaisesti onkin: pyritään löytämään suodin jonka amplitudivaste approksimoi ideaalista vastetta mahdollisimman tarkasti.

tiistai 3. maaliskuuta 2015

Luento 4.3: suodinsuunnittelu käytännössä


Tänään käsiteltiin kappale 5 loppuun. Alussa oli alla olevan kuvan mukainen demo, jossa suotimen kertoimien määrää kasvatettiin ja havaittiin ettei amplitudivastetta saa tällä keinolla tiettyjen rajojen alle.
Tämän jälkeen käytiin kappale 5 loppuun, ja todettiin että suodinsuunnittelu sisältää seuraavat vaiheet. 
  1. Valitse ikkuna vaimennusvaatimusten perusteella.
  2. Päättele tarvittava kertoimien määrä N siirtymäkaistan leveyden (delta_f) perusteella.
  3. Laske ideaalinen impulssivaste (vaatii siirtymäkaistan keskipisteen f_c laskennan).
  4. Kerro ideaalinen impulssivaste valitun ikkunafunktion lausekkeella.
Taululla ratkaistiin toukokuun 2013 tentin tehtävä 4, jossa suodinsuunnittelu tehdään alusta loppuun paperilla. Yleisiä tentissä esiintyviä virheitä ovat:
  1. Muuttujat f_c ja delta_f sekoittuvat keskenään
  2. Käytetään normalisoimattomia taajuuksia (esim. 11000 eikä 11000/32000)
  3. Rajataajuudet on laskettu väärin tai sekoitettu keskenään.
  4. Ikkuna on valittu väärin tai N on laskettu väärin.
  5. Lopputuloksessa on avoimia muuttujia (f_c, delta_f tai N).
Toisen tunnin lopuksi luotiin katsaus kahteen sovellukseen. Ensimmäinen oli Kaggle-alustalla ollut epilepsian tunnistuskilpailu, jonka olennaisena komponenttina on EEG-signaalin jako taajuuskaistoihin. Kilpailun aineisto oli huomattavan suuri, joten ennustuksen vaatimasta laskennasta valtaosa kului taajuuksien erottelussa (eli suodatuksessa). Sijoituimme kilpailussa sijalle 31.

Toisena sovelluksena mainittiin TTY-lähtöinen Yousician-yritys, joka suunnittelee akustisilla soittimilla ohjattavia pelejä. Tässä haasteena on soitetun nuotin luotettava tunnistus mikrofonisignaalista, missä suodatuksella on keskeinen rooli.

maanantai 23. helmikuuta 2015

Luento 25.2: Suodinsuunnittelu


Tunnin aluksi tarkasteltiin demoa, jossa kompleksinen taajuusvaste esitetään painotettujen kompleksisten eksponenttifunktioiden summana. Näin havaittiin mm. ettei pienellä määrällä kertoimia voida muodostaa kovin monimutkaisia amplitudivasteita. Alla olevassa kuvassa suotimessa on 9 kerrointa, jolloin taajuusvaste saadaan yhdeksän kompleksiluvun summana. Amplitudivaste on oikean alakulman käyrä, joka on siis vasemman alakulman käyrän etäisyys origosta.

Tämän jälkeen tutustuttiin suodinsuunnitteluun ikkunamenetelmällä. Suunnittelukriteerit ovat kahtalaiset: suotimen taajuusvasteen määräämiseksi pitää tietää millainen vaihevaste halutaan ja millainen amplitudivaste halutaan.

Vaihevasteen osalta vaaditaan että kaikkien taajuuksien tulee viivästyä yhtä paljon. Tämä toteutuu jos vaihevaste on lineaarinen. Yksinkertaisimmissa tapauksissa vaihevasteen lauseke voi olla siis esimerkiksi muotoa -2w, joka taatusti on lineaarinen. Matlabissa tällainen kuvaaja saadaan esim. komennoilla:

>> [H,W] = freqz([1, 1, 1]);
>> plot(angle(H));
>> grid on

Freqz-funktiosta saa siis ulos taajuusvastefunktion arvoja vektorissa H. Vektorissa on lueteltu taajuusvasteen kompleksiset lukuarvon 512:ssa pisteessä taajuusakselilla. 

Vaihevasteen derivaatasta käyteään nimeä ryhmäviive, ja se ilmaisee suoraan eri taajuuksille tulevan viiveen näytteinä (miinusmerkkisenä). Lopuksi todettiin, että vaihevaste on aina lineaarinen, jos impulssivasteen termit ovat symmetrisesti keskipisteen suhteen.

Amplitudivasteen osalta tavoitteena on saada vaste päästökaistalla ykköseksi ja estokaistalla nollaksi. Käytännössä tämä ei ole mahdollista, vaan suotimelle täytyy antaa hieman toleranssia ja sallia tietty määrä värähtelyä molemmilla kaistoilla. Lisäksi kaistojen väliin täytyy sallia "don't care" -alue, jossa amplitudivaste saa olla mitä vain.

Prujussa ratkaistaan mikä impulssivaste toteuttaisi ideaalisen amplitudivasteen (arvot vain nollaa tai ykköstä). Osoittautuu että impulssivasteen muoto on tuttu sinc-funktio, mutta sen pituus on ääretön. Tämän vuoksi suotimesta ei saataisi ainuttakaan vastearvoa koskaan, vaan laskentaa tarvittaisiin äärettömän paljon.

Tästä ongelmasta päästään katkaisemalla impulssivaste, mutta tämä luonnollisesti vaikuttaa amplitudivasteeseen. Oikealla olevan kuvan mukaisen demottiin, että suoralla katkaisulla ei estokaistan värähtelyä saada millään alle n. 21 desibelin, ja päästökaistallakin suurin heitto on luokkaa 0.7 dB. Ratkaisu tähän on käyttää ikkunointia, eli kertoa katkaistu impulssivaste jollain ikkunafunktiolla. Näin voidaan päästä parempiin vaimennusominaisuuksiin.

Ideaalisen suotimen impulssivasteen pituus on ääretön, eikä sitä voi käytännössä toteuttaa. Näin ollen impulssivaste on katkaistava, mistä seuraa vääristymä amplitudivasteeseen. Matlab-testeillä havaittiin, että tätä ei voi kompensoida esim. kertoimia lisäämällä, vaan on käytettävä ikkunaa, joka pehmentää katkaisun vaikutusta. Ikkunoita on lueteltu esim. sivun 84 taulukossa, ja mitä paremmat vaimennusominaisuudet niillä on, sitä leveämpi siirtymakaistasta tulee. Onneksi tätä voidaan kuitenkin kompensoida kertoimia lisäämällä.


tiistai 17. helmikuuta 2015

Luento 18.2: Z-muunnoksen laskenta ja sovellukset



Tänään käsiteltiin suotimen analysointi (kappale 4) loppuun.

Menetelmässähän ratkaistaan ensin impulssivaste, sitten siirtofunktio ja lopuksi taajuusvaste. Taajuusvaste on kompleksifunktio, joten sitä ei voida sellaisenaan piirtää 2-ulotteiseen koordinaatistoon. Näin ollen piirretään kaksi kuvaajaa: funktion itseisarvon kuvaaja sekä sen vaihekulman kuvaaja. Näistä edellinen kertoo kuinka paljon eri taajuuksien amplitudit muuttuvat suodatuksessa ja jälkimmäinen paljonko ne viivästyvät suodatuksessa. Amplitudivaste on näistä mielenkiintoisempi, koska sen avulla taajuuksia saadaan esim. poistettua yksinkertaisesti huolehtimalla että amplitudivaste ko. taajuudella on nolla.Vaihevaste puolestaan kertoo paljonko eri taajuudet viivästyvät suodatettaessa.

Amplitudivastetta tarkasteltaessa on kätevämpi käyttää desibeliasteikkoa, joka on logaritminen. Logaritmi tekee kertolaskusta yhteenlaskua, ja korostaa lähellä nollaa olevia eroja, jotka molemmat ovat meille käteviä ominaisuuksia.


Kappaleen 4 kaksi viimeistä lukua käytiin läpi ratkaisemalla kevään 2013 toukokuun tentin tehtävä 4. Tässä tehtävässä on annettu suotimen yhtälö, josta täytyy ratkaista siirtofunktio, piirtää napa-nollakuvio sekä päätellä stabiilisuus.

Lopuksi tutkittiin napa-nollakuvion ja taajuusvasteen suhdetta. Taajuusvastehan saadaan siirtofunktiosta H(z) evaluoimalla se pisteissä z = exp(iw). Geometrisesti tämä tarkoittaa yksikköympyrän reaaliakselin yläpuolella olevia pisteitä. Jokainen napa-nollakuvion nolla laskee taajuusvastetta ja jokainen napa nostaa taajuusvastetta. Tästä nähtiin alla olevan kuvan mukainen demo, jossa hiirellä voidaan sijoitella napoja ja nollia yksikköympyrälle. Alimpaan kuvaan piirtyy jokaisen klikkauksen jälkeen suorimen amplitudi- ja taajuusvasteet.



tiistai 10. helmikuuta 2015

Luento 11.2: Z-muunnos


Ensimmäisen tunnin aluksi luotiin katsaus Fourier-muunnoksen ja sen yleistysten soveltamiseen koneoppimisessa. Fourier-analyysissähän kysytään kuinka paljon kutakin sinisignaalia on mukana tarkasteltavassa signaalissa. Yleisempi muoto on käyttää jotain muuta signaalikokoelmaa, tai oppia tämä kokoelma datasta. Klassiset menetelmät ovat pääkomponenttianalyysi (PCA) tai Helsingissä kehitetty riippumattomien komponenttien analyysi (ICA), joissa signaalit esitetään sellaisten rakennuspalikoiden avulla että suuria kertoimia tulee mahdollisimman vähän.

Käytimme erästä tällaista hajotelmaa (SPAMS dictionary learning) osallistuessamme Kaggle-alustalla organisoituun linnunlauluntunnistuskilpailuun. Alkuvaiheessa käytimme mm. Fourier-muunnosta, mutta pelkkä taajuuksien analyysi ei tuottanut tulosta. Tämän vuoksi päätimme oppia "sanakirjan" suoraan datasta, ja toivoimme että sanakirjaan päätyisi tyypillisiä eri lintulajien viserryksiä. Näiden viserrysten lukumäärä toimi sitten indikaattorina siitä mitä lintulajeja äänityksessä oli.

Toisena esimerkkinä koneoppimiskilpailusta tarkasteltiin viime kesänä ollutta MEG-aivodatan analyysikilpailua, johon osallistuimme laitoksen kesätyöntekijöiden kanssa.

Toisella tunnilla tarkasteltiin Z-muunnosta ja sen tärkeimpiä ominaisuuksia. Z-muunnoksen avulla voidaan selvittää mm. suotimen stabiilisuus: suodin on stabiili jos kaikki siirtofunktion navat ovat yksikköympyrän sisäpuolella.

maanantai 2. helmikuuta 2015

Luento 4.2: FFT-algoritmi

Tänään tarkasteltiin Fourier muunnoksen ominaisuuksia, sovelluksia sekä nopeaa toteutusta.

Luennon aluksi esiteltiin alkeellinen menetelmä puheen tunnistukseen. Kirjan Elements of statistical learning kappaleessa 5.2.3 opetetaan tietokone erottelemaan kaksi vokaalia niiden Fourier-muunnosten perusteella. Menetelmä on nimeltään logistinen regressio, joka monimutkaisista kaavoista huolimatta on varsin yksinkertainen toteuttaa: menetelmä etsii kertoimet kullekin Fourier-muunnoksen taajuudelle, ja laskee tulokset yhteen. Jos luku on positiivinen, tulkitaan äänne ä-kirjaimeksi, muutoin a-kirjaimeksi.

Menetelmää demottiin Matlab-toteutuksella, jossa luokittelija opetettiin erottamaan S-äänne muista äänteistä näyttämällä luokittimelle esimerkkejä kahteen luokkaan kuuluvista Fourier-muunnoksista. Menetelmä toimi kohtalaisen hyvin ottaen huomioon opetusaineiston erot testiaineistoon.

Esimerkki kuvaa hyvin tämän päivän signaalinkäsittelyalgoritmia: perusmenetelmiä (Fourier-muunnos, konvoluutio, jne.) käytetään piirregeneraattoreina, jotka tuottavat hieman parempaa raakadataa kuin suora mittaussignaali (esim. taajuustietoa eikä raakaa mittausdataa). Laskettujen piirteiden perusteella sitten nostetaan tiedon abstraktiotasoa edelleen. Esimerkiksi äänteen tunnistuksessa hierarkia on esimerkiksi seuraava:

16000 aikatason näytettä -> 128 taajuustason kerrointa -> 1 bitti, joka kertoo kumpi äänne on kyseessä

Toisena  esimerkkinä oppivasta järjestelmästä mainittiin tamperelaisen Visy Oy:n rekisterikilven tunnistus: tällöinkin luokittelijalle on näytetty kymmeniä tuhansia käsin kerättyjä kirjainmerkkejä, ja algoritmi on oppinut erottelemaan ne toisistaan.

Tämän jälkeen siirryttiin tarkastelemaan Fourier-muunnoksen ominaisuuksia. Ominaisuuksista tutustuttiin lähemmin siirtoon ajassa (esim. laske signaalin x(n+20) muunnos, kun tiedetään x(n):n muunnos) sekä konvoluution muunnokseen (DFT muuntaa konvoluution kertolaskuksi, eli x(n)*y(n) -> X(n)Y(n)). Tämä on perustana mm. dekonvoluutiolle joka on konvoluutiolle käänteinen operaatio. Menetelmää käytettiin mm. Hubble-teleskoopin alkuaikoina, jolloin yhdessä peilissä olleen hiontavirheen vuoksikuvat olivat sumuisia. Kuvantamisprosessia voidaan nimittäin mallintaa (kaksilulotteisella) konvoluutiolla

y(n,m) = h(n,m) * x(n,m),

missä x on todellinen näkymä, y on havaittu sumuinen kuva, ja h on linssin impulssivaste (nk. point spread function; PSF). Yhtälössä y ja h ovat tunnettuja, ja tehtävänä on ratkaista x. Ratkaisu löytyy taajuustasossa, koska

Y(n,m) = H(n,mX(n,m),

joten (Matlabin syntaksilla ilmaistuna):

x(n,m) = ifft (Y(n,m) ./ H(n,m)).

Dekonvoluutiosta on hyötyä yleisemminkin lineaarisen kanavan aiheuttaman häiriön poistossa. Jos tiedetään signaalin x kulkeneen kanavan h läpi, voidaan vastaanotetusta mittaustuloksesta ypäätellä x, jos meillä on joku käsitys kanavasta h. Esimerkkinä tästä on esim. langattoman tiedonsiirtokanavan estimointi ja sen aiheuttaman vääristymän kompensointi.

Toinen menetelmän tuottama etu on että Fourier-muunnoksen (käytännössä FFT:n) avulla voidaan laskea konvoluutio kaavasta (Matlabin syntaksilla ilmaistuna):

conv(x,y) = ifft(fft(x) .* fft(y))

Lisäksi käsiteltiin nopeaa Fourier-muunnosta eli FFT:tä, joka on vain nopeampi tapa toteuttaa diskreetti Fourier-muunnos (DFT). FFT perustuu signaalin jakamiseen lyhyempiin pätkiin, jotka muunnetaan jakamalla ne edelleen rekursiivisesti kahtia. Rekursio päättyy, kun muunnoksen pituus on 1, jolloin muunnosta ei tarvitse enää tehdä. 1-ulotteisen vektorin tapauksessa muunnosmatriisi on yksinkertaisesti F = [1], joka tarkoittaa pelkkää ykkösellä kertomista eikä sitä tarvitse tehdä. Lyhyemmistä vektoreista saadaan koostettua pidemmät vektorit kaavoilla (3.3) ja (3.4).

Alla on vielä luennon esimerkkikoodi S-kirjaimen tunnistuksesta. Funktio käyttää Stanfordin yliopistossa kehitettyä glmnet-pakettia.
function vokaalin_tunnistus()
%
% Esimerkki vokaalin ja S-kirjaimen erottelusta äänisignaalista.
% heikki.huttunen@tut.fi -- 4.2.2015
%

close all

addpath /home/hehu/Documents/Libraries/glmnet_matlab/

% Ladataan opetusaineisto:

[x, Fs] = audioread('seiska.wav');

[X, H, numFrames] = extractFeatures(x, Fs);
title ('Merkitse S-kirjaimet hiirella');

isConsonant = zeros(numFrames, 1);

while true
    
    [x1, y1] = ginput(1);
    [x2, y2] = ginput(1);
    
    if x1 > x2
        xt = x1;
        x1 = x2;
        x2 = xt;
    end
    
    isConsonant(round(x1 * numFrames) : round(x2 * numFrames)) = 1;
    
    response = questdlg('Jatketaanko annotointia?', ...
        'Kysymys', ...
        'Kyllä', 'Ei', 'Kyllä');
    
    if strcmp(response, 'Ei')
        break
    end
    
end

cvob2 = cvglmnet(X, isConsonant, 'binomial', [], 'class');
yHat = glmnetPredict(cvob2.glmnet_fit, X, cvob2.lambda_min, 'response');

coefficients = H * cvob2.glmnet_fit.beta(:, cvob2.lambda == cvob2.lambda_min);

figure()
subplot(211)
plot(yHat);
ylabel('S-kirjaimen TN')
subplot(212)
stem(coefficients)

response = questdlg('Valmiina tunnistamaan?', ...
        'Tunnistus', ...
        'OK', 'OK');

while true
    
    close all

    myRecObj = audiorecorder(Fs, 16, 1);
    recordblocking(myRecObj, 2);
    y = getaudiodata(myRecObj);

    X = extractFeatures(y, Fs);
    yHat = glmnetPredict(cvob2.glmnet_fit, X, cvob2.lambda_min, 'response');

    figure()
    plot(yHat);

    response = questdlg('Jatketaanko tunnistusta?', ...
        'Kysymys', ...
        'Kyllä', 'Ei', 'Kyllä');
    
    if strcmp(response, 'Ei')
        break
    end
    
end

end

function [F, H, numFrames] = extractFeatures(x, Fs)

    [~,f,t,S] = spectrogram(x, 256, 128, 256, Fs, 'yaxis');
    surf(t, f, 10*log10(abs(S)), 'EdgeColor', 'none');
    axis xy; axis tight; colormap(jet); view(0,90);

    S = log10(S)';
    
    H = [];
    n = (1:size(S, 2))';
    
    for k = 0:3
        H = [H, n.^k];
    end
    
    F = S * H;
    numFrames = size(S, 1);
    
end