logo FAV
Semestrální práce KIV/PC Václav Löffelmann 2014-12-31
Osobní číslo, mail
1
Zadání Naprogramujte v ANSI C přenositelnou konzolovou aplikaci, která jako vstup obdrží soubor obsahující obrázek ručně psané číslice a soubor s váhami a topologií již natrénované dopředné neuronové sítě, na jejich základě vytvoří odpovídající neuronovou sít’ a následně provede klasifikaci obsahu zadaného obrázku. Výstupem aplikace je třída obrázku po klasifikaci. Plné znění zadání je k dispozici zde[1].
Analýza úlohy Naším úkolem je vytvořit program, který bude simulovat vzruchy umělé neuronové sítě. Množina vstupních dat je již vytvořená a síť je naučená. Nebudeme tedy vytvářet tu nejzajímavější část - učení. Pokud bychom se dostali k takovému problému v praxi, určitě by prvním krokem mělo být prozkoumání možností současného softwaru. Aneb jak jedno staré pořekadlo praví „Poslední věc, co by programátor měl dělat je programování.“, měli bychom se nejdříve kouknout po hotových řešeních. Po krátkém hledání zjistíme, že v oblasti umělých neuronových sítí již existuje mnoho projektů. Bez problémů lze najít nespočet knihoven, v libovolných jazycích [2, 3, 4, 5, 6, 7, 8, ?]. Většina z nich má svobodnou licenci a lze je tedy bezplatně využít. Jelikož se ale nenacházíme v praxi, ale ve škole, kde děláme cvičné příklady, musíme se uchýlit k vlastní implementaci. Před začátkem prací na implementaci je nanejvýš vhodné zvážit nástroje, které v projektu použijeme. Důležité je zejména vybrat vhodný programovací jazyk. Zvolit knihovny, jež nám ušetří práci. Dále pak, jestli-že se jedná o týmovou práci, vybrat nástroje pro synchronizaci a verzování zdrojových kódů, metodiku vývoje, software pro kolaboraci, databázi (nebo formu) pro ukládání znalostí. Nástroj pro verzování zdrojových kódů se hodí i při práci v jednom člověku. Zde máme na výběr z několika známých a ověřených projektů. Jako prvním bych uvedl Git[9]. Git je pokročilý verzovací systém s podporou všech funkcí, které jsou pro vývoj potřeba. Jedná se o distribuovaný systém, který používají i ty největší projekty na světě. Příkladem budiž Linuxové jádro[10]. Dalšími zástupci softwaru pro verzování jsou Mercurial[11] a SVN[12]. Jelikož s Gitem mám největší zkušenosti, rozhodl jsem se pro svojí práci použít právě Git. Vzhledem k tomu, že je vhodné mít gitový repozitář někde hostovaný - hodí se zejména pro zálohy a kolaboraci. Rozhodl jsem se využít služeb od poskytovatele GitHub Inc[13]. Tato renomovaná společnost nabízí hostování veřejně přístupných repozitářů zadarmo. Pro studenty nabízí hostování až 5 privátních repozitářů také zadarmo. Za tuto starost o studenty bych této společnosti rád poděkoval přidáním odkazu na jejich vzdělávací projekt[14].
Pokud "praxí" myslíte slepování cizích kusů kódu, pak ano. Co na něm chcete vybírat, když děláte práci z předmětu KIV/PC?
Co tohle má společného s danou prací? Naprosto obecná vata bez souvislosti se zadáním a tématem.
2
vektorově nebo aspoň pořádné rozlišení
Obrázek 0.0.1: Biologický neuron. Zdroj[18]
Výběr jazyka I přes to, že byl jazyk implementace zadaný, pojďme si situaci trochu zanalyzovat. V zadání máme jasně řečeno, že máme vytvořit jednoduchou aplikaci, která bude fungovat sama o sobě. Nejedná se tedy o žádnou knihovnu, driver ani framework. Tato podmínka sama o sobě nepřináší žádné omezení. Pojďme tedy prozkoumat další aspekt, tedy doménu problému. Tato doména se vyznačuje náročností zejména na matematické výpočty, jelikož simulujeme určité množství neuronů, resp. jejich excitací, které reprezentujeme hyperbolickým tangensem součinů všech vstupů a jejich vah. Shrnuli jsme tedy, že budeme potřebovat výkonnou aplikaci, jelikož zadání hovoří o obecném fungování řešení, tedy libovolnou velikostí sítě. Odtud můžeme předpokládat, že některé použití mají rozsáhlé sítě a velké množství neuronů. Pokud budeme uvažovat malou síť na vstupu, zajisté oceníme i ekvivalentní paměťové nároky, odpovídající malému množství vstupních dat. V předchozích odstavcích jsme z výběru diskvalifikovali jazyky s tristním výkonem, nicméně pojďme se podívat na vyšší vyspělé programovací jazyky. Reprezentanty této skupiny mohou být třeba Java, Python, Node.js. Minimálně první dva zmíněné mají velice dobrou podporu napříč operačními systémy a přenositelnost, což byl také jeden z aspektů zadání. Node.js jako poměrně nová technologie má podporu u běžných operačních systémů, jež byly v zadání vyjmenované. Co se výkonu, který pro naši úlohu požadujeme, těchto programovacích jazyků týká, dá se říci, že uspokojují naše potřeby. Java se svou HotSpot[15] optimalizací, která kompiluje kód do nativního kódu platformy má velice dobré výsledky. U Node.js máme v zásadě dvě možnosti. Buď použijeme kompilátor a interpret V8[16], který Google vyladil pro vysoký výkon, a nebo použijeme novinku z Javy verze 8 a budeme ho spouštět nad JVM a jsme na tom stejně
3 jako v případě Javy. V případě Pythonu máme také možnosti kompilace do C kódu, takže o samotný výkon máme postaráno. Vzhledem k výše uvedenému je jasné, že při výběru jazyka nemůžeme jednoduše opomenout vyšší programovací jazyky. Já osobně bych se klonil k použití vyššího programovacího jazyka, jelikož nám přináší přenositelnost nativně a další výhody, jako jsou například automatický garbage collector, vyšší úroveň abstrakce a nebo netypovost. Upřímně se domnívám, že vývoj ve vyšším programovacím jazyku, nebo dokonce ještě vyšším transkompileru, uvažujme třeba CoffeeScript[17], by byl o poznání rychlejší. Dalším zajímavým pohledem by mohl být pohled řešení úlohy ve funkcionálním programovacím jazyku. Uveďme zde čistý funkcionální jazyk, implementující lambda kalkulus - Haskell. Konkrétně tento jazyk má veliké možnosti a splnění takovéto úlohy by nebyl problém. Pokud se podíváme na řešení, která se vyskytují při řešení problematiky neuronových sítí, narazíme nutně na zpracování na grafických kartách. Výpočet na grafických kartách je vhodný zejména díky paralelnímu zpracování. Excitace jednotlivých neuronů v rámci jedné vrstvy lze totiž vypočítat současně. Jestliže zajdeme v problematice neuronových sítí ještě dál, zjistíme, že pro tuto doménu úloh se vytváří i specializovaná hardwarová řešení. Jejich použití je tedy nasnadě. Jazyk je, nicméně, daný a proto práce bude implementována v C kvůli edukačním účelům. Avšak v reálném světě by tento jazyk pravděpodobně nevyhrál.
Dekompozice problému Problém není nikterak složitý a proto můžeme při analýze problém rozebrat tak, jak půjde běh programu. Vstupem jsou dva soubory, jeden s neuronovou sítí a druhý se vstupem do této sítě. Rozeberme tedy zpracování souboru s naučenou neuronovou sítí. Soubor je potřeba naparsovat a následně reprezentovat pomocí vhodné datové struktury. Parsování je v celku jasné, jelikož se jedná o textový soubor, kde jsou jednotlivé sekce uvedeny speciálním řádkem. O trochu složitější jsou datové struktury, jenž mají vzniknout. Nechť budeme uvažovat neuronovou síť jako množinu neuronů, jakožto samostatných entit sdruženým po vrstvách. Jelikož je při výpočtu excitace neuronu z vyšší vrstvy potřeba zjistit excitace propojených neuronů z předchozí vrstvy, máme zde vcelku jasný požadavek na rychlý náhodný přístup k neuronům z určité vrstvy. Tento požadavek uspokojuje pole, hash nebo při velkých objemech dat strom. Abstrakce neuronu by měla obsahovat propojení a jejich váhy s ostatními neurony, dále pak bias a výslednou hodnotu excitace při průchodu vzruchu. Propojení neuronu se budou vždy procházet sekvenčně a vzhledem k dynamickému množství propojení se zde nabízí k použití spojový seznam. Datový typ této entity by tedy měl zapouzdřovat všechny výše zmíněné vlastnosti. Co se týká druhého souboru, tedy vstupu pro neuronovou síť, máme pro tato data stejné nároky jako na kteroukoliv jinou vrstvu - určitě budeme potřebovat
Obecné blábolení zcela mimo téma není analýzou zadaného problému. Měl jste analyzovat problémy plynoucí ze zadání a navrhnout přístupy, jak je řešit v jazyce C a bez týmové práce nebo cizích knihoven, takže netuším, proč to sem píšete. Ničím neopodstatněné a nepravdivé řeči, nejrychlejší knihovny pro ANN (pro CPU), jako je např. Eblearn nebo Caffe, používají C / C++. Nejrychlejší obecně používají CUDA, což je osekané Céčko pro GPU.
4 rychlý přístup k náhodnému vstupu. Parsování bude velice přímé, jelikož soubor obsahuje pouze užitečná binární data. Následně můžeme analyzovat vlastní algoritmus. Běh by se dal rozdělit do tří hlavních částí. První část naplní první vrstvu vstupy ze vstupní vrstvy a vypočte excitace neuronů v první vrstvě. Druhá část vezme všechny následující vrstvy (pokud nějaké jsou) a postupně, po vrstvách, vypočítává jednotlivé excitace. Poslední částí je výpočet maxima z excitací neuronů z výstupní vrstvy.
číslovat
Popis implementace Implementace se skládá z parsování vstupních souboru a následné vytváření vhodných datových struktur. Jako datovou strukturu pro reprezentaci neuronů v rámci jedné vrstvy jsem použil pole, jelikož se jednoduše implementuje a poskytuje rychlý náhodný přístup. Abstrakce nad vrstvou, struktura layer, je pouze obalem nad tímto polem neuronů, což jsou samy o sobě také struktury, které mají vlastnosti vyjmenované výše v analýze. Pro snadný přístup k vrstvám jsem použil reprezentaci jako pole vrstev. Další struktura, kterou jsem vytvořil je zapouzdření pro neuronové spojení. Toto spojení obsahuje informaci o tom, s kterým neuronem z předchozí vrstvy je vytvořené, dále pak váhu tohoto spojení a následně i odkaz na další spojení. Jedná se tedy o zřetězený seznam. Každý neuron si uchovává odkaz na začátek toho seznamu. Struktura programu je dekomponována logicky po funkcích. Program samozřejmě validuje všechny vstupy a dělá správu paměti.
Uživatelská příručka
popis modulů a funkcí, konkrétně jste nic moc nepopsal
Program má ovládání pomocí parametrů z příkazové řádky. Po spuštění již neobsahuje žádné uživatelské rozhraní. zvýraznit kde jsou konktrétní příkazy pro každý OS Překlad programu je zajištěn utilitou make. Program se spouští binárním souborem neural_net.exe. Tento příkaz očekává dva argumenty. Prvním je soubor s definicí neuronové sítě a druhý je cesta k souboru se vstupem sítě. Očekávaný formát těchto souborů je definovaný v zadání.
screenshot, podmínky překladu a spuštění
5
Závěr Závěrem bych chtěl předně poděkovat jednak za možnost výběru zadání a jednak za zajímavé téma. Problematika neuronových sítí je dle mého názoru velice zajímavá, škoda jen, že byla vynechána nejzajímavější část a to učení. Nicméně to je pochopitelné, vzhledem k tomu, že se jedná pouze o semestrální práci. S výsledným programem jsem spokojen. Doba běhu a paměťové nároky odpovídají nezbytně nutným výpočtům. Při implementaci jsem se snažil vyvarovat zbytečným iteracím nebo používáním neefektivních datových struktur. Jako možnost dalšího rozšiřování bych viděl jednoznačně v implementaci některého učícího algoritmu, jelikož klasifikace je v tomto případě pouze špička ledovce.
měření času a výkonu, testovací konfigurace, celkově velmi krátké
Literatura [1] http://www.kiv.zcu.cz/studies/predmety/pc/doc/work/sw2014-02.pdf [2] http://leenissen.dk/fann/wp/ [3] http://pybrain.org/ [4] http://opennn.cimne.com/ [5] http://neuroph.sourceforge.net/ [6] https://github.com/hannes-brt/hebel [7] http://caffe.berkeleyvision.org/ [8] http://www.intelnics.com/opennn [9] http://git-scm.com/ [10] https://git.kernel.org/cgit/ [11] http://mercurial.selenic.com/ [12] https://subversion.apache.org/ [13] https://github.com/ [14] https://education.github.com/ [15] http://www.oracle.com/technetwork/java/whitepaper-135217.html [16] https://code.google.com/p/v8/ [17] http://coffeescript.org/ [18] http://home.agh.edu.pl/~vlsi/AI/intro/
6