다음을 통해 공유


DirectMLX

DirectMLX는 개별 연산자를 그래프로 쉽게 작성할 수 있도록 하는 DirectML용 C++ 헤더 전용 도우미 라이브러리입니다.

DirectMLX는 모든 DML(DirectML) 연산자 형식에 편리한 래퍼와 직관적인 연산자 오버로드를 제공하여 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
  • 클랑 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 지원하여 헤더의 다양한 부분을 사용자 지정합니다.

옵션 설명
DMLX_NO_EXCEPTIONS #define가 설정되면, 예외를 처리하는 대신 std::abort을 호출하여 에러를 처리합니다. 이는 예외를 사용할 수 없는 경우(예: 컴파일러 옵션에서 예외가 비활성화된 경우) 기본적으로 정의됩니다.
DMLX_USE_WIL #define를 사용한 경우 Windows 구현 라이브러리 예외 유형을 사용하여 예외가 던져집니다. 그렇지 않으면 표준 예외 형식(예: std::runtime_error)이 대신 사용됩니다. DMLX_NO_EXCEPTIONS 정의된 경우에는 이 옵션이 적용되지 않습니다.
DMLX_USE_ABSEIL #define 경우 C++11에서 사용할 수 없는 표준 라이브러리 형식에 대한 드롭인 대체 항목으로 Abseil 을 사용합니다. 이러한 형식에는 absl::optional (대신 std::optional), absl::Span (대신 std::span), 및 absl::InlinedVector.
DMLX_USE_GSL GSL을 대체로 사용할지 여부를 제어합니다std::span. #define될 경우, 네이티브 std::span 구현이 없는 컴파일러에서는 gsl::span의 사용이 std::span로 대체됩니다. 그렇지 않으면 인라인 드롭인 구현이 대신 제공됩니다. 이 옵션은 지원 std::span없이 C++20 이전 컴파일러에서 컴파일할 때와 다른 드롭인 표준 라이브러리 대체(예: Abseil)가 사용되지 않는 경우에만 사용됩니다.

텐서 레이아웃 제어

대부분의 연산자의 경우 DirectMLX는 사용자 대신 연산자의 출력 텐서 속성을 계산합니다. 예를 들어 사이즈가 dml::Reduce인 입력 텐서에 대해 여러 축 { 0, 2, 3 }을 기준으로 { 3, 4, 5, 6 }을 수행할 때, DirectMLX는 올바른 모양 { 1, 4, 1, 1 }을 포함하여 출력 텐서의 속성을 자동으로 계산합니다.

그러나 출력 텐서의 다른 속성에는 Strides, TotalTensorSizeInBytesGuaranteedBaseOffsetAlignment가 포함됩니다. 기본적으로 DirectMLX는 텐서에 스트레이딩이 없고, 기본 오프셋 맞춤이 보장되지 않으며, DMLCalcBufferTensorSize에서 계산한 총 텐서 크기(바이트)가 없으므로 이러한 속성을 설정합니다.

DirectMLX는 텐서 정책이라고 하는 개체를 사용하여 이러한 출력 텐서 속성을 사용자 지정하는 기능을 지원합니다. TensorPolicy는 DirectMLX에서 호출되는 사용자 지정 가능한 콜백이며, 텐서의 계산된 데이터 형식, 플래그 및 크기가 지정된 출력 텐서 속성을 반환합니다.

텐서 정책은 dml::Graph 개체에서 설정할 수 있으며 해당 그래프의 모든 후속 연산자에 사용됩니다. 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(/* ... */);

참고하십시오