DirectMLX

DirectMLX は DirectML 用の C++ ヘッダー専用ヘルパー ライブラリであり、個々の演算子をグラフに簡単に作成することを目的としています。

DirectMLX は、すべての DirectML (DML) 演算子型に便利なラッパーと直感的な演算子のオーバーロードを提供します。これにより、DML 演算子を簡単にインスタンス化し、それらを複雑なグラフに連結できます。

DirectMLX.h を検索する場所

DirectMLX.h は、MIT ライセンスの下でオープンソース ソフトウェアとして配布されます。 最新バージョンは DirectML GitHub にあります。

バージョンの要件

DirectMLX には DirectML バージョン 1.4.0 以降が必要です (DirectML のバージョン履歴を参照)。 それより前の DirectML バージョンはサポートされていません。

DirectMLX.h には、次のような C++11 対応コンパイラが必要です (ただし、これらに限定されません)。

  • Visual Studio 2017
  • Visual Studio 2019
  • Clang 10

C++17 (またはそれ以降) コンパイラが推奨されるオプションであることに注意してください。 C++11 のコンパイルは可能ですが、不足している標準ライブラリ機能を置き換えるには、サードパーティのライブラリ (GSLAbseil など) を使用する必要があります。

DirectMLX.h のコンパイルに失敗する構成がある場合は、GitHub で問題を報告してください

基本的な使用方法

#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

二次方程式の解の公式を計算できる DirectML グラフを作成する別の例を次に示します。

#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

その他の例

DirectMLX を使用した完全なサンプルは、DirectML GitHub リポジトリにあります。

コンパイル時のオプション

DirectMLX では、ヘッダーのさまざまな部分をカスタマイズするためのコンパイル時 #define's がサポートされています。

オプション 説明
DMLX_NO_EXCEPTIONS #define'd の場合、エラーが発生し、例外がスローされるのではなく std::abort への呼び出しが発生します。 これは、例外が使用できない場合 (たとえば、コンパイラ オプションで例外が無効になっている場合) に既定で定義されます。
DMLX_USE_WIL #define'd の場合は、Windows 実装ライブラリの例外の種類を使用して例外がスローされます。 それ以外の場合は、代わりに標準の例外の種類 (std::runtime_error など) が使用されます。 DMLX_NO_EXCEPTIONS が定義されている場合、このオプションは無効です。
DMLX_USE_ABSEIL #define'd の場合は、C++11 で使用できない標準ライブラリの種類のドロップイン置換として Abseil を使用します。 これらの型には、absl::optional (std::optional の代わり)、absl::Span (std::span の代わり)、および absl::InlinedVector が含まれます。
DMLX_USE_GSL GSLstd::span の置換として使用するかどうかを制御します。 #define'd の場合は、ネイティブ std::span 実装のないコンパイラで std::span の使用が gsl::span によって置き換えられます。 それ以外の場合は、代わりにインライン ドロップイン実装が提供されます。 このオプションは、std::span のサポートなしで C++20 より前のコンパイラでコンパイルする場合、および他のドロップイン標準ライブラリ置換 (Abseil など) が使用されていない場合にのみ使用されることに注意してください。

テンソル レイアウトの制御

ほとんどの演算子では、DirectMLX は、ユーザーに代わって演算子の出力テンソルのプロパティを計算します。 たとえば、サイズ { 3, 4, 5, 6 } の入力テンソルを使用して複数の軸 { 0, 2, 3 } 全体で dml::Reduce を実行する場合、DirectMLX は正しい形状の { 1, 4, 1, 1 } を含む出力テンソルのプロパティを自動的に計算します。

ただし、出力テンソルの他のプロパティには、StridesTotalTensorSizeInBytes、および GuaranteedBaseOffsetAlignment があります。 既定では、DirectMLX では、テンソルにストライディングがなく、基本オフセットの配置が保証されておらず、DMLCalcBufferTensorSize によって計算されたテンソルの合計サイズ (バイト単位) があるように、これらのプロパティが設定されています。

DirectMLX では、テンソル ポリシーと呼ばれるオブジェクトを使用して、これらの出力テンソル プロパティをカスタマイズする機能がサポートされています。 TensorPolicy は、DirectMLX によって呼び出されるカスタマイズ可能なコールバックであり、テンソルの計算されたデータ型、フラグ、およびサイズを指定して出力テンソル プロパティを返します。

Tensor ポリシーは dml::Graph オブジェクトで設定でき、そのグラフ上の後続のすべての演算子に使用されます。 Tensor ポリシーは、TensorDesc を構築するときに直接設定することもできます。

したがって、DirectMLX によって生成されるテンソルのレイアウトは、テンソルに適切なストライドを設定する TensorPolicy を設定することで制御できます。

例 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));

例 2

DirectMLX には、組み込みの代替テンソル ポリシーも用意されています。 たとえば、InterleavedChannel ポリシーは便利な方法として提供され、NHWC の順序で書き込まれるようにストライドを持つテンソルを生成するために使用できます。

// 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(/* ... */);

関連項目