\documentclass[]{article}
\usepackage[T1]{fontenc}
\usepackage{polski}
\usepackage[utf8]{inputenc}
\usepackage[margin=1.25in]{geometry}
\usepackage{alltt}
\usepackage{titling}
\usepackage{pdfpages}
\usepackage{float}
\usepackage{amsmath}
\usepackage{booktabs}
\usepackage{tabularx}
\usepackage{amstext}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage{xspace}
\usepackage{enumerate}
\usepackage{lmodern}
\usepackage{amsfonts}
\usepackage{mathtools}
\usepackage{graphicx}
\usepackage{algorithm}
\usepackage{algpseudocode}
\usepackage{wrapfig}
\usepackage[polish]{babel}
\usepackage{etoolbox}
\usepackage{subcaption}
\usepackage{multirow} % kurwa

\pgfplotsset{compat=1.15}
\usepgfplotslibrary{groupplots}

\DeclarePairedDelimiter\ceil{\lceil}{\rceil}
\DeclarePairedDelimiter\floor{\lfloor}{\rfloor}

\usetikzlibrary{decorations.pathmorphing, arrows.meta, positioning}
\usetikzlibrary{shapes.geometric, arrows, intersections}
\usetikzlibrary{external}
\tikzexternalize

\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}%

% opening
\title{Retusz starych zdjęć \\ \small{Projekt ze Sztzucznej Inteligencji, WETI, PG 2018}}
\author{\protect\begin{tabular}{ll|l}
    Szymon Szczyrbak & \textit{165760} & Informatyka 2016/2017 \\
    Kacper Donat     & \textit{165581} & Semestr IV, gr. 1
\protect\end{tabular}}
\floatname{algorithm}{Program}

\makeatletter
\newcommand{\imgresult}[1]{%
    \gdef\tablerow{
        \includegraphics[height=1.6cm]{out/#1_damaged.jpg} &%
        \foreach \v in {damaged,1,2,4,8,16,32,64,128,200} {%
            \includegraphics[height=1.6cm]{out/#1_\v.jpg} &%
        }%
        \includegraphics[height=1.6cm]{out/#1_ok.jpg} \\%
    }%
}
\makeatother

\begin{document}
    \maketitle
    \section{Cel projektu}
    Celem projektu było przygotowanie programu, który w sposób automatyczny umożliwiałby retuszowanie starych zdjęć z
    wykorzystaniem technik sztucznej inteligencji.

    \begin{figure}[H]
        \centering
        \includegraphics{./oczekiwane.jpg}
        \caption{Oczekiwany rezultat działania aplikacji}
    \end{figure}

    Do realizacji celu zdecydowano się wykorzystać technikę GAN\footnote{https://arxiv.org/abs/1406.2661} zakładającą
    stworzenie 2 sieci neuronowych, próbujących się wzajemnie oszukać. Jedna sieć - Generator - odpowiada za generowanie danych na
    podstawie wektora wejściowego (w tym wypadku uszkodzonego zdjęcia) starając się przekonać drugą sieć -
    Dyskryminatora - że jest to nieuszkodzone zdjęcie.

    \subsection{Pozyskanie datasetu}
    Jednym z problemów, na które natknęliśmy się podczas opracowywania rozwiązania był brak dostępnego wystarczająco
    dużego datasetu, mogącego posłużyc do wyuczenia sieci. aby poradzić sobie z tym problemem została napisana aplikacja
    umożliwająca generyczne niszczenie zdjęć.

    \begin{figure}[H]
        \centering
        \begin{tikzpicture}[node distance=1.5cm]
            \node (in) {\includegraphics[height=2cm]{steps/in.jpg}};
            \node[right=of in] (sepia) {\includegraphics[height=2cm]{steps/sepia.jpg}};
            \node[right=of sepia] (brightness) {\includegraphics[height=2cm]{steps/brightness.jpg}};
            \node[below=of in] (noise) {\includegraphics[height=2cm]{steps/noise.jpg}};
            \node[right=of noise] (decals) {\includegraphics[height=2cm]{steps/decals.jpg}};
            \node[right=of decals] (blur) {\includegraphics[height=2cm]{steps/blur.jpg}};

            \draw [->] (in) -- node [above] {sepia} (sepia);
            \draw [->] (sepia) -- node [above] {jasność} (brightness);
            \draw [->] (brightness) -- node [sloped, above] {szum} (noise);
            \draw [->] (noise) -- node [above] {zniszczenia} (decals);
            \draw [->] (decals) -- node [above] {rozmycie} (blur);
        \end{tikzpicture}
        \caption{Proces niszczenia zdjęć}
    \end{figure}

    Każdy z kroków jest parametryzowalny, oraz każde zdjęcie zawiera losową zmianę do parametru w celu zapobiegnięcia
    zbyt szybkiemu overfittingowi sieci.
    
    \subsection{Architektura modelu GAN}
    Technika GAN zakłada jednoczesne uczenie dwóch modelów: generatora i dyskryminatora. W niniejszym projekcie dla generatora wejściem jest uszkodzone zdjęcie i wyjsciem jest zdjęcie po retuszu, a dla dyskryminatora wejściem jest zdjęcie po retuszu, a wyjściem jest mapa wartości od $0.0$ do $1.0$ oceniających prawdopodobieństwo przynależności wejściowego zdjęcia do datasetu zawierającego prawidłowo wyretuszowane zdjęcia.
    
    Dyskryminator to sztuczna sieć neuronowa składająca się z czterech warstw konwolucyjnych (filtr 4x4x3, krok 1x1 i liczba map aktywacji dla pierwszej warstwy równa 32 i dla kolejnych dwukrotnie większa od liczby warstwy poprzedniej) i dodatkowej warstwy wyjściowej zwracającej jedną mapę o głębokości 1. W warstwach ukrytych po konwolucji wykonywana jest normalizacja. We wszystkich warstwach opróch warstwy wyjściowej stosowana jest funkcja aktywacyji LeakyReLU o $\alpha = 0.2$. W warstwie wyjściowej zastosowano funckję aktywacji Sigmoid.
    
    Generator składa się identycznie tak jak dyskryminator z czterech warstw konwolucyjnych oraz dodatkowych lustrzanie zbudowanych warstw dekonwolucyjnych. W warstwie wyjściowej przed dekonwolucją stosowana się dodatkowa funkcja aktywacyji LeakyReLU, a po dekonwolucji zastosowano funkcję aktywacyji tanh.
    
    Obie sieci neuronowe są uczone dostarczonym przez bibliotekę PyTorch algorytmem Adam o tempie uczenia $lr = 0.0002$. 
    Użyte funkcje straty generatora $G_{loss}$ i dyskryminatora $D_{loss}$ zdefiniowano poprzez funkcje straty L1 oraz Binary Cross-Entropy jako:
    $$G_{loss} = BCE(D(G(x), real) + \lambda L1(G(x), y)$$
    $$D_{loss} = BCE(D(y),real_{smooth}) + BCE(D(G(x)),fake_{smooth})$$
    gdzie $x$ to zniszczone zdjęcie z datasetu, a $y$ to wyretuszowane zdjęcie z datasetu. $real$ to mapa wartości $1.0$ opisująca perfekcyjnie zretuszowanie zdjęcia, a $fake$ to analogiczna mapa samych $0.0$.
    Dodanie do funkcji straty generatora sterowanej parametrem $\lambda = 100$ straty L1 zdaje się zapobiegać nauce oszukiwania dyskryminatora poprzez manipulacje kolorem palety barw zdjęcia.
    Jako że dyskryminator uczy się oceniać jakość retuszu znacznie szybciej, niż generator uczy się dobrze retuszować, spowolniono szybkość jego nauki techniką znaną jako label smoothing dodając do $real$ i $fake$ losowy szum z zakresu kolejno od $-0.3$ do $0.2$ oraz od $0.0$ do $0.3$, w wyniku uzyskując $real_{smooth}$ i $fake_{smooth}$.
    


    \section{Rezultaty}
    \begin{center}\textit{\color{red} wstaw budowę sieci plox
    - nope jest textowo opisana}\end{center}

    \begin{figure}[H]
        \centering
        \begin{tikzpicture}
            \begin{axis}[grid=both, width=\linewidth, height=8cm, no marks, xmin=0, xmax=200, xlabel={Epoka}, ylabel={Strata}]
                \addplot[very thin, blue] table [x=epoch,y=g,col sep=comma] {iterations.csv};
                \addplot[very thick] table [x=epoch,y=g,col sep=comma] {loss.csv};
            \end{axis}
        \end{tikzpicture}
        \caption{Funkcja straty dla generatora}
        \label{fig:results}
    \end{figure}

    \begin{figure}[H]
        \centering
        \begin{tikzpicture}
            \begin{axis}[grid=both, width=\linewidth, height=8cm, no marks, xmin=0, xmax=200, xlabel={Epoka}, ylabel={Strata}]
                \addplot[very thin, red] table [x=epoch,y=d,col sep=comma] {iterations.csv};
                \addplot[very thick] table [x=epoch,y=d,col sep=comma] {loss.csv};
            \end{axis}
        \end{tikzpicture}
        \caption{Funkcja straty dla dyskryminatora}
    \end{figure}
     
    \begin{table}[H]
        \centering
        \def\arraystretch{.6}
        \setlength{\tabcolsep}{0pt} % for the horizontal padding
        \begin{tabular}{cccccccccccc}
            zniszczone & 1 & 2 & 4 & 8 & 16 & 32 & 64 & 128 & 200 & oczekiwane \tabularnewline \hline
            \input{table.tex}
        \end{tabular}
        \caption{Zestawienie wyników dla kolejnych epok, zdjęcia z 3 oraz 4 rzędu pochodzą z internetu, pozostałe zostały zniszczone generycznie}
    \end{table}

    \subsection{Obserwacje}
    Powyższe dane zostały pozyskane z uczenia sieci na datasecie zawierajacym 100 różnych elementów. W zestawieniu
    \ref{fig:results} wyraźnie widać, że wraz z każdą generacją generator osiąga coraz lepsze wyniki jednak, od pewnego
    momentu szybkość uczenia się zdecydowanie maleje.

    \subsection{Problemy}
    Głównym blokujący problemem podczas rozwijania projektu były niezwykle długie czasy uczenia się sieci na CPU, oraz
    dość wysoka podatność na zmiany w parametrach sieci czy wygenerowanego datasetu, nie pozwoliło to na zrobienie zbyt
    wielu iteracji programu, a tym samym na jego skuteczny rozwój. 

    Wyraźnie również widać przekolorowanie na obrazkach oraz zmianę jasności - prawdopodobnie oba te problemy wynikają z
    zastosowania normalizacji zarówno wektora wejściowego jak i na poszczególnych etapach Generatora oraz przy konwersji
    z tensorów, którymi posługuje się do obrazów. 

    Po sprawdzeniu kilku różnych zestawu danych do uczenia się, można zauważyć, że efekty na obrazach pochodzących z
    realnego śiata są do siebie bardzo podobne, co wskazywałoby na relatywną stabilność rozwiązania i problem ze
    sposobem generowania danych, który dostarcza zbyt mało różnorodne wejście. Problem ten można by rozwiązać
    wykorzystując dataset zbudowany na podstawie kilku różnych metod generowania zniszczeń, bądź najlepiej wykorzystując
    dane pochodzące z realnego świata.

    Dodatkową trudnością jest fakt, że sieć nie tylko musi nauczyć się generować brakujące części obrazu ale też
    decydować, które części są uszkodzeniem, a które detalem do zachowania. Problem ten widać w 3 wierszu prezentowanych
    danych - wzór na koszuli został uznany za uszkodzenie i usunięty przez sieć.
\end{document}


