Neuronové sítě
Lidský mozek se skládá z miliard neuronů – buněk, které zpracovávají informace. Každá tato buňka funguje jako jednoduchý procesor a jen masivní interakce mezi nimi dává mozku všechny jeho úžasné schopnosti. Umělá neuronová síť je distribuovaný výpočetní systém sestávající z dílčích podsystémů (tzv. neuronů), který je inspirován neurofyziologickými poznatky o struktuře a činnosti neuronů a nervových systémů živých organizmů, a který je ve větší či menší míře realizuje.
Historie
Prvním matematickým modelem neuronu byl perceptron (1958), navržený F. Rosenblattem (1928–1969). Tento jednoduchý prvek pracoval pouze s binárními hodnotami a jejich sítě byly schopny řešit jednoduché logické funkce, jako je AND nebo OR. O jedenáct let později představili M. Minski a S. Papert vícevrstvý perceptron (1969). V roce 1982 vzniklo hned několik nových modelů najednou. J. J. Hopfield sestavil tzv. Hopfieldův model a T. Kohonen svou samoorganizující se mapu. V té se neurony samy organizují a simulují tak lépe vývoj mozku. Také se poprvé objevuje zpětná vazba. Dnes velmi rozšířenou neuronovou síť se zpětnou propagací chyby představili v roce 1986 badatelé G. E. Hinton, E. Rumelhart a R. J. Williams.
Neuron
Neuron je základní mozkovou buňkou. Bez zbytečného zabíhání do biologických detailů jej lze rozložit na dendrity (vstupy), tělo a axon (výstup). Jeho model se analogicky skládá z několika vstupů (X), které mají přiřazenou číselnou váhu (w). Ta udává „důležitost“ či „sílu“ daného vstupu. Vstupy jsou v modelu složeny (nejčastěji prostým součtem vážených hodnot vstupů) a výsledek je jako argument předán nelineární prahové funkci. Proces učení zpravidla spočívá ve vhodném nastavení všech vah.
schéma biologického neuronu
Matematický model
Nejjednodušší model neuronu sečte vstupy (X) vážené odpovídajícími vahami (w) a výsledek vloží do prahové funkce (f). Jako prahové funkce se například používají různé parametrizovatelné sigmoidy a funkce signum. Pro funkci neuronové sítě je významná i platnost Kolmogorovovy věty.
matematický model neuronu (perceptron)

Prahová funkce
Prahová funkce by měla být nelineární a alespoň velmi přibližně modelovat reálné chování neuronu.
Log-Sigmoida (logistická funkce):

Tan-Sigmoida:

Signum:

Využití
Neuronová síť má asi jako každý přírodou inspirovaný přístup velmi široké možnosti uplatnění, především při řešení problémů z reálného světa. V této oblasti jsou totiž počítače nejslabší. Dále se přímo nabízí využití v umělé inteligenci. Konkrétní typ a architektura neuronové sítě se většinou silně upravuje na míru danému konkrétnímu problému.
Nejzajímavější vlastností neuronových sítí je jejich odolnost vůči chybám. Jakmile se neuronová síť jednou dobře naučí, je schopná řešit i příbuzné problémy, se kterými se dosud nesetkala. Na druhou stranu, není však garantovaná kvalita ani správnost řešení. Neoddělitelnou součástí výsledku je vždy určitá chyba.
V těchto oblastech se neuronové sítě používají nejčastěji:
- klasifikace
- detekce pravidelnosti
- zpracování řeči
- zpracování obrazu
- optimizační problémy
- ovládání robotů
- predikce časových řad
- simulace
Vícevrstvý perceptron
Vícevrstvý perceptron (multilayer perceptron) je typ neuronové sítě, která se chová podobně jako jeden perceptron, ale skládá se z většího počtu umělých neuronů. Tyto neurony jsou rozděleny do vrstev. První vrstva, tzv. vstupní vrstva je vstupem neuronové sítě. Počet neuronů ve vstupní vrstvě odpovídá velikosti vstupního vektoru. Za ní následují tzv. skryté vrstvy. Těch může být i více, přičemž jejich počet i velikost je libovolná. Poslední skrytá vrstva je napojena na poslední, tzv. výstupní vrstvu. Počet neuronů ve výstupní vrstvě odpovídá velikosti výstupního vektoru. Všechny neurony jsou spojené pouze dopředně – směrem ze vstupu na výstup.
vícevrstvý perceptron
Při učení se nejprve nastaví vstupní vektor jako výstup vstupní vrstvy. Poté je spuštěn výpočet výstupů všech neuronů, a to postupně od první skryté vrstvy po výstupní vrstvu. Následuje nastavení správného výstupu na výstupní vrstvu. Ta vypočítá chybu a zpětně ji rozšíří až do první skryté vrstvy. Poté jsou podle chyby upraveny jednotlivé váhy všech neuronů.
Implementace (Java)
Neuron
import java.util.HashSet;
import java.util.Set;
/**
* Třída představující jednoduchý neuron.
* @author Vojtěch Hordějčuk
*/
public class Neuron
{
/**
* počítadlo instancí neuronů
*/
private static int counter = 1;
/**
* unikátní ID neuronu
*/
final protected int id;
/**
* množina synapsí - vstupní neurony
*/
final private Set<Synapsis> inputs;
/**
* výstupní hodnota
*/
protected double output;
/**
* velikost chyby
*/
protected double error;
/**
* Vytvoří nový neuron.
*/
public Neuron ()
{
this.id = Neuron.counter ++;
this.inputs = new HashSet<Synapsis> ();
this.output = 0;
this.error = 0;
}
/**
* Vrátí unikátní ID neuronu.
* @return ID neuronu
*/
public int getId ()
{
return this.id;
}
/**
* Vrátí výstup neuronu.
* @return výstup neuronu
*/
public double getOutput ()
{
return this.output;
}
/**
* Nastaví výstup neuronu.
* @param value hodnota výstupu neuronu
*/
public void setOutput (final double value)
{
this.output = value;
}
/**
* Vynuluje výstup a chybu neuronu, nastaví náhodné váhy synapsím.
*/
public void reset ()
{
this.output = 0;
this.error = 0;
for (final Synapsis temp: this.inputs)
{
temp.reset ();
}
}
/**
* Spojí neuron s výstupem jiného neuronu.
* @param neuron vstupní neuron
*/
public void addInput (final Neuron neuron)
{
this.inputs.add (new Synapsis (neuron));
}
/**
* Přidá k neuronu speciální vstup, tzv. bias.
*/
public void addBiasInput ()
{
this.inputs.add (new Synapsis (new Bias ()));
}
/**
* Vypočítá výstup neuronu na základě jeho vstupů a odpovídajících vah.
* 1) Sečtou se vážené vstupy neuronu.
* 2) Výsledná hodnota je předána jako parametr nelineární prahové funkci.
*/
public void calculateOutput ()
{
this.output = 0;
for (final Synapsis temp: this.inputs)
{
this.output += temp.getWeight () * temp.getNeuron ().getOutput ();
}
this.output = Neuron.getThreshold (this.output);
}
/**
* Vyresetuje chybu neuronu.
*/
public void resetError ()
{
this.error = 0;
}
/**
* Vypočítá chybu a zpropaguje ji dál do všech vstupních neuronů.
* Tato metoda je určena pro výstupní vrstvu.
* @param ideal správný výstup neuronu
*/
public void propagateError (final double ideal)
{
this.error = ideal - this.output;
this.propagateError ();
}
/**
* Zpropaguje chybu dál do všech vstupních neuronů.
* Tato metoda je určena pro skrytou vrstvu.
*/
public void propagateError ()
{
for (final Synapsis temp: this.inputs)
{
temp.getNeuron ().error += this.error * temp.getWeight ();
}
}
/**
* Opraví váhy synapsí podle velikosti chyby a rychlosti učení.
* @param rate rychlost učení (nenulová hodnota).
*/
public void fixWeights (final double rate)
{
if (rate <= 0)
{
throw new UnsupportedOperationException ("Invalid learning rate!");
}
for (final Synapsis temp: this.inputs)
{
temp.increaseWeight (rate * this.error * Neuron.getThresholdDerivated (this.output) * temp.getNeuron ().output);
}
}
/**
* Vypočítá hodnotu prahové funkce. Zde je použit hyperbolický tangens.
* F(x) = tanh (x)
* @param input vstupní hodnota
* @return hodnota prahové funkce
*/
private static double getThreshold (final double input)
{
return Math.tanh (input);
}
/**
* Vypočítá hodnotu derivace prahové funkce. Zde je použita derivace hyperbolického tangens.
* F'(x) = 1 - tanh^2 (x)
* @param input vstupní hodnota
* @return hodnota derivace prahové funkce
*/
private static double getThresholdDerivated (final double input)
{
return 1.0 - (Math.tanh (input) * Math.tanh (input));
}
@Override
public String toString ()
{
return String.format ("N%d (out = %f, err = %f, in = %s)", this.id, this.output, this.error, this.inputs.toString ());
}
}
zdrojový kód (Java) - zobrazit (4060 znaků)
Bias (speciální neuron)
/**
* Speciální neuron, který má na výstupu neustále 1.
* Používá se pro zvýšení kvality neuronové sítě.
* @author Vojtěch Hordějčuk
*/
public class Bias extends Neuron
{
@Override
public double getOutput ()
{
return 1;
}
}
zdrojový kód (Java) - zobrazit (257 znaků)
Synapse
/**
* Třída představující synapsi - vážený spoj mezi dvěma neurony.
* @author Vojtěch Hordějčuk
*/
public class Synapsis
{
/**
* neuron napojený na synapsi
*/
final private Neuron neuron;
/**
* váha synapse
*/
private double weight;
/**
* Vytvoří novou synapsi.
* @param neuron napojený neuron
*/
public Synapsis (final Neuron neuron)
{
this.neuron = neuron;
this.weight = 1;
}
/**
* Vrátí napojený neuron.
* @return napojený neuron
*/
public Neuron getNeuron ()
{
return this.neuron;
}
/**
* Vrátí váhu synapse.
* @return váha synapse
*/
public double getWeight ()
{
return this.weight;
}
/**
* Nastaví váhu synapse na náhodnou hodnotu.
*/
public void reset ()
{
this.weight = - 1.0 + (Math.random () * 2.0);
}
/**
* Změní váhu synapse.
* @param delta velikost změny
*/
public void increaseWeight (final double delta)
{
this.weight += delta;
}
@Override
public String toString ()
{
return String.format ("N%d (w = %f)", this.neuron.getId (), this.weight);
}
}
zdrojový kód (Java) - zobrazit (1126 znaků)
Vrstva neuronů
import java.util.HashSet;
import java.util.Set;
/**
* Třída představující vrstvu neuronové sítě.
* @author Vojtěch Hordějčuk
*/
public class Layer
{
/**
* množina neuronů ve vrstvě
*/
final private Set<Neuron> neurons;
/**
* Vytvoří novou vrstvu a její neurony.
* @param size počet neuronů ve vrstvě
*/
public Layer (final int size)
{
this.neurons = new HashSet<Neuron> ();
for (int i = 0; i < size; i ++)
{
this.neurons.add (new Neuron ());
}
// každému neuronu přidat jeden speciální vstup (bias)
// (toto jejen optimalizace, k funkci to není nutné)
for (final Neuron temp: this.neurons)
{
temp.addBiasInput ();
}
}
/**
* Vrátí výstupní vektor vrstvy.
* @return výstupní vektor
*/
public double[] getOutputs ()
{
final double[] outputs = new double[this.neurons.size ()];
int i = 0;
for (final Neuron temp: this.neurons)
{
outputs[i ++] = temp.getOutput ();
}
return outputs;
}
/**
* Nastaví neuronům výstup podle vektoru.
* @param values vektor hodnot
*/
public void setOutputs (final double[] values)
{
// zkontrolovat parametr
if (values.length != this.neurons.size ())
{
throw new UnsupportedOperationException ("Invalid output vector size!");
}
// přiřadit jednotlivé hodnoty neuronům
int i = 0;
for (final Neuron temp: this.neurons)
{
temp.setOutput (values[i ++]);
}
}
/**
* Přidá každý neuron této vrstvy jako vstup neuronu další vrstvy.
* @param target další cílová vrstva
*/
public void connectTo (final Layer target)
{
for (final Neuron tNext: target.neurons)
{
for (final Neuron tPrev: this.neurons)
{
tNext.addInput (tPrev);
}
}
}
/**
* Vyresetuje všechny neurony ve vrstvě.
*/
public void reset ()
{
for (final Neuron temp: this.neurons)
{
temp.reset ();
}
}
/**
* Vypočítá výstupní hodnotu všech neuronů.
*/
public void calculateOutput ()
{
for (final Neuron temp: this.neurons)
{
temp.calculateOutput ();
}
}
/**
* Vyresetuje chybu všech neuronů.
*/
public void resetError ()
{
for (final Neuron temp: this.neurons)
{
temp.resetError ();
}
}
/**
* Zpětně zpropagovat chybu.
* Tato metoda je určena pro výstupní vrstvu.
* @param output výstupní vektor
*/
public void propagateError (final double[] output)
{
int i = 0;
for (final Neuron temp: this.neurons)
{
temp.propagateError (output[i ++]);
}
}
/**
* Zpětně zpropagovat chybu.
* Tato metoda je určena pro skrytou vrstvu.
*/
public void propagateError ()
{
for (final Neuron temp: this.neurons)
{
temp.propagateError ();
}
}
/**
* Opravit váhy synapsí podle chyby.
* @param rate rychlost učení
*/
public void fixWeights (final double rate)
{
for (final Neuron temp: this.neurons)
{
temp.fixWeights (rate);
}
}
@Override
public String toString ()
{
final StringBuffer buffer = new StringBuffer ();
for (final Neuron temp: this.neurons)
{
buffer.append (temp.toString () + "\n");
}
return buffer.toString ().trim ();
}
}
zdrojový kód (Java) - zobrazit (3318 znaků)
Neuronová síť
/**
* Třída představující neuronovou síť.
* Jedná se o jednoduchý vícevrstvý perceptron.
* @author Vojtěch Hordějčuk
*/
public class Network
{
/**
* vstupní vrstva neuronů
*/
final private Layer input;
/**
* skryté vrstvy neuronů
*/
final private Layer hidden[];
/**
* výstupní vrstva neuronů
*/
final private Layer output;
/**
* rychlost učení
*/
private double rate;
public Network (final int inputSize, final int outputSize, final int hiddenSize, final int hiddenCount, final double rate)
{
// zkontrolovat parametry
if (inputSize < 1 || outputSize < 1 || hiddenSize < 1 || hiddenCount < 1 || rate <= 0.0)
{
throw new UnsupportedOperationException ("Invalid parameters of neural network!");
}
// inicializovat
this.rate = rate;
// vytvořit vstupní a výstupní vrstvy
this.input = new Layer (inputSize);
this.output = new Layer (outputSize);
// vytvořit skryté vrstvy
this.hidden = new Layer[hiddenCount];
for (int i = 0; i < this.hidden.length; i ++)
{
this.hidden[i] = new Layer (hiddenSize);
}
// spojit vrstvy (IN-H...H-OUT)
this.input.connectTo (this.hidden[0]);
for (int i = 0; i < hiddenCount - 1; i ++)
{
this.hidden[i].connectTo (this.hidden[i + 1]);
}
this.hidden[this.hidden.length - 1].connectTo (this.output);
// vyresetovat síť
this.reset ();
}
/**
* Vyresetuje všechny vrstvy neuronové sítě.
*/
public void reset ()
{
this.input.reset ();
for (int i = 0; i < this.hidden.length; i ++)
{
this.hidden[i].reset ();
}
this.output.reset ();
}
/**
* Provede proces učení neuronové sítě pro daný vstupní a výstupní vektor.
* @param inputs vstupní vektor hodnot
* @param ideal správný výstupní vektor
*/
public void learn (final double[] inputs, final double[] ideal)
{
// spočítat výstupy všech neuronů
this.guess (inputs);
// vynulovat chybu
this.input.resetError ();
for (int i = 0; i < this.hidden.length; i ++)
{
this.hidden[i].resetError ();
}
this.output.resetError ();
// zpětně zpropagovat chybu (OUT-H...H)
this.output.propagateError (ideal);
for (int i = this.hidden.length - 1; i >= 0; i --)
{
this.hidden[i].propagateError ();
}
this.input.propagateError ();
// opravit váhy synapsí podle aktuální chyby (OUT-H...H)
this.input.fixWeights (this.rate);
for (int i = 0; i < this.hidden.length; i ++)
{
this.hidden[i].fixWeights (this.rate);
}
this.output.fixWeights (this.rate);
}
/**
* Provede odhad výstupu pro daný vstup.
* @param inputs vstupní vektor
* @return odhadovaný výstupní vektor
*/
public double[] guess (final double[] inputs)
{
// nastavit vstup
this.input.setOutputs (inputs);
// spočítat výstupní hodnoty všech neuronů od skrytých vrstev dál
for (int i = 0; i < this.hidden.length; i ++)
{
this.hidden[i].calculateOutput ();
}
this.output.calculateOutput ();
// vrátit výstupní vektor z výstupní vrstvy
return this.output.getOutputs ();
}
@Override
public String toString ()
{
final StringBuffer temp = new StringBuffer ();
temp.append ("Neural network\n--------------\n");
temp.append ("*** INPUT LAYER ***\n");
temp.append (this.input.toString () + "\n");
for (int i = 0; i < this.hidden.length; i ++)
{
temp.append ("*** HIDDEN LAYER " + i + " ***\n");
temp.append (this.hidden[i].toString () + "\n");
}
temp.append ("*** OUTPUT LAYER ***\n");
temp.append (this.output.toString () + "\n");
return temp.toString ().trim ();
}
}
zdrojový kód (Java) - zobrazit (3763 znaků)
Příklad použití
Tuto neuronovou síť lze například vyzkoušet na funkci XOR.
{
// vytvořit neuronovou síť
final Network network = new Network (2, 1, 5, 1, 0.2);
// vytvořit vstupní a správné datové vektory
// (toto je funkce XOR)
double[][] in = {{0,0},{0,1},{1,0},{1,1}};
double[][] out = {{0},{1},{1},{0}};
// naučit neuronovou síť
System.out.println ("Learning...");
for (int j = 0; j < 10000; j ++)
{
for (int i = 0; i < in.length; i ++)
{
network.learn (in[i], out[i]);
}
}
System.out.println (network.toString ());
// otestovat neuronovou síť
System.out.println ("Processing...");
System.out.println (network.guess (in[0])[0]);
System.out.println (network.guess (in[1])[0]);
System.out.println (network.guess (in[2])[0]);
System.out.println (network.guess (in[3])[0]);
}
zdrojový kód (Java) - zobrazit (803 znaků)
Kohonenova síť
Kohonenova síť je speciální typ samoorganizované neuronové sítě a někdy se označuje také jako Kohonenova samoorganizující se mapa. Poprvé ji představil finský vědec Teuvo Kohonen v roce 1982. Je vhodná tam, kde je třeba stabilní klasifikátor dat, který při provozu své vlastnosti již nemění. Výsledek je však závislý na pořadí vstupů, proto je nutné jejímu učení věnovat zvýšenou pozornost.
Topologie základní varianty Kohonenovy sítě je založena na obdélníkové mřížce. V každém vrcholu mřížky je umístěn jeden neuron. Jednotlivé příčky mřížky vedoucí z neuronu určují jeho sousedy. Každý neuron i vstupní vektor si lze představit jako jeden bod v n-dimenzionálním prostoru S, kde n je délka vstupního vektoru. Každá klasifikační třída odpovídá nějakému podprostoru tohoto prostoru S.
Kohonenova síť se učí sama, bez učitele. Před učením se nejprve inicializují váhy neuronů, například na náhodná malá čísla. Při učení dostává síť na vstup množinu podnětů, které si sama utřídí a svou konfigurací začne vystihovat jejich vlastnosti. Proces učení probíhá v iteracích. V každé iteraci je na vstup každého neuronu přiveden vstupní vektor a neurony vyhodnotí svůj výstup, který je roven druhé mocnině Eukleidovské vzdálenosti vektoru vah od vektoru vstupního:

- x – vstupní vektor
- w – vektor vah
- xi – jedna složka vstupního vektoru
- wi – jedna složka vektoru vah
Neuron, pro který je tato vzdálenost nejmenší, je nazván vítězným neuronem. Vstupní vektor je poté klasifikován třídou, ve které se vítězný neuron nachází. Poté jsou upraveny váhy všech neuronů a podle následujícího vztahu:
![\bar{w}_a (t + 1) = \bar{w}_a (t) + \alpha \cdot g (a, k) \cdot [x(t) - \bar{w}_a(t)]](/application/cache/latex_8a7d7b628128fd0363ee8d9c6886c442918dc85d.png)
- a – obecný neuron
- k – vítězný neuron
- wa – vektor vah neuronu a
- alfa – koeficient adaptační funkce
- g(a,k) – funkce vzdálenosti mezi neurony a a k (např. gaussián)
- t – číslo aktuální iterace
Reference
- http://cyber.felk.cvut.cz/…eursite.html
- http://fbim.fh-regensburg.de/…/e-main.html
- http://www.learnartificialneuralnetworks.com/kohonen.html
- http://www.heatonresearch.com/…1/page2.html
- Petr Michalička: semestrální práce na předmět Artificial Intelligence
- Tomasz Wolanski: semestrální práce na předmět Artificial Intelligence
- http://www.obitko.com/…onovou-siti/
- +Software
- +Umělá inteligence
- Neuronové sítě