pondělí 14. května 2012

Cvičení s trénováním neuronové sítě s libovolným počtem vrstev

Přiložená ukázka je ten nejjednodušší gradientní algoritmus (tj. backpropagation v základní podobě). Kritérium optimality je MSE. Aktivační funkce je z-funkce, což je zrcadlově převrácená sigma-funkce: z(x) = σ(-x). (Ušetří se jedno mínus.) Neuronová síť se učí všech 16 možných binárních funkcí najednou. Kód v Matlabu přikládám. Tento skript je jen pro ověření funkčnosti návrhu algoritmu. Je to docela dobré cvičení, pokud se učíte parciálně derivovat a operace s maticemi. Je to úplně jednoduché a měl by to zvládnout i začátečník. (Což ale neznamená, že jsem neudělal chybu.)

% počet vstupů NN
dimx = 2;

% počty neuronů v jednotlivých vrstvách (poslední číslo = počet výstupů)
ns = [5, 12, 16];

% počet vrstev NN (vstupy nejsou vrstva)
nL = length(ns);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% počet příkladů v trénovací množině
T = 4;

% příklady vstupů (příklady jsou v řádcích)
X = [
     0     0
     1     0
     0     1
     1     1
];

% příklady požadovaných výstupů (příklady jsou v řádcích)
Y = [
     0     0     0     0     0     0     0     0     1     1     1     1     1     1     1     1
     0     0     0     0     1     1     1     1     0     0     0     0     1     1     1     1
     0     0     1     1     0     0     1     1     0     0     1     1     0     0     1     1
     0     1     0     1     0     1     0     1     0     1     0     1     0     1     0     1
];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Alokace paměti a inicializace NN

dimsx = [dimx, ns(1:(nL - 1))];
Ws = {};
bs = {};
for i = 1:nL
    Ws{i} = 0.1 * randn(dimsx(i), ns(i));
    bs{i} = 0.1 * randn(1, ns(i));
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Alokace paměti

Bs = {};
Xis = {};
Xs = {};
dXdXis = {};
dedXs = {};
dedXis = {};
dedWs = {};
dedbs = {};
for i = 1:nL
    Xis{i} = zeros(T, ns(i));
    Xs{i} = zeros(T, ns(i));
    Bs{i} = zeros(T, ns(i));
    dXdXis{i} = zeros(T, ns(i));
    dedXs{i} = zeros(T, ns(i));
    dedXis{i} = zeros(T, ns(i));
    dedWs{i} = zeros(dimsx(i), ns(i));
    dedbs{i} = zeros(1, ns(i));
end

for icycle = 1:10000000
    
    % počítání výstupů
    
    for i = 1:nL
        Bs{i} = ones(T, 1) * bs{i};
    end
    
    for i = 1:nL
        if i == 1
            Xis{i} = X * Ws{i} + Bs{i};
        else
            Xis{i} = Xs{i - 1} * Ws{i} + Bs{i};
        end
        Xs{i} = 1 ./ (1 + exp(Xis{i}));
    end

    % tisk výstupů

    disp(Xs{nL})
    
    % počítání chyby
    
    e = sum(sum((Xs{nL} - Y).^2))
    
    if e < 0.01
        break
    end

    % počítání gradientu
    
    for i = 1:nL
        dXdXis{i} = Xs{i} .* (Xs{i} - 1);
    end
    dedXs{nL} = 2 * (Xs{nL} - Y);
    dedXis{nL} = dedXs{nL} .* dXdXis{nL};
    for i = (nL - 1):(-1):1
        dedXs{i} = dedXis{i + 1} * Ws{i + 1}';
        dedXis{i} = dedXs{i} .* dXdXis{i};
    end
    dedWs{1} = X' * dedXis{1};
    for i = 2:nL
        dedWs{i} = Xs{i - 1}' * dedXis{i};
    end    
    for i = 1:nL
        dedbs{i} = sum(dedXis{i});
    end    

    % změna parametrů NN

    LR = 0.01;
    for i = 1:nL
        Ws{i} = Ws{i} - LR * dedWs{i};
        bs{i} = bs{i} - LR * dedbs{i};
    end
    
end    

Žádné komentáře: