Program bude ovládaný pomocou terminálu a bude vykonávať tieto operácie:
Obrázky, s ktorými budeme pracovať pochádzajú z databázy MNIST. Neurónová sieť, ktorú budeme používať bola natrénovaná na tejto databáze a má úspešnosť rozpoznávania približne 90 %. MNIST je rozsiahla zbierka obrázkov rukou písaných číslic. Obsahuje číslice 0-9. Jedná sa o rozsiahlu databázu: 60 000 trénovacích obrázkov a 10 000 testovacích obrázkov.
Rozmer každého obrázku je 28 x 28 pixelov. Každý obrázok je reprezentovaný odtieňmi šedej farby (tzv. grayscale), t.j. pixely sú v rozsahu $\langle0,255\rangle$.
Obrázok budeme v zadaní reprezentovať pomocou 1D poľa (prepísané pixely po riadkoch zľava doprava).
Obrázky sú uložené v TXT súboroch a načítajú sa do poľa pomocou presmerovania štandardného vstupu (stdin
).
Hodnoty pixelov obrázku sú normalizované z pôvodného rozsahu $\langle0,255\rangle$ do rozsahu
$\langle0,1\rangle$ (je to vhodnejšia
reprezentácia pre NS).
Na zjednodušenie testovania budeme mať v tomto zadaní obrázky (resp. ich pixely) uložené v TXT súboroch a následne pomocou presmerovania štandardného vstupu v termináli ich vieme jednoducho načítať. Obrázok je v TXT súbore reprezentovaný ako 1 riadok s postupnosťou hodnôt pixelov oddelených 1 medzerou. Spolu má obrázok 784 pixelov.
Na rozpoznávanie obrázkov budeme používať 1-vrstvovú neurónovú sieť. Táto vrstva bude obsahovať 10 neurónov (keďže klasifikujeme 10 rôznych druhov číslic). Vstupom do siete bude obrázok (1D pole pixelov) a výstupom bude určenie triedy (resp. menovka), do ktorej obrázok patrí, t.j. číslo 0 až 9. Všetky neuróny budú využívať aktivačnú funkciu ReLU.
Kompletná architektúra siete, s ktorou budeme v zadaní pracovať je znázornená na obrázku 5. Vstupný obrázok s rozmermi 28x28 je reprezentovaný 1D poľom, ktoré má 784 hodnôt pixelov (červené štvorce na obrázku). Sieť obsahuje 10 neurónov (modré kruhy na obrázku). Každý neurón je zodpovedný za klasifikáciu príslušného typu číslice. Do každého neurónu vstupujú všetky pixely obrázku, t.j. vytvoríme tak plne prepojenú sieť. Každý neurón si na základe svojich vstupov vypočíta výstupnú hodnotu, tzv. aktiváciu.
Keď získame všetkých 10 aktivácií (pole 10 hodnôt), tak ich následne pošleme do funkcie Softmax. Funkcia Softmax určí pravdepodobnosti klasifikácie jednotlivých typov číslic, t.j. vráti 10-prvkové pole, ktorého hodnoty predstavujú pravdepodobnosti. Prvok s indexom 0 v tomto poli predstavuje pravdepodobnosť, že sieť klasifikuje vstupný obrázok ako 0. Rovnaký princíp platí pre ostatné čísla v poli pravdepodobností. Výstup funkcie Softmax ďalej pošleme do funkcie Findmax, ktorá v 10-prvkovom poli nájde index maxima. Tento index určí typ číslice, ktorá je klasifikovaná s najvyššou pravdepodobnosťou. Tento index zároveň prehlásime za výsledok klasifikácie číslice.
Neurón je základným stavebným prvkom neurónovej siete. Jeho úlohou je spracovať vstupné signály, výsledok spracovania poslať do svojej aktivačnej funkcie. Výstup z aktivačnej funkcie je konečným výstupom neurónu. Do každého neurónu vstupuje v našom prípade spolu 785 hodnôt = 784 hodnôt pixelov obrázku + 1 bias hodnota. Bias hodnota je špeciálna konštanta každého neurónu (každý neurón má práve 1 bias hodnotu), ktorá pomáha sieti lepšie predpovedať výsledky.
Každý pixel obrázku vstupujúci do neurónu je vynásobený svojou váhou. Každý neurón má svoje vlastné váhy. Vedomosti našej natrénovanej neurónovej siete sú uložené práve vo váhach a bias hodnotách. Keď poznáme hodnoty všetkých pixelov obrázku, všetky váhy neurónu a jeho bias hodnotu, vypočítame tzv. vážený súčet. Vážený súčet je vizualizovaný na obrázku 6.
Výsledok váženého súčtu pošleme na vstup ReLU aktivačnej funkcie. ReLU funkcia je definovaná predpisom:
$ f(x) = \begin{cases} 0 & \text{if }x \leq 0 \\ x & \text{if }x > 0 \end{cases}\ $
Na obrázku 7 vidíme kompletnú schému činnosti neurónu.
Váhy a bias hodnoty sú uložené v 1D poliach v dodanom zdrojovom súbore data.c
.
Váhy sú uložené v poli s názvom weights
a bias hodnoty sú v poli s názvom
bias
.
Počet váh je 784 x 10 = 7840 (pre každý neurón 784 váh). Počet bias hodnôt je 10 (pre každý neurón jedna).
Na obrázku 8 vidíme spôsob, akým treba sprístupňovať váhy zvoleného neurónu. V poli weights
majú jednotlivé neuróny svoje váhy uložené za sebou. Prvých 784 hodnôt poľa tak predstavuje váhy neurónu s
indexom 0, ďalších 784 hodnôt predstavuje váhy neurónu s indexom 1 a pod.
weights
.
Funkcia Softmax slúži na výpočet pravdepodobnosti klasifikácie pre každý typ číslice. Máme 10 neurónov. Každý neurón si vypočíta svoju aktiváciu (t.j. výstup z aktivačnej funkcie). Získame tak pole 10 hodnôt (na obrázku 9 je označené ako z). Toto pole odovzdáme do funkcie Softmax. Tá každému prvku v poli vypočíta jeho pravdepodobnosť klasifikácie, t.j. vytvorí nové výstupné pole. Matematický predpis funkcie Softmax pre $i$-ty prvok z poľa z je uvedený nad obrázkom 9.
$softmax(\textbf{z})_{i} = \dfrac{e^{(z_{i} - max(\textbf{z}))}}{\sum_{j=0}^{K}e^{(z_{j} - max(\textbf{z}))}}$
kde $max(\textbf{z})$ je hodnota najväčšieho prvku z poľa z a $K=9$ je index posledného neurónu.
V tomto zadaní budete pracovať s projektom, ktorý sa skladá z 5 súborov:
data.h
functions.h
data.c
functions.c
z2.c
Nasleduje krátky popis jednotlivých súborov.
Hlavičkové súbory
data.h
- Obsahuje potrebné makrá a deklarácie polí pre váhy a bias
hodnoty.
functions.h
- Obsahuje deklarácie pomocných funkcií:
Zdrojové súbory
data.c
- Obsahuje definície polí pre váhy a bias hodnotyfunctions.c
- Obsahuje definície funkcií, ktoré sú zadeklarované v data.h
z2.c
- Hlavný súbor zadania, do ktorého sú vložené všetky potrebné
hlavičkové súbory. Tento súbor po vypracovaní ako
jediný odovzdávate
Projektový konfiguračný súbor CMakeLists.txt
pre CLion
Spolu s projektovými súbormi máte k dispozícii hlavný konfiguračný súbor CLion projektu, ktorý je správne
nastavený a netreba ho meniť. V prípade, že nemáte nainštalovanú verziu programu CMake 3.27 a vyššiu, prepíšte
číslo verzie na vyhovujúcu
hodnotu. Po spustení CLion-u si otvorte projekt kliknutím na tlačidlo Open File or Project a zvoľte si koreňový
adresár projektu (t.j. adresár, v ktorom je uložený
súbor CMakeLists.txt
). CLion projekt automaticky rozpozná. Projekt
skompilujte. Ak všetko prebehne bez chýb, môžete pracovať na zadaní.
cmake_minimum_required(VERSION 3.27)
project(z2 C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -lm")
add_executable(z2 src/functions.c src/data.c src/z2.c)
target_include_directories(z2 PRIVATE ${PROJECT_SOURCE_DIR}/include)
CMakeLists.txt
.Správne vloženie hlavičkových súborov do z2.c
Zadanie je nutné implementovať v súbore z2.c
. Ostatné súbory projektu sa
nesmú upravovať.
Do súboru z2.c
je potrebné vložiť hlavičkové súbory data.h
a
functions.h
tak, aby bol uvedený len názov súborov, t.j. cesta sa nesmie
uvádzať (viď Obrázok 10).
Budeme rozlišovať 7 režimov činnosti. Aplikácia sa rozhodne, do ktorého režimu vstúpi po načítaní prvej číselnej hodnoty zo štandardného vstupu. Platné sú len čísla 1-7. Ostatné hodnoty sa budú ignorovať.
Režim 1 - Výpis váh pre zvolený neurón
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 1 (vstup do režimu 1). Nasleduje aspoň 1 biely
znak (medzera alebo nový riadok). Potom používateľ zadá
index neurónu (platné sú čísla 0-9), pre ktorý chce vypísať váhy. Následne sa vypíšu váhy daného neurónu. Treba
rešpektovať pravidlá výpisu: váhy sa vypíšu po riadkoch, v každom riadku sa vypíše 10 váh s presnosťou 2
desatinných miest (použite funkciu printf
). Váhy musia byť oddelené aspoň 1
medzerou. Okrem váh sa nič iné nevypíše.
Režim 2 - Výpis váženého súčtu pre zvolený neurón a načítaný obrázok
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 2 (vstup do režimu 2). Nasleduje aspoň 1 biely
znak (medzera alebo nový riadok). Potom používateľ zadá
index neurónu (platné sú čísla 0-9), pre ktorý chce vypočítať vážený súčet. Nasleduje aspoň 1 biely znak
(medzera alebo nový riadok). Potom používateľ zadá obrázok. Obrázok sa zadáva vo forme postupnosti pixelov
oddelených 1 medzerou. Obrázok musí
obsahovať 784 pixelov. Po zadaní obrázku prebehne výpočet a vypíše sa hodnota vypočítaného váženého súčtu. Treba
rešpektovať pravidlá výpisu: výsledok sa vypíše s presnosťou 2
desatinných miest (použite funkciu printf
). Okrem váženého súčtu sa nič iné
nevypíše.
<
spustíme program s presmerovaným štandardným vstupom zo súboru mode2.txt
.
Režim 3 - Výpis hodnoty aktivačnej funkcie
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 3 (vstup do režimu 3). Nasleduje aspoň 1 biely
znak (medzera alebo nový riadok). Potom používateľ zadá
vstupnú hodnotu pre funkciu ReLU. Následne prebehne výpočet a vypíše sa výsledok funkcie ReLU. Treba rešpektovať
pravidlá výpisu: výsledok sa vypíše s presnosťou 2
desatinných miest (použite funkciu printf
). Žiadny iný výpis sa neuskutoční.
Režim 4 - Výpis vypočítaných hodnôt funkcie Softmax
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 4 (vstup do režimu 4). Nasleduje aspoň 1 biely
znak (medzera alebo nový riadok). Potom používateľ zadá
postupnosť 10 hodnôt (ľubovoľné desatinné čísla). Tieto hodnoty treba načítať do poľa. Pole sa následne pošle do
funkcie Softmax a vypíše sa výsledok. Výsledkom je znova pole s 10 číslami, ktoré predstavujú pravdepodobnosti.
Treba rešpektovať pravidlá výpisu: výsledné pole sa vypíše tak, že jeho prvky budú oddelené 1 medzerou a každé
číslo sa zobrazí s presnosťou 2 desatinných miest (použite funkciu printf
).
Žiadny iný výpis sa neuskutoční.
Režim 5 - Výpis indexu najväčšieho prvku v poli (Findmax)
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 5 (vstup do režimu 5). Nasleduje aspoň 1 biely znak (medzera alebo nový riadok). Potom používateľ zadá postupnosť 10 hodnôt (ľubovoľné desatinné čísla). Tieto hodnoty treba načítať do poľa. Pole sa následne pošle do funkcie Findmax a vypíše sa index najväčšieho prvku v poli. Ak má pole viacero rovnakých najväčších prvkov, vypíše sa index, ktorý je najbližšie k hodnote 0. Žiadny iný výpis sa neuskutoční.
Režim 6 - Výpis načítaného obrázku číslice
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 6 (vstup do režimu 6). Nasleduje aspoň 1 biely
znak (medzera alebo nový riadok). Potom používateľ zadá
obrázok. Obrázok sa zadáva vo forme postupnosti pixelov oddelených 1 medzerou. Obrázok musí obsahovať 784
pixelov.
Následne sa vypíše načítaný obrázok. Na výpis je nutné použiť dodanú funkciu print_image
,
ktorá je deklarovaná v hlavičkovom súbore
functions.h
. Žiadny iný výpis sa neuskutoční.
<
spustíme program s presmerovaným štandardným vstupom zo súboru mode6.txt
.
Režim 7 - Výpis výsledku klasifikácie načítaného obrázku číslice
Spustíme skompilovaný program v termináli. Používateľ zadá číslo 7 (vstup do režimu 7). Nasleduje aspoň 1 biely znak (medzera alebo nový riadok). Potom používateľ zadá obrázok. Obrázok sa zadáva vo forme postupnosti pixelov oddelených 1 medzerou. Obrázok musí obsahovať 784 pixelov. Následne sa načítaný obrázok klasifikuje a vypíše sa jeho menovka (číslo 0-9). Žiadny iný výpis sa neuskutoční.
<
spustíme program s presmerovaným štandardným vstupom zo súboru mode7.txt
.
V tomto zadaní je potrebné načítavať obrázky zo štandardného vstupu. Existujú teda 2 možnosti ako obrázok načítať: zadaním 784 pixelov ručne na klávesnici (resp. CTRL+C, CTRL+V) a druhá možnosť je spustiť program s presmerovaným štandardným vstupom z TXT súboru. Z programátorského hľadiska sú obidve možnosti totožné.
Na načítanie obrázku (všetkých 784 pixelov) použite dodanú funkciu load_data
,
ktorá je deklarovaná v hlavičkovom súbore functions.h
.
Spolu s CLion projektom máte k dispozícii priečinok s testovacími súbormi (treba rozbaliť ZIP súbor). V tomto priečinku nájdete:
digits-img
, ktorý obsahuje obrázky číslic v PNG formáte na
experimentálne účely.
digits-txt
, ktorý obsahuje obrázky číslic reprezentované
pomocou TXT súborov (sú v nich hodnoty pixelov). Tieto súbory využijete v prípade, že si chcete testovať
režim 2, 6 a 7, kde je jedným zo vstupov obrázok.
python_scripts
, ktorý obsahuje pomocné experimentálne Python
skripty:
img2txt.py
na konverziu obrázku číslice do TXT súboru (očakáva
sa, že vstupný obrázok má rozmer 28x28 a jeho farebný režim je grayscale)
txt2img.py
na konverziu obrázku v TXT podobe do obrazovej podoby
(očakáva sa, že v TXT súbore bude 784 hodnôt pixelov v rozsahu $\langle0,1\rangle$)
stdin
, ktorý obsahuje testovacie príklady pre jednotlivé
režimy činnosti.
Ak si chceme napríklad otestovať režim 7 (klasifikácia obrázku), treba ísť do priečinku stdin
.
V ňom nájdeme podpriečinok mode07
. Tu sa nachádza viacero TXT súborov, ktoré
predstavujú testovacie vstupy do programu.
Program môžeme spustiť napr. nasledovne:
./z2 < example_8_2.txt
V tomto prípade si otestujeme klasifikáciu obrázku, na ktorom je číslica 8.
V programe netreba ošetrovať vstupy ani žiadne iné chybové situácie. Váš odovzdaný program bude automatizovane testovaný len s platnými a zmysluplnými vstupmi.
Odovzdávací systém otestuje a ohodnotí nasledovné oblasti funkcionality vášho programu. Na získanie bodov za konkrétny testovací scenár je nutné, aby testom prešli všetky testovacie prípady v danom scenári.
Scenár 1
Režim 1 - výpis váh
|
1,0 b |
Scenár 2
Režim 2 - výpis váženého súčtu
|
2,0 b |
Scenár 3
Režim 3 - výpis hodnoty ReLU funkcie
|
0,5 b |
Scenár 4
Režim 4 - výpis hodnôt funkcie Softmax
|
1,5 b |
Scenár 5
Režim 5 - výpis výsledku funkcie Findmax
|
0,5 b |
Scenár 6
Režim 6 - výpis načítaného obrázku
|
0,5 b |
Scenár 7
Režim 7 - výpis výsledku klasifikácie načítaného obrázku
|
4,0 b |
Súčet | 10 b |
Táto sekcia obsahuje správne očakávané hodnoty testovacích príkladov pre jednotlivé scenáre.
Vstupy pre jednotlivé testovacie príklady sa nachádzajú v priečinku stdin
,
ktorý je súčasťou testovacieho balíka súborov,
ktorý si môžete stiahnuť.
Poznámka: ideálny spôsob testovania vášho programu je prostredníctvom presmerovania štandardného vstupu v termináli z príslušného TXT súboru, ktorý obsahuje vstupy (aby ste sa tak vyhli komplikáciám pri kopírovaní údajov a ich zadávaní pomocou klávesnice).
Zoznam testovacích scenárov:
mode01
mode02
mode03
mode04
mode05
mode06
mode07
Nasledujúce zdroje vám môžu pomôcť pri programovaní zadania. Odporúčame si tieto zdroje preštudovať. Na prístup k niektorým zdrojom potrebujete byť prihlásení vo vašom Google STU konte.
Prednášky
Jazyk C
Funkcie printf
a scanf
Zdroje použité pri tvorbe zadania a prezentácie