Zurück zum Katalog
Season 55 17 Episoden 1h 8m 2026

PyTorch Fundamentals

v2.11 — Ausgabe 2026. Ein umfassender Audiokurs zur Erstellung von Deep-Learning-Modellen mit PyTorch Version 2.11. Behandelt Tensors, Autograd, Neural Networks, Optimizers, DataLoaders und den PyTorch-Compiler.

AI/ML-Frameworks Python Core Datenwissenschaft
PyTorch Fundamentals
Aktuelle Wiedergabe
Click play to start
0:00
0:00
1
Die Kernidentität von PyTorch
Entdecke den grundlegenden Zweck von PyTorch und was es von traditionellen Mathematik-Bibliotheken unterscheidet. Diese Episode erklärt die Rolle von Tensors, Autograd und GPU-Beschleunigung im modernen Deep Learning.
4m 20s
2
PyTorch Tensors verstehen
Tauche ein in Tensors, die grundlegende Datenstruktur von PyTorch. Lerne, wie sie Rohdaten mit Neural Networks verbinden und den Speicher nahtlos mit Numpy-Arrays teilen.
4m 09s
3
Tensor-Operationen und Speicher
Lerne, wie man Tensors effizient manipuliert. Diese Episode behandelt arithmetische Operationen, Konkatenation, Device-Transfers und die Speicherauswirkungen von In-Place-Operationen.
4m 02s
4
Die Magie von Autograd
Entpacke den Motor, der Deep Learning in PyTorch möglich macht. Lerne, wie Autograd Operationen dynamisch verfolgt und komplexe Ableitungen automatisch berechnet.
3m 44s
5
Gradient Tracking steuern
Entdecke, wie du das Gradient Tracking von PyTorch deaktivierst, um Speicher zu sparen und die Berechnung zu beschleunigen. Unerlässlich für die Ausführung von Inference und das Einfrieren von Modellparametern.
4m 07s
6
Datasets und Datenverarbeitung
Lerne, wie du deine Datenverarbeitung mithilfe der PyTorch Dataset-Klasse von deiner Modellarchitektur entkoppelst. Wir untersuchen Lazy Loading und benutzerdefinierte Dataset-Strukturen.
4m 01s
7
DataLoaders und Batching
Entfessele die volle Geschwindigkeit deiner Hardware, indem du Datasets in DataLoaders verpackst. Lerne, wie du deine Datenströme in Batches aufteilst, mischst und mit Multiprocessing verarbeitest.
3m 42s
8
Daten-Transformationen
Entdecke, wie du Rohdaten on-the-fly vorverarbeitest, bevor sie auf dein Neural Network treffen. Wir behandeln torchvision-Transforms wie ToTensor und benutzerdefinierte Lambda-Funktionen.
4m 34s
9
Netzwerke mit nn.Module entwerfen
Erkunde den strukturellen Bauplan jedes PyTorch Neural Networks. Lerne, wie du nn.Module als Unterklasse verwendest, Layer in der Initialisierung definierst und Daten im Forward Pass weiterleitest.
4m 21s
10
Linear Layers und Activations
Wirf einen Blick ins Innere des Neural Networks. Wir zerlegen das nn.Linear-Modul und erklären, warum nicht-lineare Activation-Funktionen wie ReLU mathematisch unerlässlich sind.
4m 20s
11
Der nn.Sequential Container
Optimiere deinen PyTorch-Code mit dem nn.Sequential-Container. Lerne, wie du Layer sauber zusammensteckst und die Parameter deines Modells überprüfst.
4m 08s
12
Loss Functions verstehen
Bevor eine KI lernen kann, muss sie ihre Fehler messen. Wir tauchen in PyTorch Loss Functions ein und vergleichen CrossEntropyLoss für Klassifikation und MSELoss für Regression.
3m 26s
13
Optimizers und Gradient Descent
Erkunde, wie der Optimizer Modellgewichte aktualisiert, um Fehler zu reduzieren. Lerne den entscheidenden Drei-Schritte-Tanz aus zero_grad(), backward() und step().
4m 01s
15
Validation und Inference
Bewerte dein Modell objektiv. Lerne, wie du dein Netzwerk in den Evaluation-Modus versetzt, Gradienten einfrierst und präzise Vorhersagen für ungesehene Daten extrahierst.
4m 14s
16
Modelle speichern und laden
Verliere nicht deinen hart erarbeiteten Fortschritt! Wir besprechen die sichersten Methoden, um deine Modellgewichte mit state_dict zu serialisieren und sie sicher wieder zu laden.
3m 35s
17
Geschwindigkeit maximieren mit torch.compile
Schalte das entscheidende Feature von PyTorch 2.0 frei. Lerne, wie der torch.compile-Decorator deinen Python-Code in optimierte Kernels JIT-compiliert, um massive Geschwindigkeitssteigerungen zu erzielen.
3m 39s
18
Compiler und Graph Breaks
Tauche unter die Haube des PyTorch-Compilers. Wir untersuchen Graph Breaks, dynamischen Kontrollfluss und warum torch.compile dort erfolgreich ist, wo ältere Systeme versagt haben.
4m 20s

Episoden

1

Die Kernidentität von PyTorch

4m 20s

Entdecke den grundlegenden Zweck von PyTorch und was es von traditionellen Mathematik-Bibliotheken unterscheidet. Diese Episode erklärt die Rolle von Tensors, Autograd und GPU-Beschleunigung im modernen Deep Learning.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 1 von 18. Du schreibst ein komplexes mathematisches Modell in Python, aber wenn du es skalierst, zwingt es deinen Prozessor komplett in die Knie. Du musst diese Berechnungen auf paralleler Hardware ausführen und kontinuierlich all ihre Ableitungen berechnen, aber alles in einer Low-Level-Sprache neu zu schreiben, würde Wochen dauern. Genau dieses Problem löst die Kernidentität von PyTorch. Wenn du dir PyTorch zum ersten Mal ansiehst, fühlt es sich oft exakt wie NumPy an. Du erstellst Arrays, multiplizierst Matrizen und manipulierst Zahlen. Diese visuelle Ähnlichkeit sorgt anfangs für viel Verwirrung. Viele Leute nehmen an, PyTorch sei nur eine weitere Standard-Math-Library. Das ist es nicht. Während Standard-Math-Libraries für CPU-bound numerische Berechnungen entwickelt wurden, ist PyTorch von Grund auf dafür designt, parallele Hardware zu nutzen und dynamische Computational Graphs aufzubauen. Der grundlegende Baustein dieses Frameworks ist der Tensor. Ein Tensor ist im Wesentlichen ein mehrdimensionales Array. Wenn du ein Grid aus Zahlen hast, das ein Bild, eine Schallwelle oder einen Textblock repräsentiert, speicherst du es in einem Tensor. Der entscheidende Unterschied zwischen einem Standard-Array und einem PyTorch-Tensor ist, wo diese Daten leben und ausgeführt werden können. Tensoren können nahtlos vom System Memory deines Computers auf eine Graphics Processing Unit verschoben werden. Nehmen wir mal eine massive Matrixmultiplikation. Du hast zwei Grids mit Millionen von Zahlen. Wenn du eine Standard-CPU anweist, sie zu multiplizieren, verarbeitet sie die Mathematik sequenziell oder in sehr kleinen Batches. Der Prozess quält sich und stockt. Weil Tensoren explizit für Hardware Acceleration designt sind, kannst du exakt dieselben Daten an eine GPU senden. Die GPU enthält Tausende kleiner Cores, die dafür designt sind, mathematische Operationen gleichzeitig auszuführen. Eine massive Berechnung, die auf einer CPU Minuten dauert, ist auf einer GPU sofort fertig. PyTorch fungiert als Brücke und übersetzt deinen Standard-Python-Code in Instructions für diese parallele Hardware. Schnelle Hardware ist aber nur die halbe Miete für Machine Learning. Das Trainieren eines Neural Networks erfordert kontinuierliche Differentialrechnung. Du musst genau wissen, wie das Anpassen einer Variable deinen finalen Output verändert, was bedeutet, dass du ständig Gradients berechnen musst. Das manuell für ein Model mit Milliarden von Parametern zu machen, ist unmöglich. Das bringt uns zur zweiten Säule von PyTorch, nämlich Autograd. Autograd ist eine Automatic Differentiation Engine. Wenn du Mathe-Operationen auf Tensoren ausführst, berechnet PyTorch nicht einfach nur die finale Zahl. Es baut im Hintergrund still und heimlich eine Map auf. Es zeichnet jede Addition, Multiplikation und Data Transformation in einem dynamischen Computational Graph auf. Wenn du am Ende deiner Berechnung angekommen bist, bittest du das Framework einfach, die Gradients zu berechnen. PyTorch geht rückwärts durch diesen unsichtbaren Graph und wendet automatisch die Kettenregel der Differentialrechnung an. Du erhältst die exakten Ableitungen für jeden einzelnen Parameter in deinem Model, ohne selbst irgendwelchen Calculus-Code schreiben zu müssen. Weil dieser Graph dynamisch on the fly aufgebaut wird, passt er sich deinem Code an. Wenn eine Standard-Python-Loop oder ein If-Statement den Flow deiner Daten ändert, passt sich der Graph sofort an. Die wahre Power von PyTorch ist nicht nur, dass es schnell läuft oder Differentialrechnung beherrscht. Es gibt dir die Execution Speed eines Supercomputers und die mathematische Präzision einer Automated Calculus Engine, komplett verborgen hinter lesbarem, ganz normalem Python. Wenn du dabei helfen willst, dass weitere dieser Episoden erscheinen, kannst du auf Patreon nach DevStoriesEU suchen und die Show unterstützen. Das war's für diese Folge. Danke fürs Zuhören und keep building!
2

PyTorch Tensors verstehen

4m 09s

Tauche ein in Tensors, die grundlegende Datenstruktur von PyTorch. Lerne, wie sie Rohdaten mit Neural Networks verbinden und den Speicher nahtlos mit Numpy-Arrays teilen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 2 von 18. Jedes Bild, jede Schallwelle und jedes Textdokument, das du in ein neuronales Netzwerk einspeist, wird letztendlich in genau dieselbe Datenstruktur umgewandelt. Wenn das alles nur ein Grid aus Zahlen ist, fragst du dich vielleicht, warum wir ein spezielles Objekt brauchen, anstatt einfach auf Standard-Arrays zurückzugreifen. Die Antwort liegt im Verständnis von PyTorch Tensors. Ein Tensor ist eine spezielle Datenstruktur, die einem Array oder einer Matrix sehr ähnlich sieht und sich auch so verhält. In PyTorch sind Tensoren die universelle Währung. Sie speichern deine Raw Inputs, die Outputs, die dein Model generiert, und die internen Parameter des neuronalen Netzwerks selbst. Leute nehmen oft an, dass Tensoren komplett identisch mit NumPy-Arrays sind. Sie sehen auch ähnlich aus und teilen viele der gleichen Verhaltensweisen. Der entscheidende Unterschied ist, was Tensoren ermöglichen. Während ein Standard-Array in deinem System Memory liegt und auf deiner CPU läuft, ist ein Tensor dafür gebaut, problemlos auf eine Graphics Processing Unit, oder GPU, verschoben zu werden, um massive Hardware Acceleration zu nutzen. Tensoren enthalten außerdem die eingebaute Infrastruktur, die für das Gradient Tracking erforderlich ist, was es neuronalen Netzwerken erst ermöglicht zu lernen. Du kannst einen Tensor auf verschiedene Arten initialisieren. Der direkteste Weg ist, Raw Data, wie eine Standard-Python-Liste von Zahlen, direkt an den Tensor Constructor zu übergeben. Du kannst auch einen neuen Tensor basierend auf einem bereits existierenden erstellen. Wenn du das machst, erbt der neue Tensor automatisch die Eigenschaften des Originals. Das heißt, er hat dieselben Dimensions und denselben Data Type, es sei denn, du überschreibst sie explizit. Alternativ, wenn du nur einen Placeholder brauchst, kannst du eine Shape definieren – was eine einfache Sammlung von Zahlen ist, die deine gewünschten Dimensions repräsentiert – und PyTorch anweisen, basierend auf dieser Shape einen Tensor zu generieren, der mit Random Numbers, lauter Einsen oder lauter Nullen gefüllt ist. Sobald du einen Tensor hast, wirst du häufig drei Haupt-Attribute überprüfen. Das erste ist die Shape, die dir die genaue Größe des Tensors entlang jeder Dimension verrät. Das zweite ist der Data Type, der angibt, welche Art von Zahlen darin gespeichert sind, wie zum Beispiel 32-bit Floats oder Integers. Das dritte ist das Device-Attribut. Das sagt dir, wo sich der Tensor gerade physisch befindet, ob das auf der CPU oder einer bestimmten GPU ist. Du musst das im Auge behalten, denn PyTorch setzt voraus, dass Tensoren auf demselben Device liegen, bevor sie miteinander interagieren können. Tensoren und Standard-Arrays müssen oft zusammenarbeiten, was uns zur NumPy Bridge bringt. Tensoren, die auf der CPU liegen, können tatsächlich ihren zugrundeliegenden Memory mit einem NumPy-Array teilen. Angenommen, du lädst ein hochauflösendes Foto mit einer Standard-Python Image Processing Library. Dieses Bild wird als Standard-NumPy-Array in deinen System Memory geladen. Du kannst dieses Array an PyTorch übergeben, indem du eine spezielle Function nutzt, die einen Tensor aus NumPy erstellt. PyTorch dupliziert die zugrundeliegenden Pixeldaten dabei nicht in einen neuen Memory-Block. Es legt einfach sein eigenes Tensor-Interface um die bestehende Memory-Adresse. Wenn du einen Value im Tensor änderst, ändert das sofort den Value im NumPy-Array, und umgekehrt. Diese Zero-Copy Conversion spart sowohl Memory als auch Processing Time. Wenn du damit fertig bist, die Daten durch dein Model zu leiten, und die Results wieder an ein Standard-Visualization-Tool übergeben musst, rufst du eine einzige Method auf dem Tensor auf, um ihn wieder als NumPy-Array bereitzustellen – und zwar unter Verwendung genau desselben Shared Memory. Die wahre Power eines Tensors liegt nicht nur darin, ein Grid aus Zahlen zu speichern, sondern den spezifischen Hardware Context und die Memory-Struktur mitzubringen, die nötig sind, um Raw Data reibungslos durch ein neuronales Netzwerk zu pushen. Danke fürs Zuhören, Happy Coding zusammen!
3

Tensor-Operationen und Speicher

4m 02s

Lerne, wie man Tensors effizient manipuliert. Diese Episode behandelt arithmetische Operationen, Konkatenation, Device-Transfers und die Speicherauswirkungen von In-Place-Operationen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 3 von 18. Ein einzelner Unterstrich in deinem Code kann Gigabytes an Memory sparen, aber auch unbemerkt dein gesamtes Neural Network zerschießen. Zu wissen, wann du diesen Unterstrich nutzt, erfordert ein gutes Verständnis von Tensor Operations und Memory. Stell dir ein praktisches Szenario vor. Du hast drei separate Feature Vectors, die Text-, Audio- und Bilddaten repräsentieren. Du willst sie kombinieren und mit einer Weight Matrix multiplizieren. Standardmäßig erstellt PyTorch Tensors auf der CPU. Aber für rechenintensive Matrix-Berechnungen willst du einen Hardware Accelerator nutzen. Du kannst mit den Built-in Checks des Frameworks prüfen, ob eine GPU verfügbar ist. Wenn ja, verschiebst du deine Tensors, indem du ihre to-Methode aufrufst. Du übergibst dieser Methode den Namen des Target Devices, zum Beispiel den String cuda. PyTorch kopiert den Tensor dann vom System-RAM in den Dedicated Memory deiner Grafikkarte. Wenn deine Tensors auf der richtigen Hardware liegen, musst du die drei separaten Feature Vectors zu einem kombinieren. Das machst du mit der concatenate-Funktion, meistens einfach cat geschrieben. Du übergibst ihr eine Liste deiner Tensors und gibst eine Dimension an. Wenn du sie entlang der Column-Dimension kombinierst, werden deine drei schmalen Tensors Seite an Seite zu einem breiteren Tensor zusammengefügt. Du hast jetzt einen einheitlichen Input, der im GPU-Memory liegt. PyTorch beherrscht über hundert verschiedene Operations, aber Arithmetik ist die Grundlage. Um deinen kombinierten Feature Vector zu verarbeiten, musst du ihn mit einer Weight Matrix multiplizieren. Du kannst die matmul-Methode nutzen, oder einfach das At-Symbol als praktische Kurzschreibweise. Das führt eine echte mathematische Matrix Multiplication durch, berechnet die Dot Products von Rows und Columns, und gibt einen komplett neuen Tensor mit den Ergebnissen zurück. Manchmal brauchst du stattdessen element-wise Math. Angenommen, du willst eine Binary Mask auf deinen Tensor anwenden, die bestimmte Werte auf Null setzt. Dafür nutzt du die mul-Methode, oder den Standard-Asterisk-Operator. Das macht keine Matrix Multiplication. Es multipliziert einfach das erste Element von Tensor A mit dem ersten Element von Tensor B, das zweite mit dem zweiten, und so weiter. Jedes Mal, wenn du Operations wie Matrix Multiplication oder element-wise Addition ausführst, allokiert PyTorch neues Memory für das Ergebnis. Wenn du mit Millionen von Parameters arbeitest, verbraucht das extrem schnell dein verfügbares Hardware-Memory. Hier musst du aufpassen. PyTorch bietet In-Place Operations, um den Memory Overhead zu managen. Jede Operation, die mit einem Unterstrich endet, operiert in-place. Wenn du die Standard-add-Methode nutzt, bekommst du einen neuen Tensor. Wenn du die add-Methode mit einem Unterstrich nutzt, überschreibt PyTorch direkt die Werte im bestehenden Tensor. Der Memory Footprint bleibt exakt gleich. Während In-Place Operations extrem effizient für das Memory sind, sind sie auch gefährlich. Wenn du einen Tensor überschreibst, löschst du seine vorherigen Werte. Neural Networks verlassen sich auf einen kompletten Verlauf der vergangenen States, um während der Learning Phase Derivatives zu berechnen. Wenn du einen Tensor mit einer In-Place Operation überschreibst, zerstörst du die Computation History, die das System braucht, um das Model zu updaten. Reserviere In-Place Operations für das Formatieren von Daten, bevor sie in dein Model gehen, und bleib während des Trainings bei Standard Operations, um deine Computation History intakt zu halten. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
4

Die Magie von Autograd

3m 44s

Entpacke den Motor, der Deep Learning in PyTorch möglich macht. Lerne, wie Autograd Operationen dynamisch verfolgt und komplexe Ableitungen automatisch berechnet.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 4 von 18. Ein Neural Network zu trainieren bedeutet, die Ableitung deines Errors nach Millionen von Parametern zu berechnen. Das von Hand zu machen, würde seitenweise Differentialrechnung und ständiges Umschreiben erfordern, jedes Mal, wenn du deine Model Architecture änderst. PyTorch löst das, indem es deine Berechnungen im Hintergrund trackt – ein Konzept, das als die Magie von Autograd bekannt ist. Autograd ist die eingebaute Differentiation Engine von PyTorch. Sie berechnet automatisch Gradients für jeden Computational Graph. Um zu sehen, wie das funktioniert, stell dir eine ganz normale lineare Transformation vor. Du hast einen Input Tensor mit deinen Daten, eine Weight Matrix und einen Bias Vector. Das Ziel ist es, einen Output zu berechnen, ihn mit dem eigentlichen Target Value zu vergleichen und den Error, also den Loss, zu berechnen. Deine Input-Daten sind fest, also brauchst du ihre Ableitungen nicht. Aber die Weight und Bias Tensoren müssen später geupdatet werden, was bedeutet, dass du unbedingt ihre Gradients brauchst. Das signalisierst du PyTorch, indem du ein Flag namens requires grad auf true setzt, wenn du diese Parameter Tensoren erstellst. Das sagt der Autograd Engine, dass sie anfangen soll, diese zu überwachen. Wenn du Operationen auf diesen überwachten Tensoren ausführst – also den Input mit den Weights multiplizierst, den Bias addierst und den finalen Loss berechnest – macht PyTorch zwei Dinge gleichzeitig. Es berechnet das eigentliche numerische Ergebnis und konstruiert gleichzeitig einen Directed Acyclic Graph, oder DAG. In diesem Graph sind deine Start-Tensoren die Leaves, und die mathematischen Operationen, die du angewendet hast, sind die Roots. Jeder neue Tensor, der durch eine Operation erstellt wird, hat ein Attribut, das eine Referenz auf die Funktion speichert, die ihn erstellt hat. Das sagt Autograd ganz genau, wie die Ableitung für diesen spezifischen mathematischen Schritt berechnet werden muss. Dieser Graph ist keine statische Struktur, die am Anfang deines Scripts definiert wird. PyTorch baut den DAG in jeder einzelnen Iteration dynamisch komplett neu auf. Wenn du einen Forward Pass ausführst, wird on the fly ein brandneuer Graph konstruiert. Diese dynamische Execution bedeutet, dass dein Network sein Verhalten bei jedem Schritt ändern kann. Du kannst ganz normalen Python Control Flow nutzen, wie if Statements oder Loops, und die Engine trackt sauber genau den Pfad, den die Daten während dieses spezifischen Runs tatsächlich genommen haben. Sobald dein Forward Pass den finalen Loss Tensor produziert, triggerst du die Gradientenberechnung, indem du die backward Methode auf diesem Loss aufrufst. Autograd durchläuft den Graph sofort rückwärts. Es nutzt die Chain Rule, um die Ableitungen des Loss in Bezug auf jeden Tensor zu berechnen, bei dem requires grad auf true gesetzt ist. Dann nimmt es diese berechneten Werte und speichert sie im grad Attribut deiner Weight und Bias Tensoren. Die komplexe Differentialrechnung wird komplett abstrahiert. Es gibt Momente, in denen du Daten nur durch das Model pushen willst, ohne Gradients zu berechnen, zum Beispiel wenn du ein trainiertes Model evaluierst. Die History zu tracken, erfordert extra Memory und Rechenleistung. Du kannst Autograd komplett davon abhalten, den Graph zu bauen, indem du deinen Code Block in den torch no grad Context Manager wrappst. Das stoppt das Tracking vorübergehend und führt die Berechnungen viel schneller aus. Die wahre Power von Autograd ist, dass es beliebigen Python Code in eine vollständig differenzierbare mathematische Struktur verwandelt, ohne dass du jemals die Ableitungsformeln von Hand schreiben musst. Danke fürs Zuhören. Macht's gut zusammen.
5

Gradient Tracking steuern

4m 07s

Entdecke, wie du das Gradient Tracking von PyTorch deaktivierst, um Speicher zu sparen und die Berechnung zu beschleunigen. Unerlässlich für die Ausführung von Inference und das Einfrieren von Modellparametern.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 5 von 18. Wenn du ein neu trainiertes Modell auf einem großen Batch von Testbildern ausführst, ohne eine bestimmte Einstellung zu ändern, stürzt deine Anwendung irgendwann mit einem Out-of-Memory Error ab. Obwohl du nur Predictions machst, hortet das Modell heimlich Memory, um sich jede mathematische Operation zu merken, die es ausführt, bis das System abstürzt. Genau das verhinderst du, indem du das Gradient Tracking kontrollierst. Standardmäßig sind PyTorch-Tensoren fürs Lernen gebaut. Wenn bei einem Tensor das Gradient Requirement auf True gesetzt ist, trackt PyTorch jede Operation, die darauf ausgeführt wird. Es baut im Hintergrund einen Computation Graph auf, der Inputs, Weights und Outputs verknüpft, damit es später während der Backpropagation die Gradients berechnen kann. Diese Tracking Engine ist genial fürs Training, aber sie erfordert eine Menge Overhead. Wenn das Training abgeschlossen ist, ändern sich deine Prioritäten. Nehmen wir an, du hast gerade das Training eines Image Classifiers abgeschlossen und musst Predictions für eine Million neue Bilder ausführen. Du musst die Model Weights nicht mehr updaten. Du willst nur noch den Forward Pass. Wenn du die Tracking-Maschinerie weiterlaufen lässt, baut PyTorch für diese Million Bilder einen nutzlosen, riesigen Computation Graph auf, der deinen RAM frisst und deine Compute Cycles verlangsamt. Um das zu stoppen, hast du zwei primäre Tools. Das erste ist ein Context Manager namens torch dot no grad. Den benutzt du, um ganze Code-Blöcke zu wrappen. Wenn du deinen Forward Pass in einen no grad Block packst, sagst du PyTorch, dass es die Tracking Engine vorübergehend abschalten soll. Alle Operationen, die innerhalb dieses Blocks ausgeführt werden, werden nicht aufgezeichnet. Selbst wenn die Input-Tensoren normalerweise getrackt werden, wird das Gradient Requirement der Outputs, die innerhalb des Blocks erstellt werden, auf False gesetzt. Das ist dein Tool für Evaluation, Testing oder Bulk Predictions. Es schaltet den Graph für alles innerhalb seines Scopes ab. Das zweite Tool ist die detach Methode. Während no grad Code-Blöcke behandelt, kümmert sich detach um einzelne Tensoren. Wenn du detach auf einem Tensor aufrufst, bekommst du einen neuen Tensor zurück, der exakt dieselben zugrundeliegenden Daten wie das Original teilt, aber komplett vom Computation Graph getrennt ist. Er hat keine History. Die Leute verwechseln oft, wann sie was benutzen sollen. Benutze den torch dot no grad Context Manager, wenn du das Tracking für eine Sequenz von Operationen stummschalten willst, wie zum Beispiel beim Wechsel vom Training zur Inference. Benutze die detach Methode, wenn du während des Trainings aktiv einen Computation Graph aufbaust, aber einen bestimmten Tensor aus diesem Graph herausziehen musst. Ein häufiger Use Case für detach ist, wenn du einen Tensor an eine andere Python Library wie NumPy übergeben musst, die keine PyTorch Computation Graphs versteht. Du wendest zuerst detach auf den Tensor an, streifst den Tracking-Ballast ab und übergibst dann die rohen Zahlen. Das Deaktivieren von Gradient Tracking ist auch eine Kerntechnik zum Einfrieren von Parametern. Wenn du ein riesiges pre-trained Modell fine-tunst, willst du wahrscheinlich nicht das ganze Ding von Grund auf neu trainieren. Du kannst in einer Loop durch die Base Layers des Modells gehen und ihr Gradient Requirement auf False setzen. PyTorch hört komplett auf, sie zu tracken. Während des Backward Pass berechnen diese eingefrorenen Layers keine Gradients und machen kein Update, was massiv Memory spart und deinen Fine-Tuning-Prozess dramatisch beschleunigt. Gradient Tracking ist schwere industrielle Maschinerie, die strikt fürs Lernen designt wurde. Wann immer ein Tensor nicht lernen muss, schalte die Maschinerie ab, um deinen Memory und deine Geschwindigkeit zurückzugewinnen. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
6

Datasets und Datenverarbeitung

4m 01s

Lerne, wie du deine Datenverarbeitung mithilfe der PyTorch Dataset-Klasse von deiner Modellarchitektur entkoppelst. Wir untersuchen Lazy Loading und benutzerdefinierte Dataset-Strukturen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 6 von 18. Dein Modell ist nur so gut wie die Daten, mit denen du es fütterst, aber was machst du, wenn dein Dataset ein Terabyte groß ist und dein Rechner nur sechzehn Gigabyte RAM hat? Die Antwort liegt darin, wie du diese Daten fetchst. Diese Folge behandelt Datasets und Data Handling. Data Processing Logik kann schnell unübersichtlich werden. Wenn du deinen Code zum Lesen, Decoden und Formatieren von Files direkt in deinen Model Training Loop mischst, wird dein Projekt fehleranfällig und schwer zu warten. PyTorch ermutigt dich, diese Bereiche zu entkoppeln. Du willst deine Data Preparation komplett getrennt von deinem Training Algorithm haben. Um das zu erreichen, bietet PyTorch ein Primitive namens Dataset im Modul torch dot utils dot data. Die Dataset Klasse dient als standardisierter Wrapper für deine Raw Data. Um deine eigenen spezifischen Files zu handlen, erstellst du eine Custom Class, die von diesem Primitive erbt. Wenn du ein Custom Dataset baust, musst du drei spezifische Methoden implementieren. Diese sind init, len und getitem. Die init Methode läuft genau einmal, wenn du das Dataset Objekt erstellst. Hier konfigurierst du deine Directories und Paths. Ein häufiger Fehler, den Anfänger machen, ist der Versuch, die gesamten eigentlichen Daten genau hier in den Memory zu laden. Mach das nicht. Wenn du fünfzigtausend hochauflösende Bilder hast, crasht das Einlesen all dieser Bilder in den Memory während der Initialisierung sofort deine Maschine. Nutze stattdessen init, um einen simplen Index zu laden. Zum Beispiel könntest du ein CSV File einlesen, das in einer Column die Filenames der Bilder und in einer anderen die zugehörigen Text Labels enthält. Du baust nur die Map, du hältst nicht das Territory. Als Nächstes kommt die len Methode. Diese gibt einfach die Gesamtzahl der Samples in deinem Dataset zurück. Wenn dein CSV File fünfzigtausend Rows hat, gibt diese Methode die Zahl fünfzigtausend zurück. Das System verlässt sich darauf, um die absoluten Grenzen deiner verfügbaren Daten zu kennen, damit es keinen Index anfragt, der nicht existiert. Die eigentliche Arbeit passiert in der getitem Methode. Diese Funktion ist dafür designt, ein einzelnes Sample an einem spezifisch angefragten Index zu laden und zurückzugeben. Wenn das System Sample Nummer zweiundvierzig braucht, ruft es getitem auf und übergibt diese Nummer. Dein Code sucht Row zweiundvierzig in dem CSV, das du vorhin geladen hast. Er liest den File Path String aus dieser Row. Dann, und nur dann, greift er auf die Disk zu, findet das File und decodet die eigentlichen Image Pixel in den Memory. Er schnappt sich das Label aus derselben CSV Row und gibt das Image und das Label zusammen als Tuple zurück. Diese Technik wird Lazy Loading genannt. Du verbrauchst nur Memory für den spezifischen Teil der Daten, den du brauchst, genau in dem Moment, in dem du bereit bist, ihn zu verarbeiten. Durch das Isolieren dieser Logik in der getitem Methode muss dein Training Code nie wissen, ob die Daten von einem lokalen Hard Drive, einem Network Stream oder einer komplexen Database stammen. Er fragt einfach einen Index an und erhält einen standardisierten Output. Den Mechanismus, wie Daten gefetcht werden, davon zu trennen, wie sie consumed werden, ist die Foundation von skalierbarem Machine Learning Code. Wenn du diese Folgen hilfreich findest und die Show unterstützen möchtest, kannst du auf Patreon nach DevStoriesEU suchen. Das war's für diese Folge. Danke fürs Zuhören und keep building!
7

DataLoaders und Batching

3m 42s

Entfessele die volle Geschwindigkeit deiner Hardware, indem du Datasets in DataLoaders verpackst. Lerne, wie du deine Datenströme in Batches aufteilst, mischst und mit Multiprocessing verarbeitest.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 7 von 18. GPUs sind unglaublich schnell, aber sie bleiben komplett ungenutzt, wenn deine CPU ihnen nicht schnell genug Daten liefern kann. Bei Training Loops liegt der Bottleneck oft nicht bei der Mathematik, sondern beim Laden der nächsten Files von der Festplatte. Die Lösung dafür ist, den Datenabruf von der Model Execution zu trennen, und zwar mit DataLoaders und Batching. Es ist leicht, die Rollen von einem Dataset und einem DataLoader zu verwechseln. Ein Dataset hat genau einen Job: ein einzelnes Item und sein Label zu fetchen. Es weiß nichts über den restlichen Trainingsprozess. Der DataLoader ist ein Wrapper um dieses Dataset. Er fungiert als Manager, der dafür verantwortlich ist, diese einzelnen Items in Gruppen zu organisieren, ihre Reihenfolge zu randomisieren und mehrere Prozesse zu nutzen, um sie effizient zu laden. Während des Trainings schauen sich Modelle selten nur einen Datenpunkt auf einmal an. Sie updaten ihre internen Weights basierend auf einer Gruppe von Items, die gleichzeitig evaluiert werden – einem sogenannten Minibatch. Dieser Ansatz macht den Trainingsprozess stabiler und nutzt die parallele Processing Power der Hardware voll aus. Um einen Minibatch manuell zu bauen, müsstest du einen Loop schreiben, der einzelne Samples zieht, sie zu einer größeren Tensor-Struktur zusammenfügt und Edge Cases behandelt, wie zum Beispiel, dass der letzte Batch kleiner ist als der Rest. Der DataLoader übernimmt all das automatisch. Du initialisierst einen DataLoader, indem du ihm dein Dataset-Objekt und einen Parameter namens Batch Size übergibst. Wenn du die Batch Size auf 64 setzt, zieht der DataLoader 64 verschiedene Items aus dem Dataset, fasst sie in einem einzigen Tensor zusammen und stellt sie auf einmal bereit. In deinem Code verhält sich der DataLoader wie ein Standard-Python-Iterable. Du iterierst in einem Loop darüber. Jedes Mal, wenn der Loop weitergeht, yieldet der DataLoader den nächsten kompletten Batch an Daten und den dazugehörigen Batch an Labels. Du übergibst außerdem einen Shuffle-Parameter. Wenn ein Neural Network Trainingsdaten jedes Mal in exakt derselben Sequenz verarbeitet, merkt es sich vielleicht diese spezifische Sequenz, anstatt die eigentlichen Features zu lernen. Wenn du Shuffle auf True setzt, sagst du dem DataLoader, dass er die Reihenfolge der Dataset-Items zu Beginn jeder Epoch randomisieren soll. Sobald jeder Batch geyieldet wurde und das Dataset durch ist, endet der Loop. Wenn du das nächste Mal über den DataLoader iterierst, generiert er eine komplett neue, randomisierte Sequenz. Das ist der Teil, auf den es ankommt. Der DataLoader akzeptiert auch einen Parameter für die Anzahl der Worker-Prozesse. Wenn du mehrere Worker nutzt, startet der DataLoader CPU-Prozesse im Hintergrund, um die Daten zu fetchen. Stell dir vor, du fütterst diese 64 Bilder in ein Neural Network. Während deine GPU damit beschäftigt ist, Gradients für den aktuellen Batch zu berechnen, lesen, decodieren und stacken die CPU-Worker im Hintergrund gleichzeitig die nächsten 64 Bilder. Sobald die GPU ihren aktuellen mathematischen Schritt beendet hat, wartet der nächste Batch an Daten bereits im Memory. Die GPU läuft nie leer. Ein High-Performance Training Loop isoliert die langsame, unvorhersehbare Realität von Disk Operations von der schnellen, strukturierten Realität des Model Trainings. Der DataLoader sorgt für diese Isolation und verwandelt eine Sammlung einzelner Files in eine kontinuierliche, parallelisierte Pipeline von Minibatches. Das war's für diese Folge. Danke fürs Zuhören und keep building!
8

Daten-Transformationen

4m 34s

Entdecke, wie du Rohdaten on-the-fly vorverarbeitest, bevor sie auf dein Neural Network treffen. Wir behandeln torchvision-Transforms wie ToTensor und benutzerdefinierte Lambda-Funktionen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 8 von 18. Neural Networks berechnen nur Zahlen, aber deine realen Daten sind meist eine chaotische Sammlung von Raw Image Files und Textkategorien. Wenn du manuelle Loops schreibst, um jedes einzelne Bild und Label zu konvertieren, bevor du mit dem Training beginnst, wird dein Code schnell zu einem fehleranfälligen, unlesbaren Chaos. Data Transformations sind der Mechanismus, der dieses Problem löst, indem sie deine Raw Data automatisch in ein model-ready Format konvertieren – genau dann, wenn es benötigt wird. Daten kommen selten bereit für Machine Learning an. Du musst sie in ein bestimmtes Tensor-Format umwandeln, bevor du sie an dein Network übergibst. PyTorch erledigt das elegant, indem es Transforms on the fly während des Data Loading Prozesses anwendet. Wenn du ein Dataset initialisierst, besonders in Libraries wie torchvision, definierst du diese Modifikationen mit zwei spezifischen Argumenten. Das transform-Argument nutzt du ausschließlich für deine Input Features, wie deine Raw Images. Das target transform Argument nutzt du ausschließlich für deine Labels. Es ist extrem wichtig, diese beiden getrennt zu halten, da sie unabhängig voneinander auf unterschiedlichen Hälften deiner Daten operieren. Schauen wir uns zuerst die Input Features an. Angenommen, du hast ein Dataset mit rohen PIL Images. Ein Neural Network kann ein PIL Image Object nicht direkt lesen. Um das zu beheben, übergibst du einen eingebauten torchvision Transform namens ToTensor an das transform-Argument. Wenn das Dataset ein Bild lädt, führt ToTensor automatisch zwei Schritte aus. Erstens konvertiert es das PIL Image in einen PyTorch Float Tensor. Zweitens skaliert es die Pixel Intensity Values. Die Pixel von Raw Images liegen normalerweise zwischen null und 255. Die ToTensor-Operation normalisiert diese Werte auf einen Floating-Point-Bereich zwischen null und eins. Das Dataset wendet diese Operation strikt beim Abrufen jedes einzelnen Bildes an. Das deckt die Inputs ab, aber was ist mit den Outputs? Die Labels deines Datasets könnten einfache Integers sein, die verschiedene Kategorien repräsentieren. Zum Beispiel könnte die Zahl drei für einen Hund stehen. Aber um den Loss während des Trainings zu berechnen, verlangt dein Model oft, dass diese Labels One-Hot-Encoded Vectors sind, anstatt einzelner Integers. Das bedeutet, du brauchst ein Array, in dem alle Werte null sind, außer an dem Index, der die korrekte Class repräsentiert; dieser wird auf eins gesetzt. Um solche Custom Logic zu handhaben, bietet PyTorch Lambda Transforms. Ein Lambda Transform kapselt eine beliebige User-Defined Function, sodass sie beim Data Loading angewendet werden kann. Du schreibst eine kurze Funktion, die dein Integer-Label als Input nimmt. Innerhalb dieser Funktion erstellst du einen Tensor aus Nullen, der der Gesamtzahl der Kategorien in deinem Dataset entspricht. Dann nutzt du eine interne PyTorch-Operation, um den Wert eins in den spezifischen Index zu scattern, der deinem Integer-Label entspricht. Du übergibst diese Custom Function an einen Lambda Transform und weist diesen dann dem target transform Argument deines Datasets zu. Das erzeugt eine hocheffiziente Pipeline. Ein Worker Thread zieht einen einzelnen Raw Record von deiner Disk. Das Bild trifft auf das transform-Argument, durchläuft ToTensor und kommt als normalisierter Float Tensor heraus. Gleichzeitig trifft die Integer-Kategorie auf das target transform Argument, führt deine Custom Lambda Function aus und verwandelt sich in einen One-Hot-Encoded Vector. Beide Teile sind nun mathematisch formatiert und werden direkt an dein Model übergeben. Die wahre Stärke dieser Architektur ist die Separation of Concerns. Indem du diese Data Transforms direkt an die Dataset-Definition anhängst, bleibt dein eigentlicher Training Loop völlig blind für die chaotische Realität deiner Raw Files. Das war’s für diese Folge. Danke fürs Zuhören und keep building!
9

Netzwerke mit nn.Module entwerfen

4m 21s

Erkunde den strukturellen Bauplan jedes PyTorch Neural Networks. Lerne, wie du nn.Module als Unterklasse verwendest, Layer in der Initialisierung definierst und Daten im Forward Pass weiterleitest.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 9 von 18. Jedes Neural Network in PyTorch, vom einfachen Image Classifier bis zum riesigen Language Model, teilt sich exakt denselben zugrundeliegenden Blueprint. Wenn du nicht verstehst, wie dieser Blueprint Daten und Logik organisiert, wirst du bei jedem Schritt mit dem Framework kämpfen. Netzwerke mit nn.Module zu designen, ist der Weg, wie du diese Struktur meisterst. Das nn.Module ist die Base Class für alle Neural Network Komponenten in PyTorch. Es fungiert als universeller Container. Wenn du ein Custom Model baust, erstellst du eine Klasse, die von nn.Module erbt. Diese Vererbung gibt deiner Klasse automatisch die Fähigkeit, ihre eigenen Parameter zu tracken, Gradients zu berechnen und sich nahtlos in den Rest des PyTorch-Ökosystems zu integrieren. Es erlaubt außerdem verschachtelte Architekturen. Du kannst Module in andere Module packen und so einen Baum aus Layers erstellen, den das Parent-Module trackt und als eine einzige Einheit managt. Stell dir vor, du baust das leere Skeleton eines brandneuen Image Classifiers auf. Um dieses Skeleton zu bauen, musst du zwei spezifische Methoden definieren: die initialize-Methode und die forward-Methode. PyTorch erzwingt eine strikte Separation of Concerns zwischen diesen beiden Phasen. Zuerst kommt die initialize-Methode. Stell dir das wie dein Inventar vor. Wenn die Klasse instanziiert wird, läuft diese Methode genau einmal. Du nutzt sie, um all die einzelnen Layers und mathematischen Operationen zu deklarieren, die dein Model später brauchen wird. Du verarbeitest hier noch keine echten Daten. Du nimmst einfach nur strukturelle Komponenten aus dem Regal, konfigurierst ihre Input- und Output-Shapes und speicherst sie als interne Variablen in deiner Klasse. Als Nächstes kommt die forward-Methode. Das ist dein aktives Fließband. Die forward-Methode nimmt einen Input-Tensor und diktiert genau, wie er durch das Inventar wandert, das du gerade deklariert hast. Du schreibst die Sequenz der Operationen Schritt für Schritt. Du nimmst den Input-Image-Tensor, übergibst ihn an eine Flattening-Operation, fütterst das Ergebnis in eine Reihe von Dense Layers und gibst schließlich die Output-Predictions zurück. Jedes Custom Model muss diese forward-Methode definieren, um den Data Flow zu etablieren. Das bringt uns zu einer häufigen Falle. Weil du die Data-Flow-Logik explizit in einer Methode namens forward geschrieben hast, ist der natürliche Instinkt, deine Daten zu übergeben, indem du model Punkt forward aufrufst. Tu das nicht. Du musst das Model direkt aufrufen, als wäre es eine reguläre Funktion, und deinen Input direkt an das instanziierte Model-Objekt übergeben. Under the hood triggert die direkte Ausführung des Model-Objekts mehrere kritische Background-Hooks, die PyTorch braucht, um den Network State zu managen. Die forward-Methode direkt aufzurufen, umgeht diese Hooks und wird während deiner Training Loop zu unerwartetem Verhalten führen. Sobald deine Klasse definiert ist und du ein Model-Objekt erstellt hast, hast du ein funktionierendes Netzwerk. Standardmäßig erstellt PyTorch dieses Objekt und all seine internen Weights jedoch im CPU-Memory deines Systems. Um mit realistischen Geschwindigkeiten zu trainieren, musst du diese Architektur an einen Accelerator schicken. Das erreichst du, indem du checkst, ob eine CUDA-GPU oder spezialisiertes Silicon wie Apples MPS verfügbar ist, und dieses Hardware-Target einer Device-Variable zuweist. Dann rufst du die to-Methode auf deinem Model auf und übergibst diese Device-Variable. Dieser einzelne Befehl verschiebt sofort alle initialisierten Model-Parameter aus dem Standard-Memory in den High-Speed-Memory deines Hardware-Accelerators. Das definierende Merkmal von nn.Module ist, wie es eine saubere architektonische Grenze erzwingt: zwischen den statischen Komponenten, die dein Model im Memory besitzt, und dem dynamischen Pfad, den deine Daten nehmen, um verarbeitet zu werden. Danke fürs Zuhören. Macht's gut zusammen.
10

Linear Layers und Activations

4m 20s

Wirf einen Blick ins Innere des Neural Networks. Wir zerlegen das nn.Linear-Modul und erklären, warum nicht-lineare Activation-Funktionen wie ReLU mathematisch unerlässlich sind.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 10 von 18. Wenn du hundert Neural Network Layers ohne einen bestimmten mathematischen Trick übereinander stapelst, kollabiert das gesamte Netzwerk mathematisch zu einer einzigen geraden Linie. Der Übeltäter ist die lineare Algebra, und die Lösung erfordert, dass du Linear Layers und Activations verstehst. Ein Neural Network ist im Grunde eine Abfolge mathematischer Operationen auf Tensoren. Die häufigste Operation ist der Linear Layer, in PyTorch definiert als nn.Linear. Dieses Modul wendet eine affine Transformation auf eingehende Daten an. Es hält zwei interne Tensoren, die es im Laufe der Zeit lernt: die Weights und die Biases. Wenn Daten durchlaufen, multipliziert der Layer den Input mit der Weight-Matrix und addiert den Bias. Nimm ein Standard-Graustufenbild mit 28 mal 28 Pixeln. Bevor ein Linear Layer das verarbeiten kann, flattenst du das zweidimensionale Grid in ein eindimensionales Array aus 784 Zahlen. Du übergibst dieses Array mit 784 Werten an einen nn.Linear Layer, der so konfiguriert ist, dass er 512 Features ausgibt. Unter der Haube erstellt PyTorch eine Weight-Matrix, die die 784 Inputs auf 512 Outputs mappt. Es multipliziert deine Pixelwerte mit diesen Weights, summiert sie auf, addiert einen Bias-Term, um das Ergebnis zu shiften, und gibt 512 neue Zahlen aus. Während des Trainings updatet PyTorch diese Weights und Biases kontinuierlich. Sie bilden das eigentliche Gedächtnis deines Models. Du nimmst vielleicht an, ein Deep Neural Network ist einfach nur eine lange Sequenz dieser Linear Layers, die direkt hintereinander gestapelt sind. Genau das ist der entscheidende Punkt. Wenn du mehrere nn.Linear Operationen ohne etwas dazwischen chainst, vereinfacht sich die Mathematik. Matrix A multipliziert mit Matrix B ist einfach nur eine weitere Matrix C. Zehn Linear Layers zu stapeln, hat exakt dieselbe mathematische Kapazität wie die Berechnung eines einzigen Linear Layers. Dein Deep Network wird auf eine flache, lineare Gleichung reduziert, die völlig unfähig ist, komplexe Muster aus der echten Welt zu lernen. Um diesen mathematischen Kollaps zu stoppen, führst du direkt nach dem Linear Layer eine Non-Linearity ein. Diese nennt man Activation Functions. Die am häufigsten verwendete Activation in PyTorch ist nn.ReLU, was für Rectified Linear Unit steht. Nachdem der Linear Layer seine 512 Outputs berechnet hat, übergibst du diesen Tensor direkt an eine ReLU-Funktion. Die Logik von ReLU ist brutal einfach. Sie schaut sich jede Zahl im Tensor an. Wenn eine Zahl kleiner als null ist, ändert ReLU sie auf exakt null. Wenn eine Zahl null oder positiv ist, lässt ReLU sie komplett in Ruhe. Dieser einzige Knick bei null zerstört die Linearität. Er verhindert, dass der nächste Linear Layer mathematisch mit dem vorherigen verschmilzt. Indem negative Werte auf null gezwungen werden, erzeugt ReLU außerdem Sparse Representations. Das bedeutet, dass für jeden gegebenen Input nur ein bestimmtes Subset von Neuronen aktiviert wird, was das Network hocheffizient macht. Der Data Flow ist konsistent. Dein geflattentes Bild geht in den Linear Layer, wird durch die Weights und Biases transformiert und trifft dann auf die ReLU-Activation, wo die negativen Outputs weggeschnitten werden. Du kannst diesen aktivierten Tensor dann sicher an einen zweiten Linear Layer übergeben, um tiefere, abstraktere Muster zu extrahieren. Ein Linear Layer bestimmt, wie viel mathematische Wichtigkeit jedem Input gegeben wird, aber die Activation Function gibt dem Network die tatsächliche Geometrie, die erforderlich ist, um die unvorhersehbaren Formen echter Daten zu lernen. Danke, dass du ein paar Minuten mit mir verbracht hast. Bis zum nächsten Mal, mach's gut.
11

Der nn.Sequential Container

4m 08s

Optimiere deinen PyTorch-Code mit dem nn.Sequential-Container. Lerne, wie du Layer sauber zusammensteckst und die Parameter deines Modells überprüfst.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 11 von 18. Eigene forward-Methoden für jedes neuronale Netzwerk zu schreiben, wird schnell mühsam, wenn du nur Standard-Layer stapelst. Du musst Daten nicht immer manuell von einer Funktion zur nächsten routen. Manchmal willst du Layer einfach wie Legosteine zusammenstecken. Genau das macht der nn.Sequential Container. Der nn.Sequential Container ist eine geordnete Pipeline von Neural Network Modulen. Wenn du Daten in diesen Container übergibst, fließen sie durch die internen Module in genau der Reihenfolge, in der sie hinzugefügt wurden. Stell dir vor, du baust ein Standard-Multilayer-Perceptron mit drei Layern. Normalerweise würdest du deine Linear-Layer und Aktivierungsfunktionen in einer init-Methode definieren und dann eine eigene forward-Methode schreiben. In dieser forward-Methode würdest du den Input explizit nehmen, ihn an Layer eins übergeben, in eine ReLU-Aktivierung packen, das Ergebnis an Layer zwei übergeben, noch ein ReLU anwenden und das Ganze an den finalen Layer weitergeben. Mit Sequential umgehst du die forward-Methode komplett. Du instanziierst den Container und übergibst deine Module direkt als Argumente hinein. Du übergibst ein Linear-Modul, gefolgt von einem ReLU-Modul, einem zweiten Linear-Modul, noch einem ReLU und einem finalen Linear-Modul. PyTorch übernimmt das Data Routing automatisch. Der Output des ersten Moduls wird sofort zum Input des zweiten, und das geht automatisch die ganze Chain hinunter. Dieser Container ist hocheffizient, hat aber ein hartes Limit. Er ist strikt für linearen, geradlinigen Data Flow gedacht. Er kann keine komplexen Architekturen verarbeiten, die Branching, Multiple Inputs oder Skip Connections erfordern. Wenn du so etwas wie ein Residual Network baust, bei dem Daten bestimmte Layer umgehen und später wieder hinzugefügt werden, wird Sequential nicht funktionieren. Für jede nicht-lineare Topologie musst du weiterhin ein eigenes Modul mit einer dedizierten forward-Methode schreiben. Sobald du deine Layer verkettet hast, musst du oft inspizieren, was du da gerade gebaut hast. Jeder Layer in deinem Sequential Container ist eine Subclass von nn.Module, was bedeutet, dass PyTorch den gesamten zugrunde liegenden State automatisch registriert und trackt. Um diesen State zu sehen, nutzt du die named_parameters Methode. Der Aufruf von named_parameters auf deinem Model liefert einen Iterator über alle Weights und Biases darin. Jedes Item, das er zurückgibt, ist ein einfaches Paar: der Name des Parameters und der Parameter-Tensor selbst. Weil du einen Sequential Container verwendet hast, ohne deine Layer explizit zu benennen, generiert PyTorch numerische Namen basierend auf ihrem Index. Du wirst Namen sehen wie zero dot weight für die Weights des ersten Linear-Layers, oder zero dot bias für seine Bias-Terms. Der dazugehörige Tensor enthält die tatsächlichen numerischen Werte, die Shape der Matrix und die Info, ob er eine Gradientenberechnung erfordert. Durch named_parameters zu loopen, ist der Standardweg, um deine Architektur zu verifizieren. Du kannst dir schnell die Size jeder Weight-Matrix ausgeben lassen, um zu bestätigen, dass deine Input- und Output-Dimensions über die gesamte Chain hinweg perfekt übereinstimmen, bevor du überhaupt anfängst, echte Daten durch das System zu pushen. Die wahre Power des Sequential Containers in Kombination mit Parameter-Tracking ist, dass PyTorch das Bookkeeping für State Management und Data Routing übernimmt, sodass du dich komplett auf die Shape deines Networks konzentrieren kannst. Das war's für dieses Mal. Bis zum nächsten Mal!
12

Loss Functions verstehen

3m 26s

Bevor eine KI lernen kann, muss sie ihre Fehler messen. Wir tauchen in PyTorch Loss Functions ein und vergleichen CrossEntropyLoss für Klassifikation und MSELoss für Regression.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 12 von 18. Um einem Neural Network beizubringen, richtig zu liegen, musst du zuerst genau messen, wie falsch es liegt. Wenn du Fehler nicht quantifizieren kannst, kann dein Model nicht daraus lernen. Das bringt uns zum Thema Loss Functions. Wenn ein ungetrainiertes Neural Network Daten verarbeitet, ist sein Output im Grunde nur geraten. Eine Loss Function bewertet diesen Guess. Sie misst den Grad der Abweichung zwischen dem vom Model erzeugten Ergebnis und der absoluten Wahrheit des Target-Werts. Der Output einer Loss Function ist immer eine einzelne skalare Zahl. Dein gesamter Trainingsprozess existiert nur, um diese eine Zahl so nah wie möglich an null zu bringen. Da verschiedene Machine-Learning-Tasks unterschiedliche Definitionen von falsch haben, bietet PyTorch mehrere Loss Functions. Wenn du ein Regression Model baust, um einen kontinuierlichen Wert wie die morgige Temperatur vorherzusagen, misst du den Abstand zwischen deinem Guess und der echten Temperatur. Dafür verwendest du den Mean Square Error, der in PyTorch nn.MSELoss heißt. Aber Classification ist anders. Angenommen, du hast ein Model, das Bilder von Kleidung in zehn Fashion-Kategorien einteilt. Das Model betrachtet ein Bild von einem Mantel und gibt zehn Raw Scores aus, einen für jede mögliche Kategorie. Diese rohen, unnormalisierten Scores nennt man Logits. Die richtige Antwort ist einfach ein einzelner Integer, der die korrekte Klasse repräsentiert. Du kannst nicht einfach einen Class Index von einem Raw Score subtrahieren. Stattdessen brauchst du eine Funktion, die das Model dafür bestraft, wenn es der richtigen Klasse niedrige Scores und den falschen Klassen hohe Scores gibt. Für Classification ist das Standard-Tool nn.CrossEntropyLoss. Du initialisierst deine Loss Function, übergibst ihr die zehn Raw Logits von deinem Model zusammen mit dem korrekten Integer Label, und sie gibt dir deine skalare Penalty zurück. Das ist der Teil, auf den es ankommt. Hier gibt es eine riesige Falle für Developer. In vielen Machine-Learning-Lehrbüchern endet ein Classification Network mit einem Softmax Layer. Softmax zwingt Raw Logits in eine saubere Probability Distribution, bei der sich alle Scores auf exakt eins addieren. Deswegen fügen Developer oft manuell eine Softmax Operation ganz am Ende ihres PyTorch Models hinzu. Wenn du nn.CrossEntropyLoss verwendest, ist das ein Fehler. In PyTorch wendet nn.CrossEntropyLoss intern automatisch eine LogSoftmax-Funktion an, bevor die Negative Log Likelihood berechnet wird. Sie ist so gebaut, dass sie rohe, unnormalisierte Logits direkt akzeptiert. Wenn dein Model Probabilities ausgibt, weil du bereits Softmax angewendet hast, und du diese an nn.CrossEntropyLoss übergibst, wendest du die Mathematik doppelt an. Das komprimiert deine Gradients, verlangsamt das Training drastisch und ruiniert die Fähigkeit deines Models, effektiv zu lernen. Die Regel, die du dir merken musst, lautet: Dein Neural Network sollte einfach nur Raw Numbers ausgeben. Lass deine Model Outputs roh, übergib sie direkt an nn.CrossEntropyLoss und lass PyTorch die schwere Arbeit machen, diese Logits in eine sinnvolle Penalty zu verwandeln. Danke fürs Zuhören und Happy Coding zusammen!
13

Optimizers und Gradient Descent

4m 01s

Erkunde, wie der Optimizer Modellgewichte aktualisiert, um Fehler zu reduzieren. Lerne den entscheidenden Drei-Schritte-Tanz aus zero_grad(), backward() und step().

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 13 von 18. Der häufigste Bug beim PyTorch-Training liegt nicht an schlechten Daten oder einer falschen Architektur. Er passiert, wenn du vergisst, deine alten Berechnungen zu löschen, was dazu führt, dass dein Network außer Kontrolle gerät. Heute behandeln wir Optimizer und Gradient Descent, was genau steuert, wie dein Model aus seinen Fehlern lernt. Dein Model macht eine Prediction, und du berechnest den Loss, um zu sehen, wie weit es daneben lag. Jetzt musst du die internen Weights des Neural Networks anpassen, um die nächste Prediction etwas genauer zu machen. Dieser Prozess, die Parameter anzupassen, um den Loss zu minimieren, wird Optimization genannt. Der Optimizer ist der spezifische Algorithmus, der steuert, wie sich diese Weights verändern. Um einen Optimizer zu konfigurieren, musst du ihm zwei Dinge übergeben. Erstens übergibst du ihm ein Iterable, das die Model-Parameter enthält, die er anpassen soll. Zweitens übergibst du eine Learning Rate. Die Learning Rate ist ein grundlegender Hyperparameter, der die Größe der Änderungen steuert, die auf die Weights angewendet werden. Wenn die Learning Rate zu klein ist, macht der Optimizer mikroskopisch kleine Steps, was das Training extrem langsam macht. Wenn die Learning Rate zu groß ist, schießt der Optimizer über die optimalen Werte hinaus, was zu wildem, unvorhersehbarem Verhalten führt. Ein Standardalgorithmus für diese Aufgabe ist Stochastic Gradient Descent, oder SGD. Er evaluiert die Steigung deiner Loss Function und macht einen Step in die entgegengesetzte Richtung, um zum geringstmöglichen Fehler abzusteigen. Sobald du deinen SGD-Optimizer mit deinen Parametern und der Learning Rate initialisierst, passieren die eigentlichen Updates in einer strikten Drei-Schritte-Sequenz. Schritt eins ist, reinen Tisch zu machen. Du rufst den zero grad Command auf dem Optimizer auf. Genau hier versteckt sich dieser häufige Bug. PyTorch akkumuliert Gradients standardmäßig. Wenn es neue Gradients berechnet, überschreibt es die alten nicht; es addiert die neuen Zahlen einfach zu den bestehenden Summen. Wenn du diesen zero grad Step überspringst, werden die Berechnungen deines aktuellen Batches durch die übrig gebliebenen Zahlen aus dem vorherigen Batch verfälscht. Setze die Gradients also immer auf null, bevor du irgendetwas anderes tust. Schritt zwei ist die Berechnung der neuen Gradients. Du nimmst deinen berechneten Loss-Wert und rufst den backward Command darauf auf. Das triggert die Backpropagation. PyTorch wandert rückwärts durch deine Network-Architektur. Es berechnet die Ableitung des Loss in Bezug auf jeden einzelnen Parameter. Im Grunde findet es genau heraus, wie viel jedes einzelne Weight zum Gesamtfehler beigetragen hat. Diese berechneten Gradients werden direkt in den Parameter-Objekten gespeichert. Schritt drei ist das Anwenden der Korrektur. Du rufst den step Command auf dem Optimizer auf. Der Optimizer schaut sich die Gradients an, die während des backward Pass in jedem Parameter gespeichert wurden. Er multipliziert diese Gradients mit der Learning Rate, um die genaue Größe der Anpassung herauszufinden, und aktualisiert dann die tatsächlichen Weights im Memory. Dieser Zyklus wiederholt sich für jeden Batch. Gradients auf null setzen, den backward Loss berechnen, den Optimizer einen Step machen lassen. Das entscheidende Detail, das du dir merken musst, ist, dass der Optimizer nur die Parameter aktualisiert, die ihm beim Setup explizit übergeben wurden. Wenn du einen Layer in deinem Network einfrieren musst, schließt du seine Parameter bei der Initialisierung des Optimizers einfach aus, und diese Weights bleiben dauerhaft fixiert. Übrigens, wenn ihr die Show unterstützen möchtet, könnt ihr auf Patreon nach DevStoriesEU suchen. Danke fürs Zuhören. Macht's gut, Leute.
15

Validation und Inference

4m 14s

Bewerte dein Modell objektiv. Lerne, wie du dein Netzwerk in den Evaluation-Modus versetzt, Gradienten einfrierst und präzise Vorhersagen für ungesehene Daten extrahierst.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 15 von 18. Dein Modell funktioniert vielleicht perfekt auf seinen Trainingsdaten, aber der einzig wahre Test für eine KI ist, wie sie mit dem Unbekannten umgeht. Wenn du dich ausschließlich auf das Feedback verlässt, das dein Optimizer sieht, baust du vielleicht nur eine sehr teure Memory Bank. Um zu sehen, ob dein Modell tatsächlich auf die reale Welt generalisiert, brauchst du Validation und Inference. Während der Trainingsphase schaust du dir den Training Loss an. Diese Zahl ist dafür da, den internen Optimizer zu steuern. Sie zwingt das Modell, seine Weights anzupassen, bis der mathematische Fehler schrumpft. Aber ein niedriger Training Loss bedeutet nicht, dass du ein gutes Modell hast. Er bedeutet einfach nur, dass das Modell sehr gut darin ist, Fragen zu beantworten, die es bereits gesehen hat. Die Validation Accuracy ist eine völlig separate Metrik, die uns Menschen sagt, ob das Modell korrekte Predictions für komplett neue Daten machen kann. Um diese Metrik zu bekommen, musst du einen Validation Loop gegen ein dediziertes Test Dataset laufen lassen. Bevor du auch nur einen einzigen Testdatenpunkt in das Network fütterst, musst du den State des Modells ändern. Das machst du, indem du die eval Methode auf deinem Model Object aufrufst. Der Aufruf von eval schaltet das Network in den Evaluation Mode. Bestimmte interne Layers verhalten sich während des Trainings anders als während der Inference. Der Aufruf von eval zwingt sie dazu, ihr Verhalten zu sperren, damit deine Predictions konsistent bleiben. Wenn du diesen Schritt überspringst, werden deine Testergebnisse absolut unzuverlässig sein. Damit hätten wir den Model State abgedeckt. Als Nächstes musst du die Engine selbst steuern, indem du das Gradient Tracking ausschaltest. Das machst du, indem du deinen Validation Code in einen no grad Context Manager packst. Während des Trainings baut PyTorch kontinuierlich einen Computational Graph im Memory auf und speichert die History jeder Operation, damit es später Gradients berechnen kann. In einem Validation Loop bist du mit dem Training komplett fertig. Du willst keine Weights mehr updaten. Der no grad Block sagt PyTorch, dass es aufhören soll, die History zu tracken. Das ist der Teil, auf den es ankommt. Das Deaktivieren des Trackings verhindert versehentliche Updates an deinem Modell, aber es gibt auch massiv Memory frei und beschleunigt die Computation drastisch. Innerhalb dieses no grad Blocks ist die eigentliche Logik ziemlich simpel. Du iterierst in Batches über dein Test Dataset. Für jeden Batch schickst du die Input Data durch das Modell. Das Modell berechnet den Forward Pass und gibt seine Raw Predictions zurück. Wenn du Classification machst, gibt das Modell kein sauberes Text Label aus. Stattdessen gibt es eine Liste von numerischen Scores für jede einzelne Kategorie aus, die es kennt. Um herauszufinden, welche Kategorie das Modell tatsächlich ausgewählt hat, brauchst du die argmax Funktion. argmax schaut sich die Liste der Raw Scores an und findet die höchste Zahl. Dann gibt sie die Index-Position dieses höchsten Scores zurück. Dieser Index ist deine gewählte Class Prediction. Sobald du die Model Predictions hast, vergleichst du sie direkt mit den True Labels, die vom Test Dataset bereitgestellt werden. Du zählst genau, wie viele Predictions mit den True Labels übereinstimmen. Du führst ein Running Total dieser korrekten Treffer über alle Batches hinweg. Wenn der Loop endet, teilst du die Gesamtzahl der korrekten Predictions durch die Gesamtzahl der Elemente im Test Dataset. Das Ergebnis ist deine finale Accuracy in Prozent. Der Training Loop zwingt dein Modell, sich an die historischen Daten anzupassen, aber die strengen Bedingungen des Validation Loops beweisen, ob dieses Modell tatsächlich nützlich ist. Danke fürs Zuhören. Macht's gut, Leute.
16

Modelle speichern und laden

3m 35s

Verliere nicht deinen hart erarbeiteten Fortschritt! Wir besprechen die sichersten Methoden, um deine Modellgewichte mit state_dict zu serialisieren und sie sicher wieder zu laden.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 16 von 18. Einen Image Classifier für fünfzig Epochen zu trainieren, kann Wochen dauern und Tausende von Dollar an Compute verschlingen. Doch in dem Moment, in dem dein Python-Skript durchgelaufen ist, verschwinden all diese hart erarbeiteten Muster komplett aus dem Memory. Um dieses Investment zu schützen, brauchst du einen Weg, deinen Fortschritt auf Disk zu persistieren. Genau dieses Problem löst das Speichern und Laden von Models. In jedem PyTorch-Model steckt ein internes Dictionary, das sogenannte state dict. Dieses Dictionary mappt jeden Layer deines Networks auf die entsprechenden Parameter-Tensoren. Es enthält die eigentlichen Weights und Biases, die dein Model während des Trainings gelernt hat. Die Struktur des Models ist nur Code, aber das state dict ist die Intelligenz. Um dein Model zu persistieren, extrahierst du dieses Dictionary und schreibst es in eine Datei. Das machst du mit einer Funktion namens torch dot save. Du übergibst ihr zwei Dinge. Erstens, das state dict deines Models. Zweitens, den Filepath, wo du es speichern willst, der traditionell eine dot pth Extension nutzt. Mit nur einer Zeile Code ist dein Training Run über fünfzig Epochen sicher als einzelne Datei auf deiner Festplatte gespeichert, die nichts als rohe Tensor-Daten enthält. Du siehst online vielleicht Beispiele, die das state dict komplett überspringen und das Model-Objekt direkt an torch dot save übergeben. Mach das nicht. Das ganze Model zu speichern, verlässt sich stark auf die Python Pickle Serialization. Das bindet das gespeicherte File an die exakte Directory-Struktur und die Class Definitions, die vorhanden waren, als das File erstellt wurde. Wenn du später deinen Code refactorst oder ein File verschiebst, wird das Model beim Laden fehlschlagen. Beim state dict zu bleiben, ist viel sicherer und deutlich robuster, weil du nur die Daten speicherst, nicht den Code. Wenn es an der Zeit ist, deinen Classifier für die Production Inference zu deployen, musst du den Prozess umkehren. Weil du nur die Weights gespeichert hast, muss PyTorch wissen, wie die Struktur des Networks aussieht. Du startest, indem du eine komplett leere Version deiner Model Class instanziierst. Das gibt dir die architektonische Shell. Als Nächstes rufst du torch dot load auf und übergibst deinen Filepath, um das Dictionary wieder in den Memory zu lesen. Wenn du torch dot load aufrufst, gibt es eine extrem wichtige moderne Best Practice, die du befolgen musst. Übergib immer das Argument weights only auf true gesetzt. Python Pickle Files können beliebigen ausführbaren Code enthalten. Wenn du ein pre-trained Model aus dem Internet herunterlädst und es blind lädst, könnte es bösartige Skripte auf deiner Maschine ausführen. weights only auf true zu setzen, beschränkt den Loader darauf, nur Standard-PyTorch-Tensoren zu deserialisieren, was dein System sicher hält. Schließlich, wenn dein leeres Model bereit und dein sicheres Dictionary geladen ist, rufst du load state dict auf dem Model auf und übergibst das Dictionary. PyTorch mappt die geladenen Weights auf die entsprechenden Layer in der leeren Shell. Dein Model ist jetzt vollständig wiederhergestellt und bereit, Predictions zu machen. Vertraue dein Training-Investment niemals einem fragilen serialisierten Objekt an; trenne immer die Architektur in deinem Code von den gelernten Parametern auf deiner Disk. Danke fürs Dabeisein. Ich hoffe, du hast etwas Neues mitgenommen.
17

Geschwindigkeit maximieren mit torch.compile

3m 39s

Schalte das entscheidende Feature von PyTorch 2.0 frei. Lerne, wie der torch.compile-Decorator deinen Python-Code in optimierte Kernels JIT-compiliert, um massive Geschwindigkeitssteigerungen zu erzielen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 17 von 18. Du verbringst Wochen damit, eine Model Architecture zu optimieren, für fünf Prozent Speedup. Aber oft ist das eigentliche Bottleneck gar nicht deine Mathematik. Es ist Python selbst, und die ständigen, ineffizienten Datentransfers zwischen deinem Memory und der GPU. Um das zu fixen, musst du nicht deine ganze Codebase neu schreiben. Heute schauen wir uns an, wie du den Speed mit torch dot compile massiv steigern kannst. Dieses Feature wurde in PyTorch 2.0 eingeführt und verlagert deinen Code von der Standard Execution in einen hochoptimierten Workflow. Oft wird angenommen, dass ein PyTorch-Speedup für Production bedeutet, custom C plus plus Kernels zu schreiben oder deine Architecture grundlegend zu ändern. Das ist nicht der Fall. Du änderst nichts an deinem Model. Du wrappst dein bestehendes Model einfach in einen einzigen Function Call. Um zu verstehen, warum das einen massiven Performance-Sprung bringt, musst du dir ansehen, wie PyTorch normalerweise läuft. Standard-PyTorch arbeitet im Eager Mode. Es führt genau das aus, was du ihm sagst, und zwar genau dann, wenn du es verlangst – eine Operation nach der anderen. Wenn dein Code der GPU sagt, sie soll zwei Tensoren addieren, das Ergebnis mit einem anderen Tensor multiplizieren und eine Activation Function anwenden, behandelt der Eager Mode das als drei isolierte Events. Für jeden Schritt liest die GPU Daten aus ihrem Main Memory, führt die Berechnungen durch und schreibt das Zwischenergebnis zurück. Die Memory Bandwidth der GPU ist begrenzt. Dieses ständige Hin- und Herschieben von Daten dauert deutlich länger als die eigentlichen Berechnungen. Wenn du dein Model durch die Compile Function schickst, ändert PyTorch seine Taktik. Es nutzt ein internes Tool namens TorchDynamo, um deine Operationen vor der Ausführung in einem Computation Graph zu erfassen. Indem es sich die gesamte Sequenz ansieht, findet es Ineffizienzen. Dann nutzt es einen Backend Compiler, um eine neue, stark optimierte Version deiner Operationen zu generieren. Die primäre Technik, die dabei zum Einsatz kommt, ist Kernel Fusion. Anstatt dreimal separat aus dem Memory zu lesen und dorthin zu schreiben, fasst der kompilierte Code diese Schritte zusammen. Die GPU liest die Daten einmal, behält sie in ihren schnellsten internen Registern, führt Addition, Multiplikation und Activation direkt nacheinander aus und schreibt das Endergebnis nur ein einziges Mal zurück. Der Python Overhead verschwindet, und das Memory Bottleneck wird umgangen. Die Implementierung ist unkompliziert. Du instanziierst dein Model wie gewohnt. Dann rufst du torch dot compile auf, übergibst dein Model und weist den Output einer neuen Variable zu. Du leitest deine Daten durch diese kompilierte Version. Wenn TorchDynamo auf ein obskures Python-Konstrukt stößt, das es nicht sicher optimieren kann, bricht es dein Programm nicht ab. Es belässt diesen kleinen Abschnitt einfach im Standard Eager Mode und kompiliert den Rest. Wenn du das benchmarkst, achte auf den ersten Durchlauf. Der erste Durchlauf dauert deutlich länger, weil die eigentliche Kompilierung genau dann passiert, wenn die ersten Daten ankommen. Aber beim zweiten Durchlauf sinkt die Inference Time drastisch. Du musst dich nicht mehr zwischen der Flexibilität des Eager Mode während der Entwicklung und dem rohen Speed eines kompilierten Backends in Production entscheiden. Das war's für diese Folge. Danke fürs Zuhören, und keep building!
18

Compiler und Graph Breaks

4m 20s

Tauche unter die Haube des PyTorch-Compilers. Wir untersuchen Graph Breaks, dynamischen Kontrollfluss und warum torch.compile dort erfolgreich ist, wo ältere Systeme versagt haben.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. PyTorch Fundamentals, Folge 18 von 18. Ältere AI-Compiler verlangten absolut vorhersehbare Execution Paths und versagten spektakulär, sobald du komplexe, dynamische Python-Konstrukte in dein Model eingebaut hast. Du hast nur ein einziges Conditional Statement angepasst, und der gesamte Compilation-Prozess ist abgestürzt. PyTorch zwei Punkt null verarbeitet genau diesen beliebigen Code ohne zu meckern. Die Engine hinter dieser Flexibilität basiert darauf, wie der Compiler mit Graph Breaks umgeht. Wenn du mit dem Legacy-Compilation-Tool TorchScript gearbeitet hast, weißt du, dass es starre Code-Strukturen erfordert hat. TorchScript basierte auf striktem, statischem Typing und vorhersehbarer Execution. Wenn dein Model hochdynamischen Control Flow hatte, auf Standard-Python-Dictionaries angewiesen war oder externe Non-Tensor-Libraries aufgerufen hat, hat TorchScript es oft abgelehnt. Engineers mussten häufig große Teile ihrer Model-Architektur umschreiben, nur um den Compiler zufriedenzustellen. PyTorch zwei Punkt null geht das völlig anders an. Anstatt von vornherein statischen Code zu verlangen, analysiert der native Compiler deine Python-Execution dynamisch. Er erfasst alle mathematischen Operationen, die er sicher optimieren kann, und packt sie in einen hocheffizienten Computational Graph. Zwangsläufig stößt der Compiler auf Code, den er nicht ohne Weiteres auf eine optimierte Graph-Struktur mappen kann. Wenn er auf diese unvorhersehbare Logik trifft, triggert er einen Graph Break. Ein Graph Break ist kein Error und auch kein Crash. Es ist einfach nur ein Fallback-Mechanismus. Das bedeutet, dass der Compiler die Kontrolle für dieses spezifische Code-Segment elegant an die Standard-PyTorch-Eager-Execution zurückgibt. Stell dir eine Funktion vor, in der du eine Reihe rechenintensiver Matrix-Multiplikationen ausführst, gefolgt von einem Python-If-Statement, das den Mittelwert eines Tensors prüft, um die nächste Operation zu bestimmen. Diese Condition ist datenabhängig. Der Execution Path ist völlig unbekannt, bis zu dem genauen Moment, in dem die Tensor-Werte zur Runtime berechnet werden. Wenn du diese Funktion mit dem Compiler tracest, analysiert er den Flow. Er nimmt die Matrix-Multiplikationen, die vor der Condition passieren, und kompiliert sie in einen schnellen, optimierten Sub-Graph. Dann trifft er auf das knifflige If-Statement. Weil er das Ergebnis nicht vorhersagen kann, erzeugt er einen Graph Break. Der Compiler lässt Standard-Python die Condition im Eager Mode ausführen. Sobald die Condition evaluiert und der Path gewählt ist, übernimmt der Compiler wieder die Kontrolle, nimmt die restlichen Operationen und kompiliert sie in einen zweiten optimierten Sub-Graph. Das System segmentiert deinen Code automatisch. Du bekommst kompilierte Inseln aus schneller Mathematik, getrennt durch Standard-Python-Brücken. Dein Model läuft weiterhin nahtlos. Das ist der entscheidende Punkt. Du wirst wahrscheinlich Performance Logs sehen, die auf Graph Breaks in deiner Architektur hinweisen. Obwohl du sie generell minimieren willst, um die maximale Execution Speed herauszuholen, existieren sie rein als Sicherheitsnetz. Sie stellen sicher, dass dein Code immer das korrekte mathematische Ergebnis liefert, selbst wenn nicht jede einzelne Zeile in einen einzigen Kernel gefused werden kann. Der primäre Design Shift in der modernen PyTorch-Compilation ist, nahtlose Execution über totale Optimierung zu priorisieren. Das stellt sicher, dass sich die Engine an deine beliebige Logik anpasst, anstatt deine Logik zu zwingen, sich an die Engine anzupassen. Damit endet unsere PyTorch-Serie. Ich kann dir nur wärmstens empfehlen, die offizielle Documentation zu erkunden, diese Compilation Tools hands-on auszuprobieren und DEV STORIES DOT EU zu besuchen, um Themen für zukünftige Serien vorzuschlagen. Ich möchte mir kurz die Zeit nehmen, dir fürs Zuhören zu danken – das hilft uns sehr. Mach's gut!