Ein Notebook des Codes, mit dem wir gerade gearbeitet haben, finden Sie online unter:
https://github.com/makeyourownneuralnetwork/gan/blob/master/00_pytorch_basics.ipynb
Berechnungsgraphen
Diese eben vorgestellte automatische Gradientenberechnung scheint magisch zu sein, aber das ist sie natürlich nicht.
Es lohnt sich trotzdem, ein wenig davon zu verstehen, weil dieses Wissen uns später helfen wird, wenn es um den Aufbau größerer Netze geht.
Sehen Sie sich das sehr einfache Netz in Abbildung 1-13 an. Es ist kein neuronales Netz, sondern lediglich eine Folge von Berechnungen.
Abbildung 1-13: Ein sehr einfaches Netz
Abbildung 1-13 zeigt einen Eingang x, der verwendet wird, um y zu berechnen, das dann verwendet wird, um z, den Ausgang, zu berechnen.
Stellen Sie sich vor, dass y und z wie in Abbildung 1-14 gezeigt berechnet werden.
Abbildung 1-14: Berechnung von y und z
Wenn wir wissen wollen, wie sich die Ausgabe z verändert, wenn x variiert, müssen wir einige Berechnungen anstellen, um den Gradienten dy/dx zu ermitteln. Wir führen das schrittweise durch.
Abbildung 1-15: Schritte beim Berechnen des Gradienten
Die erste Zeile ist die Kettenregel der Differenzialrechnung. Als Ausgangspunkt ist sie uns hier sehr nützlich. Falls Sie eine Auffrischung brauchen: Einer der Anhänge meines Buchs Neuronale Netze selbst programmieren ist eine Einführung in die Analysis und die Kettenregel.
Wir haben also gerade herausgefunden, dass die Ausgabe z mit x als 4x variiert. Wenn x = 3.5 ist, wird dz/dx zu 4*3.5 = 14.
Wenn y in Form von x und z in Form von y definiert ist, erstellt PyTorch ein Bild, wie diese Tensoren verknüpft sind. Dieses Bild ist ein sogenannter Berechnungsgraph.
Abbildung 1-16 zeigt, wie er für unser Beispiel aussehen könnte.
Abbildung 1-16: Der Berechnungsgraph für unser Beispiel
In Abbildung 1-16 sehen Sie, wie y aus x und z aus y berechnet wird. Zusätzlich fügt PyTorch Rückwärtspfeile hinzu, die zeigen, wie sich y ändert, wenn sich x ändert und wie sich z ändert, wenn sich y ändert. Das sind die Gradienten, mit denen ein neuronales Netz während des Trainings aktualisiert wird. Die Analysis übernimmt PyTorch, wir brauchen diese Berechnungen nicht selbst anzustellen.
Um herauszufinden, wie z sich ändert, wenn x sich ändert, folgen wir dem Pfad von z zurück nach x über y, wobei wir die Gradienten zusammenfassen. Dies ist praktisch die Kettenregel der Differenzialrechnung.
Probieren wir mit Code aus, ob es funktioniert. Legen Sie ein neues Notebook an, importieren Sie torch und geben Sie danach den folgenden Code ein, um die Beziehungen zwischen x, y und z einzurichten:
# Einen einfachen Graphen in Bezug auf x, y und z einrichten
x = torch.tensor(3.5, requires_grad=True)
y = x*x
z = 2*y + 3
PyTorch erstellt den Berechnungsgraphen aber nur in der Vorwärtsrichtung. Wir müssen PyTorch mit der Funktion backward() dazu bringen, die Gradienten in Rückwärtsrichtung zu berechnen:
# Gradienten berechnen
z.backward()
Der Gradient dz/dx ist im Tensor x als x.grad gespeichert.
# Den Gradienten bei x = 3.5 berechnen
x.grad
Führen Sie den Code aus, um zu kontrollieren, ob er funktioniert.
Abbildung 1-17: Den Gradienten an der Position x = 3.5 berechnen
Die Antwort ist 14, genau wie wir es oben per Hand berechnen haben. Großartig!
Beachten Sie, dass der Gradientenwert im Tensor x angibt, wie sich z ändert. Das hängt damit zusammen, dass wir PyTorch mittels z.backward() angewiesen haben, von z aus rückwärts zu rechnen. Somit ist x.grad gleich dz/dx und nicht dy/dx.
Bei den meisten praktischen neuronalen Netzen weisen die Knoten mehrere eingehende und mehrere ausgehende Verbindungen auf. Sehen wir uns ein anderes einfaches Beispiel an, in dem mehr als eine Verbindung zu einem Knoten führt (siehe Abbildung 1-18).
Abbildung 1-18: Ein einfaches neuronales Netz, das Knoten mit mehreren eingehenden und ausgehenden Verbindungen enthält
Wie Abbildung 1-18 zeigt, tragen beide Eingänge – a und b – zu x und y bei, und die Ausgabe z wird sowohl aus x als auch aus y berechnet.
Notieren wir die Beziehungen zwischen diesen Knoten:
Abbildung 1-19: Die Beziehungen zwischen den Knoten des neuronalen Netzes
Die Gradienten können wir genau wie zuvor berechnen (siehe Abbildung 1-20).
Abbildung 1-20: Berechnung der Gradienten
Diese Informationen fügen wir jetzt in den Berechnungsgraphen ein (siehe Abbildung 1-21).
Abbildung 1-21: Der Berechnungsgraph mit den hinzugefügten Gradienten
Den Gradienten dz/da können wir nun leicht berechnen, indem wir dem Pfad von z zurück nach a folgen. Eigentlich gibt es zwei Pfade, denn einer geht durch x und der andere durch y. Das ist in Ordnung, wir folgen beiden und addieren einfach die Ausdrücke der beiden Pfade. Das ist sinnvoll, da beide