PyTorch: Warum view() nach transpose() fehlschlägt
31.10.2025
Zusammenfassung
transpose() macht Tensoren non-contiguous (logische ≠ physische Reihenfolge). view() funktioniert nur mit contiguous Tensoren → RuntimeError. Lösung: reshape() statt view()!
Das Problem
Stell dir vor, du möchtest ein kleines Farbverlauf-Bild aus 8 Pixeln in PyTorch als Tensor darstellen, um es dann mit einem Neuronalen Netz zu klassifizieren. Am einfachsten geht das mit einem 2x4-Tensor, bei welchem jeder Wert die Farbintensität widerspiegelt.
Nun möchtest du das Bild um 90° drehen, bevor es klassifiziert wird. Dafür gibt es in PyTorch die transpose-Methode, mit welcher man einen Tensor transponieren kann:
bild_gedreht = bild.transpose(0, 1)
Zum Schluss soll das Bild in einen eindimensionalen Tensor umgewandelt werden, da das neuronale Netz ausschließlich solche Inputs verarbeiten kann:
bild_flach = bild_gedreht.view(1, 8)
Doch "Oh Schreck", eine Fehlermeldung:
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces).
Warum tritt dieser Fehler auf? Und wie können wir ihn beheben?
In diesem Post lernst du:
Wie PyTorch Tensoren im Speicher ablegt
Warum transpose() den Tensor "non-contiguous" macht
Was contiguous() macht und wann du es brauchst
Zwei Lösungsvorschläge
Wie PyTorch Tensoren speichert
Tensoren können mehrdimensionale Arrays darstellen, denken wir an das obige Bild, Videos oder sonstige Matrizen. Der Arbeitsspeicher eines Computers hingegen kennt ausschließlich eindimensionale Arrays, bei welchen alle Daten zusammenhängend nacheinander im Speicher liegen.
Um diese mehrdimensionalen Tensoren effektiv speichern zu können, wendet PyTorch einen kleinen Trick an: Es speichert zwar alle Daten nacheinander in einer langen Kette, merkt sich aber in einem kleinen extra Speicher die Information (Strides), wie diese beim Verwenden interpretiert werden sollen.
Beispiel:
Das Bild vom Anfang des Posts wird im Speicher wie folgt abgelegt
Der Stride (4, 1) gibt dabei folgendes an: Der erste Wert (4) gibt an, wie viele Elemente man im Speicher nach rechts springen muss, um in die nächste Zeile der Matrix zu gelangen. Der zweite Wert (1) gibt an, wie viele Elemente man nach rechts springen muss, um in die nächste Spalte zu kommen.
Um beispielsweise das Element an Position [1, 2] (Index startet bei 0) zu finden (zweite Zeile, dritte Spalte = die 7):
Das Element an Speicher-Position 6 ist tatsächlich die 7! ✓
Warum transpose() den Tensor "non-contiguous" macht
Wenn wir nun an das Beispiel vom Anfang zurückdenken: Als wir das Bild mit der transpose()-Methode gedreht haben, könnte man meinen, dass das komplette Daten-Array im Speicher neu strukturiert wird, als hätten wir den alten Tensor gelöscht und einen neuen erstellt, welcher dann folgendermaßen im Speicher liegen würde:
Durch eine solche komplette Restrukturierung des Arrays würde ein Aufruf der transpose()-Methode die Rechenlast allerdings unnötig stark beeinflussen. PyTorch nimmt stattdessen die originale Speicher-Anordnung des Tensors und passt ausschließlich die Strides an.
In unserem Beispiel werden diese durch das transpose() zu (1, 4) umgeschrieben, was dazu führt, dass PyTorch diese beim Lesezugriff als 4x2 Matrix interpretiert.
Um beispielsweise das Element an Position [2, 1] zu finden (dritte Zeile, zweite Spalte = die 7):
Das Element an Speicher-Position 6 ist tatsächlich die 7! ✓
Contiguous vs. Non-contiguous
Doch so schön und elegant diese Stride-Manipulation auch klingt, sie bringt ein Problem mit sich: Die logische Anordnung des Tensors stimmt nicht mehr mit der physischen Anordnung im Speicher überein.
Was bedeutet "contiguous"?
Ein Tensor ist contiguous (zusammenhängend), wenn die Reihenfolge, in der wir die Elemente logisch lesen, exakt der Reihenfolge entspricht, in der sie im Speicher liegen.
Der Kern: Nach transpose() zeigt der Tensor immer noch auf dieselben Daten im Speicher, aber durch die geänderten Strides lesen wir sie in einer anderen Reihenfolge.
Das Problem mit view()
Wenn wir nun wie in dem Beispiel ganz am Anfang .view() auf einen Tensor aufrufen wollen, welcher non-contiguous ist, dann tritt dieser RuntimeError auf. Die view()-Methode kann nur contiguous Tensoren verarbeiten, da sie – wie transpose() – nur die Strides und nicht die eigentlichen Daten verändert.
bild_gedreht = bild.transpose(0, 1)
# Was view(1, 8) erwarten würde: # Eine Zeile mit den Elementen in logischer Reihenfolge # → [1, 5, 2, 6, 3, 7, 4, 8]
# Was tatsächlich im Speicher liegt: # → [1, 2, 3, 4, 5, 6, 7, 8]
# view() kann diese Diskrepanz nicht auflösen! bild_gedreht.view(1, 8) # RuntimeError! ❌
Lösung 1: .contiguous()
In PyTorch kann man einen Tensor mit .contiguous() wieder zusammenhängend machen:
reshape() ist ein intelligenter Wrapper, der automatisch prüft, ob der Tensor contiguous ist:
Ist er contiguous? → Verhält sich wie view(), keine Kopie nötig (sehr schnell!)
Ist er non-contiguous? → Ruft automatisch contiguous() auf und erstellt dann die neue Form
Empfehlung für Production-Code: Nutze reshape() statt view(), da es robuster ist und in den meisten Fällen genauso performant. Der Unterschied ist nur bei sehr großen Tensoren und häufigen Umformungen messbar.
Das Wichtigste in 30 Sekunden
Key Takeaways:
Tensoren liegen immer als 1D-Array im Speicher, Strides definieren die Interpretation
transpose() ändert nur Strides (schnell!), macht Tensor aber non-contiguous