\chapter{Úvod}
Městská hromadná doprava je efektivním způsobem přepravy lidí. Tramvaje specificky přináší řadu výhod oproti autobusu a trolejbusu, jako například větší kapacitu, větší bezpečnost cestujících, anebo možnost rychlé reakce na dopravní situaci přidáváním a odebíráním vozů soupravě. Navzdory těmto a dalším výhodám, nachází se v~jejich využití prostor pro automatizaci. Tou je například detekce obsazenosti jednotlivých kolejí v depu nebo detekce chybné pozice tramvaje. Jedním ze způsobů získání pozice tramvaje alespoň pro kontext lokálního prostoru je využití videokamery. Na automatické zpracovaní pro tento účel pořízených snímků je aplikovatelná řada postupů, z~nichž předmětem této práce je řešení konvolučními neuronovými sítěmi.

  Cílem této práce je rozšiřitelný základ automatizace založené na detekci tramvají ve videu. Takového rozšíření bude dosažitelné jak úpravou zdrojového kódu vzniklého programu, tak napojením programů nových na jeho výstup. V~kapitole~\ref{chap:soucasny-stav} je popsána funkce a operace konvolučních neuronových sítí, v~kapitole~\ref{chap:navrh} specifikace a návrh cílového programu a v~kapitole~\ref{chap:implementace} jeho implementace a výsledky testů. 


\chapter{Konvoluční neuronové sítě}\label{chap:soucasny-stav}
Některé z~problémů, které jsou žádoucí, aby se daly vyřešit počítačem, by se klasickým algoritmickým způsobem řešily velmi těžce. Příkladem jsou problémy popsané v~\cite{neural-applications}, jako například:
\begin{itemize}
	\item Nachází se v~daném obrázku osoba, jíž hledám?
	\item Jak se daná akcie zachová v~budoucnosti?
	\item Patří opravdu tento podpis osobě, která je podepsaná?
\end{itemize}
Alternativním přístupem k~jejich řešení je využití strojového učení.
\section{Strojové učení}
Strojovým učením se pro účely této práce rozumí soubor metod a algoritmů určených k~využití existujících dat k~předpovědi nových informací. Jeho výstupem je funkce $f(x)$ jejíž výsledkem je $y$, kde $x$ je jednotka dat a $y$ je jim přiřazená odpověď. $y$ může být cokoliv jako například klasifikace do skupin, nově vygenerovaná data a podobně. Zatímco klasickým způsobem by byla nejprve vytvořena funkce a ta až pak aplikovaná na data, zde je započato s~množinou dat $x$ a jim odpovídající množinou $y$ a hledaná funkce je vytvořená automaticky. Tomuto procesu se říká \textit{trénování}. Data jsou typicky před započetím trénování rozdělena na nejméně dvě disjunktní podmnožiny, z~nich jedna se stane datovou sadou \textit{trénovací} a druhá datovou sadou \textit{testovací}.~\cite{pattern}

Nejpřímočařejším způsobem, jak dosáhnout strojového učení, je vypočítat z~trénovacích dat polynom tato data přesně protínající. To je ale velmi vzácně dostačující řešení. Například pokud mají $x$ a $y$ lineární vztah ale data jsou naměřená s~drobnými nepřesnostmi, vznikne polynom zcela odtržený od reality, jak je vidět na obrázku~\ref{fig:interpolate}. V~takovém případě je lepší využít \textit{lineární regrese}. Lineární regrese je akt přiřazení přímky souboru bodů v~grafu. Jedním ze způsobů, jak tohohle dosáhnout je využití metody nejmenších čtverců. Tato metoda měří příslušnost dané přímky danému souboru bodů součtem druhých mocnin vzdáleností všech bodů od přímky. Pro přímku podle $f(x) = mx + n$ jsou hledanými hodnotami $m$ a $n$. Položením částečných derivací výpočtu ,,ceny'' nejmenšími čtverci vzhledem k~těmto hodnotám nule vznikne soustava rovnic, jejíž vyřešením získáme nejoptimálnější přímku. Na obrázku~\ref{fig:interpolate} je porovnán příklad souboru bodů proložen přesným polynomem a přímkou získanou metodou nejmenších čtverců spolu s~předpovědí odpovídající novému $x_i$. Metodu lze zobecnit i pro křivky různých tvarů, jako například v~případě polynomiální regrese. Relevantními termíny jsou zde \textit{bias} a \textit{variace}, kde bias označuje přesnost řešení pro vzorová data a variace označuje rozdíl přesnosti řešení pro zdrojová data s~přesností pro data dosud neviděná. Na příkladu~\ref{fig:interpolate} je vidět že ačkoliv má první řešení nulový bias, má velmi vysokou variaci, zatímco druhé řešení má relativně nízký bias a variaci.~\cite{pattern} 




\begin{figure}
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/polynom.pdf}
    \caption{Interpolace přesným polynomem.}
    \label{fig:polynom}
  \end{subfigure}  
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/least_squares.pdf}
    \caption{Metoda nejmenších čtverců.}
    \label{fig:least_squares}
  \end{subfigure}  
  \caption{Ilustrace různých metod interpolace stejných dat. Zelený bod je bod odhadnutý danou metodou. I~bez znalosti přesného původu dat je zřejmé, že jedna z~těchto metod je pro účely strojového učení značně užitečnější.}
    \label{fig:interpolate}
\end{figure}



\section{Neuronové sítě}
  Jedná se o~model inspirovaný reálnými neurony. Neuron má množinu vstupů $x_{1}, x_{2}, x_{3}, \dots$, které nabývají hodnot z~intervalu <0, 1>. S~těmi provede matematickou operaci (např. výběr maxima, vypočtení průměru apod.) a její výsledek pošle dál jako svůj výstup, jak je ilustrováno na obrázku~\ref{fig:neuron-basic}.
\begin{figure}
  \centering
  \includegraphics[width=15em]{obrazky/net-simple.pdf}
  \caption{Neuron}
  \label{fig:neuron-basic}
\end{figure}
Častou operací, kterou neuron se vstupy provádí, je následující: každý neuron má jeden bias $b$ a pro každý vstup $x_{1}, x_{2}, x_{3}, \dots$ váhy $w_{1}, w_{2}, w_{3}, \dots$ příslušně. Výstup je vypočten podle $\sigma(\sum_{j}w_{j}x_{j} + b)$, kde $\sigma$ je nelineární funkce, jako například sigmoidní funkce~\ref{eq:sigmoid}. V~této práci je to použitá operace všude, kde není uvedeno jinak.~\cite{neuron}
\begin{equation} \label{eq:sigmoid}
  \sigma(z) = \frac{1}{1+e^{-z}} 
\end{equation}
Jiné nelineární funkce jako například tanh, softplus nebo ReLU mohou a bývají použity. Účelem využití nelinearity je získání schopnosti modelovat nelineární vztahy --- skládáním lineárních funkcí je možné získat pouze funkce, které jsou taktéž lineární.~\cite{understanding, basiccnn} 

Uspořádáním takových neuronů do \textit{vrstev} a následném propojením těchto vrstev tak, že výstupy jedné vrstvy jsou vstupy vrstvy další (obrázek~\ref{fig:neuron-network}), vznikne neuronová síť. Na všech výstupech daného neuronu je stejná hodnota. První vrstvě se říká vrstva \textit{vstupní} a poslední vrstva \textit{výstupní}. Ostatní se nazývají vrstvami \textit{skrytými}. Konvencí je vstupní vrstvu do celkového počtu vrstev nezapočítávat. Síť na obrázku~\ref{fig:neuron-network} by tudíž měla svůj počet vrstev udán jako $2$. Účelem vstupní vrstvy je modelace vstupů simulací každé vstupní hodnoty jako neuronu. Dále se vrstvy rozdělují na \textit{plně propojené} a ostatní. Vrstva plně propojená je taková vrstva, jejíž každý neuron je propojený s~každým neuronem v~předchozí a následující vrstvě. Neuronové sítě určeně pro rozpoznávání a klasifikaci obrazových dat se typicky na obrázek ,,dívají'' vstupní vrstvou uvažováním každého pixelu jako jedné vstupní hodnoty. Vícedimenzionální pole hodnot je tudíž efektivně zpracováváno jako jednodimenzionální.~\cite{neuron}
\begin{figure}
  \centering
  \includegraphics[width=25em]{obrazky/net-fully-connected.pdf}
  \caption{Plně propojená neuronová síť}
  \label{fig:neuron-network}
\end{figure}
Pro zjednodušení se často používá vektorová notace. Vektor vstupů do sítě bývá označován jako $x$ a má tolik dimenzí, kolik má síť vstupů - každému vstupu náleží jeden prvek vektoru. Nápodobně správné výstupy se shlukují do vektoru označovaném jako $y = y(x)$ pro daný vektor $x$. 

Pro kvantifikaci kvality sítě je vhodné nadefinovat \textit{ztrátovou funkci} $C$, jako například kvadratickou cenu (rovnice~\ref{eq:kvadraticka-cena}),
\begin{equation} \label{eq:kvadraticka-cena}
  C(w, b) \equiv \frac{1}{2n}\sum_x \parallel y(x) - a \parallel^2
\end{equation}
kde $\parallel$ je operace délky vektoru a $a$ je vektor výsledků výstupní vrstvy. Pro optimálnější neuronovou síť bude mít pro daná data ztrátová funkce menší hodnotu. Sítě jsou optimalizovány snižováním hodnoty ztrátové funkce upravováním specifických hodnot parametrů jako například vah a biasů. Parametrům, jež nejsou optimalizovány zmenšováním ceny (jako například počet vrstev nebo volba nelinearity), se říká \textit{hyperparametry}.~\cite{neuron}


\subsection{Stochastický gradientní sestup}
\textit{Gradientní sestup} je metoda umožňující numerického nalezení jednoho z~lokálních minim některých funkcí. Pro funkci $f(x_1, x_2, \dots, x_n)$ a n-dimenzionální vektor $x$ symbolizující bod počátku metody existuje n-dimenzionální vektor $z$ určující směr nejstrmějšího klesání, pokud je funkce $f$ v~bode $x$ diferencovatelná. Individuální prvky vektoru $z$ jsou dány rovnicí~\ref{eq:gradient-z}:
\begin{equation} \label{eq:gradient-z}
	z_i = - \lambda \frac{\partial f}{\partial x_i}
\end{equation}
Kde $\lambda$ je pozitivní konstanta určující rychlost sestupu. Vektoru $(\frac{\partial f}{\partial x_0}, \frac{\partial f}{\partial x_1}, \dots, \frac{\partial f}{\partial x_n})$ se často říká \textit{gradient} funkce $f$, značen jako $\nabla f$. Rovnice~\ref{eq:gradient-z} může tudíž být přepsána jako $z = -\lambda \nabla f$. Opakovanou aktualizací vektoru $x$ podle rovnice~\ref{eq:gradient_general} dojde k~postupnému posunu směrem k~lokálnímu minimu.~\cite{curry1944method} 
\begin{equation} \label{eq:gradient_general}
  x_{k+1} = x_k - \lambda \nabla f_k
\end{equation}
 

Pro neuronovou síť s~váhami $w$ a biasy $b$, vektorem cvičných vstupů $x$ s~náležitým vektorem výstupů $y$ a ztrátovou funkcí $C(w, b)$ by gradientní sestup probíhal opakováním následujících kroků:
\begin{itemize}
	\item vypočtením ztráty všech cvičných vstupů 
	\item vypočtením všech částečných derivací $\frac{\partial C}{\partial w_i}$ a $\frac{\partial C}{\partial b_i}$
	\item upravením vah a biasů podle rovnic~\ref{eq:weight_gradient} a~\ref{eq:bias_gradient}
\end{itemize}
\begin{equation} \label{eq:weight_gradient}
  w_{k+1} = w_k - \lambda \frac{\partial C}{\partial w_k}
\end{equation}

\begin{equation} \label{eq:bias_gradient}
  b_{k+1} = b_k - \lambda \frac{\partial C}{\partial b_k}
\end{equation}
Postup je opakován, dokud nedojde ke splnění předem určené podmínky, jako například velikost rozdílu mezi optimalizovanými proměnnými jednotlivých iterací. Náročnost výpočtu $\frac{\partial C}{\partial w}$ a $\frac{\partial C}{\partial b}$ se s~počtem vstupů $x_j$ (kde $j$ je index specifického cvičného vstupu) však zvedá velmi rychle. Může být efektivnější využít alternativní verze gradientního sestupu, a to \textit{gradientní sestup stochastický}. Místo výpočtu částečné derivace $\frac{\partial C}{\partial w}$ a $\frac{\partial C}{\partial b}$ vzhledem ke všem cvičným vstupům najednou, cvičné vstupy jsou rozděleny do várek a gradientní sestup je aplikován na ně jednu po druhé. Ačkoliv jednotlivé gradienty neodpovídají přesně gradientu skutečnému, jejich spojením vznikne vlivem zákonů pravděpodobnosti gradient ukazující přibližně správným směrem.~\cite{amari1993backpropagation, neuron}

Pro zjednodušení analytického výpočtu $\frac{\partial C}{\partial w}$ a $\frac{\partial C}{\partial b}$ je vhodné využít takzvaného \textit{výpočetního grafu} společně s~\textit{algoritmem zpětného šíření chyby}. Výpočetní graf je způsob reprezentace matematické funkce, kde uzly reprezentují jednoduché operace a hrany reprezentují proměnné, jež do operace vstupují. Například graf funkce $f(x, y) = x + y$ by vypadal jako na obrázku~\ref{fig:comp-graph-simple}. Graf jednoduché neuronové sítě s~jednou skrytou vrstvou, kde se v~každé vrstvě nachází pouze jeden neuron, aktivační funkcí zvolenou ReLU a kvadratickou cenou by vypadal jako na obrázku~\ref{fig:comp-graph-net}. 
\begin{figure}
  \centering
  \includegraphics[width=\linewidth/5]{obrazky/comp-graph-simple.pdf}
  \caption{Jednoduchý výpočetní graf znázorňující výpočet $f(x, y) = x + y$. Uzel symbolizuje operaci $+$ zatímco jeho dvě hrany symbolizují proměnné $x$ a $y$.}
  \label{fig:comp-graph-simple}
\end{figure}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/comp-graph-net.pdf}
  \caption{Výpočetní graf znázorňující výpočet části ceny neuronové sítě s~jednou skrytou vrstvou, kde se v~každé vrstvě nachází jeden neuron.}
  \label{fig:comp-graph-net}
\end{figure}
Místo celého výpočtu je znázorněna jenom jeho část pro jeden vstup $x_j$, jejíž výsledkem je část ceny $C_j$. Pokud pro zvolenou cenu platí rovnice~\ref{eq:c-addition} (což pro kvadratickou cenu platí),
\begin{equation} \label{eq:c-addition}
\sum_{j} \nabla C_j = \nabla C
\end{equation}
algoritmus zpětného šíření chyby je možné provádět pro každý cviční vstup $x_j$ zvlášť a jednotlivé přírůstky pak sečíst. Vstupem uzlu jednoduché operace může být také vektor nebo matice, jako na obrázku~\ref{fig:comp-graph-net-backprop}, kde je znázorněna podobná síť jako výše uvedená s~rozdílem, že místo jednoho neuronu se v~každé vrstvě nachází neurony tři, společně s~postupem algoritmu zpětného šíření chyby. Tento algoritmus nejprve vypočte dopředným směrem část ceny $C_j$ pro daný vstup $x_j$ a poté za pomocí řetězového pravidla (rovnice~\ref{eq:chain-rule}) zpětně jednu po druhé všechny částečné derivace.
\begin{equation} \label{eq:chain-rule}
\frac{\partial f(g(x))}{\partial x} = \frac{\partial z}{\partial x} \frac{\partial f(z)}{\partial z}
\end{equation}
   V~uvedeném přikladu jsou specificky zajímavými $\frac{\partial C_j}{\partial w_1}$, $\frac{\partial C_j}{\partial w_2}$, $\frac{\partial C_j}{\partial b_1}$ a $\frac{\partial C_j}{\partial b_2}$, jelikož společně tvoří $\nabla C_j$.~\cite{neuron}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/comp-graph-net-backprop.pdf}
  \caption{Výpočetní graf znázorňující výpočet části ceny neuronové sítě s~jednou skrytou vrstvou, kde se v~každé vrstvě nachází tři neurony, spolu s~relevantními částečnými derivacemi. Šipky ukazují směr postupu algoritmu zpětného šíření chyby.}
  \label{fig:comp-graph-net-backprop}
\end{figure}



Pro některé tvary funkcí nemusí být čistý stochastický gradientní sestup tím nejefektivnějším způsobem nalezení lokálního minima. Příkladem je ilustrace na obrázku~\ref{fig:descent-zigzag}, kde je znázorněna kontura funkce spolu s~možným optimálním sestupem a sestupem typickým pro tento algoritmus. Jelikož stochastický gradientní sestup stráví velké množství času pohybem jiným než nejoptimálnějším směrem, nachází se zde prostor pro zlepšení. Jedním ze způsobů, jak toho dosáhnout, je do rovnice~\ref{eq:gradient_general} přidat tzv. \textit{momentum} člen jak je vidět v~rovnici~\ref{eq:gradient_general_momentum},  
\begin{equation} \label{eq:gradient_general_momentum}
  \begin{split}
  x_{k+1} = x_k - \lambda V_k \\
  V_k = \nabla f_k + \beta V_{k-1}  
  \end{split}
\end{equation}
kde $\beta$ je konstanta z~intervalu <0,1) určující význam momenta v~sestupu. Z~rovnice~\ref{eq:gradient_general_momentum} vyplývá $V_k = \beta^{k-1} \nabla f_1 + \beta^{k-2} \nabla f_2 + \dots + \beta \nabla f_{k-1} + \nabla f_k$. Algoritmus si tudíž pamatuje každé využité $\nabla f$, ale jelikož $\beta$ je konstanta z~intervalu <0,1), vliv každého $\nabla f$ na výsledný přírůstek exponenciálně klesá s~každou iterací. Momentum člen přidá do algoritmu jistou setrvačnost, ,,uhlazující'' cestu, jež algoritmus využije k~dosažení lokálního minima, jak je ilustrováno na obrázku~\ref{fig:descent-momentum}. Pro neuronovou síť, kde optimalizovanými parametry jsou váhy a biasy jednotlivých neuronů, jsou rovnice~\ref{eq:weight_gradient} a~\ref{eq:bias_gradient} upraveny na~\ref{eq:weight_gradient_momentum} a~\ref{eq:bias_gradient_momentum} příslušně.~\cite{momentum}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/descent-zigzag.pdf}
  \caption{Kontura funkce a proces optimalizace neuronové sítě skládající se z~jedné vrstvy o~jednom neuronu. Červenou barvou je znázorněn možný obyčejný stochastický sestup a modrou možné optimálnější nalezení minima.}
  \label{fig:descent-zigzag}
\end{figure}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/descent-momentum.pdf}
  \caption{Kontura z~obrázku~\ref{fig:descent-zigzag} s~prvními kroky algoritmu stochastického gradientního sestupu s~momentem. Přerušovanou čarou je vyznačen druhý krok bez momenta a modrou je vyznačen druhý krok s~momentem. Tato modifikace nemění velikost ani směr kroku, pouze místo, odkud je proveden.} 
  \label{fig:descent-momentum}
\end{figure}
\begin{equation} \label{eq:weight_gradient_momentum}
  \begin{split}
  w_{k+1} = w_k - \lambda V_k^w \\
  V_k^w = \frac{\partial C}{\partial w_k} + \beta V_{k-1}^w
  \end{split}
\end{equation}
\begin{equation} \label{eq:bias_gradient_momentum}
  \begin{split}
  b_{k+1} = b_k - \lambda V_k^b \\
  V_k^b = \frac{\partial C}{\partial b_k} + \beta V_{k-1}^b
  \end{split}
\end{equation}
Alternativou k~momentu je \textit{RMSprop} (z~anglického \textit{root mean squared propagation}). RMSprop vznikne vydělením $\nabla f_k$ variantou kvadratického průměru všech předchozích $\nabla f$, jak je vidět v~rovnici~\ref{eq:RMSprop},
\begin{equation} \label{eq:RMSprop}
  \begin{split}
  x_{k+1} = x_k - \lambda \nabla f_k / \sqrt{S_k + \epsilon} \\ 
  S_k = (\nabla f_k)^2  + \beta S_{k-1}  
  \end{split}
\end{equation}
kde $\epsilon$ je velmi malá konstanta zabraňující dělení čísly velmi blízkými nule a $\beta$ je podobně jako výše konstanta z~intervalu <0,1) určující rychlost zániku předchozích $(\nabla f_k)^2$.~\cite{hinton2012neural} Kombinací dvou výše uvedených metod vznikne metoda \textit{Adam} (\textit{adaptive moment estimation}) - rovnice~\ref{eq:adam}:
\begin{equation} \label{eq:adam}
  \begin{split}
  x_{k+1} = x_k - \lambda V_k / \sqrt{S_k + \epsilon}\\
  V_k = \nabla f_k + \beta_0 V_{k-1}\\
  S_k = (\nabla f_k)^2  + \beta_1 S_{k-1}
  \end{split}
\end{equation}
kde $\beta_0$ a $\beta_1$ jsou konstanty určující rychlost zániku příslušných členů. Tato metoda má ze všech uvedených nejlepší optimalizační schopnost. \cite{kingma2014adam}


\subsection{Významné aktivační funkce} 
\begin{figure}
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/sigmoid.pdf}
    \caption{}
    \label{fig:sigmoid}
  \end{subfigure}  
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/tanh.pdf}
    \caption{}
    \label{fig:tanh}
  \end{subfigure}  
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/ReLU.pdf}
    \caption{}
    \label{fig:ReLU}
  \end{subfigure}  
  \begin{subfigure}{0.5\textwidth}
    \includegraphics[width=20em]{obrazky/LeakyReLU.pdf}
    \caption{}
    \label{fig:LeakyReLU}
  \end{subfigure}  
   \label{fig:activation}
  \caption{Grafy využívaných aktivačních funkcí.}
\end{figure}
  Aktivační funkce uvedená v~rovnici~\ref{eq:sigmoid} se v~dnešní době již používá jen velmi zřídka. Výstup sigmoidní funkce je v~celém svém průběhu pozitivní, což z~aritmetických důvodů způsobuje stejnost znaménka gradientu parametrů daného neuronu, a tudíž má negativní efekt na rychlost učení. Řešením je ji nahradit za $tanh$ (obrázek~\ref{fig:tanh}). Co ale nevyřeší ani $tanh$ je fakt, že obě funkce jsou, jak je vidět na obrázcích~\ref{fig:sigmoid} a~\ref{fig:tanh}, v~jakékoliv nezanedbatelné vzdálenosti vstupu od nuly velmi ploché, důsledkem čehož je v~těchto částech funkce $\sigma'(x) \approx 0$. Jelikož jedním z~efektů opakované aplikace řetězového pravidla je časté násobení průběžného výsledku částečnou derivací těchto funkcí, jakýkoliv neuron nacházející se svým výstupem v~tomto prostoru dosáhne stavu \textit{nasycenosti} --- již se dále skoro neučí.~\cite{activation, comparative} 

Populární aktivační funkcí je v~současné době $ReLU(x) = max(0,x)$. Funkce, jak je vidět na obrázku~\ref{fig:ReLU}, nemá svoji derivaci alespoň pro $ReLU(x) > 0$ nikdy blízkou nule. Dle~\cite{imagenet} je ReLU výpočetně velmi levná a má potenciál i několikrát zrychlit celý proces, nicméně trpí stejnou pozitivností jako sigmoidní funkce, a navíc existuje šance, že během učení vlivem ploché části $ReLU(x) = 0$ daný neuron ,,umře'' --- gradient posune jeho parametry do oblasti, kde se už nikdy neaktivuje. ,,Aktivace'' v~kontextu ReLU znamená pro daný neuron, že jeho výstup je větší než nula. V~síti hojně využívajících tuto aktivační funkci může její část sestávající z~takto ,,mrtvých'' neuronů dosáhnout velikosti až desítek procent. Leaky ReLU ($f(x) = 1(x<0)(\alpha x)+1(x>=0)(x)$, kde $\alpha$ je parametr určující sklon $f(x) <= 0$) ilustrována na obrázku~\ref{fig:LeakyReLU} je pokusem o~řešení těchto problémů, ale její konzistentní nadřazenost je neprůkazná. Existuje také aktivační funkce, jež se dá považovat za zobecnění ReLU, tzv. \textit{maxout}. Jak je vidět v~rovnici~\ref{eq:maxout},
\begin{equation} \label{eq:maxout}
  h(x) = max(w_1 \cdot x + b_1, w_2 \cdot x + b_2, \dots ,w_j \cdot x + b_j)
\end{equation}
maxout využívá více než jedné dvojice vektoru vah a biasu, což mu dává vybráním maxima z~množiny lineárních funkcí schopnost se přiblížit velkému (až jakémukoliv v~případě jejich dostatečné kvantity) množství nelineárních funkcí. Maxout tak umožnuje neuronové síti nejen se naučit váhy a biasy, ale i aktivační funkci individuálně pro každý neuron. ReLU vznikne zvolením množství linearit dva a následném nastavení vah i biasu jedné z~nich na nula. Navzdory obecnosti maxoutu jeho vysoká výkonnostní cena vzácně stojí za to.~\cite{maxout} Obyčejná ReLU tak zůstává nejvšestrannější volbou aktivační funkce.~\cite{relu, activation}

V~některých případech je žádoucí, aby výstup poslední vrstvy byl vyjádřením pravděpodobnosti, jako například pravděpodobnosti že daný vstup patří do dané kategorie. Jednou z~nezbytně nutných vlastností takové vrstvy je, že součet výstupů všech neuronů je jedna, což žádná z~dosud uvedených aktivačních funkcí nesplňuje. Jednou z~často využitých aktivačních funkcí, jež tohle splňuje, je tzv. \textit{softmax}, uveden v~rovnici~\ref{eq:softmax}:
\begin{equation} \label{eq:softmax}
  a_j = \frac{e^{z_j}}{\sum_k e^{z_k}}
\end{equation}
kde $z_k$ je vážený součet vstupů daného neuronu a $k$ je počet neuronů v~dané vrstvě. Výstupy softmax neuronů jsou, jak je vidět v~rovnici~\ref{eq:softmax}, vždy pozitivní ($e^x$ je pozitivní v~celém svém průběhu) a tak se vlivem předešle zmíněné vlastnosti dá výstup takové vrstvy považovat za distribuci pravděpodobnosti.~\cite{imagenet, neuron}


\section{Konvoluce a neuronové sítě}
Konvoluce diskrétních funkcí $f(i,j)$ a $g(i,j)$ je vypočtena rovnicí~\ref{eq:konvoluce}.~\cite{konvoluce}
\begin{equation} \label{eq:konvoluce}
	(f \star g)(i,j) = \sum_{k}\sum_{p} f(k,p)g(i-k,j-p),  \text{ pro } i,j \in\mathbb{Z}
\end{equation}
V~kontextu počítačové grafiky $f(i,j)$ představuje vstupní obrázek, $g(i,j)$ představuje konvoluční matici a $\star$ je operace konvoluce. Proces konvoluce aplikuje matici na každý pixel, kde sečte násobky pixelů a příslušných hodnot v~matici. Hodnoty v~konvoluční matici představují váhy vlivu jednotlivých pixelů na pixel výsledný~\cite{konvoluce-vysvetleni}. Výsledek je novým pixelem na zpracovávané pozici. Pro obrázek a konvoluční matici je výpočtem rovnice~\ref{eq:konvoluce2}~\cite{understanding}
\begin{equation} \label{eq:konvoluce2}
	(x \star w)[i,j] = \sum_{m}\sum_{n} x[m,n]w[i-m,j-n]
\end{equation}
kde $x$ je vstupní obrázek a $w$ konvoluční matice.
Obrázek~\ref{fig:konvoluce-pixel} znázorňuje tento proces graficky. Obrázky~\ref{fig:konvoluce-priklady} znázorňují efekty některých konvolučních matic. Ačkoliv striktně matematická definice konvoluce konvoluční matici před aplikováním převrací, pro účely této práce je tento fakt pro zjednodušení ignorován, protože váhy jsou naučené automaticky, a tak to na výsledku nic důležitého nemění.~\cite{konvoluce}



\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/convolution.pdf}
  \caption{Efekt konvoluce na specifický pixel. Pixely na okrajích nelze zkonvulovat a proto je výsledný obrázek menší.}
  \label{fig:konvoluce-pixel}
\end{figure}


\begin{figure}
  \includegraphics[width=20em]{obrazky/identity.jpg}
  \includegraphics[width=20em]{obrazky/blur.jpg}
  \includegraphics[width=20em]{obrazky/sharpen.jpg}
  \includegraphics[width=20em]{obrazky/edge.jpg}
  \caption{Příklady různých konvolučních matic, v~pořadí:
  identita $\begin{bmatrix}
    0 & 0 & 0\\
    0 & 1 & 0\\
    0 & 0 & 0\\
  \end{bmatrix}$,\\
  rozmazání $\begin{bmatrix}
    1 & 1 & 1\\
    1 & 1 & 1\\
    1 & 1 & 1\\
  \end{bmatrix}$, zostření $\begin{bmatrix}
    0 & -1 & 0\\
    -1 & 5 & -1\\
    0 & -1 & 0\\
  \end{bmatrix}$ a detekce hran $\begin{bmatrix}
    0 & 1 & 0\\
    1 & -4 & 1\\
    0 & 1 & 0\\
  \end{bmatrix}$.}
  \label{fig:konvoluce-priklady}
\end{figure}

Ačkoliv pro malé sítě plná konektivita nezpůsobuje žádné problémy, se zvětšujícím se počtem neuronů nárust parametrů neúnosně zvyšuje náročnost na výpočet. Například pro klasifikaci obrázků o~velikosti $32*32*3$ pixelů (třetí rozměr je hloubka, tj. počet RGB kanálů), připojení vstupní vrstvy k~pouze jednomu výstupnímu neuronu si vyžádá 3072 vah, připojení ke dvěma 6144 a tak dále. Pro skrytou vrstvu o~velikosti $32*32$ si plná konektivita vyžádá vah $32*32*32*32*3$ (3145728).~\cite{understanding}

Dobrým způsobem, jak tohle množství omezit, je nepřipojovat každý skrytý neuron ke každému vstupnímu a místo toho ,,ukázat'' každému skrytému neuronu pouze malou část vstupu například o~velikosti $5*5$. Počet vah se tak zmenší na $5*5*3*32*32$ (76800). Tohle množství může být ještě dále zmenšeno použitím stejných vah pro všechny neurony skryté vrstvy, zmenšujíc počet vah na $5*5*3$ (75). Skrytá vrstva se tak stane vrstvou konvoluční, protože taková vrstva je ekvivalentní malému okýnku počítající vážený průměr s~identickými vahami pro všechny pixely a jejich okolí. Této množině vah se často říká \textit{jádro}. Je možné mít více jader zpracovávající jednu část obrázku. Každé takové jádro vyprodukuje vlastní takzvanou \textit{aktivační mapu}. Proces je ilustrován na obrázku~\ref{fig:conv-channels}. Síť tak získá schopnost hledat malé rysy, nezávisle na tom, kde se ve vstupním obrázku nachází.~\cite{understanding}

Jádro může nabývat různých rozměrů, kromě výše uvedeného $5*5*3$ například $5*5*1$ (pro černobílý obrázek) nebo $7*7*3$. Při rozměrech větších než $1*1*1$ není možné provést konvoluci obrazových dat na okrajích, jelikož nejsou žádné pixely, jež je možné přiřadit některým částem jádra, například jak je vidět na obrázku~\ref{fig:konvoluce-pixel}. To se dá řešit způsoby jako např.:
\begin{itemize}
  \item Neaplikováním jádra na okrajích. Výsledná aktivační mapa pak bude mít menší rozměry, a to přesně o okraj, který se nepodařilo zkonvulovat. Z~výše uvedeného příkladu obrázku o~rozměrech $32*32*3$ a jádra $5*5*3$ by vznikla aktivační mapa o~rozměrech $28*28*1$.
	\item Rozšířením obrázku a okraj falešný, jako například naplněný nulami, anebo zkopírováním okraje skutečného.
\end{itemize}
Není také nezbytně nutné konvulovat každý pixel, konvoluční jádro je možné posouvat o~hodnotu kroku větší než $1$. V~takovém případě je ale potřeba zvolit hyperparametry tak, aby bylo možné zkonvulovat celý obrázek. S~obrázkem například o~velikosti $7*7*3$ a jádrem $3*3*3$ by krok o~velikosti $3$ fungoval jen velmi těžko.~\cite{understanding}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/conv-channels.pdf}
  \caption{Ilustrace konvoluce vícekanálového obrázku více než jedním jádrem. Vzniklé aktivační mapy je možné vnímat jako kanály nového obrázku pro účely například další konvoluční vrstvy. Kvádry barvy červená, modrá a zelená představují jednotlivé kanály vstupního obrázku. Jednotlivé krychle představují různá jádra velikosti $3*3*3$ a příslušně nabarvené kvádry představují výsledné aktivační mapy. Celkový počet násobení pro jeden krok je $3*3*3*3$ (81).}
  \label{fig:conv-channels}
\end{figure}
\begin{figure}
  \includegraphics[width=\linewidth]{obrazky/conv-depthwise.pdf}
  \caption{Stejná konvoluce jako v~obrázku~\ref{fig:conv-channels} s~rozdílem, že v~tomto případě je využito depthwise separation. Místo tří jader $3*3*3$ je zde využito tří jader velikosti $3*3*1$. Každé z~nich je aplikováno na vlastní kanál. Na výslednou množinu aktivačních map jsou následně aplikována 3 jádra velikosti $1*1*3$, z~nichž každé vyprodukuje vlastní aktivační mapu. Celkový počet násobení pro jeden krok je $3*3*3 + 3*3$ (36).}
  \label{fig:conv-depthwise}
\end{figure}

  V~neuronových sítích obsahující konvoluční vrstvy se často nachází také vrstvy typu \textit{max pooling}. Taková vrstva je podobně jako konvoluční ekvivalentní pohybujícímu se okýnku, s~rozdílem že místo váženého součtu vrstva vybere maximum. Max pooling se setkává s~identickými problémy s~okraji s~identickými řešeními. Často použitou konfigurací je například max pooling s~velikostí $2*2$, krokem $2*2$ a ignorací okrajů. Efekt dvou takových vrstev je ilustrován na obrázku~\ref{fig:maxpooling}. Kromě vylepšení výkonnostní ceny je jednou z~vlastností takové a jí podobné max pooling vrstvy redukce sekcí vstupu na jednotlivé hodnoty. Tyto hodnoty je pak možné zpětně namapovat na sekce vstupu a vyvozovat z~nich závěry. \cite{maxpooling}

\begin{figure}
  \centering
  \includegraphics[width=24em]{obrazky/maxout.pdf}
  \caption{Výsledek dvou max pooling vrstev velikosti $2*2$ a krokem $2*2$. Jasnější pixel symbolizuje větší hodnotu. Vrstva vybere pixel nejvyšší hodnoty pro každou sekci $2*2$. Výstup je dvakrát menší jak ve výšce, tak šířce. Po dvou takových vrstvách zbyde ze vstupu $8*8$ pouze $2*2$. Každý z~těchto pixelů je možné považovat za souhrn informací sekce, ze které pochází, obzvlášť pokud se mezi max pooling vrstvami nachází i vrstvy konvoluční. Tyto sekce jsou vyznačeny červenými rámečky.}
  \label{fig:maxpooling}
\end{figure}
Ještě dalším způsobem, jak snížit výpočetní náročnost pro obrázky s~víc než jedním barevným kanálem, je místo trojrozměrných jader použít množinu jader dvojrozměrných. V~takovém případě bude každému kanálu přiřazeno $n$ dvourozměrných jader a pro $m$ kanálů vznikne $n*m$ aktivačních map tak, že z~každého kanálu vznikne $n$ aktivačních map. Tyto aktivační mapy jsou následně rozděleny do $n$ skupin po $m$ a po spojení každé skupiny do trojrozměrné aktivační mapy je na ně aplikováno libovolné množství jader tvaru $1*1*m$. Použitím množství těchto jader nezanedbatelně větším, než $n$ je možné hledat rysy v~barevné informaci s menší výpočetní cenou, než jádry trojrozměrnými. Tato optimalizace se nazývá depthwise separation a je ilustrována na obrázku~\ref{fig:conv-depthwise}.~\cite{sifre2014rigid}


\section{Regularizace}
Ačkoliv mají hluboké neuronové sítě velmi dobrou schopnost mapovat komplikované vztahy mezi vstupem a výstupem, při nekompletní datové sadě bude nezanedbatelná část těchto mapování odrážet vztahy nacházející se pouze v~datové sadě trénovací. Tyto vztahy se v~ní nachází vlivem náhodného rušení a její nekompletnosti, a tudíž jejich naučení snižuje obecnost modelu. Neuronové síti, jež se naučila vztahy a rysy přítomné pouze v~trénovací sadě se říká \textit{přetrénovaná}. Ve snaze zmírnit přetrénování neuronových sítí došlo k~vyvinutí řady regularizačních technik.~\cite{dropout} Pojem regularizace je pojem mající velmi neurčitý význam, a tak je třeba přijmout jednu z~možných definic. Definicí z~\cite{kukavcka2017regularization} je: Regularizace je jakákoliv dodatečná technika určená k~vylepšení schopnosti generalizace.
\subsection{Regularizace datovou sadou}
S~regularizací se dá začít už na úrovni dat, a to jak transformací existující datové sadě na novou, tak vytvořením nových dat z~existujících. Uměle zvětšená datová sada se nazývá \textit{augumentovaná}. Transformace, jejichž kombinovanou aplikací lze z~jednotky obrazových dat uměle vytvořit jednotku dat novou, jsou například následující:
\begin{itemize}
  \item aplikování náhodného šumu
  \item roztáhnutí
  \item rotace
  \item posunutí
\end{itemize}
  Jejich využitím lze získat datovou sadu několikrát vetší. Je lepší raději získat více unikátních dat, nicméně to není vždy přijatelně snadné nebo cenově únosné.~\cite{kukavcka2017regularization} 

  \subsection{Regularizace včasným zastavením}
Dalším způsobem předejití přetrénování je zastavení trénování ve správný čas. Při trénování při dostatečném počtu iterací dojde k~situaci, kdy počet nově nalezených vztahů nacházející se pouze v~trénovací sadě převýší počet nově nalezených vztahů platných pro celou řešenou doménu. Metodou měření, zdali k~této situaci nedochází, je například periodické testování částí datové sady nevyužité k~trénování. Pokud se kvalita sítě nad touto testovací sadou nelepší nebo dokonce zhoršuje, jedná se o~možnou indikaci začínající přetrénovanosti sítě. Jelikož je ale testovací sada použita při trénování, objektivita měření finální kvality sítě touto sadou značně upadá. V~praxi používaným řešením tudíž je rozdělení dostupné sady na tři části: 
\begin{itemize}
  \item{trénovací --- optimalizace sítě výpočtem ztráty a následném přepočtu parametrů}
  \item{validační --- periodické měření relativní přetrénovanosti}
    \item{testovací --- změření kvality sítě po ukončení trénování}
\end{itemize}
Jedním z~typických poměrů rozdělení datové sady je v~pořadí například 7:1:2.~\cite{neuron}

\subsection{Dropout}
Jeden ze spíše zřejmých způsobů, jak se vyhnout efektům přetrénování, je vycvičit více než jednu síť a následně vyzkoušet nad testovacími daty sítě všechny. Optimálnějším způsobem, jak dosáhnout podobného efektu je takzvaný \textit{dropout}. Jedná se o~následující modifikaci algoritmu zpětného šíření chyby: Pro každou vrstvu je zvolen parametr $p \in$ <0,1>. Před každou epochou má každý neuron $1-p$ jeho vrstvy šanci, že se následující epochy nebude účastnit. (Ilustrováno na obrázku~\ref{fig:dropout}.) Na konci trénování jsou všechny váhy $w$ vynásobeny jejich příslušným $p$. Výsledkem je přibližný ekvivalent průměru velkého množství individuálně vytrénovaných sítí.~\cite{dropout}
\begin{figure}
  \centering
  \includegraphics[width=25em]{obrazky/dropout.pdf}
  \caption{Plně propojená neuronová síť z~obrázku~\ref{fig:neuron-network} po aplikaci dropoutu. Příslušné hodnoty $p$ individuálních vrstev jsou uvedeny pod nimi.}
  \label{fig:dropout}
\end{figure}

Aplikace dropoutu je pro každou epochu ekvivalentem sebrání ,,zřídčeného'' vzorku z~původní neuronové sítě, jeho individuálním vytrénování a následném zprůměrování jejich vah. Těchto vzorků existuje pro každou síť možných $2^n$, kde $n$ je počet neuronů v~dané síti. Vzhledem k~povaze růstu $2^n$ je při jakékoliv nezanedbatelné velikosti sítě nepravděpodobné, že bude jeden z~těchto vzorků trénován více než jednou. Vzniklý průměr těchto síti je proto průměrem exponenciálního množství různých jednou trénovaných sítí s~velkým množstvím sdílených vah.~\cite{dropout}

\subsection{Regularizace cenovou funkcí}
Jedním z~důvodů pro výběr dané cenové funkce může být její regularizační efekt. Příbuznou možností je regularizace přidáním regularizačního členu do jinými prioritami zvolené cenové funkce, jako například způsobem uvedeným v~rovnici~\ref{eq:cost_function_regularization},
\begin{equation} \label{eq:cost_function_regularization}
  C_r(x, y) = C(x,y) + r
\end{equation}
kde $r$ je zmíněný regularizační člen. Tímto členem může být například $\frac{\lambda}{2n}\sum_w w^2$ kde $\sum_w w_2$ je suma druhých mocnin všech vah, $n$ je počet vzorků a $\lambda$ je významnost tohoto regularizačního členu pro cenu. Protože cílem stochastického gradientního sestupu je minimalizace hodnoty ceny dané konfigurace neuronové sítě, přidáním sumy druhých mocnin vah do ceny dojde i k~minimalizaci těchto vah. Preference menších vah má regularizační efekt.~\cite{kukavcka2017regularization} 

\section{Zpracování obrazu}
Obrazová data je často před jejich využitím pro účely strojového učení výhodné zpracovat. Častou transformací je transformace vyžadující znalost hodnoty pixelů na pozicích, jež nemají korespondující pozici ve zdrojovém obrázku. Příkladem může být zvětšení, zmenšení, anebo rotace. Tyto chybějící hodnoty je třeba vypočítat. K tomuto účelu existuje řada metod, z nichž nejjednodušší je metoda \textit{nearest neighbour}. Tato metoda vypočítá každý neznámý pixel změřením vzdálenosti ke každému pixelu známému. Daný neznámý pixel následně získá hodnotu rovnou známému pixelu geometricky nejbližšímu. Neznámé pixely je také možno interpolovat například lineárně. V interpolovaném jednodimenzionálním obrázku je hodnota neznámého pixelu vypočtena váženou sumou pixelů známých. V tomto případě se jedná o váženou sumu dvou nejbližších známých pixelů. Váhy těchto pixelů jsou dané jejich geometrickou vzdálenosti. Rozšířením této metody do dvou dimenzí vznikne metoda \textit{bilineární interpolace}. Tato metoda vyžaduje pro výpočet neznámého pixelu známé pixely čtyři. Při jejím využití dojde nejprve k jednorozměrným lineárním interpolacím nediagonálních disjunktních párů známých pixelů. Souřadnice těchto dvou nově vzniklých pixelů je třeba vybrat tak, aby jejich lineární interpolací bylo možné získat pixel původně hledaný. Lineární interpolací těchto dvou pixelů pro hledaný pixel je získán výsledek interpolace bilineární. Ještě dalším rozšířením je metoda \textit{bikubické interpolace}, kde zmíněným rozšířením je využití křivek.~\cite{processing}

Druhou kategorií transformací jsou transformace nevyžadující znalost hodnot neznámých pixelů. V takovém případě jsou hodnoty existujících pixelů přepočteny na nové, například při rozmazání, převodu do stupňů šedi, anebo barevných filtrů. Častým způsobem dosažení těchto transformací je operace konvoluce, jako například v obrázku~\ref{fig:konvoluce-priklady}. Pro detekci hran může být výhodnější využít takzvaného \textit{Sobelova operátoru}. Jeho aplikací podle rovnic~\ref{eq:sobel_x}~a~\ref{eq:sobel_y}, 
\begin{equation} \label{eq:sobel_x}
  G_x = \begin{bmatrix}
    1 & 2 & 1\\
    0 & 0 & 0\\
    -1 & -2 & -1\\
  \end{bmatrix} \star I
\end{equation}
\begin{equation} \label{eq:sobel_y}
  G_y = \begin{bmatrix}
    1 & 0 & -1\\
    2 & 0 & -2\\
    1 & 0 & -1\\
  \end{bmatrix} \star I
\end{equation}
kde $\star$ je operace konvoluce a $I$ je vstupní obrázek, jsou získány obě komponenty gradientu obrázku $I$. $G_x$ je horizontální komponentou hran a $G_y$ vertikální. Jejich kombinací podle rovnice~\ref{eq:sobel_g}
\begin{equation} \label{eq:sobel_g}
  \parallel G\parallel = \sqrt[][G_x^2 + G_y^2]
\end{equation}
vznikne matice velikostí gradientů $G$. Každý pixel $G$ je ohodnocením míry, do které je pixel na stejné pozici ve vstupním obrázku součástí hrany. Hrany detekované tímto způsobem mají často šířku více než jednoho pixelu, což nemusí být žádoucí. Pro řešení tohoto problému je možné využít takzvaný \textit{Cannyho detektor hran}. Některé konvoluční sítě přijímají na svůj vstup obrázek zredukovaný na pouze hrany. ~\cite{processing}



\chapter{Návrh}\label{chap:navrh}

Cíl této práce stanovuji na program se schopností co nejpřesnějšího určení polohy a velikosti všech tramvají ve vstupním videu. Tato informace bude udaná v~pixelech, relativně k~levému hornímu rohu každého snímku. Program bude otevřen snadnému pozdějšímu přidání schopnosti uvést vzdálenost a rozměr také v~metrech relativně ke kameře za předpokladu, že uživatel uvede dostatečné množství kalibračních detailů. K~tomuto účelu volím detekovatelnou část tramvaje na pouze její přední a zadní stranu, protože tyto strany mají značně nižší variabilitu rozměrů než ostatní. Jednotlivé modely tramvají mají variabilitu výšky o~dost vetší než variabilitu šířky. Tramvaje se často pohybují vysokou rychlostí, a to způsobuje na výstupu statické kamery jejich rozmazání. Znatelnost tohoto efektu je úměrná blízkosti tramvaje kameře a snímkovací rychlosti. Různé modely tramvají mají také velmi vysokou variaci rysů jejich předních stran. Taktéž jejich barevné provedení může být jakékoliv, a proto budu převádět všechna barevná data do černobílého kanálu. 

\section{Cílový program}
Využito bude následujících knihoven a technologií:
\begin{itemize}
  \item{CUDA --- technologie umožňující hardwarovou akceleraci některých typů výpočtů vybranými grafickými kartami společnosti NVIDIA. Velikost této akcelerace může být i v~tisících procent.}
  \item{ROCm --- ekvivalent CUDA pro některé grafické karty společnosti AMD.}
  \item{PyTorch --- knihovna určená pro tvorbu, trénování a využití neuronových sítí.}
  \item{OpenCV --- mimo jiné obsahuje funkce pro manipulaci s~obrazovými daty.}
\end{itemize}
Cílovou platformou bude Linux. Program bude podporovat jak CUDA, tak ROCm za předpokladu, že uživatel má systém správně sestavený a nastavený pro využití zvolené technologie. Rozhraní bude pouze příkazovou řádkou. Uživatel bude mít možnost:
\begin{itemize}
  \item{Zvolit, zdali chce pro výpočty využít grafické karty nebo procesoru.}
  \item{Dotrénovat zvolený model na vlastních datech a v~takovém případě zvolit i parametry trénování jako například velikost dávky, rychlost učení a podobně.} 
  \item{Zvolit model.}
  \item{Použít video nebo webkameru jako vstup a následně jako výstup zvolit kombinaci z:}
    \begin{itemize}
      \item{vykreslení vstupního videa obohacené o~detekované tramvaje vyznačené obdélníky na obrazovku}
      \item{výstupu zmíněného videa do souboru}
      \item{výstupu čtveřic souřadnic detekovaných tramvají na standardní výstup}
    \end{itemize}
\end{itemize}
Jedinou částí datové sady držené v~paměti bude její část bezprostředně potřebná k~výpočtu. Minimální podporované množství paměti RAM bude 16GiB. Program se bude skládat z~hlavního skriptu řídícího celý proces a vyměnitelných modulů. Před počátkem výpočtu hlavní skript vybere z~těchto modulů moduly potřebné pro uživatelem zvolený výpočet. Pro tento skript pak díky kombinaci polymorfismu a kompozice následně skoro nezávisí na jejich konkrétním původu a funkcionalitě. 

\subsection{Detekce využitím předtrénovaných modelů}
Pro zjednodušení rozpoznávání obrazu existují různé předtrénované modely. Ty je třeba dotrénovat na specifickém problému. Ačkoliv jejich využití umožňuje dosáhnout velmi dobrých výsledků velmi rychle, není jejich využití plnou náhradou za účelně navržené a od začátku vytrénované modely. PyTorch nabízí řadu předtrénovaných, přednastavených modelů. Těmi jsou:
\begin{itemize}
  \item{SSD}
  \item{SSDlite}
  \item{RetinaNet}
  \item{FCOS}
  \item{Faster R-CNN}
\end{itemize}
Tyto knihovní modely nejsou přesnou kopií originálních modelů nesoucí jejich příslušné jméno, jsou na nich pouze založené. Předtrénování proběhlo na datové sadě COCO~\cite{coco}. Tato datová sada obsahuje více než 80 kategorií. Ačkoliv žádná z~nich není tramvaj, nachází se v~ní kategorie příbuzné, jako například vlak, autobus a osobní nebo nákladní automobil. Protože detekují více kategorií, než je pro řešení tohoto problému nutné, typickým postupem by bylo nahradit několik posledních vrstev vlastním návrhem lépe se hodící k~danému účelu, v~tomto případě detekující kategorii pouze jednu. To ale do řešení vnáší zbytečný prostor pro chybu. Rozhodl jsem se raději knihovní návrh neměnit a raději zvolit jednu kategorii, jež bude ,,přeučena'' na detekci tramvaje. Při testování pak budou ostatní kategorie ignorovány. Vrstvy, jež by byly nahrazeny, mají oproti extraktoru rysů nacházejícím se před nimi zanedbatelnou výpočetní cenu.

Indikátorem přetrénovanosti bude počet validačních snímků s~nulovým počtem detekcí. Po každé epoše bude model otestován na validační sadě a pokud dosáhne zmíněný počet příliš velké části validační sady, trénování bude zastaveno. Postup zmenšování celkové ceny modelu bude taktéž sledován pro účely pozastavení s~manuální úpravou rychlosti učení. Tato rychlost začne pro každou síť na $0.0001$. Pro optimalizaci parametrů bude využito stochastického gradientního sestupu s~modifikací ADAM.  

\subsection{Detekce na míru navrženou sítí}
Síť, jež se skládá pouze z~konvolučních a max pooling vrstev, není omezena přesnou délkou vstupu, je pouze omezena nejmenší délkou. Pro binární klasifikační problém, jaký se snažím řešit zde, takový nejmenší vstup vyprodukuje po průchodu sítí právě jeden výstup. Větší vstupy vyprodukují více než jeden. Vzhledem k~povaze max pooling vrstev, pro síť tyto vrstvy obsahující tyto jednotlivé výstupy korespondují různým, možně překrývajícím se částem vstupního obrázku. Správnou interpretací takové sítě lze její výstup chápat jako teplotní mapu jednotlivých pravděpodobností, že se na příslušných částech vstupního obrázku nachází tramvaj.  Síť je možné se snažit trénovat pro rozpoznání tramvají všech velikostí, to ale v~praxi nemá moc velký úspěch. Co úspěch má, je naučení sítě jedné velikosti a při testování vstupní snímek síti předložit v~různých škálách, čímž vznikne množina teplotních map, každá z~nich popisující šanci že se při dané škále vyskytuje ve vstupu tramvaj. Pro stejnou sekci obrázku tudíž vznikne více ohodnocení. Pro danou sekci je vybrán nejjistější střed a rozměr je odhadnut podle jeho původu. 

Pokud se v~síti plně propojené vrstvy nachází, vstup je omezen přesným rozměrem. Tradičním umístěním těchto vrstev je konec sítě. Takovou síť se skládá dvou části: extraktor rysů představující většinu parametrů sítě a skládající se pouze z~konvolučních a max pooling vrstev následován klasifikátorem skládající se z~pouze vrstev plně propojených. Těchto klasifikátorů může mít síť víc než jeden. Jejich význam je dán jejich učením. Například jeden z~nich může mít jeden výstup značící přítomnost tramvaje, zatímco druhý výstupy čtyři značící její souřadnice. Klasifikátor se může skládat i z~konvolučních vrstev a získat tím identickou schopnost přijímat rozsah rozměrů vstupu. Přirozeně nabízející se architekturou mojí na míru navržené sítě je tudíž jeden extraktor rysů následován dvěma klasifikátory, oba skládající se pouze z~konvolučních vrstev --- regresor ohraničujících boxů a třídní klasifikátor. Inspirováno architekturou zmíněných předtrénovaných sítí.

Z~důvodu nedostatečné velikosti vlastní datové sady a podobnosti tramvají s~dalšími dopravními prostředky bude využito i datové sady COCO, a to specificky objektů označených jako \texttt{train}, \texttt{car}, \texttt{bus} a \texttt{truck}. Protože tato datová sada obsahuje i množství tramvají pod označením \texttt{train}, nemá smysl při jejím použití implementovat rozlišení tramvají od vlaků. Třídní klasifikátor bude mít pro nejmenší vstup čtyři výstupy, každý vyjadřující jistotu že se na vstupu nachází korespondující dopravní prostředek a podobně pro regresor ohraničujících boxů. Síť bude vytrénovaná nejprve na COCO a poté dotrénovaná na vlastní datové sadě obsahující pouze tramvaje. Důvodem je fakt že v~COCO jsou dopravní prostředky označené celé, a ne pouze jejich přední strana. Protože vytvoření takové sítě je značně náročné, bude provedeno iterativně, ve fázích se vzestupnou složitostí:
\begin{itemize}
  \item{síť s~nepřekrývajícími se segmenty vstupu a bez regresoru ohraničujících boxů}
  \item{síť s~překrývajícími se segmenty vstupu ale bez regresoru ohraničujících boxů}
  \item{kompletní síť}
  \item{kompletní síť optimalizovaná zmenšením počtu parametrů a využitím depthwise separation}
\end{itemize}

\section{Data}
Vlastní datová sada sestává z~množiny videí. Malou část této množiny jsem natočil sám na telefon 
Sony Xperia XZ1 s kamerou s rozlišením 19 megapixelů a fokální délkou 25 milimetrů na Mendlově náměstí v Brně. Zbytek mi byl poskytnut vedoucím. Data je před použitím třeba zpracovat. V~datech je třeba vyznačit oblast, kde se nachází tramvaj. Provádět tohle pro video by bylo nepraktické, a tak prvním krokem pro trénování neuronové sítě je vybrání specifických snímků. Na těchto snímcích je následně provedeno tohle vyznačení. K~tomuto účelu existuje řada programů, z~nichž mojí volbou je \textit{LabelMe}\footnote{\url{http://labelme.csail.mit.edu/Release3.0/}}. LabelMe poskytuje grafické rozhraní pro vyznačení objektů na obrázku. Pro moje účely zajímavou funkcí je vyznačení obdélníkem, kde tyto obdélníky jsou určeny koordináty dvou bodů. Obrázek je následně uložen i se všemi obdélníky do souboru JSON. Vyznačenou částí tramvaje je její přední nebo zadní strana. Ohraničující boxy mají svůj poměr stran skoro vždy blízký $2:3$ a pouze zanedbatelná část pixelů nacházející se uvnitř boxu nepatří tramvaji. Snímky jsou vlivem jejich původu zkomprimované s~vysokou ztrátou, nicméně rozměry žádného snímku nejsou méně než $1280*720$. Všechny mají stejný poměr stran a to $16:9$. Tato datová sada sestává z~celkem 339 snímků, na kterých se nachází celkem 363 anotovaných tramvají. Částečně viditelné tramvaje anotovány nebyly. Některé skupiny těchto snímků jsou si velmi podobné, protože pocházejí ze stejného videa. Příklady se nachází na obrázku \ref{fig:data}. Sada je rozdělena na trénovací, validační a testovací generátorem pseudo-náhodných čísel se šancemi 0.7, 0.1 a 0.2 příslušně. Počty snímků těchto sad jsou 247, 29 a 63.

\begin{figure}
  \includegraphics[width=19em]{obrazky/dataset/data1.jpg}
  \includegraphics[width=19em]{obrazky/dataset/data2.jpg}
  \includegraphics[width=19em]{obrazky/dataset/data3.jpg}
  \includegraphics[width=19em]{obrazky/dataset/data4.jpg}
  \centering
  \caption{Příklady snímků z datové sady.}
  \label{fig:data}
\end{figure}

Dalším využitým zdrojem dat je datová sada COCO. V~sadě nabídnuté ke stažení na stránkách COCO\footnote{\url{https://cocodataset.org/\#download}} se nachází celkem $163957$ obrázků, rozděleno na sady trénovací ($118287$), validační ($5000$) a testovací ($40670$). Pro mě užitečnými vzorky jsou pouze takové obsahující alespoň jeden objekt jedné z~kategorií  \texttt{train}, \texttt{car}, \texttt{bus} a \texttt{truck}. Po odstranění obrázků žádný z~takových objektů neobsahující zbyde v~trénovací sadě $19335$ vzorků, zatímco ve validační vzorků $836$. Testovací sada nebude využita. Vyznačenou částí objektů jsou objekty celé, pokud jsou celé viditelné. Pokud nejsou, většinou je označena pouze jejich část viditelná v~popředí, nicméně není výjimkou jejich označení podobným způsobem jako kdyby se na obrázku překážka zabraňující jejich kompletní viditelnosti nenacházela. Dopravní prostředky a obzvláště tramvaje a vlaky mohou dosahovat relativně vysokých délek, a tak pod některými úhly kamery ohraničující box takového objektu bude obsahovat velké množství pixelů patřící pozadí. Příkladem je obrázek~\ref{fig:train_box})
\begin{figure}
  \includegraphics[width=20em]{obrazky/train_box.png}
  \centering
  \caption{Ohraničující box vlaku na obrázku pocházejícím z~datové sady COCO~\cite{coco}. Poměrně velká část pixelů nacházejících se uvnitř boxu nepatří vlaku.}
  \label{fig:train_box}
\end{figure}
Obrázky jsou různých rozlišení a poměrů stran. Rozlišení se většinou pohybuje kolem $500*500$ a komprese je vysoce ztrátová. Všechny objekty nacházející se v~datové sadě jsou umístěné v~jednotném seznamu v~jednom souboru JSON s~pouhou referencí na zdrojový obrázek. Pro jednotnost byl tento soubor převeden na stejný formát, jaký vznikl anotací vlastních dat v~programu LabelMe.






\chapter{Řešení}\label{chap:implementace}

Předmětem této kapitoly je implementace a její testování. Vzniklý program se skládá z části společné pro všechny modely a z části implementované pro každý model inidividuálně. Vzniklé modely jsou po jejich vytrénování porovnány.

\section{Implementace}
Některé části zdrojového kódu jsou založené na příkladech uvedených v~dokumentacích PyTorch\footnote{\url{https://pytorch.org/docs/stable/index.html}} a OpenCV\footnote{\url{https://docs.opencv.org/4.x/d6/d00/tutorial\_py\_root.html}}. Prvním krokem po přijmutí a zpracování argumentů (což je snadno vyřešeno knihovnou \texttt{argparse}) je načtení snímků, ať už pro účely trénování, anebo testování. Pro tohle ideální konstrukcí jazyka Python je generátor. Inicializovaný generátor se chová podobně jako list, s~rozdílem že je možné jej projít pouze jednou a pouze sekvenčně. Jeho výhodou oproti standardnímu listu je schopnost nedržet všechna procházená data současně v~paměti. Generátor je definován funkcí, která místo klíčového slova \texttt{return} používá klíčové slovo \texttt{yield}. Každý objekt vrácen pomocí \texttt{yield} se pak považuje za jeden prvek generovaného listu. Při požádání inicializovaného generátoru o~další prvek v~sekvenci je předáno řízení této funkci až po moment, kdy narazí na \texttt{yield}, kde je funkce pozastavena a řízení vráceno zpět. Postup se opakuje pro každý prvek v~sekvenci až po konec funkce. Generátor je následně vyčerpaný a už nikdy žádný další objekt nevrátí. Tato konstrukce je využita pro načítání snímků ze souborů, načítání snímků z~videa a rozdělování dat do dávek. Načítající generátory vrací kromě snímku také slovník obsahující jeho metadata a ohraničující boxy, pokud to dává pro daný snímek smysl. 


Pro abstrakci detailů jednotlivých modelů se ve zdrojovém kódu nachází rozhraní pod jménem \texttt{ModelUtil}. Nejedná se sice o~rozhraní ve striktním slova smyslu, avšak použitím se o~rozhraní jedná. Třídy implementující tohle rozhraní musí povinně implementovat:
\begin{itemize}
  \item{\texttt{get\_data} --- převod snímků načtených pomocí zmíněných generátorů na data použitelná k~trénování}
  \item{\texttt{get\_model} --- získání zinicializovaného modelu}
  \item{\texttt{batch2boxes} --- otestování modelu dávkou dat}
\end{itemize}
Nepovinně pak mohou implementovat pomocnou funkci \texttt{preprocess}, která slouží třídě implementující \texttt{ModelUtil} interně. Díky této abstrakci může program s~jednou výjimkou zacházet při trénování a testování se všemi modely identickým způsobem. Výjimkou je převod vygenerovaných numpy matic na matice PyTorch. Důvodem je usnadnění manipulace s~třídami \texttt{ModelUtil} ve více procesech. Knihovna PyTorch je velmi náročná na použití ve více procesech, a tak je použití této knihovny zanecháno jen hlavnímu procesu. Protože se převáděné datové struktury mezi některými modely liší, dosažení plné abstrakce není možné. Ačkoliv paralelní funkcionalita nebyla implementována, program byl navržen s~možností jejího pozdějšího přidání.

\begin{figure}
  \begin{subfigure}{\textwidth}
    \includegraphics[width=40em]{obrazky/block-schema-train.pdf}
    \caption{Blokové schéma hlavní trénovací smyčky.}
    \label{fig:train-loop}
  \end{subfigure}  
  \begin{subfigure}{\textwidth}
    \includegraphics[width=40em]{obrazky/block-schema-test.pdf}
    \caption{Blokové schéma hlavní testovací smyčky.}
    \label{fig:test-loop}
  \end{subfigure}  
  \caption{Bloková schémata trénovací a testovací smyčky.}
\end{figure}
Soubor \texttt{run.py} obsahuje mimo jiné hlavní trénovací smyčku. Její blokové schéma se nachází na obrázku~\ref{fig:train-loop}. Tato smyčka pro každou vygenerovanou dávku vypočítá její celkovou cenu a následně provede jeden optimalizační krok. \texttt{model} se může nacházet v~módu trénovacím nebo testovacím. V~trénovacím přijímá jak vstup, tak správný výstup a vrací cenu. Ztrátová funkce je součástí modelu. V~testovacím módu přijímá pouze vstup a vrací výstup. Testovací smyčka vypadá podobně --- rozdílem je záměna výpočtu a zpětné propagace chyby za výstup souřadnic předpovězených ohraničujících boxů. Její blokové schéma se nachází na obrázku~\ref{fig:test-loop}.



Jediným zbývajícím problémem je implementace \texttt{ModelUtil} pro každý model. Předtrénované modely navzdory mým předpokladům v~době návrhu mají tyto implementace velmi podobné, a tak jsou sdílené. Jejich trénování je relativně přímočaré, kde velmi rychle začnou dosahovat dobrých výsledků. Pro model RetinaNet jsou nabízeny verze \texttt{v1} a \texttt{v2}, z~nichž jsem vybral \texttt{v2}. Podobně Faster R-CNN nabízí verze \texttt{resnet50\_fpn}, \texttt{resnet50\_fpn\_v2}, \texttt{mobilenet\_v3\_large\_fpn} a \texttt{mobilenet\_v3\_large\_320\_fpn}, ze kterých jsem se rozhodl vyzkoušet  \texttt{resnet50\_fpn\_v2} a \texttt{mobilenet\_v3\_large\_320\_fpn}. Se vstupem před předložením modelu provádím transformace převodu do jednoho černobílého kanálu a změny rozměrů. 

Pro vlastní síť je třeba také navrhnout její architekturu. První a druhá iterace se skládá z~jednoho extraktoru rysů a jednoho klasifikátoru. Hyperparametry, jež byly předmětem experimentů, jsou následující:
\begin{itemize}
  \item{počet a kombinace jednotlivých vrstev}
  \item{rozměry a krok jednotlivých vrstev}
  \item{pro každou konvoluční vrstvu počet jader}
  \item{velikost hodnoty $p$ pro dropout každé vrstvy}
  \item{aktivační a cenové funkce}
\end{itemize}
  Optimalizace hyperparametrů je otevřená problematika nemající žádný zaručeně fungující postup. Testovaní dané konfigurace je vysoce výpočetně náročná operace, kde jeden test vyžaduje jednotky dnů a kilowatthodin energie. Nejoptimálnější nalezenou konfigurací hyperparametrů je architektura TramNet. Sekvence jednotlivých vrstev této architektury se nachází v~tabulce~\ref{tram_net}. Aktivační funkcí každé konvoluční vrstvy je $ReLU()$. Zvolenou cenovou funkcí je kvadratická cena. Tato architektura nemá regresor ohraničujících boxů. Architekturu s~tímto regresorem jsem se rozhodl neimplementovat. Všechny vrstvy s~rozdílnou velikostí rozměru a kroku s~výjimkou posledních třech mají ke svému vstupu přidaný nulový okraj velikosti jedna. 

\begin{table}[]
  \centering
\begin{tabular}{lllll}
  \hline
Index & Typ vrstvy  & Rozměr     & Krok   & Počet jader \\
  \hline
1     & Konvoluční  & 3*3*1      & 1*1*1  & 6           \\
2     & Konvoluční  & 3*3*6      & 1*1*1  & 16          \\
3     & Max pooling & 2*2*1      & 2*2*1  &             \\
4     & Konvoluční  & 3*3*16     & 1*1*1  & 32          \\
5     & Konvoluční  & 3*3*32     & 1*1*1  & 64          \\
6     & Max pooling & 2*2*1      & 2*2*1  &             \\
7     & Konvoluční  & 3*3*64     & 1*1*1  & 128         \\
8     & Konvoluční  & 3*3*128    & 1*1*1  & 256         \\
9     & Max pooling & 2*2*1      & 2*2*1  &             \\
10    & Konvoluční  & 3*3*256    & 1*1*1  & 256         \\
11    & Konvoluční  & 3*3*256    & 1*1*1  & 256         \\
12    & Max pooling & 2*2*1      & 2*2*1  &             \\
13    & Konvoluční  & 3*3*256    & 1*1*1  & 256         \\
14    & Max pooling & 3*3*1      & 1*1*1  &             \\
15    & Konvoluční  & 1*1*256    & 1*1*1  & 128         \\
16    & Konvoluční  & 1*1*128    & 1*1*1  & 64          \\
17    & Konvoluční  & 1*1*64     & 1*1*1  & 4          
\end{tabular}
  \caption{Sekvence vrstev architektury TramNet.} 
\label{tram_net}
\end{table}

Všechny max pooling vrstvy kromě poslední mají rozměr i krok velikosti $2*2$. Těchto vrstev je celkem 4, tudíž každý pixel aktivační mapy 4. max pooling vrstvy koresponduje jednomu nepřekrytému segmentu $16*16$ na vstupním obrázku. Poslední max pooling vrstva je rozměru $3*3$ a kroku $1*1$. Protože má velikost kroku menší než velikost rozměru, každý pixel výsledné aktivační mapy koresponduje překrývajícím se segmentům ve vstupním obrázku. Rozměr těchto segmentů je $72*72$ a krok $16*16$. Poslední 3 konvoluční vrstvy jsou pro vstup velikosti $16*16$ ekvivalentem sekvence 3 plně propojených vrstev. V~této architektuře slouží jako klasifikátor.


\section{Testování}
Klasické zhodnocení ve formě počtu správných a nesprávných odpovědí zde není relevantní, protože každý vstupní snímek má pro řešení uvedeného problému množství správných řešení. Daná detekce může být posunutá nebo zvětšená i o~jednotky pixelů bez ztráty zdánlivé přesnosti. Porovnání manuálního vyznačení tramvaje s~automaticky předpovězeným přesnou rovností tak nepodá dostatečně přesnou kvantifikaci užitečnosti daného modelu. Sítě tudíž byly porovnány v~následujících kategoriích:
\begin{itemize}
  \item{Úspěšnost --- procento detekovaných tramvají s~dalším rozdělením na:}
    \begin{itemize}
      \item{Detekce kompletně správné, tzn. bylo by možné podle dané předpovědi přijatelně přesně odhadnout poměr zdánlivé a reálné šířky.}
      \item{Detekce částečně správné, tzn. zmíněný odhad učinit nelze.}
    \end{itemize}
  \item{Počet false pozitivů --- počet detekcí nepatřící žádné tramvaji. Pokud měla daná tramvaj více než jednu detekci, do úspěšnosti byla započítána ta nejlepší s~ostatními započtenými jako false pozitivy. }
  \item{Výpočetní náročnost --- udána jako průměrný počet milisekund potřebný ke zpracování jednoho vzorku referenčnímu systému\footnote{Systémem, na kterém byly modely testované je \textit{Lenovo Legion 5 15ACH6A}.
    (CPU AMD Ryzen 5 5600H,
    GPU AMD ATI Radeon RX 6600M, VRAM 8 GiB,
    RAM 16 GiB).}.}
\end{itemize} 
Zhodnocení bylo provedeno manuálně.

Pro každý model jsem ručně prošel 63 testovacích vstupů s~celkem 68 tramvajemi a rozřadil všechny detekce do příslušných kategorií. Do výpočetní náročnosti jsem započítal pouze čas strávený dopředným průchodem neuronovou sítí. Toho bylo dosaženo změřením času před a po průchodu. Všechny rozdíly těchto dvou časových údajů byly následně sečteny a poděleny počtem vstupů. Maximální velikost dávky byla 5 pro všechny modely. Pro některé modely by pro jejich nízkou paměťovou cenu fungovala velikost dávky i mnohonásobně větší. Ačkoliv využití této možnosti by se pozitivně odrazilo na jejich výpočetní náročnosti, pro zachování objektivity porovnání jsem se rozhodl možnosti nevyužít. Fakt že poslední dávka má jinou velikost, než všechny ostatní není pro jeho zanedbatelný efekt na průměrnou dobu zpracování nijak ošetřen. Výsledky testů se nachází v~tabulce~\ref{stats}. Správnost modelu sice koreluje s~výpočetní náročností, kde nejlepší ale zároveň nejdražší je model Faster R-CNN ResNet, nicméně poměr správnosti a výpočetní náročnosti se zvedající se výpočetní náročností klesá.  


\begin{table}[]
    \centering
\begin{tabular}{lllll}
\hline
Model                  & DKS            & DČS           & FP              & PDZ \\ \hline
SSDlite                & 60             & 8             & 5               & 17ms \\
SSD                    & 58             & 10            & 1               & 25ms \\
  FCOS                   & 65             & 3             & 10              & 55ms \\
RetinaNet              & 66             & 2             & 0               & 56ms \\
Faster R-CNN MobileNet & 7              & 49            & 76              & 5ms  \\
Faster R-CNN ResNet    & 68             & 0             & 0               & 91ms \\
TramNet                & 0              & 0             & 0               & 6ms
\end{tabular}
  \caption{Výsledky testů předtrénovaných modelů. Význam zkratek v~záhlaví je v~pořadí: Detekce Kompletně Správné, Detekce Částečně Správné, False Positives a Průměrná Doba Zpracování jednoho snímku. Celkový počet detekovatelných tramvají v testovací sadě byl 68.}
\label{stats}
\end{table}
\begin{table}[]
  \centering
  \begin{tabular}{ll}
\hline
Model                  & Barva\\ \hline  % B    G  R
SSDlite                & Růžová       \\ % (255,0,  255)
SSD                    & Žlutá        \\ % (0,  255,255)
FCOS                   & Zelená       \\ % (0,  255,0),
RetinaNet              & Tyrkysová    \\ % (255,255,0),
Faster R-CNN MobileNet & Modrá        \\ % (255,0,  0)
Faster R-CNN ResNet    & Červená      \\ % (0,  0,  255)
TramNet                & Bílá
  \end{tabular}
\caption{Barevné kódování detekcí jednotlivých sítí.}
  \label{encoding}
\end{table}

Po dokončení testování jsem znovu prošel dostupné videozáznamy a vybral 17 nových, dosud nepoužitých, snímků. Následně jsem na každý snímek vykreslil detekce všech individuálních sítí. Barevné kódovaní se nachází v tabulce \ref{encoding}. Výsledné snímky se nachází na obrázcích \ref{fig:fp}, \ref{fig:d} a \ref{fig:side}. Účelem snímků na obrázku \ref{fig:fp} bylo otestovat chovaní modelů pro vstupy s nulovým počtem detekovatelných tramvají. S malým počtem výjimek se chovají dle očekávání. Některé modely detekovali i tramvaje z velké části překryté, jako například na obrázcích \ref{fig:fp3} nebo \ref{fig:fp6}. Častým false pozitivem je označení střechy nebo strany tramvaje jako například na obrázcích \ref{fig:fp3}, \ref{fig:fp4}, \ref{fig:fp5}, anebo \ref{fig:fp7}. Taktéž na obrázku \ref{fig:side} je vidět velké množství chybně detekovaných bočních stran tramvají. Jak je ale vidět na ostatních příkladech, strany jsou detekovány pouze při dostatečné kolmosti strany ke směru kamery. Pravděpodobnou příčinou je vizuální podobnost všech stran tramvaje obsahujících okna. Model RetinaNet je na false pozitiva tohoto typu nejvíce náchylný. Podobně byly detekovány i dodávky na obrázcích \ref{fig:side1} a \ref{fig:side3}, ačkoliv ve druhém případě se jedná o pouze jednu detekci pocházející od Faster R-CNN ResNet. 

Pro vysoce hranaté tramvaje má většina modelů vysokou úspěšnost. Detekce jednotlivých modelů jsou si pro tento případ často vysoce podobné, jak je vidět například na snímcích \ref{fig:d1}, \ref{fig:d2}, \ref{fig:d3} a \ref{fig:d4}. Pro tramvaje obsahující vysoké množství křivek již ale výsledky tak konzistentní nejsou, jako například pro některé z tramvají na snímcích \ref{fig:d4}, \ref{fig:d5} a \ref{fig:d6}. Model SSD má pro některé hůře detekovatelné tramvaje horší výsledky než model SSDlite, jako například snímky \ref{fig:d4} a \ref{fig:side4}, avšak SSDlite má větší počet false pozitivů.
  
% false positives
% 0 5 8 9 10 15 16 
\begin{figure}
  \captionsetup[subfigure]{justification=raggedright}
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/5.jpg}
    \caption{}
    \label{fig:fp1}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/16.jpg}
    \caption{}
    \label{fig:fp2}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/8.jpg}
    \caption{}
    \label{fig:fp3}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/9.jpg}
    \caption{}
    \label{fig:fp4}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/10.jpg}
    \caption{}
    \label{fig:fp5}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/15.jpg}
    \caption{}
    \label{fig:fp6}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/0.jpg}
    \caption{}
    \label{fig:fp7}
  \end{subfigure}  
\hfill
%1 3 4 6 12 13 

  \caption{Všechny detekce všech vytrénovaných sítí na vybraných snímcích obsahujíc nulový počet zcela nepřekrytých tramvají.}
    \label{fig:fp}
\end{figure}

\begin{figure}
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/1.jpg}
    \caption{}
    \label{fig:d1}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/3.jpg}
    \caption{}
    \label{fig:d2}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/4.jpg}
    \caption{Tramvaj byla detekována navzdory lehké překážce.\newline}
    \label{fig:d3}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/6.jpg}
    \caption{Tramvaj nejbližší kameře má vysokou variaci dektekcí. SSDlite (růžová) má správnou detekci kvalitnější než SSD (žlutá). }
    \label{fig:d4}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/12.jpg}
    \caption{}
    \label{fig:d5}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/13.jpg}
    \caption{}
    \label{fig:d6}
  \end{subfigure} 

%1 3 4 6 12 13 

  \caption{Všechny detekce všech vytrénovaných sítí na vybraných snímcích obsahujíc tramvaje hůře detekovatelné, anebo tramvají zvýšený počet. Tramvaje na snímcích \ref{fig:d1}, \ref{fig:d2}, \ref{fig:d3} a s výjimkou tramvaje nejbližší kameře \ref{fig:d4} byly perfektně detekovány všemi předtrénovanými sítěmi kromě Faster R-CNN MobileNet. }
    \label{fig:d}
\end{figure}

% zatacka
\begin{figure}
  \captionsetup[subfigure]{justification=raggedright}
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/11cut1.jpg}
    \caption{Detekce na snímku obsahujícím tramvaj ze strany, tramvaj velmi vzdálenou a dodávku. FCOS (zelená) nejenže chybně detekoval dodávku jako tramvaj, ale také si ji spojil se vzdálenou tramvají do jednoho objektu. }
    \label{fig:side1}
  \end{subfigure}  
\hfill
  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/14cut1.jpg}
    \caption{Detekce na snímku obsahujícím tramvaj ze strany, tramvaj velmi vzdálenou a osobní automobil. \newline\newline}
    \label{fig:side2}
  \end{subfigure} 

  \begin{subfigure}{19em}
    \includegraphics[width=19em]{obrazky/dataset/7.jpg}
    \caption{Detekce na snímku obsahujícím velmi vzdálenou tramvaj a dodávku. Vzdálená tramvaj byla detekována sítěmi FCOS, RetinaNet a Faster R-CNN ResNet.\newline\newline}
    \label{fig:side3}
  \end{subfigure}
\hfill
  \begin{subfigure}{19em}
    \raggedright
    \includegraphics[width=19em]{obrazky/dataset/2cut1.jpg}
    \caption{Detekce na snímku obsahujícím tramvaj v zatáčce. Strana tramvaje má alespoň jednu nesprávnou detekci od každého předtrénovaného modelu. Správná detekce modelu SSDlite (růžová) je lepší než správná detekce SSD (žlutá).}
    \label{fig:side4}
  \end{subfigure}  
  \caption{Všechny detekce všech vytrénovaných sítí na vybraných snímcích pořízených ze stejného místa pod podobným úhlem. Všechny kromě \ref{fig:side3} jsou pro čitelnost ořízlé.}
  \label{fig:side}
\end{figure}
\chapter{Závěr}
Cílem bakalářské práce bylo popsat funkci konvolučních neuronových sítí a vytvořit systém schopný detekce pozice a rozměru tramvaje ohraničujícím boxem. Tento cíl byl splněn. Výstupem je aplikace schopná podat informaci o~všech tramvajích na vstupu. Došlo k~vytrénovaní řady modelů. Tyto modely byly následně porovnány. Uživatel má na výběr ze všech vytrénovaných modelů. Některé tramvaje jsou snadněji detekovatelné než jiné. Ačkoliv cílem bylo detekovat pouze přední a zadní stranu tramvaje, mezi detekcemi se často nachází také část strany boční nebo střechy. Nejkvalitnějším je model Faster R-CNN ResNet, ovšem ten je výpočetně velmi drahý. Modely SSD a SSDlite jsou si kvalitou i výpočetní cenou velmi podobné. Model SSDlite podá v některých výjimečných případech přesnější detekci, zatímco model SSD má menší počet false pozitivů. Stejným způsobem podobné jsou si modely FCOS a RetinaNet, kde RetinaNet je ze všech předtrénovaných modelů nejnáchylnější na detekci nesprávné strany tramvaje, zatímco FCOS často detekuje danou tramvaj více než jednou. Oba jsou ale kvalitnější než obě varianty SSD. Model Faster R-CNN MobileNet má s přehledem největší počet false pozitivů a nepřesných detekcí. 

Práce může být dále rozšířena vylepšením datové sady, jako například zvětšením počtu tramvají nebo anotace existujících dat tak, aby ohraničující boxy obsahovaly co nejmenší počet pixelů nepatřící dopravnímu prostředku. Na míru vytvořená architektura může být vylepšena optimalizací hyperparametrů například zněkolikanásobením počtu parametrů a prozkoumáním alternativních aktivačních a cenových funkcí. Zcela neprozkoumaným prostorem je využití segmentace místo ohraničujících boxů a filtrování vzniklých výsledků. Vzniklý program je otevřen možnosti přidání detekce skutečných rozměrů a pozice a optimalizaci zvýšením počtu využitých jader procesoru. 
%\end{document}
