Compartir a través de


DirectMLX

DirectMLX es una biblioteca auxiliar de C++ compuesta solo de archivos de encabezado para DirectML, diseñada para facilitar la integración de operadores individuales en grafos.

DirectMLX proporciona contenedores convenientes para todos los tipos de operadores de DirectML (DML), así como sobrecargas de operadores intuitivas, lo que simplifica la creación de instancias de operadores DML y su encadenamiento en gráficos complejos.

Dónde encontrarlo DirectMLX.h

DirectMLX.h se distribuye como software de código abierto bajo la licencia MIT. La versión más reciente se puede encontrar en GitHub de DirectML.

Requisitos de versión

DirectMLX requiere DirectML versión 1.4.0 o posterior (consulta Historial de versiones de DirectML). Las versiones anteriores de DirectML no son compatibles.

DirectMLX.h requiere un compilador compatible con C++11, que incluya (pero no se limite a):

  • Visual Studio 2017
  • Visual Studio 2019
  • Clang 10

Tenga en cuenta que la opción que recomendamos es un compilador de C++17 (o posterior). Es posible compilar para C++11, pero requiere el uso de bibliotecas de terceros (como GSL y Abseil) para reemplazar la funcionalidad de biblioteca estándar que falta.

Si tiene una configuración que no se puede compilar DirectMLX.h, presente un problema en nuestro GitHub.

Uso básico

#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

Este es otro ejemplo, que crea un gráfico de DirectML capaz de calcular la fórmula cuadrática.

#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

Más ejemplos

Los ejemplos completos con DirectMLX se pueden encontrar en el repositorio de GitHub de DirectML.

Opciones en tiempo de compilación

DirectMLX admite #define en tiempo de compilación para personalizar varias partes del encabezado.

Opción Descripción
DMLX_NO_EXCEPTIONS Si se #define, hace que los errores den lugar a una llamada a std::abort en lugar de iniciar una excepción. Esto se define de forma predeterminada si las excepciones no están disponibles (por ejemplo, si las excepciones se han deshabilitado en las opciones del compilador).
DMLX_USE_WIL Si se #define, las excepciones se producen mediante los tipos de excepción de la biblioteca de implementación de Windows . De lo contrario, se utilizan tipos de excepción estándar (como std::runtime_error). Esta opción no tiene ningún efecto si DMLX_NO_EXCEPTIONS está definido.
DMLX_USE_ABSEIL Si se #define, usa Abseil como reemplazos directos para los tipos de biblioteca estándar que no están disponibles en C++11. Estos tipos incluyen absl::optional (en lugar de std::optional), absl::Span (en lugar de std::span) y absl::InlinedVector.
DMLX_USE_GSL Controla si se utiliza GSL como sustituto std::spande . Si se #define, los usos de std::span se reemplazan por gsl::span en compiladores sin implementaciones nativas std::span . De lo contrario, se proporciona una implementación directa en su lugar. Tenga en cuenta que esta opción solo se usa cuando se compila en un compilador anterior a C++20 sin soporte para std::span, y cuando no se usa ningún otro reemplazo de biblioteca estándar directo (como Abseil).

Control de la disposición de los tensores

Para la mayoría de los operadores, DirectMLX calcula las propiedades de los tensores de salida del operador en su nombre. Por ejemplo, al realizar un dml::Reduce cruce de ejes { 0, 2, 3 } con un tensor de entrada de tamaños { 3, 4, 5, 6 }, DirectMLX calculará automáticamente las propiedades del tensor de salida, incluida la forma correcta de { 1, 4, 1, 1 }.

Sin embargo, las otras propiedades de un tensor de salida incluyen Strides, TotalTensorSizeInBytes y GuaranteedBaseOffsetAlignment. De forma predeterminada, DirectMLX establece estas propiedades de modo que el tensor no tenga stración, ni alineación de desplazamiento de base garantizada y un tamaño de tensor total en bytes, según lo calculado por DMLCalcBufferTensorSize.

DirectMLX admite la capacidad de personalizar estas propiedades de tensor de salida, mediante objetos conocidos como directivas de tensor. Un TensorPolicy es una devolución de llamada personalizable que DirectMLX invoca y devuelve propiedades de tensor de salida según el tipo de datos, las marcas y los tamaños calculados de un tensor.

Las políticas de tensor se pueden establecer en el objeto dml::Graph y se utilizarán para todos los operadores posteriores de ese gráfico. Las políticas de Tensor también se pueden establecer directamente al construir un TensorDesc.

Por lo tanto, el diseño de los tensores producidos por DirectMLX se puede controlar estableciendo un TensorPolicy que establezca los pasos adecuados en sus tensores.

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

Ejemplo 2

DirectMLX también proporciona algunas directivas de tensor alternativas integradas. La directiva InterleavedChannel , por ejemplo, se proporciona para comodidad y se puede usar para producir tensores con zancadas tales que se escriben en orden 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(/* ... */);

Consulte también