---
fontsize: 8pt
bibliography: 9_Referenzen.bib
citation_package: natbib
output:
  beamer_presentation:
    keep_tex: true
    includes:
      in_header: 9_header.tex
---


```{r, include = F}
source("9_R_common.R")
```

#  {.plain}
\center
```{r, echo = FALSE, out.width = "20%"}
knitr::include_graphics("9_Abbildungen/mvda_9_otto.png")
```

\vspace{2mm}

\Huge
Multivariate Datenanalyse
\vspace{6mm}

\Large
MSc Psychologie WiSe 2021/22

\vspace{6mm}
\large
Prof. Dr. Dirk Ostwald

# {.plain}
\vfill
\center
\huge
\textcolor{black}{(9) Neuronale Netze}
\vfill

# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

Funktionale Architektur

Lernen

Backpropagation

Anwendungsbeispiel

Selbstkontrollfragen
\vfill


# {.plain}
\vfill
\setstretch{2}
\large
**Vorbemerkungen**

Funktionale Architektur

Lernen

Backpropagation

Anwendungsbeispiel

Selbstkontrollfragen
\vfill

# Vorbemerkungen
\textcolor{darkblue}{Struktur der Prädiktiven Modellierung}

\begin{minipage}{.6\textwidth}
```{r, echo = FALSE, out.width = "80%"}
knitr::include_graphics("9_Abbildungen/mvda_9_prädiktive_modellierung_1.pdf")
```
\end{minipage}
\begin{minipage}{.4\textwidth}
```{r, echo = FALSE, out.width = "100%"}
knitr::include_graphics("9_Abbildungen/mvda_9_prädiktive_modellierung_2.pdf")
```
\end{minipage}

\flushright
\tiny
nach @dwyer_2018
\vspace{3mm}

\flushleft
\small
Rhetorik der Prädiktiven Modellierung

\center
\begin{tabular}{ll}
Daten                     & Trainingsdaten und Testdaten                  \\
Statistisches Modell      & Modell, Machine Learning Algorithmus          \\
Schätzen von Parametern   & Trainieren des Modells, Lernen von Parametern, Supervised Learning
\end{tabular}

# Vorbemerkungen
\textcolor{darkblue}{Neuronale Netze (Neural Networks)}

\small

* AKA *Künstliche Neuronale Netze (Artificial Neural Networks)*.
* Keine Modelle für biologische neuronale Netze.
* Mathematische Modelle zur Approximation multivariater vektorwertiger Funktionen.

\vspace{3mm}
Typische Visualisierungen


\begin{minipage}{.5\linewidth}
```{r, echo = FALSE, out.width = "90%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neural_network.pdf")
```
\end{minipage}
\begin{minipage}{.5\linewidth}
```{r, echo = FALSE, out.width = "90%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neuron.pdf")
```
\end{minipage}

# Vorbemerkungen

\textcolor{darkblue}{Zur Geschichte neuronaler Netze}

\footnotesize
Anfänge

* @mcculloch_1943 | Analyse der mit biologischen Neuronen möglichen logischen Operationen.
* @rosenblatt_1958 | Implementation eines Mustererkennungsalgorithmus in einem frühen Computer.
* @minsky_1969 | Mathematische Analyse der logischen Stärken und Schwächen eines Perzeptrons.

$\quad\quad\quad\Rightarrow$ Erster Winter Neuronaler Netze

Erste Renaissance

* @hopfield_1982 | Mehrschichtige neuronale Netze beleben das Interesse an neuronalen Netzen erneut.
* @rumelhart_1986 | Popularisierung des Backpropagation Algorithmus.
* Hauptinteresse in den 1990er und 2000er Jahren im Machine Learning gilt aber SVMs und Bayesian Inference.

$\quad\quad\quad\Rightarrow$ Zweiter Winter Neuronaler Netze

Zweite Renaissance

* 2009 - 2012 | @schmidhuber_2015  gewinnen Klassifikationswettbewerbe mit neuronalen Netzen.
* @lecun_2015 | Neuronale Netze unter dem Label "Deep Learning" wieder sehr in Mode.
* 2015 - 2022 | Viele Menschen verwechseln die Begriffe "Künstliche Intelligenz" und "Neuronales Netz".
* @ostwald_2021 | Beweis der Validität des Backpropagation Algorithmus in Matrixform.

# Vorbemerkungen
\textcolor{darkblue}{Neuronale Netze und Prädiktive Modellierung}
\vspace{3mm}

```{r, echo = FALSE, out.width = "80%"}
knitr::include_graphics("9_Abbildungen/mvda_9_prädiktive_vs_explanatorische_modellierung.pdf")
```
\vspace{3mm}

\small
$\Rightarrow$ Neuronale Netze zur Approximation  multivariater vektorwertiger Funktionen im prädiktiven Sinn.

# Vorbemerkungen
\textcolor{darkblue}{Universelle Approximationstheoreme}
\small
\setstretch{1.8}

Topologische Aussagen über die Dichten von Funktionenräumen (cf. @friedman_1970).

Neuronale Netze können eine Vielzahl von Funktionen sehr genau approximieren, wenn

* \small \justifying die Anzahl der Neurone gegen Unendlich geht (*arbitrary width case*) bzw.
* die Anzahl der Neuronenschichten gegen Unendlich geht (*arbitrary depth case*).


Arbitrary width case $\Rightarrow$ @cybenko_1989, @hornik_1991, @leshno_1993, @pinkus_1999

Arbitrary depth case $\Rightarrow$ @lu_2017a, @hanin_2018, @kidger_2020

Universelle Approximationstheoreme sind Existenzaussagen, keine Konstruktionsaussagen.

$\quad\Rightarrow$ Parameter neuronaler Netze müssen durch Gradientenverfahren gelernt werden.

# Vorbemerkungen
\textcolor{darkblue}{Universelle Approximationstheoreme}

\small
Beispiel
\footnotesize
\setstretch{1.2}
\begin{theorem}[Universelles Approximationstheorem nach Kidger (2020)]
\justifying
\normalfont
$\mathcal{X}$ sei eine kompakte Teilmenge von $\mathbb{R}^m$, $\sigma:\mathbb{R} \to \mathbb{R}$
sei eine nicht-affine stetige und zumindest in einem Punkt stetig differenzierbare Funktion
mit einer von Null verschiedenen Ableitung in diesem Punkt. $F$ sei
die Menge der neuronalen Netze $f$ mit Inputdimension $m$, Outputdimension $n_k$ und einer
beliebigen Anzahl verdeckter Schichten mit jeweils $m + n_k + 2$ Neuronen und Aktivierungsfunktion
$\sigma$, sowie der Identitätsabbildung als Aktivierungsfunktion der Outputschicht. 
Dann existiert zu jeder stetigen multivariaten vektorwertigen Funktion
\begin{equation}
g : \mathcal{X} \to \mathbb{R}^{n_k}, x \mapsto g(x)
\end{equation}
ein neuronales Netz $f \in F$, so dass für ein beliebig kleines
$\epsilon > 0$ gilt, dass
\begin{equation}
\sup_{x \in \mathcal{X}} \Vert f(x) - g(x) \Vert < \epsilon.
\end{equation}
\end{theorem}

Bemerkungen

* \justifying Das Supremum $\sup$ kann intuitiv als Maximum verstanden werden.
* $\Vert \cdot \Vert$ bezeichnet eine *Metrik* (Abstandsfunktion) auf $\mathbb{R}^{n_k}$.
* Für jedes $x \in \mathcal{X}$ wird der Abstand zwischen dem Wert von $g$ und dem Wert von $f$ also beliebig klein.
* Man sagt dazu auch, dass $F$ im Raum der stetigen multivariaten vektorwertigen Funktionen *dicht* ist.
* Man kann das Theorem sicherlich noch präziser formulieren und sollte es beweisen. 
* Wir verzichten hier darauf und führen das Theorem nur als "intuitives Beispiel" auf.

# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

**Funktionale Architektur**

Lernen

Backpropagation

Anwendungsbeispiel

Selbstkontrollfragen
\vfill



# Funktionale Architektur
\setstretch{1.1}
\footnotesize
\begin{definition}[Potentialfunktionen]\label{def:potential_functions}
\justifying
$W \in \mathbb{R}^{m \times (n+1)}$ sei eine Matrix, die wir \textit{Wichtungsmatrix}
nennen und $a \in \mathbb{R}^n$  sei ein Vektor, den wir \textit{Aktivierungsvektor}
nennen. Dann nennen wir eine Funktion der Form
\begin{equation}\label{eq:Phi}
\Phi : \mathbb{R}^{m \times (n+1)} \times \mathbb{R}^{n} \to \mathbb{R}^m,
(W,a) \mapsto \Phi(W,a)
:= W\cdot
\begin{pmatrix}
a \\ 1
\end{pmatrix}
\end{equation}
eine \textit{bivariate Potentialfunktion}. Für ein festes $a \in \mathbb{R}^n$
nennen wir eine Funktion der Form
\begin{equation}\label{eq:Phi_a}
\Phi_a : \mathbb{R}^{m \times (n+1)} \to \mathbb{R}^m, \,
W \mapsto \Phi_a(W) := \Phi(W,a)
\end{equation}
eine \textit{Wichtungsmatrix-variate Potentialfunktion}. Weiterhin nennen wir für
eine feste Matrix  $W \in \mathbb{R}^{m \times (n+1)}$ eine Funktion der Form
\begin{equation}\label{eq:Phi_W}
\Phi_W : \mathbb{R}^{n} \to \mathbb{R}^m,
a \mapsto \Phi_W(a) := \Phi(W,a)
\end{equation}
eine \textit{Potentialfunktion}. Schließlich nennen wir $z := \Phi_W(a)$ einen
\textit{Potentialvektor}.
\end{definition}

\footnotesize
\begin{definition}[Aktivierungsfunktion]\label{def:activation_functions}
\justifying
Wir nennen eine multivariate vektorwertige Funktion der Form
\begin{equation}\label{eq:Sigma}
\Sigma : \mathbb{R}^n \to \mathbb{R}^n,
z \mapsto \Sigma(z) := (\sigma(z_1), ..., \sigma(z_n))^T,
\end{equation}
mit
\begin{equation}\label{eq:sigma}
\sigma: \mathbb{R} \to \mathbb{R},
z_i \mapsto \sigma(z_i) =: a_i
\mbox{ für alle } i = 1,...,n,
\end{equation}
eine \textit{komponentenweise Aktivierungsfunktion} und die
univariate reellwertige Funktion $\sigma$ eine \textit{Aktivierungsfunktion}.
\end{definition}

# Funktionale Architektur
Typische Aktivierungsfunktionen und ihre Ableitungen
\vspace{3mm}
\small
\begin{tabularx}{\textwidth}{XXX}
Name
& Definition
& Ableitung
\\
\hline
\\
Standard logistic
& $\sigma(z_i) := \frac{1}{1+\exp(-z_i)}$
& $\sigma'(z_i) = \frac{\exp(z_i)}{(1 + \exp(z_i))^2}$
\\
\\
Hyperbolic tangent
& $\sigma(z_i) := \mbox{tanh}(z_i)$
& $\sigma'(z_i) = 1 - \mbox{tanh}^2(z_i)$
\\
\\
ReLU
& $\sigma(z_i) := \max(0, z_i)$
& $\sigma'(z_i) =
\begin{cases}
0, 					& z_i < 0 \\
\emptyset,			& z_i = 0 \\
1, 					& z_i > 0 \\
\end{cases}$
\\
\\
Leaky ReLU
&
$\sigma(z_i) :=
\begin{cases}
0.1z_i,	& z_i \le 0 	\\
z_i, 		& z_i > 0 	\\
\end{cases}$
& $\sigma'(z_i) =
\begin{cases}
0.01,		& z_i \le 0 	\\
1, 			& z_i > 0 	\\
\end{cases}$
\\
\end{tabularx}


# Funktionale Architektur
Typische Aktivierungsfunktionen und ihre Ableitungen
\vspace{1cm}

```{r, echo = F, out.width = "100%"}
knitr::include_graphics("9_Abbildungen/mvda_9_aktivierungsfunktionen.pdf")
```

# Funktionale Architektur
\footnotesize
\begin{definition}[$k$-schichtiges neuronales Netz]\label{def:neural_network}
Eine multivariate vektorwertige Funktion
\begin{equation}
f : \mathbb{R}^{n_0} \to \mathbb{R}^{n_k}, x \mapsto f(x) =: y
\end{equation}
heißt  \textit{$k$-schichtiges neuronales Netz}, wenn $f$ von der Form
\begin{multline}
f : \mathbb{R}^{n_0}
\xrightarrow[]{\Phi^1_{W^1}}
\mathbb{R}^{n_1}
\xrightarrow[]{\Sigma^1}
\mathbb{R}^{n_1}
\xrightarrow[]{\Phi^2_{W^2}}
\mathbb{R}^{n_2}
\xrightarrow[]{\Sigma^2}
\mathbb{R}^{n_2}
\xrightarrow[]{\Phi^3_{W^3}}
\\
\cdots
\xrightarrow[]{\Phi^{k-1}_{W^{k-1}}}
\mathbb{R}^{n_{k-1}}
\xrightarrow[]{\Sigma^{k-1}}
\mathbb{R}^{n_{k-1}}
\xrightarrow[]{\Phi^k_{W^k}}
\mathbb{R}^{n_{k}}
\xrightarrow[]{\Sigma^{k}}
\mathbb{R}^{n_{k}},
\end{multline}
ist, wobei für  $l = 1,...,k$
\begin{equation}
\Phi^l_{W^l} : \mathbb{R}^{n_{l-1}} \to \mathbb{R}^{n_l},
a^{l-1} \mapsto \Phi^l_{W^l}(a^{l-1}) :=
W^l
\cdot
\begin{pmatrix}
a^{l-1} \\ 1
\end{pmatrix}
=: z^l
\end{equation}
Potentialfunktionen und
\begin{equation}
\Sigma^l : \mathbb{R}^{n_l} \to \mathbb{R}^{n_l},
z^l \to \Sigma^l(z^l) =: a^l
\end{equation}
komponentenweise Aktvierungsfunktionen sind. Für ein $x \in \mathbb{R}^{n_0}$
nimmt ein $k$-schichtiges neuronales Netz den Wert
\begin{equation}
f(x) :=
\Sigma^{k}
(\Phi^k_{W^k}(\Sigma^{k-1}(\Phi^{k-1}_{W^{k-1}}(\Sigma^{k-2}(\cdots(\Sigma^{1}(\Phi^1_{W^1}(x))\cdots))))))
\in \mathbb{R}^{n_k}.
\end{equation}
an.
\end{definition}

# Funktionale Architektur
\footnotesize
Bemerkungen
\setstretch{1.8}

* \justifying Die Vektoren $a^l = (a_1^l, ..., a_{n_l}^l)^T \in \mathbb{R}^{n_l}, l = 0,1,..., k$ heißen *Aktivierungsvektoren der $l$ten Schicht*.
* Die Komponenten $a_i^l \in \mathbb{R},i = 1,...,n_l, l = 0,1,...,k$ heißen *Aktivierungen der $l$ten Schicht*.
* Die Schicht mit Index $l = 0$ und Dimension $n_0$ heißt *Inputschicht*.
* Der Aktivierungsvektor mit Index $l = 0$ heißt *Input* und wird mit $x := a^0$ bezeichnet.
* Die Schicht mit Index $l = k$ und Dimension $n_k$ heißt *Outputschicht*
* Der Aktivierungsvektor mit Index $l = k$ heißt Output und wird mit $y := a^k$ bezeichnet.
* Die Schichten mit den Indizes $l = 1,...,k-1$ heißen *verdeckte Schichten (hidden layers)*.
* $w_{ij}^l \in \mathbb{R}$ sei der $ij$te Eintrag der $l$ten Wichtungsmatrix, d.h.
\begin{equation}
W^l = (w_{ij}^l)_{1 \le i \le n_l, 1 \le j \le n_{l-1}+1} \in \mathbb{R}^{n_l \times (n_{l-1}+1)}
\mbox{ für }
l = 1,...,k.
\end{equation}
* $w_{ij}^l$ heißt *(synaptisches) Gewicht* der Verbindung von Neuron $j$ in Schicht $l-1$ and Neuron $i$ in Schicht $l$.
* Für $i = 1,...,n_l$ heißt $w_{i,n_{l-1}+1}$ *Bias* von Neuron $i$ in Schicht $l$.
* Die letzte Spalte von $W^l$ enkodiert also die Biases für die Neuronen in Schicht $l$.

# Funktionale Architektur
\footnotesize
Bemerkungen

Auf der Ebene einzelner Neurone ergibt sich damit folgende Nomenklatur:

* Das *Potential* von Neuron $i$ in Schicht $l$ für $i = 1,...,n_l$ und $l = 1,...,k$  ist gegeben durch
\begin{equation}
z_i^l = \sum_{j = 1}^{n_{l-1}} w^l_{ij}  a_j^{l-1} + w_{i, n_{l-1} + 1} \in \mathbb{R}.
\end{equation}

* Die *Aktivierung* von  Neuron $i$ in Schicht $l$ für $i = 1,...,n_l$ und $l = 1,...,k$ ist gegeben durch
\begin{equation}
a_i^l = \sigma\left(\sum_{j = 1}^{n_{l-1}} w^l_{ij}  a_j^{l-1} + w_{i, n_{l-1} + 1} \right) \in \mathbb{R},
\end{equation}

* Die Aktivierung $a_i^l$ kann als die mittlere Feuerungsrate des $i$ten Neuron in der $l$ten Schicht verstanden werden.


# Funktionale Architektur
```{r, echo = FALSE, out.width = "80%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neuron_annotated.pdf")
```

# Funktionale Architektur
Beispiel

\small
$k = 3, n_0 = 2, n_1 = 3$, $n_2 = 3, n_3 = 2$


```{r, echo = FALSE, out.width = "100%"}
knitr::include_graphics("9_Abbildungen/mvda_9_beispiel_1.pdf")
```

Es gilt $x = a^0$ und $a^3 = y$.


# Funktionale Architektur
Beispiel

\small
$k = 3, n_0 = 2, n_1 = 3$, $n_2 = 3, n_3 = 2$


```{r, echo = FALSE, out.width = "40%"}
knitr::include_graphics("9_Abbildungen/mvda_9_beispiel_2.pdf")
```

Es gilt $x = a^0$ und $a^3 = y$.

# Funktionale Architektur
Beispiel

\small
$k = 3, n_0 = 2, n_1 = 3$, $n_2 = 3, n_3 = 2$

```{r, echo = FALSE, out.width = "60%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neural_network_annotated.pdf")
```

* Die Biases sind hier nicht visualiert.

# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

Funktionale Architektur

**Lernen**

Backpropagation

Anwendungsbeispiel

Selbstkontrollfragen
\vfill

# Lernen
\textcolor{darkblue}{Überblick}
\small
\justifying

Anhand eines Trainingsdatensatzes werden die Parameter eines neuronalen Netzes  wie folgt gelernt:

* \justifying Zunächst wird eine Funktion definiert, die misst, inwiefern sich bei einem 
gegebenen Inputvektor und Zielvektor der Output des neuronalen Netzes basierend
auf einem Wert der Parameter unterscheidet. Diese Funktion nennt
man eine *Kostenfunktion* oder *Zielfunktion*.

* Der summierte Wert der Kostenfunktion über alle Trainingsdatenpunkte wird dann 
durch Veränderung der Parameter minimiert, so dass Parameterwerte
gefunden werden, für die die Abweichung zwischen Zielvektor und Output des neuronalen
Netzes bei gegebenemen Inputvektor möglichst gering ist.

* Zur Minimierung der Kostenfunktion wird üblicherweise ein Gradientenverfahren benutzt.

* \justifying Zur Berechnung der in diesem Verfahren auftretenden Zielfunktionsgradienten wird 
ein komputational effizienter Algorithmus eingesetzt, der die spezielle Struktur neuronaler 
Netze ausnutzt und unter dem Namen *Backpropagation Algorithmus* bekannt ist.

In der Folge wollen wir die Aspekte dieses Lernprozesses genauer betrachten.



# Lernen
\small
\begin{definition}[Trainingsdatensatz]
Ein \textit{Trainingsdatensatz} für ein neuronales Netz ist eine Menge
\begin{equation}
\mathcal{D}
:= \lbrace(x^{(i)}, y^{(i)})\rbrace_{i=1}^n,
\end{equation}
wobei $x^{(i)} \in \mathbb{R}^{n_0}$ \textit{Featurvektor} und $y^{(i)} \in \mathbb{R}^{n_k}$
\textit{Zielvektor} genannt werden.
\end{definition}

Bemerkungen
\begin{itemize}
\item Im Kontext der zuvor betrachteten multivariaten Verfahren gilt hier $n_0 = m$.
\item Typische Zielvektorformate beim Training neuronaler Netze sind
\begin{itemize}
\begin{footnotesize}
\item[] $y^{(i)} \in \{0,1\}$ für binäre Klassifikationsprobleme,
\item[] $y^{(i)} \in \{0,1\}^{n_k}$ mit $\sum_{i=1}^{n_k} y_i = 1, n_k > 1$ für $n_k$-fache Klassifikationsprobleme,
\item[] $y^{(i)} \in \mathbb{R}^{n_k}, n_k > 1$ für Regressionsprobleme.
\end{footnotesize}
\end{itemize}
\end{itemize}

# Lernen
\small
\begin{definition}[Trainieren eine neuronalen Netzes]
\justifying
$f$ sei ein $k$-schichtiges neuronales Netz und $\mathcal{D}$ sei ein Trainingsdatensatz.
Dann bezeichnet der Begriff des \textit{Trainierens} den Prozess der Adaptation
der Wichtungsmatrizen $W^1, ..., W^k$ des neuronalen Netzes mit dem Ziel, ein
Abweichungskriterium zwischen der Ouptutaktivierung $f(x^{(i)})$ und dem assoziierten
Wert des Zielvektors $y^{(i)}$ über alle Trainingsdatenpunkte $(x^{(i)},y^{(i)}), i = 1,...,n$
des Trainingsdatensatzes $\mathcal{D}$ hinweg zu minimieren.
\end{definition}


Bemerkungen

* Wir erinnern an das Ziel $f := \mbox{argmin}_{\tilde{f} \in F} \Vert Y -  \tilde{f}(X) \Vert$ der prädiktiven Modellierung.
* Das erwähnte Abweichungskriterium wird in Form von *Kostenfunktionen* definiert.
* Wir benötigen noch den Begriff der *Wichtungsmatrix-variaten neuronalen Netzfunktion*.

# Lernen

\footnotesize
\begin{definition}[Wichtungsmatrix-variate neuronale Netzfunktion]\label{def:matrix_variate_neural_network_function}
\justifying
$f$ sei ein $k$-schichtiges neuronales Netz und $x$ sei ein Input von $f$. Dann ist
\textit{Wichtungsmatrix-variate neuronale Netzfunktion $f_x$ von $f$} definiert als die
Funktion
\begin{multline}\label{eq:f_x}
f_x : \mathbb{R}^{n_{1} \times (n_0 + 1)} \times \cdots \times \mathbb{R}^{n_{k} \times (n_{k-1} + 1)} \to \mathbb{R}^{n_k},
(W^1, ..., W^k) \mapsto f_x(W^1,...,W^k)
\\
:= \Sigma^k(\Phi^k(W^k,\Sigma^{k-1}(\Phi^{k-1}(W^{k-1}, \cdots (W^2,\Sigma^1(\Phi^1(W^1,x)))\cdots)))),
\end{multline}
wobei für $l = 1,...,k$, $\Phi^l$ die bivariate Potentialfunktion bezeichnet,
die der Potentialfunktion $\Phi^l_{W^l}$ in der Definition des neuronalen Netzes entspricht.
Weiterhin definieren wir für $l = 1,..., k$, die  \textit{Wichtungsmatrix-variate neuronale Netzfunktion der $l$ten Schicht $f_x^l$}
für festes fixed $W^\ell \in \mathbb{R}^{n_\ell \times (n_{\ell-1} + 1)}$m mit $\ell = 1,..., k$ und $\ell \neq l$ als
\begin{equation}\label{eq:f_x_l}
f_x^l : \mathbb{R}^{n_{1} \times (n_{l-1} + 1)} \to \mathbb{R}^{n_k},
W^l \mapsto f_x^l(W^l) := f_x^l(W^1, ..., W^k).
\end{equation}
\end{definition}

Bemerkungen

* \justifying Die Definition von $f$ in der Definition eines $k$-schichtiges neuronales Netzes
ist eine Funktion des Inputs $x$ bei festen Wichtungsmatrizen $W^1, ..., W^l$. Zum Trainieren eines 
neuronalen Netzes ist es aber entscheidend, bei festem Input den Output des neuronalen Netzes 
bei Variation der Parameter $W^1, ..., W^l$ zu monitoren. Dies motiviert den Begriff
der Wichtungsmatrix-variaten neuronalen Netzfunktion: Die Definition von $f_x$ in 
\eqref{eq:f_x} ist eine Funktion der Wichtungsmatrizen $W^1, ..., W^l$ bei festem Input $x$.


# Lernen
\footnotesize
\begin{definition}[Output-spezifische Kostenfunktionen]\label{def:cost_function_1}
$f$ sei ein $k$-schichtiges neuronales Netz und $y$ sei ein Zielvektor von $f$. Dann wird
eine multivariate reelwertige Funktion der Form 
\begin{equation}\label{eq:output_cost_function}
c_y : \mathbb{R}^{n_k} \to \mathbb{R}, a^k \mapsto c_y(a^k)
\end{equation}
\textit{Output-spezifische Kostenfunktion} genannt.
\end{definition}

Bemerkung

* \justifying Eine Output-spezifische Kostenfunktion $c_y$ misst die Abweichung des 
Outputs $a^k$ eines neuronalen Netzes von einem Zielvektor $y$. Untenstehende 
Tabelle führt zwei typische Beispiele für Output-spezifische Kostenfunktionen 
und ihre Gradienten, die in der Folge wichtig werden, auf.

\setstretch{1.6}
\begin{tabularx}{\textwidth}{ll}
\underline{Quadratische Kostenfunktion}
&
\\
Definition
& Gradient
\\
$c_y(a^k) := \frac{1}{2}\sum_{j=1}^{n_k}(a_j^k - y_j)^2$
& $\nabla c_y(a^k) := \left(a_j^k - y_j\right)_{j = 1,...,n_k}$
\\
\underline{Cross-entropy Kostenfunktion}
\\
Definition
& Gradient
\\
$c_y(a^k) := -\sum_{i=1}^{n_k}y_j \ln a_j^k + (1 - y_j)\ln (1-a_j^k)$
& $\nabla c_y(a^k) := \left(-\frac{y_j}{a_j^k} + \frac{1-y_j}{1-a_j^k}\right)_{j = 1,...,n_k}$
\end{tabularx}

# Lernen

\small
Output-spezifische Kostenfunktionswerte für $y = (0,1)^T$ bei logistischer Aktivierungsfunktion
\vspace{2mm}

```{r, echo = FALSE, out.width = "80%"}
knitr::include_graphics("9_Abbildungen/mvda_9_kostenfunktionen.pdf")
```

* Beide Funktionen haben ihr Minimum bei $a = y$.
* Die Pfeile bilden die skalierten Gradientenwerte der jeweiligen Funktion ab.



# Lernen
\footnotesize
\begin{definition}[Trainingsdatenpunkt-spezifische Kostenfunktionen]\label{def:cost_function_2}
\justifying
$f$ sei ein $k$-schichtiges neuronales Netz, $f_x$ sei die zugehörige wichtungsmatrix-variate 
neuronale Netzfunktion, $x$ und $y$ seien Inputs und Outputs des neuronalen Netzes, 
$\mathcal{D}$ sei ein Trainingsdatensatz und $c_y$ sei eine Output-spezifische Kostenfunktion. 
Dann heißt eine multimatrixvariate reellwertige Funktion der Form
\begin{multline}\label{eq:training_exemplar_cost_function}
c_{xy} :
\mathbb{R}^{n_1 \times (n_0 + 1)} \times \cdots \times
\mathbb{R}^{n_k \times (n_{k-1} + 1)}
\to \mathbb{R},
\\
(W^1, ..., W^k) \mapsto c_{xy}(W^1, ..., W^k) := c_y(f_x(W^1,...,W^k))
\end{multline}
\textit{Trainingsdatenpunkt-spezifische Kostenfunktion}.
\end{definition}

Bemerkung

* \justifying Eine Trainingsdatenpunkt-spezifische Kostenfunktion $c_{xy}$ misst die 
Abweichung des Outputs $a^k$ eines neuronalen Netzes von einem Zielvektor $y$ 
mithilfe einer Output-spezifischen Kostenfunktion $c_y$ für einen festen Input $x$ 
als Funktion der (also bei variablen) Wichtungsmatrizen.


# Lernen
\footnotesize
\begin{definition}[Gewichtsvektor]
\justifying
$f$ sei ein $k$-schichtige neuronales Netz mit $n_l \times n_{l-1} + 1$-dimensionalen
Gewichtsmatrizen $W^l, l = 1,.., k$ und es sei
\begin{equation}
p:=\sum_{l=1}^{n_k} n_{l} (n_{l-1} + 1).
\end{equation}
die Anzahl der Gewichtsparameter des neuronalen Netzes. Dann heißt
\begin{equation}\label{eq:weight_vector}
\mathcal{W} :=
\begin{pmatrix}
\mbox{vec}\left(W^l\right)
\end{pmatrix}_{1 \le l \le k}
\in \mathbb{R}^p
\end{equation}
der \textit{Gewichtsvektor} des neuronalen Netzes. 
\end{definition}

Bemerkung

* \justifying Die Vektorisierung und Konkatenation der Wichtungsmatrizen im Sinne des Gewichtsvektors
erlaubt es, dass Trainieren eines neuronalen Netzes als ein Standardoptimierungsproblem
einer multivariaten (nicht multimatrixvariaten) reellwertigen zu formulieren.


# Lernen
\footnotesize
\begin{definition}[Additive Kostenfunktion]
\justifying
$\mathcal{D}$ sei ein Trainingsdatensatz und $c_{xy}$ sei eine Trainingsdatenpunkt-spezifische
Kostenfunktion. Dann nennt man eine multivariate reellwertige Funktion der Form
\begin{equation}\label{eq:additive_cost_function}
c_{\mathcal{D}}: \mathbb{R}^{p} \to \mathbb{R},
\mathcal{W} \mapsto c_\mathcal{D}(\mathcal{W})
:= \frac{1}{n}\sum_{i=1}^n c_{x^{(i)}y^{(i)}}(W^1, ..., W^k)
\end{equation}
eine \textit{additive Kostenfunktion}.
\end{definition}

Bemerkung

* \justifying Die additive Kostenfunktion ist die zentrale Zielfunktion beim Trainierung eines neuronalen Netzes.

* $c_{\mathcal{D}}$ ist eine multivariate reellwertige Funktion, es liegt also ein Standardoptimierungsproblem vor.

* Wir nehmen dabei stillschweigend an, dass die sinnvolle Aufteilung des 
Gewichtsvektors $\mathcal{W}$ auf die Wichtungsmatrizen $W^1, ..., W^k$ in der 
Auswertung der Funktion $c_\mathcal{D}$ geschieht.

# Lernen
\footnotesize
\setstretch{1.1}
\begin{definition}[Batch Gradientenverfahren für neuronale Netze]\label{def:gradient_descent}
\justifying
$f$ sei ein $k$-schichtiges neuronales Netz mit Gewichtsvektor  $\mathcal{W}$,
$\mathcal{D}$ sei ein Trainingsdatensatz bestehend aus $n$ Trainingsdatenpunkten,
und $c_{\mathcal{D}}$ sei eine additive Kostenfunktion mit assoziierter Trainingsexemplar-spezifischer
Kostenfunktion $c_{xy}$. Dann ist ein Gradientenverfahren zur Minimierung der additiven 
Kostenfunktion $c_{\mathcal{D}}$ (und damit zum Lernen der Parameter von $f$) definiert durch
\vspace{1mm}

\noindent\underline{Initialisierung}
\vspace{1mm}

\noindent Wahl eines Startpunktes $\mathcal{W}^{(0)}$ und einer Lernrate $\alpha > 0$.
\vspace{1mm}

\noindent\underline{Iterationen}
\vspace{1mm}

\noindent Für $j = 1,2,...$ setze
\begin{equation}\label{eq:w_update}
\mathcal{W}^{(j)} :=
\mathcal{W}^{(j-1)}
- \frac{\alpha}{n}
\sum_{i=1}^n
\nabla c_{x^{(i)}y^{(i)}}(W^1, ..., W^k),
\end{equation}
wobei
\begin{equation}\label{eq:c_gradient}
\nabla c_{x^{(i)}y^{(i)}}(W^1, ..., W^k)
=
\begin{pmatrix}
\nabla_{W^l} c_{x^{(i)}y^{(i)}}(W^1, ..., W^k)
\end{pmatrix}_{1\le l \le k}
\end{equation}
für $i = 1,...,n$ den Gradienten der $i$ten Trainingsexemplar-spezifischen Kostenfunktion
bezeichnet
\end{definition}
\vspace{-2mm}
Bemerkungen

* \justifying $\mathcal{W}^{(j)}$ wird in (22) in die negative Richtung des 
Gradientenmittelwerts über Trainingsdatenpunkte adaptiert. Wird der Gradientenmittelwert 
dagegen nur über eine zufällig gewählte Teilmenge der Trainingsdatenpunkte berechnet, 
so spricht man von einem *stochastischen Gradientenverfahren*.

# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

Funktionale Architektur

Training

**Backpropagation**

Anwendungsbeispiel

Selbstkontrollfragen
\vfill

# Backpropagation
\setstretch{1.2}
\textcolor{darkblue}{Wesen und Motivation des Backpropagation Algorithmus}
\small

Der Backpropagation (BP) Algorithmus dient der numerischen Bestimmung der Komponenten
\begin{equation}\label{eq:partial_derivatives}
\frac{\partial}{\partial w_{ij}^{l}} c_{xy}(W^1,...,W^k)
\mbox{ für alle }
i = 1,...,n_l, j = 1,...,n_{l-1}+1, \mbox{ und } l = 1,...,k.
\end{equation}
des Gradienten $\nabla c_{x^{(i)}y^{(i)}}(W^1, ..., W^k)$ der $i$ten Trainingsexemplar-spezifischen Kostenfunktion.
\vspace{2mm}

Prinzipiell können diese partiellen Ableitungen numerisch durch
\begin{equation}
\frac{\partial}{\partial w_{ij}^{l}} c_{xy}(W^1,..., W^k)
\approx
\frac{c_{xy}(W^1,..., \tilde{W}^l,..., W^k) - c_{xy}(W^1,..., W^l, ...,W^k)}{\epsilon},
\end{equation}
mit

* $\tilde{W}^l := W^l + 1_{ij}^{l}\epsilon$ ,
* einer Matrix $1_{ij}^{l} \in \mathbb{R}^{n_l \times (n_{l-1}+1)}$ aus $0$en mit einer $1$ an der $w_{ij}^{l}$ Stelle in $W^l$ und
* einem Schrittweitenparameter $\epsilon > 0$ 

approximiert werden (vgl. Definition der partiellen Ableitung).


# Backpropagation
\textcolor{darkblue}{Wesen und Motivation des Backpropagation Algorithmus}
\small

Dieses Vorgehen würde für jede Iteration des Gradientenverfahren und für jeden Trainingsdatenpunkt
\begin{equation}
K := 1 + \sum_{l = 1}^k n_{l}({n_{l-1}}+1)
\end{equation}
Auswertungen der Trainingsdatenpunkt-spezifischen Kostenfunktion $c_{xy}$ und somit von $f$ erfordern.
Man nennt die Auswertung von $f$ für einen Trainingsdatenpunkt $x$ einen *Forward Pass*.

Die zentrale Eigenschaft des Backpropagation Algorithmus ist es, für die Auswertung 
von $\nabla c_{xy}$ die Anzahl der notwendigen *Forward Passes* pro Gradientenverfahrensiteration
von $K$ auf $1$ zu reduzieren.

Um dies zu erreichen, nutzt der Backpropagation Algorithmus einen sogenannten *Backward Pass*,
der die gleiche komputationale Komplexität wie der *Forward Pass* hat und auf einer multivariate
Version der Kettenregel der Differentialrechnung sowie der repetitiven funktionalen Architektur
neuronaler Netze beruht. 

Der Backpropagation Algorithmus reduziert die Anzahl nötiger *Passes* zur Auswertung von 
$\nabla c_{xy}$ also von $K$ *Forward Passes* auf $1$ *Forward Pass* und $1$ *Backward Pass*.


# Backpropagation
\footnotesize
\setstretch{1.2}

\begin{theorem}[Backpropagation Algorithmus]\label{thm:BP_algorithm}
\justifying
\normalfont
$f$ sei ein $k$-schichtiges neuronales Netz, $W_\bullet^{l} \in \mathbb{R}^{n_l \times n_{l-1}}$
seien für $l = 1,...,k$ Matrizen, die durch das Entfernen der letzten Spalte der
Wichtungsmatrizen $W^{l} \in \mathbb{R}^{n_l \times n_{l-1} + 1}$ entstehen, $c_{xy}$
sei eine Trainingsdatenpunkt-spezifische Kostenfunktion, $\nabla c_y(a^k)$ sei der
Gradient der Output-spezifischen Kostenfunktion, $\tilde{\Sigma}^l(z^l) := (\sigma'(z^l_1), ..., \sigma'(z^l_{n_l}))^T$
sei der Vektor der Aktivierungsfunktionenableitungen ausgewertet an der Stelle $z^l$
und $\Sigma^l(z^l)$ die komponentenweise Aktivierungsfunktion evaluiert an der Stelle
$z^l$. Dann können die partiellen Gradienten von $c_{xy}$ hinsichtlich der
Wichtungsmatrizen $W^l$ für $l = k, k-1, ...,1$ mit folgendem Algorithmus berechnet werden:
\vspace{1mm}

\underline{Initialisierung}
\vspace{1mm}

Setze
$W^{k+1} :=
(\begin{matrix}
1 & 0
\end{matrix})$
und
$\delta^{k+1} := \nabla c_y(a^{k})$.
\vspace{1mm}

\underline{Iterationen}
\vspace{1mm}

Für $l = k, k-1, k-2, ..., 1$, setze
\begin{equation}\label{eq:error}
\delta^l
:= 	\left(
		 \left(W^{l+1}_{\bullet}\right)^T \cdot \delta^{l+1}
	\right)
	\circ \tilde{\Sigma}^{l}(z^l)
\end{equation}
\noindent und
\begin{equation}\label{eq:partial_gradient}
\nabla_{W^l}
c_{xy}(W^1,..., W^k)
:= \mbox{vec}
	\left(
		\delta^l
		\cdot
		\begin{pmatrix} \Sigma^{l-1} (z^{l-1})^T & 1 \end{pmatrix}
	 \right),
\end{equation}
mit Rekursionstermination durch $\Sigma^0(z^0) := x^T$ und dem Hadamard-Produkt $\circ$.
\end{theorem}

Für weitere Details und einen Beweis verweisen wir auf @ostwald_2021.



# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

Funktionale Architektur

Training

Backpropagation

**Anwendungsbeispiele**

Selbstkontrollfragen
\vfill



# Anwendungsbeispiele
\small
\textcolor{darkblue}{Simulation und Analyse mit Matlab Implementation} (@ostwald_2021)

\footnotesize
* Neuronales Netz mit $k = 3, n_0 = 2, n_1 = 3$, $n_2 = 3, n_3 = 2$.
* Trainingsdatensatz anhand eines LDA Modells simuliert.

\vspace{2mm}
```{r, echo = FALSE, out.width = "80%"}
knitr::include_graphics("9_Abbildungen/mvda_9_matlab_implementation.pdf")
```
# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Eine verdeckte Schicht mit zwei Neuronen
\vspace{3mm}

\tiny
\setstretch{1}
```{r, message = F}
# R Pakete
library(foreign)
library(neuralnet)

# Einlesen der Studienerfolgdaten und Fokus auf binäre Klassifikation
D              = read.spss(file.path(getwd(), "9_Daten", "studienerfolg.sav"),
                          to.data.frame = T)
D              = D[D[,1] != "befriedigend",]                  # Binärisierung des Datensatzes
D$Intelligenz  = D$X1                                         # Variablenbennenung
D$Mathematik   = D$X2                                         # Variablenbenennung
D$Erfolg       = c(rep(0,15), rep(1,15))                      # Recoding der Binärisierung


# Trainieren eines neuronalen Netzes mit 2 Hidden Neurons
set.seed(7)                                                   # Der Algorithmus ist nicht deterministisch!
nn             = neuralnet(Erfolg ~ Intelligenz + Mathematik, # y^{(i)}, x^{(i)} Definitionen
                           data          = D,                 # Datensatz
                           hidden        = 2,                 # 2 Neurone in 1 verdeckte Schicht
                           err.fct       = "ce",              # Cross Entropie Kostenfunktion
                           linear.output = FALSE)             # Sigmoide Aktivierungsfunktion


# Resultatsaufbereitung
R              = data.frame(nn$covariate, nn$response, nn$net.result[[1]], as.numeric(nn$net.result[[1]] > 0.5))
colnames(R)    = c("Intelligenztest", "Mathematiktest", "Erfolg", "Output", "Prädiktion")
print(sprintf("Prädiktionsakkuratheit = %0.2f", mean(R$Prädiktion == R$Erfolg)))
```

# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Eine verdeckte Schicht mit zwei Neuronen

\tiny
\setstretch{0.8}
```{r, echo = F}
knitr::kable(R, "pipe", digits = 1)
```


# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Eine verdeckte Schicht mit zwei Neuronen

```{r,eval = F}
plot(nn)
```
\vspace{3mm}

```{r, eval = F, echo = F}
dev.new()
graphics.off()
plot(nn)
fdir = file.path(getwd(), "9_Abbildungen")
dev.copy2pdf(file   = file.path(fdir, "mvda_9_neural_network_beispiel_1.pdf"),
             width  = 8,
             height = 4)
```
\center
```{r, echo = FALSE, out.width = "100%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neural_network_beispiel_1.pdf")
```


# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Zwei verdeckte Schichten mit drei Neuronen
\vspace{3mm}

\tiny
\setstretch{1}
```{r, message = F}
# R Pakete
library(foreign)
library(neuralnet)

# Einlesen der Studienerfolgdaten und Fokus auf binäre Klassifikation
D              = read.spss(file.path(getwd(), "9_Daten", "studienerfolg.sav"),
                          to.data.frame = T)
D              = D[D[,1] != "befriedigend",]                  # Binärisierung des Datensatzes
D$Intelligenz  = D$X1                                         # Variablenbennenung
D$Mathematik   = D$X2                                         # Variablenbenennung
D$Erfolg       = c(rep(0,15), rep(1,15))                      # Recoding der Binärisierung


# Trainieren eines neuronalen Netzes mit 2 Hidden Neurons
set.seed(7)                                                   # Der Algorithmus ist nicht deterministisch!
nn             = neuralnet(Erfolg ~ Intelligenz + Mathematik, # y^{(i)}, x^{(i)} Definitionen
                           data          = D,                 # Datensatz
                           hidden        = c(3,3),            # 3 Neurone in 2 verdeckten Schichten
                           err.fct       = "ce",              # Cross Entropie Kostenfunktion
                           linear.output = FALSE)             # Sigmoide Aktivierungsfunktion


# Resultstatsaufbereitung
R              = data.frame(nn$covariate, nn$response, nn$net.result[[1]], as.numeric(nn$net.result[[1]] > 0.5))
colnames(R)    = c("Intelligenztest", "Mathematiktest", "Erfolg", "Output", "Prädiktion")
print(sprintf("Prädiktionsakkuratheit = %0.2f", mean(R$Prädiktion == R$Erfolg)))
```

# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Zwei verdeckte Schichten mit drei Neuronen

\tiny
\setstretch{0.8}
```{r, echo = F}
knitr::kable(R, "pipe", digits = 1)
```


# Anwendungsbeispiele
\small
\textcolor{darkblue}{Prädiktive Modellierung von \textit{studienerfolg.sav} mit neuralnet()} (@gunther_2010)

$\Rightarrow$ Zwei verdeckte Schichten mit drei Neuronen

```{r,eval = F}
plot(nn)
```
\vspace{3mm}

```{r, eval = F, echo = F}
dev.new()
graphics.off()
plot(nn)
fdir = file.path(getwd(), "9_Abbildungen")
dev.copy2pdf(file   = file.path(fdir, "mvda_9_neural_network_beispiel_2.pdf"),
             width  = 8,
             height = 4)
```
\center
```{r, echo = FALSE, out.width = "100%"}
knitr::include_graphics("9_Abbildungen/mvda_9_neural_network_beispiel_2.pdf")
```

# {.plain}
\vfill
\setstretch{2}
\large
Vorbemerkungen

Funktionale Architektur

Lernen

Backpropagation

Anwendungsbeispiel

**Selbstkontrollfragen**
\vfill

# Selbstkontrollfragen
\footnotesize
\begin{enumerate}
\justifying
\item Erläutern Sie die zentralen Ideen Universeller Approximationstheoreme im Kontext neuronaler Netze.
\item Nennen Sie die Formel für das Potential $z_i^l$ eines Neurons $i$ in einer Schicht $l$ eines neuronalen Netzes
und erläutern Sie die verschiedenen Komponenten dieser Formel und ihre intuitive Bedeutung.
\item Skizzieren Sie die Standard Logistic und ReLU Aktivierungsfunktionen und ihre Ableitungen.
\item Nennen Sie die Formel für die Aktivierung $a_i^l$ eines Neurons $i$ in einer Schicht $l$ eines neuronalen Netzes und erläutern Sie ihre Bestandteile und deren intuitive Bedeutung.
\item Erläutern Sie das prinzipielle Vorgehen zum Trainieren eines neuronalen Netzes.
\item Definieren Sie die (Output-spezifische) Quadratische  Kostenfunktion und erläutern Sie ihre Bestandteile.
\item Geben Sie das Batch Gradientenverfahren zum Trainieren neuronaler Netze wieder.
\item Differenzieren Sie die Begriffe Batch und Stochastischen Gradientenverfahren zum Trainieren neuronaler Netze.
\item Erläutern Sie Wesen und Motivation des Backpropagation Algorithmus.
\item Lesen Sie den Datensatz \href{http://www3.hogrefe.de/fileadmin/redakteure/hogrefe_de/Psychlehrbuchplus/Multivariate_Verfahren_2Aufl/Diskriminanzanalyse/Studienerfolg.sav}{studienerfolg.sav} 
mit R ein und bestimmen Sie den Trainingsdatenprädiktionsfehler nach Trainieren eines neuronalen Netzes mithilfe des R Pakets neuralnet
zur prädiktiven Modellierung des Studienerfolgs (gut, ungenügend) basierend auf (1) den Intelligenztestdaten,
(2) den Intelligenz- und Mathematiktestdaten und (3) den Intelligenztest-, Mathematiktest-, und Gewissenhaftigkeitsdaten. Wiederholen Sie Ihre Analyse zur Bestimmung des 
Generalisierungsfehlers im Rahmen einer Leave-One-Out Kreuzvalidierung.
\end{enumerate}

# References {.allowframebreaks}
\setstretch{1}
\footnotesize