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,m) X(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
Ei kommentteja:
Lähetä kommentti