Diskrétní
perceptronová síť
Zadání:
Vytvořte a natrénujte diskrétní perceptronovou síť pro rozpoznávání dodaných obrazů znaků anglické abecedy (A..Z). Síť bude vracet rozpoznané znaky v kódu 1 z 26. Písmena jsou kódována jako bitová mapa 5x7, jednička je černá barva, nula bílá.
Obecná část:
Výstup sítě je dán rovnicí , kde:
W je váhová matice vazeb (26x35), kde každý prvek wij je ohodnocení vazby z j-tého zdroje do i-tého perceptronu;
x je sloupcový vektor (35x1) s bitovou mapou obrazu písmene (řádky uloženy za sebou od prvního do sedmého)
b je sloupcový vektor (26x1) prahových hodnot 43572xpr97hzd1d
y je sloupcový vektor (26x1) obsahující výstupy jednotlivých perceptronů (0 nebo 1)
sgn je funkce, která nabývá 1, pokud je její parametr kladné číslo, 0 pokud je parametr záporné číslo nebo nulový
Učení perceptronové sítě
K učení sítě je využívána trénovací množina – v tomto případě identická matice U (26x26), která obsahuje požadovaný výstup sítě odpovídající danému znaku (určen řádkou matice). Pro vstup sítě při učení je použita matice X (26x35) obsahující po řádkách vzorové bitové mapy jednotlivých znaků. pz572x3497hzzd
Princip učení:
Matice W(1) a b(1) jsou vhodně inicializovány. Na vstup sítě je v k-tém kroku přiveden sloupcový vektor xp p-tého písmene. Sloupcový vektor yp tedy obsahuje výstup sítě při použití matic W(k) a b(k). Tento výstup je porovnán s požadovaným výstupem up pro i-té písmeno a matice W a b jsou upraveny podle následujících formulí:
Tato úprava je provedena pro každý z 26 znaků a celý cyklus je opakován tak dlouho, až bude splněna podmínka nulové chyby učení (tj. každý trénovací znak je rozpoznán správně):
Programové řešení v Matlabu
Program obsahuje čtyři makra: poznej_znak.m, trenuj_sit.m, sign2.m, loadx.m, loadu.m
function trenuj_sit;
global W b;
disp('Probiha trenovani perceptronove site. Moment...');
% inicializace
W = eye(26,35); % jednotkova matice
b = rand(26, 1); % nahodny vektor
loadx; % nacteni trenovaci a vstupni matice
loadu;
celk_odchylka = -1;
pocitadlo = 0;
% opakovani celeho trenovaciho cyklu, dokud není chyba uceni nulova
while celk_odchylka ~= 0,
celk_odchylka = 0; % vynulovani chybi uceni pro tento cyklus uceni
% pro kazde pismeno abecedy
for vzorek = 1:26,
x = transpose(X(vzorek,:)); % vektory jsou radkove, musime je transponovat
u = transpose(U(vzorek,:));
y = sign2(W * x + b); % vystup sit
odchylka = u - y; % odchylka od pozadovaneho vystupu
W = W + odchylka * transpose(x); % uprava vahove a prahove matice
b = b + odchylka;
% vypocet celkove odchylky k danemu kroku
celk_odchylka = celk_odchylka + sum(odchylka.*odchylka);
end % for
pocitadlo = pocitadlo + 1; % zvyseni pocitadla pruchodu cyklem
end % while
disp('Sit je natrenovana. Pocet prubehu:');
disp(pocitadlo);
Před vlastním rozpoznáváním znaků je třeba natrénovat síť voláním „trenuj_sit“. Makro vytvoří váhovou matici W a prahový vektor b. Tyto matice jsou deklarovány jako globální, je tedy možné je mimo makro zpřístupnit voláním „global W“ (resp. „global b“). V programu je W inicializována jako jednotková matice, b jako vektor náhodných čísel. Při takovéto inicializaci byla síť vždy natrénována v 18 cyklech (pokud je W taktéž matice náhodných čísel, cyklů je 19, pokud jsou W i b náhodné, počet cyklů je náhodně rozložen od cca 14 do cca 26).
Jsou-li tyto matice vytvořeny, můžeme síť již použít voláním „poznej_znak(znak)“, kde znak je řádkový vektor (1x35) obsahující bitovou mapu poznávaného znaku. Makro vrací rozpoznaný znak, případně řetězec „Nerozpoznano.“, pokud znak nebyl rozpoznán.
Automatické rozpoznávání izolovaných slov
Zadání:
Vytvořte program, který rozpozná izolované slovo (z množiny „jedna“, „dva“, „tři“, „čtyři“, „pět“) závislé na řečníkovi. Program má pracovat na základě množiny referenčních slov, výběru příznaků pomocí krátkodobé funkce středního počtu průchodů signálu nulou a funkce DTW (Dynamic Time Warping).
Obecná část:
Příznaky daného signálu jsou určeny pomocí krátkodobé funkce středního počtu průchodů signálu nulou:
Promluvu rozdělíme na mikrosegmenty o délce 20 ms a příznak Zi pro i-tý mikrosegment promluvy se vypočte podle vztahu:
kde
k je aktuální vzorek, N je počet vzorků mikrosegmentu a wi je rámec, kterému přiřazujeme příznak (rámec překrývá vždy polovinu dvou sousedních mikrosegmentů). Použijeme N=160 (což při vzorkovací frekvenci 8 kHz odpovídá délce mikrosegmentu 20 ms). Pokud je poslední segment promluvy předčasně ukončen, doplníme jej nulami na délku 20 ms.
Algoritmus DTW
Soubor příznaků testovaného slova (počet příznaků I) je porovnáván se souborem příznaků referenčního slova (počet příznaků J) pomocí DTW funkce, která rekurentně vytvoří prvky g(i, j) matice G (IxJ) podle předpisu:
Konečná normalizovaná vzdálenost pro testované slovo A a referenční slovo B:
Funkci DTW provedeme pro dané testované slovo A s každým referenčním slovem Br a jako výsledné rozpoznané slovo r* vybereme takové, pro které platí:
Programové řešení v Matlabu
Program se skládá z následujících souborů:
priznaky.mat – pracovní prostor, v němž jsou uloženy vektory příznaků pěti referenčních slov (ref1 až ref5) – vytvořeny funkcí pruchody_0.m
pruchody_0.m – makro, které realizuje krátkodobou funkci středního počtu průchodů signálu nulou
dtw.m – makro, které realizuje DTW funkci a vypočítá konečnou normalizovanou vzdálenost
poznej_slovo.m – makro, které porovná testované slovo (zadané jako jméno wav souboru) se všemi pěti referenčními a vybere takové, pro něž je konečná normalizovaná vzdálenost nejmenší
function x = pruchody_0(data);
delka = length(data);
doplnit = 160 - mod(delka, 160); % kolik nul doplnit
%pokud je treba nuly doplnit, doplnime je
if doplnit ~= 0
data(delka + 1 : delka + doplnit) = zeros(1, doplnit);
delka = length(data);
end
ramec = 0; % aktualni ramec
ramcu = delka / 80 - 1; % pocet ramcu
x = zeros(1, ramcu); % inicializace vektoru priznaku
% opakujeme cyklus pro kazdy ramec
while ramec < ramcu,
z = 0;
% vnitrni cyklus probiha pro 159 vzorku ramce
for i = (ramec * 80 + 2) : (ramec * 80 + 160),
s_prev = data(i - 1); % hodnota predchozicho vzorku
s = data(i); % hodnota aktualniho
% pripocteme 0, pokud signal neprosel nulou, nebo 2, pokud prosel
z = z + abs(my_sign(s) - my_sign(s_prev));
end % for
x(ramec + 1) = z; % do vektoru priznaku ulozime priznak pro dany ramec
ramec = ramec + 1; % dalsi ramec
end
% upravene signum - pro nulu vraci 1
function zn = my_sign(number);
if number < 0
zn = -1;
else
zn = 1;
end
function [D, G] = DTW(tested, ref);
delka_ref = length(ref);
delka_test = length(tested);
% inic. matice a vektoru moznosti
G = zeros(delka_test, delka_ref);
moznosti = zeros(1,3);
% inic. 1. prvku matice
G(1,1) = abs(tested(1) - ref(1));
% plnime matici
for j = 1 : delka_ref,
for i = 1 : delka_test,
% pokud se nenachazime na 1. prvku matice, uzijeme rekurzi
if or((i > 1), (j > 1))
% prvni moznost
if j > 1
moznosti(1) = G(i, j - 1) + abs(tested(i) - ref(j));
else % pokud nelze, dame nekonecno
moznosti(1) = Inf;
end
% druha moznost
if and((j > 1), (i > 1))
moznosti(2) = G(i - 1, j - 1) + 2 * abs(tested(i) - ref(j));
else
moznosti(2) = Inf; % pokud nelze, dame nekonecno
end
% treti moznost
if i > 1
moznosti(3) = G(i - 1, j) + abs(tested(i) - ref(j));
else
moznosti(3) = Inf; % pokud nelze, dame nekonecno
end
% dany prvek matice je minimalni ze tri moznosti
G(i, j) = min(moznosti);
end
end
end
% vypocet konecne normalizovane vzdalenosti
D = G(delka_test, delka_ref) / (delka_test + delka_ref);
function poznej_slovo(soubor);
disp('Nacitam soubor...');
load 'priznaky.mat'; % nacteni priznaku
slovo = wavread(soubor); % nacteni testov. wavu
disp('Hledam priznaky...');
tested = pruchody_0(slovo); % urceni pruchodu nulou test. wavu
D = zeros(1, 5); % inicializace vektoru moznych norm. vzdalenosti
disp('Porovnavam...');
% do vektoru zapsany vysledky DTW pro kazde ref. slovo
[D(1), G] = DTW(tested, ref1);
disp('.');
[D(2), G] = DTW(tested, ref2);
disp('.');
[D(3), G] = DTW(tested, ref3);
disp('.');
[D(4), G] = DTW(tested, ref4);
disp('.');
[D(5), G] = DTW(tested, ref5);
% vybereme minimalni vzdalenost na i-te pozici
[d, i] = min(D);
% hledani druheho nejmensiho prvku a urceni jeho
% vzdalenosti od prvniho nejmensiho
foo = D;
foo(i) = Inf;
[kontrola, i2]=min(abs(foo - d));
% i-ta pozice je i rozpoznane cislo - vypiseme
disp(' ');
disp(i);
% pokud je rozdil 1. a 2. nejmensiho maly, rozpoznani neni
% prilis jiste
if kontrola < 0.3
disp('Nejsem si jisty, mozna to je');
disp(i2);
end
sound(slovo, 8000);
Výsledky klasifikace testovaných promluv
soubor |
úspěšnost |
obsahuje |
rozpoznáno |
je si jist (další možnost) |
TEST1 |
N |
5 |
2 |
N (5) |
TEST2 |
A |
4 |
4 |
A |
TEST3 |
A |
3 |
3 |
A |
TEST4 |
A |
2 |
2 |
A |
TEST5 |
N |
1 |
2 |
N (1) |
TEST6 |
A |
1 |
1 |
A |
TEST7 |
A |
2 |
2 |
N (5) |
TEST8 |
A |
3 |
3 |
A |
TEST9 |
A |
4 |
4 |
A |
TEST10 |
A |
5 |
5 |
A |
TEST11 |
A |
1 |
1 |
N (2) |
TEST12 |
A |
3 |
3 |
A |
Pozn.: další možnost znamená, které číslo program navrhne jako jiné možné rozpoznané v případě, že si není rozpoznáním jist
Test1 – Ref2 (d = 3,8592)
Test1– Ref4 (d = 26,0283)