Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
DirectMLX é uma biblioteca auxiliar somente de cabeçalho C++ para DirectML, destinada a facilitar a composição de operadores individuais em gráficos.
O DirectMLX oferece invólucros convenientes para todos os tipos de operadores DirectML (DML), bem como sobrecargas de operadores intuitivas, o que torna mais simples instanciar operadores DML e encadeá-los em gráficos complexos.
Onde encontrar DirectMLX.h
DirectMLX.h é distribuído como software de código aberto sob a licença MIT. A versão mais recente pode ser encontrada no DirectML GitHub.
Requisitos de versão
O DirectMLX requer o DirectML versão 1.4.0 ou mais recente (consulte Histórico de versões do DirectML). Não há suporte para versões mais antigas do DirectML.
DirectMLX.h requer um compilador compatível com C++11, incluindo (mas não limitado a):
- Visual Studio 2017
- Visual Studio 2019
- Clang 10
Observe que um compilador C++17 (ou mais recente) é a opção que recomendamos. A compilação para C++11 é possível, mas requer o uso de bibliotecas de terceiros (como GSL e Abseil) para substituir a funcionalidade de biblioteca padrão ausente.
Se você tiver uma configuração que não consegue compilar DirectMLX.h, registre um problema em nosso GitHub.
Utilização básica
#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
Aqui está outro exemplo, que cria um gráfico DirectML capaz de calcular a fórmula quadrá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
Mais exemplos
Exemplos completos usando DirectMLX podem ser encontrados no repositório DirectML GitHub.
Opções em tempo de compilação
O DirectMLX suporta #define em tempo de compilação para personalizar várias partes do cabeçalho.
| Opção | Descrição |
|---|---|
| DMLX_NO_EXCEPTIONS | Se #define'd, faz com que os erros resultem em uma chamada para std::abort em vez de gerar uma exceção. Isso é definido por padrão se as exceções não estiverem disponíveis (por exemplo, se as exceções tiverem sido desabilitadas nas opções do compilador). |
| DMLX_USE_WIL | Caso #define esteja definido, as exceções são lançadas utilizando os tipos de exceção da Biblioteca de Implementação do Windows. Caso contrário, tipos de exceção padrão (como std::runtime_error) são usados. Esta opção não tem efeito se DMLX_NO_EXCEPTIONS estiver definida. |
| DMLX_USE_ABSEIL | Se estiver #define'd, usa Abseil como substitutos diretos para tipos de biblioteca padrão indisponíveis em C++11. Estes tipos incluem absl::optional (em vez de std::optional), absl::Span (em vez de std::span), e absl::InlinedVector. |
| DMLX_USE_GSL | Controla se o GSL deve ser usado como substituto do std::span. Se definido com #define, os usos de std::span são substituídos por gsl::span em compiladores sem implementações nativas de std::span. Caso contrário, uma implementação drop-in inline é fornecida. Note que esta opção só é usada ao compilar em um compilador pré-C++20 sem suporte para std::span, e quando nenhuma outra substituição direta de biblioteca padrão (como Abseil) está em uso. |
Controlo da disposição do tensor
Para a maioria dos operadores, o DirectMLX calcula as propriedades dos tensores de saída do operador em seu nome. Por exemplo, ao realizar um dml::Reduce através de eixos { 0, 2, 3 } com um tensor de entrada de tamanhos { 3, 4, 5, 6 }, o DirectMLX calculará automaticamente as propriedades para o tensor de saída, incluindo a forma correta do { 1, 4, 1, 1 }.
No entanto, as outras propriedades de um tensor de saída incluem Strides, TotalTensorSizeInBytes e GuaranteedBaseOffsetAlignment. Por padrão, o DirectMLX define essas propriedades de modo que o tensor não tenha striding, nenhum alinhamento de deslocamento de base garantido e um tamanho total do tensor em bytes, conforme calculado pelo DMLCalcBufferTensorSize.
O DirectMLX suporta a capacidade de personalizar essas propriedades de tensor de saída, usando objetos conhecidos como políticas de tensores. Um TensorPolicy é um callback personalizável invocado pelo DirectMLX, que retorna as propriedades do tensor de saída, dado o tipo de dados, sinalizadores e tamanhos computados de um tensor.
As políticas de tensor podem ser definidas no objeto dml::Graph e serão usadas para todos os operadores subsequentes nesse gráfico. As políticas do Tensor também podem ser definidas diretamente ao construir um TensorDesc.
O layout dos tensores produzidos pelo DirectMLX pode, portanto, ser controlado definindo um TensorPolicy que define os saltos apropriados nos seus tensores.
Exemplo 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));
Exemplo 2
O DirectMLX também fornece algumas políticas de tensor alternativas incorporadas. A política InterleavedChannel, por exemplo, é disponibilizada para facilitar o uso e pode ser utilizada para produzir tensores com intervalos de tal forma que sejam escritos na ordem 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(/* ... */);