Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Das Geheimnis um Deep Learning lüften

Warum – und wie genau – funktioniert Deep Learning so gut? Die Zutaten, die wir bisher haben:

Was noch fehlt, und was wir in diesem und den nächsten Kapiteln angehen:

Parameter von Hand wählen

Bevor wir Netze trainieren, überzeugen wir uns davon, dass die gesuchten Gewichte überhaupt existieren: Wir bauen kleine Netze von Hand.

Easy mode: Boolesche Variablen

Seien x,y∈{0,1}={FALSE,TRUE}x, y \in \{0, 1\} = \{\text{FALSE}, \text{TRUE}\} und f ⁣:R2→Rf \colon \mathbb{R}^2 \to \mathbb{R}, f(x,y):=x OR yf(x, y) := x \text{ OR } y, also f(0,0)=0f(0,0) = 0, f(1,0)=1f(1,0) = 1, f(0,1)=1f(0,1) = 1, f(1,1)=1f(1,1) = 1. Welches neuronale Netz berechnet als Inferenz die Funktion ff?

Idee: Schreibe ff als Verkettung von gewichteten Summen (= Skalarprodukten) und Aktivierungsfunktionen (z.B. [x>0][x > 0] oder ReLU⁡(x):=max⁡(0,x)\operatorname{ReLU}(x) := \max(0, x)). Dabei müssen wir OR interpolieren – entscheiden, was z.B. f(0,5,0)f(0{,}5, 0) sein soll – und extrapolieren – entscheiden, was z.B. f(−1,2)f(-1, 2) sein soll. Denn ein neuronales Netz ist auf ganz R2\mathbb{R}^2 definiert, nicht nur auf den vier Ecken.

Easiest mode: eindimensional

Sei x∈Rx \in \mathbb{R} mit der Interpretation (x≤0)=FALSE(x \le 0) = \text{FALSE}, (x≥1)=TRUE(x \ge 1) = \text{TRUE}, und n ⁣:R→Rn \colon \mathbb{R} \to \mathbb{R}, n(x):=NOT xn(x) := \text{NOT } x. Also n(0)=1n(0) = 1, n(1)=0n(1) = 0, allgemeiner n(x)≤0n(x) \le 0 falls x≥1x \ge 1. Die Funktion

n(x)=1−xn(x) = 1 - x

erfüllt die Eigenschaft, NOT zu inter- und extrapolieren. Als neuronales Netz: 1 Neuron, Gewicht w=−1w = -1, Bias b=+1b = +1, Aktivierungsfunktion id⁡\operatorname{id}.

Zurück zu OR

Ansatz: f(x,y)=x+yf(x, y) = x + y. Leider ist f(1,1)=2≠1f(1, 1) = 2 \neq 1. Besser: f(x,y)=[x+y>0]f(x, y) = [x + y > 0] – ein Neuron mit Gewichtsvektor (1,1)(1, 1), Bias b=0b = 0 und Aktivierungsfunktion [ ⋅>0][\,\cdot > 0] mit Werten in {0,1}\{0, 1\}. Dafür ändern wir die Interpretation leicht zu (x≤0)=F(x \le 0) = \text{F}, (x>0)=T(x > 0) = \text{T}. Damit ist der erste Ansatz wieder brauchbar: Dass f(1,1)=2f(1,1) = 2 herauskommt, stört nun nicht mehr, weil alles über null TRUE heißt. Softere Varianten sind also f(x,y):=x+yf(x, y) := x + y oder σ(x+y)\sigma(x + y); und noch besser, weil es Negatives sauber abschneidet:

f(x,y):=ReLU⁡(x)+ReLU⁡(y).f(x, y) := \operatorname{ReLU}(x) + \operatorname{ReLU}(y).
OR und NOR als Funktionen auf ganz \mathbb{R}^2: Die vier Booleschen Ecken sind markiert, die schwarze Linie ist die Nullstellenmenge.

OR und NOR als Funktionen auf ganz R2\mathbb{R}^2: Die vier Booleschen Ecken sind markiert, die schwarze Linie ist die Nullstellenmenge.

Komplizierteres aus Einfachem: NOR

Sei g(x,y):=x NOR yg(x, y) := x \text{ NOR } y, also g(F,F)=Tg(\text{F}, \text{F}) = \text{T} und sonst F\text{F}. NOR = NOT OR, also g(x,y)=n(f(x,y))g(x, y) = n(f(x, y)) für ein ff, welches OR implementiert. Mit f(x,y):=ReLU⁡(x)+ReLU⁡(y)f(x, y) := \operatorname{ReLU}(x) + \operatorname{ReLU}(y) und n(x):=1−xn(x) := 1 - x:

g(x,y):=1−(ReLU⁡(x)+ReLU⁡(y)).g(x, y) := 1 - \bigl(\operatorname{ReLU}(x) + \operatorname{ReLU}(y)\bigr).

Als Netz: erste Schicht mit zwei ReLU-Neuronen, eines pro Eingabe (Gewicht 1, Bias 0), zweite Schicht mit Gewichtsvektor (−1,−1)(-1, -1), Bias 1 und id⁡\operatorname{id}. Ein einzelnes Neuron mit Gewichtsvektor (1,1)(1,1) täte es nicht: Das berechnet ReLU⁡(x+y)\operatorname{ReLU}(x + y), und das ist etwas anderes als ReLU⁡(x)+ReLU⁡(y)\operatorname{ReLU}(x) + \operatorname{ReLU}(y) – bei (1,−1)(1, -1) etwa 0 gegen 1. Auf den vier Booleschen Ecken fällt der Unterschied nicht auf, außerhalb schon, und genau darum geht es in diesem Kapitel.

Weiter so? XOR

Sei f(x,y):=x XOR yf(x, y) := x \text{ XOR } y. Die „Region“ XOR in der Ebene, also die Punkte (x,y)(x, y) mit XOR(x,y)>0\text{XOR}(x, y) > 0, ist der Schnitt von NAND(x,y)>0\text{NAND}(x, y) > 0 mit OR(x,y)>0\text{OR}(x, y) > 0:

XOR(x,y)=AND(NAND(x,y), OR(x,y)).\text{XOR}(x, y) = \text{AND}\bigl(\text{NAND}(x, y),\ \text{OR}(x, y)\bigr).

Setzt man das mit den obigen Bausteinen zusammen, so müsste es mit 4 Hidden Layers zu je 4 Neuronen klappen. Gradientenabstieg mit Backpropagation findet allerdings auch Approximationen mit 3 Hidden Layers – und mit 2 Hidden Layers (siehe die beiden Abbildungen unten aus dem TensorFlow Playground).

XOR als Schnitt von NAND und OR.

XOR als Schnitt von NAND und OR.

Vom Gradientenabstieg gefundene Approximation im TensorFlow Playground mit 3 versteckten Schichten.

Vom Gradientenabstieg gefundene Approximation im TensorFlow Playground mit 3 versteckten Schichten.

Dasselbe mit 2 versteckten Schichten.

Dasselbe mit 2 versteckten Schichten.

Take-Home Message

Boolesche Funktionen lassen sich mit neuronalen Netzen darstellen bzw. approximieren, d.h. es gibt Gewichte, sodass die resultierende Funktion tut, was sie soll. Also kann auch Optimierung diese idealen Gewichte finden. Aus elementaren Funktionen lassen sich komplexe verknüpfen; neuronale Netze können aber auch „Abkürzungen“ nehmen und Platz verschwenden (überflüssige Neuronen).

Arithmetik

Wie können wir z.B. f(x,y):=x3+xy2−3yf(x, y) := x^3 + x y^2 - 3y mit einem neuronalen Netz berechnen oder approximieren? Einfachere Probleme, die wir dafür zuerst lösen müssen: f(x,y):=xyf(x, y) := xy und f(x):=x2f(x) := x^2.

Auf [−3,+3][-3, +3] approximieren wir x2x^2 mit einer stückweise linearen Funktion an ganzzahligen Stützstellen. Die Interpolation durch die Punkte (k,k2)(k, k^2) für k=−3,…,3k = -3, \dots, 3 hat auf [k,k+1][k, k+1] die Steigung 2k+12k + 1, also an jeder inneren Stützstelle einen Knick, bei dem die Steigung um 2 wächst – und jeder Knick ist eine ReLU:

Q(x)=9−5 ReLU⁡(x+3)+∑k=−222 ReLU⁡(x−k).Q(x) = 9 - 5\,\operatorname{ReLU}(x + 3) + \sum_{k=-2}^{2} 2\,\operatorname{ReLU}(x - k).

Probe: Q(0)=9−15+2(2+1)=0Q(0) = 9 - 15 + 2(2 + 1) = 0 und Q(3)=9−30+2(5+4+3+2+1)=9Q(3) = 9 - 30 + 2(5 + 4 + 3 + 2 + 1) = 9. Das ist ein Netz mit einer versteckten Schicht aus 6 ReLU-Neuronen (Gewicht 1, Bias −k-k für k=−3,…,2k = -3, \dots, 2) und einer linearen Ausgabeschicht mit Gewichten (−5,2,2,2,2,2)(-5, 2, 2, 2, 2, 2) und Bias 9. Die Symmetrie x2=(−x)2x^2 = (-x)^2 haben wir dabei ignoriert – geht das besser? Der Betrag ist selbst ein kleines Netz, ∣x∣=ReLU⁡(x)+ReLU⁡(−x)|x| = \operatorname{ReLU}(x) + \operatorname{ReLU}(-x) (zwei Neuronen mit Gewichten 1 und -1, dann ein Neuron mit Gewichtsvektor (1,1)(1, 1)), und damit reicht die Interpolation auf [0,3][0, 3]:

P(x)=∣x∣+2ReLU⁡(∣x∣−1)+2ReLU⁡(∣x∣−2).P(x) = |x| + 2\operatorname{ReLU}(|x| - 1) + 2\operatorname{ReLU}(|x| - 2).

Das sind nur noch 3 Neuronen in der Interpolationsschicht – dafür ist das Netz tiefer, weil ∣x∣|x| zwei Schichten vorweg kostet. Weniger Neuronen pro Schicht gegen mehr Schichten: ein Tausch, den wir noch öfter sehen werden.

In der Praxis könnte man PyTorch auch direkt bitten, x2x^2 oder xyxy exakt zu berechnen (Stichwort Gates, etwa in LSTMs), auch wenn man damit das reine MLP verlässt. Der Haken: Im Allgemeinen weiß man vorher nicht, ob man x2x^2 braucht, um die gesuchte Funktion gut zu approximieren.

x^2 auf [-3, 3] und die stückweise lineare Interpolation Q(x) an ganzzahligen Stützstellen, ein Netz mit 6 ReLU-Neuronen.

x2x^2 auf [−3,3][-3, 3] und die stückweise lineare Interpolation Q(x)Q(x) an ganzzahligen Stützstellen, ein Netz mit 6 ReLU-Neuronen.

Wenn x2x^2 gut approximiert werden kann, dann auch xyxy über die Polarisationsidentität:

(x+y)2−(x−y)24=x2+2xy+y2−x2+2xy−y24=xy.\frac{(x + y)^2 - (x - y)^2}{4} = \frac{x^2 + 2xy + y^2 - x^2 + 2xy - y^2}{4} = xy .

Damit setzen wir für eine Approximation QQ der Quadratfunktion

MUL⁡(x,y):=14Q(x+y)−14Q(x−y),\operatorname{MUL}(x, y) := \tfrac14 Q(x + y) - \tfrac14 Q(x - y),

und x+yx + y sowie x−yx - y sind lineare Schichten. Mit MUL und Addition bekommen wir alle Polynome, und damit (Weierstraß) alle stetigen Funktionen auf beschränkten Bereichen.

Take-Home Message

Funktionen lassen sich mit neuronalen Netzen darstellen bzw. approximieren. Mit einer Lookup-Table (LUT) und Interpolation sind beliebig gute Näherungen auf beschränkten Definitionsbereichen möglich – so rechnet auch die GPU z.B. den Sinus aus. Außerhalb der Stützstellen wird die Approximation beliebig schlecht: Neuronale Netze interpolieren gut, extrapolieren schlecht.

Übung

  1. Geben Sie Gewichte und Bias für ein einzelnes Perzeptron an, das AND auf {0,1}2\{0,1\}^2 berechnet. Prüfen Sie alle vier Eingaben nach.

  2. Bauen Sie NAND aus Ihrem AND, ohne neu zu rechnen. Tipp: Was macht das Vorzeichenwechseln von ww und bb mit der Entscheidungsgrenze?

Antwortprobe: Bei (1) gibt es viele richtige Antworten; alle erfüllen dieselben vier Ungleichungen.