Freigeben über


DirectMLX

DirectMLX ist eine Hilfsbibliothek, die nur aus C++-Header-Dateien besteht und für DirectML gedacht ist, um das Zusammensetzen einzelner Operatoren in Graphen zu erleichtern.

DirectMLX bietet praktische Wrapper für alle DirectML (DML)-Operatortypen sowie intuitive Operatorüberladungen, die das Instanziieren von DML-Operatoren und das Verketten in komplexen Diagrammen vereinfachen.

Wo zu finden DirectMLX.h

DirectMLX.h wird als Open-Source-Software unter der MIT-Lizenz vertrieben. Die neueste Version finden Sie auf dem DirectML GitHub.

Versionsanforderungen

DirectMLX erfordert DirectML Version 1.4.0 oder höher (siehe DirectML-Versionsverlauf). Ältere Versionen von DirectML werden nicht unterstützt.

DirectMLX.h erfordert einen C++11-fähigen Compiler, einschließlich (aber nicht beschränkt auf):

  • Visual Studio 2017
  • Visual Studio 2019
  • Klirren 10

Beachten Sie, dass ein C++17-Compiler (oder neuer) die Option ist, die wir empfehlen. Das Kompilieren für C++11 ist möglich, erfordert jedoch die Verwendung von Bibliotheken von Drittanbietern (z. B. GSL und Abseil), um fehlende Standardbibliotheksfunktionen zu ersetzen.

Wenn Sie eine Konfiguration haben, die nicht kompiliert DirectMLX.hwerden kann, melden Sie bitte ein Problem auf unserem GitHub.

Grundlegende Nutzung

#include <DirectML.h>
#include <DirectMLX.h>

IDMLDevice* device;

/* ... */

dml::Graph graph(device);

// Input tensor of type FLOAT32 and sizes { 1, 2, 3, 4 }
auto x = dml::InputTensor(graph, 0, dml::TensorDesc(DML_TENSOR_DATA_TYPE_FLOAT32, {1, 2, 3, 4}));

// Create an operator to compute the square root of x
auto y = dml::Sqrt(x);

// Compile a DirectML operator from the graph. When executed, this compiled operator will compute
// the square root of its input.
DML_EXECUTION_FLAGS flags = DML_EXECUTION_FLAG_NONE;
ComPtr<IDMLCompiledOperator> op = graph.Compile(flags, { y });

// Now initialize and dispatch the DML operator as usual

Hier ist ein weiteres Beispiel, das ein DirectML-Diagramm erstellt, das die quadratische Formel berechnen kann.

#include <DirectML.h>
#include <DirectMLX.h>

IDMLDevice* device;

/* ... */

std::pair<dml::Expression, dml::Expression>
    QuadraticFormula(dml::Expression a, dml::Expression b, dml::Expression c)
{
    // Quadratic formula: given an equation of the form ax^2 + bx + c = 0, x can be found by:
    //   x = -b +/- sqrt(b^2 - 4ac) / (2a)
    // https://en.wikipedia.org/wiki/Quadratic_formula

    // Note: DirectMLX provides operator overloads for common mathematical expressions. So for 
    // example a*c is equivalent to dml::Multiply(a, c).
    auto x1 = -b + dml::Sqrt(b*b - 4*a*c) / (2*a);
    auto x2 = -b - dml::Sqrt(b*b - 4*a*c) / (2*a);

    return { x1, x2 };
}

/* ... */

dml::Graph graph(device);

dml::TensorDimensions inputSizes = {1, 2, 3, 4};
auto a = dml::InputTensor(graph, 0, dml::TensorDesc(DML_TENSOR_DATA_TYPE_FLOAT32, inputSizes));
auto b = dml::InputTensor(graph, 1, dml::TensorDesc(DML_TENSOR_DATA_TYPE_FLOAT32, inputSizes));
auto c = dml::InputTensor(graph, 2, dml::TensorDesc(DML_TENSOR_DATA_TYPE_FLOAT32, inputSizes));

auto [x1, x2] = QuadraticFormula(a, b, c);

// When executed with input tensors a, b, and c, this compiled operator computes the two outputs
// of the quadratic formula, and returns them as two output tensors x1 and x2
DML_EXECUTION_FLAGS flags = DML_EXECUTION_FLAG_NONE;
ComPtr<IDMLCompiledOperator> op = graph.Compile(flags, { x1, x2 });

// Now initialize and dispatch the DML operator as usual

Weitere Beispiele

Vollständige Beispiele für die Verwendung von DirectMLX finden Sie im GitHub-Repository von DirectML.

Optionen für die Kompilierzeit

DirectMLX unterstützt #define zur Kompilierzeit, um verschiedene Teile des Headers anzupassen.

Auswahlmöglichkeit BESCHREIBUNG
DMLX_NO_EXCEPTIONS Wenn #define wird, führt dies dazu, dass Fehler zu einem Aufruf std::abort von führen, anstatt eine Ausnahme auszulösen. Dies ist standardmäßig definiert, wenn Ausnahmen nicht verfügbar sind (z. B. wenn Ausnahmen in den Compileroptionen deaktiviert wurden).
DMLX_USE_WIL Wenn #define, werden Ausnahmen mithilfe von Ausnahmetypen der Windows Implementation Library ausgelöst. Andernfalls werden stattdessen Standardausnahmetypen (z. B std::runtime_error. ) verwendet. Diese Option hat keine Auswirkungen, wenn DMLX_NO_EXCEPTIONS definiert ist.
DMLX_USE_ABSEIL Wenn #define, wird Abseil als Drop-In-Ersatz für Standardbibliothekstypen verwendet, die in C++11 nicht verfügbar sind. Zu diesen Typen gehören absl::optional (anstelle von std::optional), absl::Span (anstelle von std::span) und absl::InlinedVector.
DMLX_USE_GSL Steuert, ob GSL als Ersatz für std::spanverwendet werden soll. Wenn #define, wird die Verwendung von std::span durch gsl::span on-Compiler ohne native std::span Implementierungen ersetzt. Andernfalls wird stattdessen eine Inline-Drop-In-Implementierung bereitgestellt. Beachten Sie, dass diese Option nur verwendet wird, wenn auf einem Compiler vor C++20 kompiliert wird, der nicht unterstützt wird std::span, und wenn keine andere Drop-In-Standardbibliotheksersetzung (wie Abseil) verwendet wird.

Steuerung des Tensor-Layouts

Bei den meisten Operatoren berechnet DirectMLX die Eigenschaften der Ausgabetensoren des Operators in Ihrem Namen. Wenn Sie z. B. eine quer dml::Reduce durch Achsen { 0, 2, 3 } mit einem Eingabetensor der Größen { 3, 4, 5, 6 }ausführen, berechnet DirectMLX automatisch die Eigenschaften des Ausgabetensors, einschließlich der korrekten Form von { 1, 4, 1, 1 }.

Zu den anderen Eigenschaften eines Ausgabetensors gehören jedoch Strides, TotalTensorSizeInBytes und GuaranteedBaseOffsetAlignment. Standardmäßig legt DirectMLX diese Eigenschaften so fest, dass der Tensor kein Schreiten, keine garantierte Basisoffsetausrichtung und eine Gesamttensorgröße in Byte aufweist, die von DMLCalcBufferTensorSize berechnet wird.

DirectMLX unterstützt die Möglichkeit, diese Ausgabetensoreigenschaften mithilfe von Objekten anzupassen, die als Tensorrichtlinien bezeichnet werden. Eine TensorPolicy ist ein anpassbarer Rückruf, der von DirectMLX aufgerufen wird und Ausgabetensoreigenschaften zurückgibt, die den berechneten Datentyp, die Flags und die Größen eines Tensors angeben.

Tensor-Richtlinien können für das dml::Graph-Objekt festgelegt werden und werden für alle nachfolgenden Operatoren in diesem Diagramm verwendet. Tensor-Richtlinien können auch direkt beim Erstellen eines TensorDesc festgelegt werden.

Das Layout der von DirectMLX erzeugten Tensoren kann daher durch Festlegen einer TensorPolicy gesteuert werden, die die entsprechenden Schritte für ihre Tensoren festlegt.

Beispiel 1

// Define a policy, which is a function that returns a TensorProperties given a data type,
// flags, and sizes.
dml::TensorProperties MyCustomPolicy(
    DML_TENSOR_DATA_TYPE dataType,
    DML_TENSOR_FLAGS flags,
    Span<const uint32_t> sizes)
{
    // Compute your custom strides, total tensor size in bytes, and guaranteed base
    // offset alignment
    dml::TensorProperties props;
    props.strides = /* ... */;
    props.totalTensorSizeInBytes = /* ... */;
    props.guaranteedBaseOffsetAlignment = /* ... */;
    return props;
};

// Set the policy on the dml::Graph
dml::Graph graph(/* ... */);
graph.SetTensorPolicy(dml::TensorPolicy(&MyCustomPolicy));

Beispiel 2

DirectMLX bietet auch einige integrierte alternative Tensorrichtlinien. Die InterleavedChannel-Richtlinie wird beispielsweise als Annehmlichkeit bereitgestellt und kann verwendet werden, um Tensoren mit Schritten so zu erzeugen, dass sie in NHWC-Reihenfolge geschrieben werden.

// Set the InterleavedChannel policy on the dml::Graph
dml::Graph graph(/* ... */);
graph.SetTensorPolicy(dml::TensorPolicy::InterleavedChannel());

// When executed, the tensor `result` will be in NHWC layout (rather than the default NCHW)
auto result = dml::Convolution(/* ... */);

Siehe auch