Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
DirectML-Tensoren, die von Direct3D 12-Puffern unterstützt werden, werden durch Eigenschaften beschrieben, die als Größen und Strides des Tensors bezeichnet werden. Die Größen des Tensors beschreiben die logischen Dimensionen des Tensors. Beispielsweise kann ein 2D-Tensor eine Höhe von 2 und eine Breite von 3 aufweisen. Logisch weist der Tensor 6 unterschiedliche Elemente auf, obwohl die Größen nicht angeben, wie diese Elemente im Speicher gespeichert werden. Die Schritte des Tensors beschreiben das physische Speicherlayout der Tensorelemente.
Zweidimensionale (2D)-Arrays
Betrachten Sie einen 2D-Tensor mit einer Höhe von 2 und einer Breite von 3; die Daten bestehen aus Textzeichen. In C/C++ kann dies mithilfe eines mehrdimensionalen Arrays ausgedrückt werden.
constexpr int rows = 2;
constexpr int columns = 3;
char tensor[rows][columns];
tensor[0][0] = 'A';
tensor[0][1] = 'B';
tensor[0][2] = 'C';
tensor[1][0] = 'D';
tensor[1][1] = 'E';
tensor[1][2] = 'F';
Die logische Ansicht des obigen Tensors wird unten dargestellt.
A B C
D E F
In C/C++ wird ein mehrdimensionales Array in der Zeilen-Hauptreihenfolge gespeichert. Mit anderen Worten, die aufeinander folgenden Elemente entlang der Breitendimension werden zusammenhängend im linearen Speicherbereich gespeichert.
| Offset: | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| Wert: | Ein | B | C | D | E | F |
Der Schritt einer Dimension ist die Anzahl der zu überspringenden Elemente, um auf das nächste Element in dieser Dimension zuzugreifen. Strides beschreiben das Layout des Tensors im Arbeitsspeicher. Bei einer Zeilenmastreihenfolge ist die Schrittweite der Breitedimension immer 1, weil angrenzende Elemente entlang der Dimension zusammenhängend gespeichert werden. Der Abstand der Höhenmaß hängt von der Größe des Breitenmaßes ab; im obigen Beispiel entspricht der Abstand zwischen aufeinanderfolgenden Elementen entlang des Höhenmaßes (z. B., A bis D) der Breite des Tensors (in diesem Beispiel 3).
Wenn Sie ein anderes Layout veranschaulichen möchten, sollten Sie die Spalten-Hauptreihenfolge in Betracht ziehen. Mit anderen Worten, die aufeinander folgenden Elemente entlang der Höhendimension werden zusammenhängend im linearen Arbeitsspeicher gespeichert. In diesem Fall ist der Höhen-Schritt immer 1, und der Breiten-Schritt ist 2 (die Größe der Höhen-Dimension).
| Offset: | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| Wert: | Ein | D | B | E | C | F |
Höhere Abmessungen
Wenn es um mehr als zwei Dimensionen geht, ist es mühsam, ein Layout als zeilenorientiert oder spaltenorientiert zu bezeichnen. Der Rest dieses Themas verwendet also Begriffe und Bezeichnungen wie diese.
- 2D: "HW" – Höhe ist die höchste Dimension in einer zeilenweise Anordnung.
- 2D: "WH"—Breite ist die höchstrangige Dimension (Spalten-major).
- 3D: "DHW" – Tiefe ist die höchste Dimension, gefolgt von Höhe und dann Breite.
- 3D: "WHD" – Breite ist die höchste Dimension, gefolgt von Höhe und dann Tiefe.
- 4D: "NCHW" – die Anzahl der Bilder (Batchgröße), dann die Anzahl der Kanäle, dann höhe und breite.
Im Allgemeinen entspricht die gepackte Stride einer Dimension dem Produkt der Größen der Abmessungen niedrigerer Ordnung. Beispielsweise entspricht beim "DHW"-Layout der D-Schritt H * W; der H-Schritt entspricht W; und der W-Schritt entspricht 1. Strides sind gepackt, wenn die gesamte physische Größe des Tensors gleich der gesamten logischen Größe des Tensors ist; mit anderen Worten, es gibt keinen zusätzlichen Platz oder überlappende Elemente.
Lassen Sie uns das 2D-Beispiel auf drei Dimensionen erweitern, sodass wir einen Tensor mit Tiefe 2, Höhe 2 und Breite 3 haben (für insgesamt 12 logische Elemente).
A B C
D E F
G H I
J K L
Mit einem "DHW"-Layout wird dieser Tensor wie folgt gespeichert.
| Offset: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Wert: | Ein | B | C | D | E | F | G | H | Ich | J | K | L |
- D-Strichlänge = Höhe (2) * Breite (3) = 6 (z. B. der Abstand zwischen 'A' und 'G').
- H-stride = width (3) = 3 (z. B. der Abstand zwischen 'A' und 'D').
- W-stride = 1 (z. B. der Abstand zwischen 'A' und 'B').
Das Punktprodukt der Indizes/Koordinaten eines Elements und die Strides stellen den Offset für dieses Element im Puffer bereit. Beispielsweise ist der Offset des H-Elements (d=1, h=0, w=1) 7.
{1, 0, 1} ** {6, 3, 1} = 1 * 6 + 0 * 3 + 1 * 1 = 7
Verpackte Tensoren
Die obigen Beispiele veranschaulichen gepackte Tensoren. Ein Tensor soll gepackt werden, wenn die logische Größe des Tensors (in Elementen) der physischen Größe des Puffers (in Elementen) entspricht, und jedes Element eine eindeutige Adresse/einen Offset aufweist. Beispielsweise wird ein 2x2x3-Tensor gepackt, wenn der Puffer 12 Elemente lang ist und kein Paar von Elementen denselben Offset im Puffer teilt. Gepackte Tensoren sind der häufigste Fall; Strides ermöglichen jedoch komplexere Speicherlayouts.
Fortschritte im Rundfunk
Wenn die Puffergröße eines Tensors (in Elementen) kleiner als das Produkt seiner logischen Dimensionen ist, muss es eine Überschneidung von Elementen geben. Der übliche Fall dafür wird als Rundfunk bezeichnet; wobei die Elemente einer Dimension ein Duplikat einer anderen Dimension sind. Beispiel: Schauen wir uns das 2D-Beispiel erneut an. Angenommen, wir möchten einen Tensor, der logisch 2x3 ist, aber die zweite Zeile ist identisch mit der ersten Zeile. Das sieht so aus.
A B C
A B C
Dies könnte als verpackter HW/Row-Major-Tensor gespeichert werden. Ein kompakterer Speicher würde jedoch nur 3 Elemente (A, B und C) enthalten und eine Höhenstrende von 0 anstelle von 3 verwenden. In diesem Fall beträgt die physische Größe des Tensors 3 Elemente, die logische Größe beträgt jedoch 6 Elemente.
Wenn der Schritt einer Dimension 0 ist, werden im Allgemeinen alle Elemente in den Dimensionen der unteren Reihenfolge entlang der übertragenen Dimension wiederholt; Wenn der Tensor z. B. NCHW ist und der C-Stride 0 ist, weist jeder Kanal die gleichen Werte entlang von H und W auf.
Polsterung mit Strides
Ein Tensor wird als aufgefüllt bezeichnet, wenn seine physische Dimension größer ist als die Mindestgröße, die notwendig ist, um seine Elemente aufzunehmen. Wenn keine Sende- oder Überschneidungselemente vorhanden sind, ist die Mindestgröße des Tensors (in Elementen) einfach das Produkt seiner Dimensionen. Sie können die Hilfsfunktion DMLCalcBufferTensorSize (siehe DirectML-Hilfsfunktionen für eine Auflistung dieser Funktion) verwenden, um die minimale Puffergröße für Ihre DirectML-Tensoren zu berechnen.
Angenommen, ein Puffer enthält die folgenden Werte (die "x"-Elemente geben Abstandswerte an).
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|---|---|---|---|---|
| Ein | B | C | x | x | D | E | F | x | x |
Der abgepolsterte Tensor kann mit einem Höhenstride von 5 statt 3 beschrieben werden. Anstatt um drei Elemente weiterzugehen, um zur nächsten Zeile zu gelangen, beträgt der Schritt nun 5 Elemente (3 reale Elemente plus 2 Abstandselemente). Der Abstand ist in Computergrafiken üblich, um beispielsweise sicherzustellen, dass ein Bild eine Power-of-Two-Ausrichtung aufweist.
A B C
D E F
Beschreibungen von DirectML-Puffer-Tensoren
DirectML kann mit einer Vielzahl physischer Tensorlayouts arbeiten, da die DML_BUFFER_TENSOR_DESC Struktur sowohl Sizes als auch Strides Elemente aufweist. Einige Operatorimplementierungen können mit einem bestimmten Layout effizienter sein, daher ist es nicht ungewöhnlich, zu ändern, wie Tensordaten für eine bessere Leistung gespeichert werden.
Die meisten DirectML-Operatoren erfordern entweder 4D- oder 5D-Tensoren, und die Reihenfolge der Größen und Strides-Werte ist fest. Durch Das Korrigieren der Reihenfolge der Größen und Stridewerte in einer Tensorbeschreibung ist es möglich, dass DirectML verschiedene physische Layouts ableiten kann.
4D
- DML_BUFFER_TENSOR_DESC::Size = { N-Size, C-size, H-size, W-size }
- DML_BUFFER_TENSOR_DESC::Schritte = { N-Schritt, C-Schritt, H-Schritt, W-Schritt }
5D
- DML_BUFFER_TENSOR_DESC::Size = { N-Size, C-size, D-size, H-size, W-size }
- DML_BUFFER_TENSOR_DESC::Schritte = { N-Schritt, C-Schritt, D-Schritt, H-Schritt, W-Schritt }
Wenn ein DirectML-Operator einen 4D- oder 5D-Tensor erfordert, aber die tatsächlichen Daten einen kleineren Rang haben (z. B. 2D), sollten die führenden Dimensionen mit 1 gefüllt werden. Beispielsweise wird ein "HW"-Tensor mit DML_BUFFER_TENSOR_DESC::Sizes = { 1, 1, H, W } festgelegt.
Wenn Tensordaten in NCHW/NCDHW gespeichert werden, ist es nicht erforderlich, DML_BUFFER_TENSOR_DESC::Strides festzulegen, es sei denn, Sie möchten Broadcasting oder Padding verwenden. Sie können das Feld "strides" auf nullptr festlegen. Wenn jedoch die Tensordaten in einem anderen Layout gespeichert sind, z. B. NHWC, benötigen Sie Schritte, um die Transformation von NCHW zu diesem Layout auszudrücken.
Betrachten Sie für ein einfaches Beispiel die Beschreibung eines 2D-Tensors mit Höhe 3 und Breite 5.
Gepacktes NCHW (implizite Schritte)
- DML_BUFFER_TENSOR_DESC::Größen = { 1, 1, 3, 5 }
-
DML_BUFFER_TENSOR_DESC::Schritte =
nullptr
Gepackter NCHW (expliziter Schritt)
- N-Schritt = C-Größe * H-Größe * W-Größe = 1 * 3 * 5 = 15
- C-Schritt = H-Größe * W-Größe = 3 * 5 = 15
- H-Schrittweite = W-Größe = 5
- W-Schritt = 1
- DML_BUFFER_TENSOR_DESC::Größen = { 1, 1, 3, 5 }
- DML_BUFFER_TENSOR_DESC::Schritte = { 15, 15, 5, 1 }
Gepacktes NHWC
- N-Schritt = H-Größe * W-Größe * C-Größe = 3 * 5 * 1 = 15
- H-Schritt = W-Größe * C-Größe = 5 * 1 = 5
- W-Schritt = C-Größe = 1
- C-Schritt = 1
- DML_BUFFER_TENSOR_DESC::Größen = { 1, 1, 3, 5 }
- DML_BUFFER_TENSOR_DESC::Schritte = { 15, 1, 5, 1 }