🧠 MLP Builder

OpenTechLab Jablonec nad Nisou · Science Micro Elementary School

Navrhni síť, připrav data, trénuj a pozoruj jak se učí vícevrstvá neuronová síť

💡 Co je tu nové? V tomto kurzu už síť neučíme ručně – necháváme ji počítat vlastní chybu a opravovat se sama.

⚙️ Konfigurace sítě

🔧
Návrh
📚
Trénink
▶️
Provoz
0
±0.5
0.10
0.1

RUČNÍ TRÉNINK

AUTOMATICKÝ TRÉNINK

Zadej vstupní hodnoty a spusť síť:

🔗 Vizualizace sítě
Epocha 0
Chyba
Data
Váhy
Log

📊 Tréninková data

⚖️ Váhy sítě

📋 Tréninkový log

Epocha: 0
Krok: 0
Celková chyba: -
Cílová chyba: 0.01

💡 Síť neví, zda odpověděla správně – vidí jen číslo chyby.

🎯 Praktická aplikace: Rozpoznávání číslic (OCR)

Pochopili jste, jak funguje vícevrstvá neuronová síť? Nyní ji použijte k něčemu užitečnému! Digit Trainer – síť s 15 vstupy (LCD mřížka 3×5), 11 skrytými neurony a 4 výstupy, která se dokáže naučit rozlišovat číslice 0–9 zakódované v binárním formátu.

⚠️ Síť se učí pouze z malého množství příkladů – proto může chybovat na nových vzorech.

🖌️ Kreslící mřížka (2×4)

📝
Sběr dat
🔍
Rozpoznání
Klikni na buňky pro zapnutí/vypnutí (LCD styl 3×5)
Najeď myší na skrytý neuron pro zobrazení vah

🎯 Přiřadit číslici


?
Nakresli vzor a spusť rozpoznání

🔗 Neuronová síť 15→11→4

Epocha: 0 Chyba:

📊 Tréninková data (0 vzorů)

Zatím žádná data.
Nakresli vzor a přiřaď číslici.


⚙️ Nastavení

0.30
0.1
Epocha: 0
Celková chyba:
Stav: Připraveno

📚 Teorie vícevrstvých neuronových sítí

Pochopte, proč a jak funguje učení v MLP

🔄 Backpropagation vs. Perceptron

Jednoduchý perceptron má pouze vstupní a výstupní vrstvu. Chybu můžeme přímo připsat každé váze – kolik přispěla k chybě, tolik ji upravíme.

Vícevrstvá síť (MLP) má problém: Jak zjistit, kolik k chybě přispěla váha ve skryté vrstvě?

💡 Řešení: Backpropagation

Chybu šíříme zpět od výstupu ke vstupu. Každý neuron dostane "díl viny" podle toho, jak moc se podílel na výstupu.

🎯 Klíčový vhled: Síť neví, která váha je špatná. Backpropagation je jen systematický způsob, jak to odhadnout.

Klíčový rozdíl: Perceptron = přímá úprava vah. MLP = chyba se "rozloží" mezi všechny vrstvy pomocí gradientu.

🏗️ Volba architektury sítě

Kolik skrytých vrstev?

  • 1 vrstva – stačí pro většinu běžných úloh
  • 2+ vrstvy – složitější vzory, hlubší abstrakce
  • Více vrstev = těžší trénink (mizící gradient)

Kolik neuronů ve skryté vrstvě?

📏 Praktická pravidla:

  • Začněte s (vstupy + výstupy) / 2
  • Nebo 2/3 vstupů + výstupy
  • Příliš málo → síť se nenaučí
  • Příliš mnoho → přeučení (overfitting)

📈 Aktivační funkce Sigmoid

Sigmoid "zmáčkne" jakýkoliv vstup do rozsahu (0, 1):

σ(x) = 1 / (1 + e-x)

Proč je důležitá pro backpropagation?

  • Je diferencovatelná – můžeme počítat gradient
  • Derivace: σ'(x) = σ(x) × (1 - σ(x))
  • Umožňuje "jemné" úpravy vah

💡 Srovnej s perceptronem, který používal skokovou funkci (0 nebo 1).

⚡ Learning Rate & Momentum

Learning Rate (η) – jak velké kroky děláme:

  • Příliš malá → učení trvá věčnost
  • Příliš velká → přeskakujeme optimum, síť diverguje
  • Typicky: 0.01 – 0.3

Momentum (α) – "setrvačnost" učení:

Přidává část předchozí změny k aktuální. Pomáhá překonat lokální minima a urychluje konvergenci v "údolích".

Vzorec: Δw = η × δ × input + α × Δwpředchozí

💡 Praktické tipy pro trénink

  1. Normalizujte vstupy – hodnoty v rozsahu 0-1 fungují nejlépe
  2. Inicializujte váhy náhodně – malé hodnoty kolem nuly
  3. Míchejte tréninková data – zabraňuje uvíznutí v lokálních minimech
  4. Sledujte chybovou křivku – měla by klesat
  5. Validujte na nových datech – testujte na vzorech, které síť neviděla

⊕ Proč perceptron selže na XOR?

XOR (exkluzivní OR) není lineárně separabilní – nemůžete nakreslit jednu přímku, která oddělí 0 od 1.

❌ Perceptron

Jen 1 vrstva = 1 přímka

✓ MLP

Skrytá vrstva = více přímek

Vyzkoušej v simulátoru nahoře! Načti XOR data a sleduj, jak síť najde řešení.

💻 Implementační průvodce

1. Třída neuronové sítě

class NeuralNetwork {

    constructor(inputSize, hiddenSize, outputSize) {

        this.inputSize = inputSize;

        this.hiddenSize = hiddenSize;

        this.outputSize = outputSize;

        

        // Inicializace vah (náhodné malé hodnoty)

        // +1 pro bias v každé vrstvě

        this.weightsIH = this.randomMatrix(inputSize + 1, hiddenSize, 0.5);

        this.weightsHO = this.randomMatrix(hiddenSize + 1, outputSize, 0.5);

        

        // Hodnoty aktivací

        this.hiddenValues = new Array(hiddenSize).fill(0);

        this.outputValues = new Array(outputSize).fill(0);

    }

    

    randomMatrix(rows, cols, range) {

        return Array.from({ length: rows }, () =>

            Array.from({ length: cols }, () => 

                (Math.random() - 0.5) * 2 * range

            )

        );

    }

    

    sigmoid(x) { return 1 / (1 + Math.exp(-x)); }

    sigmoidDerivative(y) { return y * (1 - y); }

}

2. Forward Pass (dopředný průchod)

forward(inputs) {

    this.inputValues = [...inputs];

    

    // Skrytá vrstva

    for (let j = 0; j < this.hiddenSize; j++) {

        let sum = this.weightsIH[this.inputSize][j]; // Bias

        for (let i = 0; i < this.inputSize; i++) {

            sum += inputs[i] * this.weightsIH[i][j];

        }

        this.hiddenValues[j] = this.sigmoid(sum);

    }

    

    // Výstupní vrstva

    for (let k = 0; k < this.outputSize; k++) {

        let sum = this.weightsHO[this.hiddenSize][k]; // Bias

        for (let j = 0; j < this.hiddenSize; j++) {

            sum += this.hiddenValues[j] * this.weightsHO[j][k];

        }

        this.outputValues[k] = this.sigmoid(sum);

    }

    

    return this.outputValues;

}

3. Backpropagation (zpětná propagace)

backward(targets, learningRate, momentum = 0.1) {

    // 1. Výpočet chyby výstupní vrstvy

    const outputDeltas = [];

    for (let k = 0; k < this.outputSize; k++) {

        const error = targets[k] - this.outputValues[k];

        outputDeltas[k] = error * this.sigmoidDerivative(this.outputValues[k]);

    }

    

    // 2. Výpočet chyby skryté vrstvy (backprop)

    const hiddenDeltas = [];

    for (let j = 0; j < this.hiddenSize; j++) {

        let error = 0;

        for (let k = 0; k < this.outputSize; k++) {

            error += this.weightsHO[j][k] * outputDeltas[k];

        }

        hiddenDeltas[j] = error * this.sigmoidDerivative(this.hiddenValues[j]);

    }

    

    // 3. Aktualizace vah Hidden→Output

    for (let j = 0; j <= this.hiddenSize; j++) {

        for (let k = 0; k < this.outputSize; k++) {

            const input = j < this.hiddenSize ? this.hiddenValues[j] : 1;

            const change = learningRate * outputDeltas[k] * input;

            this.weightsHO[j][k] += change + momentum * this.deltaHO[j][k];

            this.deltaHO[j][k] = change;

        }

    }

    

    // 4. Aktualizace vah Input→Hidden (podobně)

    for (let i = 0; i <= this.inputSize; i++) {

        for (let j = 0; j < this.hiddenSize; j++) {

            const input = i < this.inputSize ? this.inputValues[i] : 1;

            const change = learningRate * hiddenDeltas[j] * input;

            this.weightsIH[i][j] += change + momentum * this.deltaIH[i][j];

            this.deltaIH[i][j] = change;

        }

    }

}

4. Tréninková smyčka

function trainEpoch(network, trainingData, learningRate) {

    // Zamíchat data (důležité!)

    const shuffled = [...trainingData].sort(() => Math.random() - 0.5);

    

    for (const pattern of shuffled) {

        network.forward(pattern.inputs);

        network.backward(pattern.outputs, learningRate);

    }

    

    // Spočítat celkovou chybu

    let totalError = 0;

    for (const pattern of trainingData) {

        network.forward(pattern.inputs);

        totalError += calculateMSE(network.outputValues, pattern.outputs);

    }

    

    return totalError / trainingData.length;

}



function calculateMSE(outputs, targets) {

    let error = 0;

    for (let i = 0; i < outputs.length; i++) {

        error += Math.pow(targets[i] - outputs[i], 2);

    }

    return error / outputs.length;

}



// Trénink

let epoch = 0;

while (totalError > 0.01 && epoch < 10000) {

    totalError = trainEpoch(network, trainingData, 0.2);

    epoch++;

}

📐 Matematický přehled

Forward Pass
hj = σ(Σwijxi + bj)
yk = σ(Σwjkhj + bk)
Output Error
δk = (tk - yk) × σ'(yk)
Hidden Error
δj = (Σδkwjk) × σ'(hj)
Weight Update
Δw = η × δ × input + α × Δwprev

© 2024 OpenTechLab Jablonec nad Nisou · Vytvořeno pro vzdělávací účely